Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:

jobs:
build:
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
tags:
- "v*"
workflow_dispatch:

permissions:
contents: write
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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#
Expand Down
21 changes: 21 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
9 changes: 9 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"dotnet.defaultSolution": "ContextMenuProfiler.sln",
"files.watcherExclude": {
"**/wpfui-repo/**": true,
"**/ContextMenuManager-repo/**": true
},
"omnisharp.path": "latest",
"omnisharp.useModernNet": true
}
49 changes: 49 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
16 changes: 0 additions & 16 deletions BenchmarkSuite1/BenchmarkSuite1.csproj

This file was deleted.

15 changes: 0 additions & 15 deletions BenchmarkSuite1/PackageScannerBenchmark.cs

This file was deleted.

12 changes: 0 additions & 12 deletions BenchmarkSuite1/Program.cs

This file was deleted.

13 changes: 7 additions & 6 deletions ContextMenuProfiler.UI/Converters/IconToImageConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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);
}
}
}
11 changes: 9 additions & 2 deletions ContextMenuProfiler.UI/Core/ExtensionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions ContextMenuProfiler.UI/Core/Helpers/SmoothScrollingHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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))
{
Expand Down Expand Up @@ -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;
Expand Down
27 changes: 14 additions & 13 deletions ContextMenuProfiler.UI/Core/PackageScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static IEnumerable<BenchmarkResult> ScanPackagedExtensions(string? target

private static void ProcessPackage(Package package, List<BenchmarkResult> 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");
Expand Down Expand Up @@ -83,15 +83,15 @@ 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;

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);
Expand All @@ -101,19 +101,19 @@ private static void ProcessExtensionElement(Package package, XElement extElement
}

private static bool TryParseVerb(Package package, XElement verb, Dictionary<Guid, string> 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;

Expand All @@ -135,12 +135,13 @@ private static bool TryParseVerb(Package package, XElement verb, Dictionary<Guid
return true;
}

private static string ResolveBestLogo(Package package, XDocument doc, string installPath)
private static string? ResolveBestLogo(Package package, XDocument? doc, string installPath)
{
try
{
if (doc == null) return null;
// 1. 尝试从 XML 提取相对路径
string relativeLogo = ExtractRelativeLogoFromManifest(doc);
string? relativeLogo = ExtractRelativeLogoFromManifest(doc);
if (string.IsNullOrEmpty(relativeLogo)) return null;

// 2. 统一返回 ms-appx 协议,让 Converter 的智能逻辑去处理缩放和稀疏包路径
Expand All @@ -150,7 +151,7 @@ private static string ResolveBestLogo(Package package, XDocument doc, string ins
catch { return null; }
}

private static string ExtractRelativeLogoFromManifest(XDocument doc)
private static string? ExtractRelativeLogoFromManifest(XDocument doc)
{
var visualElements = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "VisualElements");
if (visualElements != null)
Expand All @@ -170,8 +171,8 @@ private static Dictionary<Guid, string> 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;
Expand Down Expand Up @@ -221,4 +222,4 @@ private static bool IsTypeMatch(string type, string targetExt)
catch { return null; }
}
}
}
}
Loading