From c8c82e1a43991f1258878a1224f48142c2738fce Mon Sep 17 00:00:00 2001
From: Haerbin23456 <60066765+Haerbin23456@users.noreply.github.com>
Date: Thu, 5 Mar 2026 16:20:17 +0800
Subject: [PATCH 1/2] chore: unify build setup and clean warnings
---
.github/workflows/build.yml | 4 +-
.gitignore | 8 +--
.vscode/launch.json | 21 ++++++
.vscode/settings.json | 9 +++
.vscode/tasks.json | 49 ++++++++++++++
BenchmarkSuite1/BenchmarkSuite1.csproj | 16 -----
BenchmarkSuite1/PackageScannerBenchmark.cs | 15 -----
BenchmarkSuite1/Program.cs | 12 ----
.../Converters/IconToImageConverter.cs | 13 ++--
.../Core/ExtensionManager.cs | 11 ++-
.../Core/Helpers/SmoothScrollingHelper.cs | 7 +-
ContextMenuProfiler.UI/Core/PackageScanner.cs | 27 ++++----
.../Core/RegistryScanner.cs | 8 +--
.../Core/Services/LogService.cs | 2 +-
ContextMenuProfiler.UI/MainWindow.xaml.cs | 2 +-
.../ViewModels/DashboardViewModel.cs | 6 +-
ContextMenuProfiler.sln | 14 ----
scripts/build_hook.bat | 67 +++++++++++++------
scripts/redeploy.bat | 11 +++
19 files changed, 184 insertions(+), 118 deletions(-)
create mode 100644 .vscode/launch.json
create mode 100644 .vscode/settings.json
create mode 100644 .vscode/tasks.json
delete mode 100644 BenchmarkSuite1/BenchmarkSuite1.csproj
delete mode 100644 BenchmarkSuite1/PackageScannerBenchmark.cs
delete mode 100644 BenchmarkSuite1/Program.cs
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4688591..e5c094a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -22,8 +22,8 @@ jobs:
with:
dotnet-version: 8.0.x
- - name: Build WPF UI
- run: dotnet build ContextMenuProfiler.UI\ContextMenuProfiler.UI.csproj -c Release
+ - name: Build Solution
+ run: dotnet build ContextMenuProfiler.sln -c Release
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
diff --git a/.gitignore b/.gitignore
index e184b8f..ed864d2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,10 +16,10 @@ crash_log.txt
*.ilk
# VS Code
-.vscode/
-! .vscode/launch.json
-! .vscode/tasks.json
-! .vscode/settings.json
+.vscode/*
+!.vscode/launch.json
+!.vscode/tasks.json
+!.vscode/settings.json
.trae/
# .NET / C#
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..0b36e72
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,21 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "ContextMenuProfiler.UI",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/ContextMenuProfiler.UI/bin/Debug/net8.0-windows10.0.19041.0/ContextMenuProfiler.UI.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/ContextMenuProfiler.UI",
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach"
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..d7cad5e
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,9 @@
+{
+ "dotnet.defaultSolution": "ContextMenuProfiler.sln",
+ "files.watcherExclude": {
+ "**/wpfui-repo/**": true,
+ "**/ContextMenuManager-repo/**": true
+ },
+ "omnisharp.path": "latest",
+ "omnisharp.useModernNet": true
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..95984c3
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,49 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/ContextMenuProfiler.sln",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary;ForceNoAlign"
+ ],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ }
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/ContextMenuProfiler.UI/ContextMenuProfiler.UI.csproj",
+ "-c",
+ "Release",
+ "-r",
+ "win-x64",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary;ForceNoAlign"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/ContextMenuProfiler.UI/ContextMenuProfiler.UI.csproj"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
diff --git a/BenchmarkSuite1/BenchmarkSuite1.csproj b/BenchmarkSuite1/BenchmarkSuite1.csproj
deleted file mode 100644
index 46e05c2..0000000
--- a/BenchmarkSuite1/BenchmarkSuite1.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- net8.0-windows10.0.19041.0
- Exe
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BenchmarkSuite1/PackageScannerBenchmark.cs b/BenchmarkSuite1/PackageScannerBenchmark.cs
deleted file mode 100644
index 909ded4..0000000
--- a/BenchmarkSuite1/PackageScannerBenchmark.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using BenchmarkDotNet.Attributes;
-using ContextMenuProfiler.UI.Core;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.VSDiagnostics;
-
-[CPUUsageDiagnoser]
-public class PackageScannerBenchmark
-{
- [Benchmark]
- public List ScanPackagedExtensions()
- {
- return PackageScanner.ScanPackagedExtensions(null).ToList();
- }
-}
\ No newline at end of file
diff --git a/BenchmarkSuite1/Program.cs b/BenchmarkSuite1/Program.cs
deleted file mode 100644
index 68e2fdd..0000000
--- a/BenchmarkSuite1/Program.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using BenchmarkDotNet.Running;
-
-namespace BenchmarkSuite1
-{
- internal class Program
- {
- static void Main(string[] args)
- {
- var _ = BenchmarkRunner.Run(typeof(Program).Assembly);
- }
- }
-}
diff --git a/ContextMenuProfiler.UI/Converters/IconToImageConverter.cs b/ContextMenuProfiler.UI/Converters/IconToImageConverter.cs
index afb1445..202260d 100644
--- a/ContextMenuProfiler.UI/Converters/IconToImageConverter.cs
+++ b/ContextMenuProfiler.UI/Converters/IconToImageConverter.cs
@@ -88,7 +88,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
{
string? path = value as string;
- if (string.IsNullOrEmpty(path) || path == "NONE") return null;
+ if (string.IsNullOrEmpty(path) || path == "NONE") return DependencyProperty.UnsetValue;
if (_iconCache.TryGetValue(path, out var cached)) return cached;
@@ -102,9 +102,9 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
{
_iconCache.TryAdd(path, result);
}
- return result;
+ return result ?? DependencyProperty.UnsetValue;
}
- catch { return null; }
+ catch { return DependencyProperty.UnsetValue; }
}
private ImageSource? InnerConvert(string path)
@@ -114,8 +114,9 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
// Handle ms-appx:// URIs (UWP resources)
if (path.StartsWith("ms-appx://"))
{
- path = ResolveMsAppxUri(path);
- if (string.IsNullOrEmpty(path)) return null;
+ var resolvedPath = ResolveMsAppxUri(path);
+ if (string.IsNullOrEmpty(resolvedPath)) return null;
+ path = resolvedPath;
}
// Expand environment variables
@@ -224,4 +225,4 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
[DllImport("user32.dll", EntryPoint = "DestroyIcon", SetLastError = true)]
private static extern int DestroyIcon(IntPtr hIcon);
}
-}
\ No newline at end of file
+}
diff --git a/ContextMenuProfiler.UI/Core/ExtensionManager.cs b/ContextMenuProfiler.UI/Core/ExtensionManager.cs
index eed5c37..79954f0 100644
--- a/ContextMenuProfiler.UI/Core/ExtensionManager.cs
+++ b/ContextMenuProfiler.UI/Core/ExtensionManager.cs
@@ -160,7 +160,11 @@ private static void CopyRegistryKey(RegistryKey source, RegistryKey dest)
// Copy values
foreach (var valueName in source.GetValueNames())
{
- dest.SetValue(valueName, source.GetValue(valueName), source.GetValueKind(valueName));
+ var value = source.GetValue(valueName);
+ if (value != null)
+ {
+ dest.SetValue(valueName, value, source.GetValueKind(valueName));
+ }
}
// Copy subkeys
@@ -169,7 +173,10 @@ private static void CopyRegistryKey(RegistryKey source, RegistryKey dest)
using (var srcSub = source.OpenSubKey(subKeyName))
using (var destSub = dest.CreateSubKey(subKeyName))
{
- CopyRegistryKey(srcSub, destSub);
+ if (srcSub != null && destSub != null)
+ {
+ CopyRegistryKey(srcSub, destSub);
+ }
}
}
}
diff --git a/ContextMenuProfiler.UI/Core/Helpers/SmoothScrollingHelper.cs b/ContextMenuProfiler.UI/Core/Helpers/SmoothScrollingHelper.cs
index 5788a7a..caf0868 100644
--- a/ContextMenuProfiler.UI/Core/Helpers/SmoothScrollingHelper.cs
+++ b/ContextMenuProfiler.UI/Core/Helpers/SmoothScrollingHelper.cs
@@ -25,7 +25,7 @@ private static void OnIsSmoothScrollingEnabledChanged(DependencyObject d, Depend
}
}
- private static void Element_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
+ private static void Element_PreviewMouseWheel(object? sender, MouseWheelEventArgs e)
{
var uiElement = sender as UIElement;
var scrollViewer = FindParentScrollViewer(uiElement);
@@ -38,8 +38,9 @@ private static void Element_PreviewMouseWheel(object sender, MouseWheelEventArgs
GetSmoother(scrollViewer).DoScroll(e.Delta);
}
- private static ScrollViewer FindParentScrollViewer(DependencyObject child)
+ private static ScrollViewer? FindParentScrollViewer(DependencyObject? child)
{
+ if (child == null) return null;
var parent = VisualTreeHelper.GetParent(child);
while (parent != null && !(parent is ScrollViewer))
{
@@ -89,7 +90,7 @@ public void DoScroll(int delta)
}
}
- private void OnRendering(object sender, EventArgs e)
+ private void OnRendering(object? sender, EventArgs e)
{
double current = _sv.VerticalOffset;
double diff = _targetOffset - current;
diff --git a/ContextMenuProfiler.UI/Core/PackageScanner.cs b/ContextMenuProfiler.UI/Core/PackageScanner.cs
index 516b1d7..c57d65a 100644
--- a/ContextMenuProfiler.UI/Core/PackageScanner.cs
+++ b/ContextMenuProfiler.UI/Core/PackageScanner.cs
@@ -48,7 +48,7 @@ public static IEnumerable ScanPackagedExtensions(string? target
private static void ProcessPackage(Package package, List results, string targetExt, bool scanAll)
{
- string installPath = package.InstalledLocation?.Path;
+ string? installPath = package.InstalledLocation?.Path;
if (string.IsNullOrEmpty(installPath)) return;
string manifestPath = Path.Combine(installPath, "AppxManifest.xml");
@@ -83,7 +83,7 @@ private static void ProcessExtensionElement(Package package, XElement extElement
foreach (var itemType in itemTypes)
{
- string type = itemType.Attribute("Type")?.Value?.ToLower();
+ string? type = itemType.Attribute("Type")?.Value?.ToLower();
if (string.IsNullOrEmpty(type)) continue;
if (!scanAll && !IsTypeMatch(type, targetExt)) continue;
@@ -91,7 +91,7 @@ private static void ProcessExtensionElement(Package package, XElement extElement
var verbs = itemType.Descendants().Where(e => e.Name.LocalName == "Verb");
foreach (var verb in verbs)
{
- if (TryParseVerb(package, verb, clsidToPath, installPath, out var result))
+ if (TryParseVerb(package, verb, clsidToPath, installPath, out var result) && result != null)
{
if (!results.Any(r => r.Clsid == result.Clsid))
results.Add(result);
@@ -101,19 +101,19 @@ private static void ProcessExtensionElement(Package package, XElement extElement
}
private static bool TryParseVerb(Package package, XElement verb, Dictionary clsidToPath,
- string installPath, out BenchmarkResult result)
+ string installPath, out BenchmarkResult? result)
{
result = null;
- string clsidStr = verb.Attribute("Clsid")?.Value;
+ string? clsidStr = verb.Attribute("Clsid")?.Value;
if (!Guid.TryParse(clsidStr, out Guid clsid)) return false;
string name = package.DisplayName;
if (string.IsNullOrEmpty(name)) name = package.Id.Name;
- string verbId = verb.Attribute("Id")?.Value;
+ string? verbId = verb.Attribute("Id")?.Value;
if (!string.IsNullOrEmpty(verbId)) name += $" ({verbId})";
- string logoPath = ResolveBestLogo(package, verb.Document, installPath);
+ string? logoPath = ResolveBestLogo(package, verb.Document, installPath);
string binaryPath = clsidToPath.TryGetValue(clsid, out var relPath) ?
ResolveBinaryPath(installPath, relPath) : installPath;
@@ -135,12 +135,13 @@ private static bool TryParseVerb(Package package, XElement verb, Dictionary e.Name.LocalName == "VisualElements");
if (visualElements != null)
@@ -170,8 +171,8 @@ private static Dictionary MapClsidToBinaryPath(XDocument doc, stri
foreach (var cls in classes)
{
- string idStr = cls.Attribute("Id")?.Value;
- string path = cls.Attribute("Path")?.Value;
+ string? idStr = cls.Attribute("Id")?.Value;
+ string? path = cls.Attribute("Path")?.Value;
if (Guid.TryParse(idStr, out Guid guid) && !string.IsNullOrEmpty(path))
{
map[guid] = path;
@@ -221,4 +222,4 @@ private static bool IsTypeMatch(string type, string targetExt)
catch { return null; }
}
}
-}
\ No newline at end of file
+}
diff --git a/ContextMenuProfiler.UI/Core/RegistryScanner.cs b/ContextMenuProfiler.UI/Core/RegistryScanner.cs
index 9de0049..5cd3138 100644
--- a/ContextMenuProfiler.UI/Core/RegistryScanner.cs
+++ b/ContextMenuProfiler.UI/Core/RegistryScanner.cs
@@ -70,7 +70,7 @@ public static Dictionary> ScanHandlers(ScanMode
ScanLocation(handlers, $"SystemFileAssociations\\{keyName}\\shellex\\-ContextMenuHandlers", $"Extension ({keyName}) [Disabled]");
// Get ProgID
- string progId = GetProgID(keyName);
+ string? progId = GetProgID(keyName);
if (!string.IsNullOrEmpty(progId))
{
ScanLocation(handlers, $"{progId}\\shellex\\ContextMenuHandlers", $"ProgID ({progId} for {keyName})");
@@ -109,7 +109,7 @@ private static void ScanLocation(ConcurrentDictionary> verb
if (string.IsNullOrEmpty(command)) continue;
// Get Display Name (MUIVerb > Default)
- string displayName = verbKey.GetValue("MUIVerb") as string;
+ string? displayName = verbKey.GetValue("MUIVerb") as string;
if (string.IsNullOrEmpty(displayName))
{
displayName = verbKey.GetValue("") as string; // Default value
diff --git a/ContextMenuProfiler.UI/Core/Services/LogService.cs b/ContextMenuProfiler.UI/Core/Services/LogService.cs
index 5bc84c0..8c748d2 100644
--- a/ContextMenuProfiler.UI/Core/Services/LogService.cs
+++ b/ContextMenuProfiler.UI/Core/Services/LogService.cs
@@ -16,7 +16,7 @@ private LogService()
try
{
var dir = Path.GetDirectoryName(LogFile);
- if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
+ if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
}
catch { /* Best effort */ }
}
diff --git a/ContextMenuProfiler.UI/MainWindow.xaml.cs b/ContextMenuProfiler.UI/MainWindow.xaml.cs
index 203615c..ed5a6bf 100644
--- a/ContextMenuProfiler.UI/MainWindow.xaml.cs
+++ b/ContextMenuProfiler.UI/MainWindow.xaml.cs
@@ -130,7 +130,7 @@ private void Window_DragOver(object sender, DragEventArgs e)
}
}
- private T FindChild(DependencyObject parent) where T : DependencyObject
+ private T? FindChild(DependencyObject? parent) where T : DependencyObject
{
if (parent == null) return null;
diff --git a/ContextMenuProfiler.UI/ViewModels/DashboardViewModel.cs b/ContextMenuProfiler.UI/ViewModels/DashboardViewModel.cs
index 578c914..2eb5c6c 100644
--- a/ContextMenuProfiler.UI/ViewModels/DashboardViewModel.cs
+++ b/ContextMenuProfiler.UI/ViewModels/DashboardViewModel.cs
@@ -447,7 +447,7 @@ private async Task ScanFile(string filePath)
{
var results = await Task.Run(() =>
{
- List threadResult = null;
+ List? threadResult = null;
var thread = new Thread(() =>
{
try
@@ -462,10 +462,10 @@ private async Task ScanFile(string filePath)
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
- return threadResult;
+ return threadResult ?? new List();
});
- if (results != null)
+ if (results.Count > 0)
{
// Use InsertSorted logic for consistency and performance
foreach (var res in results.OrderByDescending(r => r.TotalTime))
diff --git a/ContextMenuProfiler.sln b/ContextMenuProfiler.sln
index 154b532..b88bf9f 100644
--- a/ContextMenuProfiler.sln
+++ b/ContextMenuProfiler.sln
@@ -4,8 +4,6 @@ VisualStudioVersion = 18.3.11520.95 d18.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContextMenuProfiler.UI", "ContextMenuProfiler.UI\ContextMenuProfiler.UI.csproj", "{AE0FB575-F9F7-4FA5-BACF-E007199E47E4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkSuite1", "BenchmarkSuite1\BenchmarkSuite1.csproj", "{A20861A9-411E-6150-BF5C-69E8196E5D22}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -28,18 +26,6 @@ Global
{AE0FB575-F9F7-4FA5-BACF-E007199E47E4}.Release|x64.Build.0 = Release|Any CPU
{AE0FB575-F9F7-4FA5-BACF-E007199E47E4}.Release|x86.ActiveCfg = Release|Any CPU
{AE0FB575-F9F7-4FA5-BACF-E007199E47E4}.Release|x86.Build.0 = Release|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|x64.ActiveCfg = Debug|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|x64.Build.0 = Debug|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|x86.Build.0 = Debug|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|Any CPU.Build.0 = Release|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|x64.ActiveCfg = Release|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|x64.Build.0 = Release|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|x86.ActiveCfg = Release|Any CPU
- {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/scripts/build_hook.bat b/scripts/build_hook.bat
index 2f692e2..d579c78 100644
--- a/scripts/build_hook.bat
+++ b/scripts/build_hook.bat
@@ -1,4 +1,5 @@
@echo off
+setlocal EnableExtensions
cd /d "%~dp0.."
echo Building ContextMenuProfiler.Hook (x64) - Modularized...
@@ -7,39 +8,48 @@ set "OBJ_DIR=%BUILD_DIR%\obj"
if not exist "%BUILD_DIR%" mkdir "%BUILD_DIR%"
if not exist "%OBJ_DIR%" mkdir "%OBJ_DIR%"
-:: Check if cl.exe is already in the path and configured for x64
-:: We use 'where' which is more stable in both CMD and PowerShell
-where cl >nul 2>nul
-if %ERRORLEVEL% EQU 0 (
- cl 2>&1 | findstr /i "x64" >nul
- if %ERRORLEVEL% EQU 0 (
- echo Environment already configured for x64, skipping vcvars64.bat
- goto :compile
- )
+if /I "%VSCMD_ARG_TGT_ARCH%"=="x64" (
+ echo Environment already configured for x64, skipping vcvars64.bat
+ goto :compile
)
:: Try to find VS path using vswhere
-for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath`) do set "VS_PATH=%%i"
+set "VS_PATH="
+set "VSWHERE_EXE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
+if exist "%VSWHERE_EXE%" (
+ for /f "usebackq tokens=*" %%i in (`"%VSWHERE_EXE%" -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_PATH=%%i"
+)
-if not exist "%VS_PATH%" (
- :: Fallback to common paths
- set "VS_PATH=C:\Program Files\Microsoft Visual Studio\2022\Community"
+if not defined VS_PATH (
+ for %%E in (Community Professional Enterprise BuildTools) do (
+ if exist "C:\Program Files\Microsoft Visual Studio\2022\%%E\VC\Auxiliary\Build\vcvars64.bat" set "VS_PATH=C:\Program Files\Microsoft Visual Studio\2022\%%E"
+ )
)
-if not exist "%VS_PATH%" (
- echo Error: Visual Studio not found. Please install VS 2022 or higher, or edit build_hook.bat to set VS_PATH.
+if not defined VS_PATH (
+ echo Error: Visual Studio C++ build tools not found.
+ echo Hint: Install VS 2022 with Desktop development with C++ workload.
exit /b 1
)
+if not exist "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat" (
+ echo Error: vcvars64.bat not found in "%VS_PATH%".
+ exit /b 1
+)
echo Using VS Path: %VS_PATH%
-if exist "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat" (
- call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat"
-) else (
- echo Error: vcvars64.bat not found in %VS_PATH%
+call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat" >nul 2>&1
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: Failed to initialize VC++ x64 environment.
exit /b 1
)
:compile
+where cl >nul 2>nul
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: cl.exe not found after environment initialization.
+ exit /b 1
+)
+
:: Build Hook DLL
cl /LD /MT /Zi /EHsc /utf-8 /Fo"%OBJ_DIR%\\" /Fd"%BUILD_DIR%\\vc140.pdb" ^
ContextMenuProfiler.Hook\src\dllmain.cpp ^
@@ -54,18 +64,31 @@ cl /LD /MT /Zi /EHsc /utf-8 /Fo"%OBJ_DIR%\\" /Fd"%BUILD_DIR%\\vc140.pdb" ^
ContextMenuProfiler.Hook\src\hde\hde64.c ^
/I ContextMenuProfiler.Hook\include ^
/link /DLL /DEBUG /OUT:"%BUILD_DIR%\\ContextMenuProfiler.Hook.dll" /PDB:"%BUILD_DIR%\\ContextMenuProfiler.Hook.pdb" /IMPLIB:"%BUILD_DIR%\\ContextMenuProfiler.Hook.lib" user32.lib ole32.lib shell32.lib shlwapi.lib advapi32.lib gdiplus.lib comctl32.lib gdi32.lib
-if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: Hook DLL build failed.
+ exit /b %ERRORLEVEL%
+)
echo Building Injector...
cl /MT /Zi /EHsc /utf-8 /Fo"%OBJ_DIR%\\" /Fd"%BUILD_DIR%\\vc140.pdb" ^
ContextMenuProfiler.Hook\src\injector.cpp ^
/I ContextMenuProfiler.Hook\include ^
/link /DEBUG /OUT:"%BUILD_DIR%\\ContextMenuProfiler.Injector.exe" /PDB:"%BUILD_DIR%\\ContextMenuProfiler.Injector.pdb" user32.lib kernel32.lib advapi32.lib
-if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: Injector build failed.
+ exit /b %ERRORLEVEL%
+)
copy /Y "%BUILD_DIR%\ContextMenuProfiler.Hook.dll" "ContextMenuProfiler.Hook.dll" >nul
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: Failed to copy ContextMenuProfiler.Hook.dll
+ exit /b 1
+)
copy /Y "%BUILD_DIR%\ContextMenuProfiler.Injector.exe" "ContextMenuProfiler.Injector.exe" >nul
-if %ERRORLEVEL% NEQ 0 exit /b 1
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: Failed to copy ContextMenuProfiler.Injector.exe
+ exit /b 1
+)
echo Done.
exit /b 0
diff --git a/scripts/redeploy.bat b/scripts/redeploy.bat
index ba75581..0014de5 100644
--- a/scripts/redeploy.bat
+++ b/scripts/redeploy.bat
@@ -30,9 +30,20 @@ echo Waiting for Explorer to initialize...
timeout /t 8 /nobreak >nul
echo Injecting DLL...
+if not exist ContextMenuProfiler.Injector.exe (
+ echo Injection FAILED: ContextMenuProfiler.Injector.exe not found.
+ echo Hint: Run scripts\build_hook.bat and verify output files.
+ exit /b 1
+)
+if not exist ContextMenuProfiler.Hook.dll (
+ echo Injection FAILED: ContextMenuProfiler.Hook.dll not found.
+ echo Hint: Run scripts\build_hook.bat and verify output files.
+ exit /b 1
+)
ContextMenuProfiler.Injector.exe ContextMenuProfiler.Hook.dll
if %ERRORLEVEL% NEQ 0 (
echo Injection FAILED.
+ echo Hint: Re-run as Administrator and ensure Explorer is running.
exit /b 1
)
From 210a27ffb5019cbcba241962a2c8a47781c84762 Mon Sep 17 00:00:00 2001
From: Haerbin23456 <60066765+Haerbin23456@users.noreply.github.com>
Date: Thu, 5 Mar 2026 16:50:15 +0800
Subject: [PATCH 2/2] ci: enable manual workflow triggers and guard release
step
---
.github/workflows/build.yml | 2 +-
.github/workflows/release.yml | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e5c094a..78c54a5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -4,7 +4,7 @@ on:
push:
branches: [ "main" ]
pull_request:
- branches: [ "main" ]
+ workflow_dispatch:
jobs:
build:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index bc8c69e..9fb5a11 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -4,6 +4,7 @@ on:
push:
tags:
- "v*"
+ workflow_dispatch:
permissions:
contents: write
@@ -55,6 +56,7 @@ jobs:
if (!(Test-Path "artifacts/ContextMenuProfiler-win-x64-self-contained.zip")) { throw "self-contained zip missing" }
- name: Create GitHub Release
+ if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
draft: false