From 69d9270f847afbc165e33484a5184e12ca143844 Mon Sep 17 00:00:00 2001 From: calmripple Date: Tue, 24 Mar 2026 22:51:11 +0800 Subject: [PATCH 1/8] =?UTF-8?q?build:=20=E5=8D=87=E7=BA=A7=E5=88=B0=20.NET?= =?UTF-8?q?=2010.0,=20=E9=85=8D=E7=BD=AEvscode=E7=BC=96=E8=AF=91=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/extensions.json | 6 ++ .vscode/launch.json | 72 ++++++++++++++++ .vscode/settings.json | 15 ++++ .vscode/tasks.json | 126 ++++++++++++++++++++++++++++ SystemTrayMenu.csproj | 30 ++----- Utilities/File/FileLnk.cs | 56 ++++++++----- Utilities/FolderOptions.cs | 35 ++++++-- Utilities/GenerateDriveShortcuts.cs | 58 +++++++++++-- Utilities/Log.cs | 46 ++++++++-- Utilities/SingleAppInstance.cs | 15 ++++ azure-pipelines.yml | 4 +- 11 files changed, 397 insertions(+), 66 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..6cbde431 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..3d0eb0b7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,72 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "SystemTrayMenu: Rebuild + Debug", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "stm: rebuild Debug", + "program": "${workspaceFolder}/bin/AnyCPU/Debug/net10.0-windows10.0.22000.0/win-x64/SystemTrayMenu.exe", + "cwd": "${workspaceFolder}", + "env": { + "STM_DEBUG_ALLOW_MULTI_INSTANCE": "1" + }, + "stopAtEntry": false, + "justMyCode": true, + "console": "internalConsole", + "internalConsoleOptions": "neverOpen", + "logging": { + "moduleLoad": false, + "programOutput": true, + "exceptions": true, + "diagnosticsLog": { + "protocolMessages": false + }, + "browserStdOut": false, + "browserStdErr": false + } + }, + { + "name": "SystemTrayMenu: Build + Debug", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "stm: build Debug", + "program": "${workspaceFolder}/bin/AnyCPU/Debug/net10.0-windows10.0.22000.0/win-x64/SystemTrayMenu.exe", + "cwd": "${workspaceFolder}", + "env": { + "STM_DEBUG_ALLOW_MULTI_INSTANCE": "1" + }, + "stopAtEntry": false, + "justMyCode": true, + "console": "internalConsole", + "internalConsoleOptions": "neverOpen", + "logging": { + "moduleLoad": false, + "programOutput": true, + "exceptions": true, + "diagnosticsLog": { + "protocolMessages": false + }, + "browserStdOut": false, + "browserStdErr": false + } + }, + { + "name": "SystemTrayMenu: Attach to Process", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}", + "justMyCode": true, + "logging": { + "moduleLoad": false, + "programOutput": true, + "exceptions": true, + "diagnosticsLog": { + "protocolMessages": false + }, + "browserStdOut": false, + "browserStdErr": false + } + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..5c80982e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "dotnet.defaultSolution": "SystemTrayMenu.sln", + "debug.internalConsoleOptions": "neverOpen", + "omnisharp.enableRoslynAnalyzers": true, + "omnisharp.enableEditorConfigSupport": true, + "csharp.suppressBuildAssetsNotification": true, + "files.exclude": { + "**/bin": true, + "**/obj": true + }, + "search.exclude": { + "**/bin": true, + "**/obj": true + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..50bb85db --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,126 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "stm: stop running instances", + "type": "shell", + "command": "pwsh", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$processes = @(Get-Process -Name SystemTrayMenu -ErrorAction SilentlyContinue); foreach ($process in $processes) { Stop-Process -Id $process.Id -Force }; exit 0" + ], + "problemMatcher": [], + "presentation": { + "reveal": "never", + "panel": "shared", + "clear": false + } + }, + { + "label": "stm: restore", + "type": "shell", + "command": "dotnet", + "args": [ + "restore", + "${workspaceFolder}/SystemTrayMenu.csproj" + ], + "problemMatcher": "$msCompile", + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": true + } + }, + { + "label": "stm: clean Debug", + "type": "shell", + "command": "dotnet", + "args": [ + "clean", + "${workspaceFolder}/SystemTrayMenu.csproj", + "-c", + "Debug" + ], + "problemMatcher": "$msCompile", + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": false + } + }, + { + "label": "stm: build Debug", + "type": "shell", + "command": "dotnet", + "args": [ + "build", + "${workspaceFolder}/SystemTrayMenu.csproj", + "-c", + "Debug" + ], + "dependsOrder": "sequence", + "dependsOn": [ + "stm: stop running instances", + "stm: restore" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": "$msCompile", + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": false + } + }, + { + "label": "stm: rebuild Debug", + "type": "shell", + "command": "dotnet", + "args": [ + "build", + "${workspaceFolder}/SystemTrayMenu.csproj", + "-c", + "Debug" + ], + "dependsOrder": "sequence", + "dependsOn": [ + "stm: stop running instances", + "stm: restore", + "stm: clean Debug" + ], + "problemMatcher": "$msCompile", + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": false + } + }, + { + "label": "stm: run Debug", + "type": "shell", + "command": "pwsh", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$env:STM_DEBUG_ALLOW_MULTI_INSTANCE='1'; & \"${workspaceFolder}/bin/AnyCPU/Debug/net10.0-windows10.0.22000.0/win-x64/SystemTrayMenu.exe\"" + ], + "dependsOrder": "sequence", + "dependsOn": [ + "stm: build Debug" + ], + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": false + } + } + ] +} diff --git a/SystemTrayMenu.csproj b/SystemTrayMenu.csproj index 092f29e9..93158374 100644 --- a/SystemTrayMenu.csproj +++ b/SystemTrayMenu.csproj @@ -2,11 +2,11 @@ - - net7.0-windows10.0.22000.0 + + net10.0-windows10.0.22000.0 - win-x64 - linux-x64 + win-x64 + linux-x64 True enable true @@ -88,7 +88,7 @@ EXIT 0 - + @@ -106,24 +106,4 @@ EXIT 0 - - - {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} - 1 - 0 - 0 - tlbimp - False - True - - - {50A7E9B0-70EF-11D1-B75A-00A0C90564FE} - 1 - 0 - 0 - tlbimp - False - True - - \ No newline at end of file diff --git a/Utilities/File/FileLnk.cs b/Utilities/File/FileLnk.cs index ce84a6fd..e577c832 100644 --- a/Utilities/File/FileLnk.cs +++ b/Utilities/File/FileLnk.cs @@ -6,8 +6,9 @@ namespace SystemTrayMenu.Utilities { using System; using System.IO; + using System.Reflection; + using System.Runtime.InteropServices; using System.Threading; - using Shell32; internal class FileLnk { @@ -56,38 +57,53 @@ private static string GetShortcutFileNamePath(object shortcutFilename, out bool isFolder = false; try { - string? pathOnly = Path.GetDirectoryName((string)shortcutFilename); - string? filenameOnly = Path.GetFileName((string)shortcutFilename); - - Shell shell = new(); - Folder folder = shell.NameSpace(pathOnly); - if (folder == null) + string shortcutPath = (string)shortcutFilename; + Type? shellType = Type.GetTypeFromProgID("WScript.Shell"); + if (shellType == null) { - Log.Info($"{nameof(GetShortcutFileNamePath)} folder == null for path:'{shortcutFilename}'"); + Log.Info($"{nameof(GetShortcutFileNamePath)} WScript.Shell COM type not found for path:'{shortcutFilename}'"); return resolvedFilename; } - FolderItem folderItem = folder.ParseName(filenameOnly); - if (folderItem == null) + object shell = Activator.CreateInstance(shellType)!; + object? shortcut = shellType.InvokeMember( + "CreateShortcut", + BindingFlags.InvokeMethod, + binder: null, + target: shell, + args: new object[] { shortcutPath }); + if (shortcut == null) { - Log.Info($"{nameof(GetShortcutFileNamePath)} folderItem == null for path:'{shortcutFilename}'"); + Log.Info($"{nameof(GetShortcutFileNamePath)} CreateShortcut returned null for path:'{shortcutFilename}'"); return resolvedFilename; } - ShellLinkObject link = (ShellLinkObject)folderItem.GetLink; - isFolder = link.Target.IsFolder; - if (string.IsNullOrEmpty(link.Path)) + Type shortcutType = shortcut.GetType(); + object? targetPathObject = shortcutType.InvokeMember( + "TargetPath", + BindingFlags.GetProperty, + binder: null, + target: shortcut, + args: null); + string targetPath = targetPathObject as string ?? string.Empty; + if (!string.IsNullOrEmpty(targetPath)) { - // https://github.com/Hofknecht/SystemTrayMenu/issues/242 - // do not set CLSID key (GUID) shortcuts as resolvedFilename - if (!link.Target.Path.Contains("::{")) + // Keep previous behavior: skip virtual-shell CLSID paths. + if (!targetPath.Contains("::{", StringComparison.InvariantCulture)) { - resolvedFilename = link.Target.Path; + resolvedFilename = targetPath; + isFolder = Directory.Exists(targetPath); } } - else + + if (Marshal.IsComObject(shortcut)) + { + _ = Marshal.FinalReleaseComObject(shortcut); + } + + if (Marshal.IsComObject(shell)) { - resolvedFilename = link.Path; + _ = Marshal.FinalReleaseComObject(shell); } } catch (UnauthorizedAccessException) diff --git a/Utilities/FolderOptions.cs b/Utilities/FolderOptions.cs index 55cffd6c..d14c9f4a 100644 --- a/Utilities/FolderOptions.cs +++ b/Utilities/FolderOptions.cs @@ -8,29 +8,52 @@ namespace SystemTrayMenu.Utilities using System.IO; using System.Reflection; using System.Runtime.InteropServices; - using Shell32; internal static class FolderOptions { private static bool hideHiddenEntries; private static bool hideSystemEntries; - private static IShellDispatch4? iShellDispatch4; internal static void Initialize() { try { - iShellDispatch4 = (IShellDispatch4?)Activator.CreateInstance( - Type.GetTypeFromProgID("Shell.Application")!); + Type? shellType = Type.GetTypeFromProgID("Shell.Application"); + if (shellType == null) + { + Log.Info("Get Shell COM type failed"); + return; + } + + object shell = Activator.CreateInstance(shellType)!; // Using SHGetSetSettings would be much better in performance but the results are not accurate. // We have to go for the shell interface in order to receive the correct settings: // https://docs.microsoft.com/en-us/windows/win32/shell/ishelldispatch4-getsetting const int SSF_SHOWALLOBJECTS = 0x00000001; - hideHiddenEntries = !(iShellDispatch4?.GetSetting(SSF_SHOWALLOBJECTS) ?? false); + object? showAllObjectsObject = shellType.InvokeMember( + "GetSetting", + BindingFlags.InvokeMethod, + binder: null, + target: shell, + args: new object[] { SSF_SHOWALLOBJECTS }); + bool showAllObjects = showAllObjectsObject is bool currentShowAllObjects && currentShowAllObjects; + hideHiddenEntries = !showAllObjects; const int SSF_SHOWSUPERHIDDEN = 0x00040000; - hideSystemEntries = !(iShellDispatch4?.GetSetting(SSF_SHOWSUPERHIDDEN) ?? false); + object? showSuperHiddenObject = shellType.InvokeMember( + "GetSetting", + BindingFlags.InvokeMethod, + binder: null, + target: shell, + args: new object[] { SSF_SHOWSUPERHIDDEN }); + bool showSuperHidden = showSuperHiddenObject is bool currentShowSuperHidden && currentShowSuperHidden; + hideSystemEntries = !showSuperHidden; + + if (Marshal.IsComObject(shell)) + { + _ = Marshal.FinalReleaseComObject(shell); + } } catch (Exception ex) { diff --git a/Utilities/GenerateDriveShortcuts.cs b/Utilities/GenerateDriveShortcuts.cs index 2b5bdece..825317ef 100644 --- a/Utilities/GenerateDriveShortcuts.cs +++ b/Utilities/GenerateDriveShortcuts.cs @@ -8,7 +8,8 @@ namespace SystemTrayMenu.Utilities using System.Collections.Generic; using System.IO; using System.Linq; - using IWshRuntimeLibrary; + using System.Reflection; + using System.Runtime.InteropServices; internal class GenerateDriveShortcuts { @@ -44,14 +45,57 @@ public static void Start() private static void CreateShortcut(string linkPath, string targetPath) { - WshShell shell = new(); - IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(linkPath); - shortcut.Description = "Generated by SystemTrayMenu"; - shortcut.TargetPath = targetPath; - try { - shortcut.Save(); + Type? shellType = Type.GetTypeFromProgID("WScript.Shell"); + if (shellType == null) + { + Log.Info("CreateShortcut WScript.Shell COM type not found"); + return; + } + + object shell = Activator.CreateInstance(shellType)!; + object? shortcut = shellType.InvokeMember( + "CreateShortcut", + BindingFlags.InvokeMethod, + binder: null, + target: shell, + args: new object[] { linkPath }); + if (shortcut == null) + { + Log.Info($"CreateShortcut returned null for path:'{linkPath}'"); + return; + } + + Type shortcutType = shortcut.GetType(); + _ = shortcutType.InvokeMember( + "Description", + BindingFlags.SetProperty, + binder: null, + target: shortcut, + args: new object[] { "Generated by SystemTrayMenu" }); + _ = shortcutType.InvokeMember( + "TargetPath", + BindingFlags.SetProperty, + binder: null, + target: shortcut, + args: new object[] { targetPath }); + _ = shortcutType.InvokeMember( + "Save", + BindingFlags.InvokeMethod, + binder: null, + target: shortcut, + args: null); + + if (Marshal.IsComObject(shortcut)) + { + _ = Marshal.FinalReleaseComObject(shortcut); + } + + if (Marshal.IsComObject(shell)) + { + _ = Marshal.FinalReleaseComObject(shell); + } } catch (Exception ex) { diff --git a/Utilities/Log.cs b/Utilities/Log.cs index 406676db..bad6e179 100644 --- a/Utilities/Log.cs +++ b/Utilities/Log.cs @@ -10,10 +10,10 @@ namespace SystemTrayMenu.Utilities using System.Diagnostics; using System.IO; using System.Reflection; + using System.Runtime.InteropServices; using System.Threading; using System.Windows; using Clearcove.Logging; - using IWshRuntimeLibrary; using File = System.IO.File; internal static class Log @@ -169,16 +169,50 @@ internal static void ProcessStart( .Equals(".lnk", StringComparison.InvariantCultureIgnoreCase); if (isLink) { - WshShell shell = new(); - IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(fileName); - bool startAsAdmin = shortcut.WindowStyle == 3; - if (startAsAdmin) + Type? shellType = Type.GetTypeFromProgID("WScript.Shell"); + if (shellType != null) { - verb = "runas"; + object shell = Activator.CreateInstance(shellType)!; + object? shortcut = shellType.InvokeMember( + "CreateShortcut", + BindingFlags.InvokeMethod, + binder: null, + target: shell, + args: new object[] { fileName }); + if (shortcut == null) + { + Log.Info($"CreateShortcut returned null for path:'{fileName}'"); + goto StartProcess; + } + + Type shortcutType = shortcut.GetType(); + object? windowStyleObject = shortcutType.InvokeMember( + "WindowStyle", + BindingFlags.GetProperty, + binder: null, + target: shortcut, + args: null); + int windowStyle = windowStyleObject is int style ? style : 0; + bool startAsAdmin = windowStyle == 3; + if (startAsAdmin) + { + verb = "runas"; + } + + if (Marshal.IsComObject(shortcut)) + { + _ = Marshal.FinalReleaseComObject(shortcut); + } + + if (Marshal.IsComObject(shell)) + { + _ = Marshal.FinalReleaseComObject(shell); + } } } } + StartProcess: using Process p = new() { StartInfo = new ProcessStartInfo(fileName) diff --git a/Utilities/SingleAppInstance.cs b/Utilities/SingleAppInstance.cs index c8be514c..4727e48c 100644 --- a/Utilities/SingleAppInstance.cs +++ b/Utilities/SingleAppInstance.cs @@ -14,12 +14,19 @@ internal static class SingleAppInstance private const string IpcServiceName = nameof(SingleAppInstance); private const string IpcWakeupCmd = "wakeup"; private const string IpcWakeupResponseOK = "OK"; + private const string DebugAllowMultiInstanceEnvironmentVariable = "STM_DEBUG_ALLOW_MULTI_INSTANCE"; private static IpcPipe? ipcPipe; internal static event Action? Wakeup; internal static bool Initialize() { + if (ShouldSkipSingleInstance()) + { + Log.Info("Skip single instance check for debug session"); + return true; + } + bool success = true; try @@ -92,5 +99,13 @@ internal static void Unload() { ipcPipe?.Dispose(); } + + private static bool ShouldSkipSingleInstance() + { + string? environmentValue = Environment.GetEnvironmentVariable(DebugAllowMultiInstanceEnvironmentVariable); + return Debugger.IsAttached || + string.Equals(environmentValue, "1", StringComparison.OrdinalIgnoreCase) || + string.Equals(environmentValue, "true", StringComparison.OrdinalIgnoreCase); + } } } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 896aa60f..a96f7c31 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,7 +20,7 @@ steps: - task: UseDotNet@2 inputs: packageType: sdk - version: 6.0.x + version: 10.0.x - task: DotNetCoreCLI@2 inputs: @@ -40,7 +40,7 @@ steps: - task: ArchiveFiles@2 displayName: 'Archive $(Build.ArtifactStagingDirectory)' inputs: - rootFolderOrFile: '$(Build.SourcesDirectory)\bin\AnyCPU\Release\net6.0-windows10.0.22000.0\publish\win-x64\' + rootFolderOrFile: '$(Build.SourcesDirectory)\bin\AnyCPU\Release\net10.0-windows10.0.22000.0\publish\win-x64\' includeRootFolder: false archiveFile: '$(Build.ArtifactStagingDirectory)/SystemTrayMenu-$(AssemblyInfo.AssemblyVersion).zip' From dea1904b20ab53dc649a958ba1688e17acb88097 Mon Sep 17 00:00:00 2001 From: calmripple Date: Tue, 24 Mar 2026 23:43:29 +0800 Subject: [PATCH 2/8] =?UTF-8?q?build:=20=E8=BF=81=E7=A7=BB=E5=88=B0=20slnx?= =?UTF-8?q?=20=E8=A7=A3=E5=86=B3=E6=96=B9=E6=A1=88=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 2 +- SystemTrayMenu.csproj | 12 ++++-------- SystemTrayMenu.slnx | 30 ++++++++++++++++++++++++++++++ log-APCAPOYKIDLPMOO.txt | 2 ++ 4 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 SystemTrayMenu.slnx create mode 100644 log-APCAPOYKIDLPMOO.txt diff --git a/.vscode/settings.json b/.vscode/settings.json index 5c80982e..4980f2b7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "dotnet.defaultSolution": "SystemTrayMenu.sln", + "dotnet.defaultSolution": "SystemTrayMenu.slnx", "debug.internalConsoleOptions": "neverOpen", "omnisharp.enableRoslynAnalyzers": true, "omnisharp.enableEditorConfigSupport": true, diff --git a/SystemTrayMenu.csproj b/SystemTrayMenu.csproj index 93158374..51c6a254 100644 --- a/SystemTrayMenu.csproj +++ b/SystemTrayMenu.csproj @@ -2,12 +2,10 @@ - - net10.0-windows10.0.22000.0 + net10.0-windows10.0.22000.0 - win-x64 - linux-x64 - True + win-x64 + true enable true x64 @@ -35,7 +33,6 @@ EXIT 0 icon.png hofknecht.eu/systemtraymenu/ LICENSE - SystemTrayMenu 10.0.22000.0 README.md @@ -87,8 +84,7 @@ EXIT 0 - - + diff --git a/SystemTrayMenu.slnx b/SystemTrayMenu.slnx new file mode 100644 index 00000000..babecbdf --- /dev/null +++ b/SystemTrayMenu.slnx @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log-APCAPOYKIDLPMOO.txt b/log-APCAPOYKIDLPMOO.txt new file mode 100644 index 00000000..5a7b9768 --- /dev/null +++ b/log-APCAPOYKIDLPMOO.txt @@ -0,0 +1,2 @@ +2026/03/24 15:41:48.470 2 INFO Skip single instance check for debug session +2026/03/24 15:41:48.706 2 INFO Application Start SystemTrayMenu.dll | 2.0.0.0 | ScalingFactor=1 From 566e7147e68f61bef4cef54336c6295ae0483ad9 Mon Sep 17 00:00:00 2001 From: calmripple Date: Wed, 25 Mar 2026 00:07:20 +0800 Subject: [PATCH 3/8] =?UTF-8?q?perf:=20=E6=B7=BB=E5=8A=A0=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E5=86=85=E5=AE=B9=E7=BC=93=E5=AD=98=E4=BB=A5=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Helpers/DirectoryHelpers.cs | 82 ++++++++++++++++++++++++++++++++++--- log-APCAPOYKIDLPMOO.txt | 6 +++ 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/Helpers/DirectoryHelpers.cs b/Helpers/DirectoryHelpers.cs index c3066039..01b67132 100644 --- a/Helpers/DirectoryHelpers.cs +++ b/Helpers/DirectoryHelpers.cs @@ -7,7 +7,6 @@ namespace SystemTrayMenu.Helpers using System; using System.Collections.Generic; using System.ComponentModel; - using System.Data; using System.Diagnostics; using System.IO; using System.Linq; @@ -19,6 +18,7 @@ internal static class DirectoryHelpers internal static void DiscoverItems(BackgroundWorker? worker, string path, ref MenuData menuData) { bool isNetworkRoot = false; + Dictionary directoryContentCache = new(StringComparer.InvariantCultureIgnoreCase); try { isNetworkRoot = FileLnk.IsNetworkRoot(path); @@ -28,7 +28,7 @@ internal static void DiscoverItems(BackgroundWorker? worker, string path, ref Me } else { - DiscoverLocalDirectories(worker, path, ref menuData); + DiscoverLocalDirectories(worker, path, ref menuData, directoryContentCache); } } catch (Exception ex) @@ -50,7 +50,7 @@ internal static void DiscoverItems(BackgroundWorker? worker, string path, ref Me { foreach (var additionalPath in GetAddionalPathsForMainMenu()) { - GetDirectoriesAndFilesRecursive(ref menuData, additionalPath.Path, additionalPath.OnlyFiles, additionalPath.Recursive); + GetDirectoriesAndFilesRecursive(ref menuData, additionalPath.Path, additionalPath.OnlyFiles, additionalPath.Recursive, directoryContentCache); } } @@ -185,7 +185,11 @@ private static void DiscoverNetworkRootDirectories(string path, ref MenuData men } } - private static void DiscoverLocalDirectories(BackgroundWorker? worker, string path, ref MenuData menuData) + private static void DiscoverLocalDirectories( + BackgroundWorker? worker, + string path, + ref MenuData menuData, + Dictionary directoryContentCache) { if (!Directory.Exists(path)) { @@ -201,6 +205,11 @@ private static void DiscoverLocalDirectories(BackgroundWorker? worker, string pa return; } + if (!ShouldDisplayDirectory(directory, directoryContentCache)) + { + continue; + } + menuData.RowDatas.Add(new RowData(true, false, menuData.Level, directory)); } @@ -219,7 +228,8 @@ private static void GetDirectoriesAndFilesRecursive( ref MenuData menuData, string path, bool onlyFiles, - bool recursiv) + bool recursiv, + Dictionary directoryContentCache) { try { @@ -230,6 +240,11 @@ private static void GetDirectoriesAndFilesRecursive( foreach (string directory in Directory.GetDirectories(path)) { + if (!ShouldDisplayDirectory(directory, directoryContentCache)) + { + continue; + } + if (!onlyFiles) { menuData.RowDatas.Add(new RowData(true, true, menuData.Level, directory)); @@ -237,7 +252,7 @@ private static void GetDirectoriesAndFilesRecursive( if (recursiv) { - GetDirectoriesAndFilesRecursive(ref menuData, directory, onlyFiles, recursiv); + GetDirectoriesAndFilesRecursive(ref menuData, directory, onlyFiles, recursiv, directoryContentCache); } } } @@ -247,6 +262,61 @@ private static void GetDirectoriesAndFilesRecursive( } } + private static bool ShouldDisplayDirectory(string directoryPath, Dictionary directoryContentCache) + { + if (directoryContentCache.TryGetValue(directoryPath, out bool shouldDisplayDirectory)) + { + return shouldDisplayDirectory; + } + + shouldDisplayDirectory = HasDisplayableChildItems(directoryPath, directoryContentCache); + directoryContentCache[directoryPath] = shouldDisplayDirectory; + return shouldDisplayDirectory; + } + + private static bool HasDisplayableChildItems(string directoryPath, Dictionary directoryContentCache) + { + if (IsEntryHidden(directoryPath)) + { + directoryContentCache[directoryPath] = false; + return false; + } + + try + { + foreach (string file in GetFilesBySearchPattern(directoryPath, Config.SearchPattern)) + { + if (!IsEntryHidden(file)) + { + directoryContentCache[directoryPath] = true; + return true; + } + } + + foreach (string childDirectory in Directory.GetDirectories(directoryPath)) + { + if (ShouldDisplayDirectory(childDirectory, directoryContentCache)) + { + directoryContentCache[directoryPath] = true; + return true; + } + } + } + catch (Exception ex) + { + Log.Warn($"HasDisplayableChildItems path:'{directoryPath}'", ex); + } + + directoryContentCache[directoryPath] = false; + return false; + } + + private static bool IsEntryHidden(string path) + { + FolderOptions.ReadHiddenAttributes(path, out _, out bool isDirectoryToHide); + return isDirectoryToHide; + } + private static List GetFilesBySearchPattern(string path, string searchPatternCombined) { string[] searchPatterns = searchPatternCombined.Split('|'); diff --git a/log-APCAPOYKIDLPMOO.txt b/log-APCAPOYKIDLPMOO.txt index 5a7b9768..46457ecb 100644 --- a/log-APCAPOYKIDLPMOO.txt +++ b/log-APCAPOYKIDLPMOO.txt @@ -1,2 +1,8 @@ 2026/03/24 15:41:48.470 2 INFO Skip single instance check for debug session 2026/03/24 15:41:48.706 2 INFO Application Start SystemTrayMenu.dll | 2.0.0.0 | ScalingFactor=1 +2026/03/24 16:05:45.295 2 INFO Skip single instance check for debug session +2026/03/24 16:05:45.474 2 INFO Application Start SystemTrayMenu.dll | 2.0.0.0 | ScalingFactor=1 +2026/03/24 16:06:20.464 2 INFO Restart by 'ByConfigChange' +2026/03/24 16:06:20.949 2 INFO Skip single instance check for debug session +2026/03/24 16:06:21.057 2 INFO Application Start SystemTrayMenu.dll | 2.0.0.0 | ScalingFactor=1 +2026/03/24 16:07:09.375 2 INFO Hotkey registration cannot unregister key Control, Windows with modifiers Control, Windows From b29034128207fd0f87a4b812d0373a177a66754d Mon Sep 17 00:00:00 2001 From: calmripple Date: Wed, 25 Mar 2026 00:22:47 +0800 Subject: [PATCH 4/8] fix: update CI build workflow to use dotnet CLI --- .github/workflows/dotnet-build.yml | 35 ++++++++++++++ .github/workflows/dotnet-release.yml | 66 +++++++++++++++++++++++++++ .github/workflows/dotnetframework.yml | 16 ------- Packaging/Package.appxmanifest | 2 +- Properties/AssemblyInfo.cs | 4 +- SystemTrayMenu.csproj | 2 +- 6 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/dotnet-build.yml create mode 100644 .github/workflows/dotnet-release.yml delete mode 100644 .github/workflows/dotnetframework.yml diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml new file mode 100644 index 00000000..8fc03e6e --- /dev/null +++ b/.github/workflows/dotnet-build.yml @@ -0,0 +1,35 @@ +name: Dotnet Build + +on: + push: + branches: + - '**' + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + env: + BUILD_CONFIGURATION: Release + SDK_VERSION: 10.0.201 + steps: + - name: Checkout repository + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git init + git remote add origin "https://x-access-token:${env:GITHUB_TOKEN}@github.com/${env:GITHUB_REPOSITORY}.git" + git fetch --depth=1 origin "${env:GITHUB_SHA}" + git checkout --force FETCH_HEAD + - name: Install .NET SDK + shell: pwsh + run: | + $installScript = Join-Path $env:RUNNER_TEMP "dotnet-install.ps1" + Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile $installScript + & $installScript -Version "${env:SDK_VERSION}" -InstallDir "$env:RUNNER_TEMP\dotnet" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\dotnet" + - name: Restore + run: dotnet restore SystemTrayMenu.csproj + - name: Build + run: dotnet build SystemTrayMenu.csproj -c ${{ env.BUILD_CONFIGURATION }} --no-restore diff --git a/.github/workflows/dotnet-release.yml b/.github/workflows/dotnet-release.yml new file mode 100644 index 00000000..cd83573d --- /dev/null +++ b/.github/workflows/dotnet-release.yml @@ -0,0 +1,66 @@ +name: Dotnet Release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + runs-on: windows-latest + env: + BUILD_CONFIGURATION: Release + SDK_VERSION: 10.0.201 + OUTPUT_DIR: bin\AnyCPU\Release\net10.0-windows10.0.22000.0\win-x64 + steps: + - name: Checkout repository + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git init + git remote add origin "https://x-access-token:${env:GITHUB_TOKEN}@github.com/${env:GITHUB_REPOSITORY}.git" + git fetch --depth=1 origin "${env:GITHUB_SHA}" + git checkout --force FETCH_HEAD + - name: Install .NET SDK + shell: pwsh + run: | + $installScript = Join-Path $env:RUNNER_TEMP "dotnet-install.ps1" + Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile $installScript + & $installScript -Version "${env:SDK_VERSION}" -InstallDir "$env:RUNNER_TEMP\dotnet" + Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\dotnet" + - name: Restore + run: dotnet restore SystemTrayMenu.csproj + - name: Build + run: dotnet build SystemTrayMenu.csproj -c ${{ env.BUILD_CONFIGURATION }} --no-restore + - name: Create release archive + shell: pwsh + run: | + $archiveName = "SystemTrayMenu-${env:GITHUB_REF_NAME}-win-x64.zip" + $archivePath = Join-Path $env:RUNNER_TEMP $archiveName + if (Test-Path $archivePath) + { + Remove-Item $archivePath -Force + } + + Compress-Archive -Path "${env:OUTPUT_DIR}\*" -DestinationPath $archivePath + Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_ASSET_PATH=$archivePath" + Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_ASSET_NAME=$archiveName" + - name: Publish GitHub Release + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release view "${env:GITHUB_REF_NAME}" --repo "${env:GITHUB_REPOSITORY}" *> $null + if ($LASTEXITCODE -eq 0) + { + gh release upload "${env:GITHUB_REF_NAME}" "${env:RELEASE_ASSET_PATH}#${env:RELEASE_ASSET_NAME}" --repo "${env:GITHUB_REPOSITORY}" --clobber + } + else + { + gh release create "${env:GITHUB_REF_NAME}" "${env:RELEASE_ASSET_PATH}#${env:RELEASE_ASSET_NAME}" --repo "${env:GITHUB_REPOSITORY}" --generate-notes + } diff --git a/.github/workflows/dotnetframework.yml b/.github/workflows/dotnetframework.yml deleted file mode 100644 index 0a316f58..00000000 --- a/.github/workflows/dotnetframework.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: NetFramework - -on: [push] -jobs: - build: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Setup Nuget.exe - uses: nuget/setup-nuget@v1 - - name: Nuget Restore - run: nuget restore SystemTrayMenu.sln - - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v1 - - name: Build with MSBuild - run: msbuild SystemTrayMenu.sln -p:Configuration=Release diff --git a/Packaging/Package.appxmanifest b/Packaging/Package.appxmanifest index b6dc1c68..20254cb2 100644 --- a/Packaging/Package.appxmanifest +++ b/Packaging/Package.appxmanifest @@ -10,7 +10,7 @@ + Version="3.0.0.0" /> SystemTrayMenu diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index fafdd92a..25df4616 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -39,5 +39,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.0.0.0")] +[assembly: AssemblyVersion("3.0.0.0")] +[assembly: AssemblyFileVersion("3.0.0.0")] diff --git a/SystemTrayMenu.csproj b/SystemTrayMenu.csproj index 51c6a254..597ef1ef 100644 --- a/SystemTrayMenu.csproj +++ b/SystemTrayMenu.csproj @@ -24,7 +24,7 @@ false true 0 - 1.0.0.%2a + 3.0.0.%2a true false taskkill /f /fi "pid gt 0" /im SystemTrayMenu.exe >nul From 2039e8f3062cfd8ee5395a16bba49e7ea4557c37 Mon Sep 17 00:00:00 2001 From: calmripple Date: Thu, 26 Mar 2026 16:00:59 +0800 Subject: [PATCH 5/8] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=20VS=20Code=20?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E4=BB=BB=E5=8A=A1=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 2 +- .vscode/tasks.json | 114 ++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 68 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3d0eb0b7..bdaaa3e4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "SystemTrayMenu: Rebuild + Debug", "type": "coreclr", "request": "launch", - "preLaunchTask": "stm: rebuild Debug", + "preLaunchTask": "stm: build Debug", "program": "${workspaceFolder}/bin/AnyCPU/Debug/net10.0-windows10.0.22000.0/win-x64/SystemTrayMenu.exe", "cwd": "${workspaceFolder}", "env": { diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 50bb85db..7572ac65 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,12 +12,7 @@ "-Command", "$processes = @(Get-Process -Name SystemTrayMenu -ErrorAction SilentlyContinue); foreach ($process in $processes) { Stop-Process -Id $process.Id -Force }; exit 0" ], - "problemMatcher": [], - "presentation": { - "reveal": "never", - "panel": "shared", - "clear": false - } + "problemMatcher": [] }, { "label": "stm: restore", @@ -27,29 +22,7 @@ "restore", "${workspaceFolder}/SystemTrayMenu.csproj" ], - "problemMatcher": "$msCompile", - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": true - } - }, - { - "label": "stm: clean Debug", - "type": "shell", - "command": "dotnet", - "args": [ - "clean", - "${workspaceFolder}/SystemTrayMenu.csproj", - "-c", - "Debug" - ], - "problemMatcher": "$msCompile", - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": false - } + "problemMatcher": "$msCompile" }, { "label": "stm: build Debug", @@ -70,57 +43,64 @@ "kind": "build", "isDefault": true }, - "problemMatcher": "$msCompile", - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": false - } + "problemMatcher": "$msCompile" }, { - "label": "stm: rebuild Debug", + "label": "stm: watch run (Hot Reload)", "type": "shell", - "command": "dotnet", + "command": "pwsh", "args": [ - "build", - "${workspaceFolder}/SystemTrayMenu.csproj", - "-c", - "Debug" + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$env:STM_DEBUG_ALLOW_MULTI_INSTANCE='1'; dotnet watch --project \"${workspaceFolder}/SystemTrayMenu.csproj\" run -c Debug" ], "dependsOrder": "sequence", "dependsOn": [ "stm: stop running instances", - "stm: restore", - "stm: clean Debug" + "stm: restore" ], - "problemMatcher": "$msCompile", - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": false - } + "isBackground": true, + "group": "none", + "problemMatcher": [ + { + "owner": "dotnet-watch", + "fileLocation": "absolute", + "pattern": [ + { + "regexp": "^(.*)\\((\\d+),(\\d+)\\):\\s*(error|warning)\\s*([A-Z]+\\d+):\\s*(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "code": 5, + "message": 6 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": ".*dotnet watch.*", + "endsPattern": ".*(Hot reload enabled|Watching for file changes).*" + } + } + ] }, { - "label": "stm: run Debug", + "label": "stm: watch test", "type": "shell", - "command": "pwsh", + "command": "dotnet", "args": [ - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-Command", - "$env:STM_DEBUG_ALLOW_MULTI_INSTANCE='1'; & \"${workspaceFolder}/bin/AnyCPU/Debug/net10.0-windows10.0.22000.0/win-x64/SystemTrayMenu.exe\"" - ], - "dependsOrder": "sequence", - "dependsOn": [ - "stm: build Debug" + "watch", + "--project", + "${workspaceFolder}/SystemTrayMenu.csproj", + "test", + "-c", + "Debug" ], - "problemMatcher": [], - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": false - } + "isBackground": true, + "group": "test", + "problemMatcher": "$msCompile" } ] -} +} \ No newline at end of file From 0f5cef455bb14a279715d2e8647f39a464ab5855 Mon Sep 17 00:00:00 2001 From: calmripple Date: Sat, 28 Mar 2026 00:54:00 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E6=8F=90=E5=8D=87=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E6=80=A7=E4=B8=8E=E5=85=BC=E5=AE=B9=E6=80=A7=EF=BC=8C=E6=B8=85?= =?UTF-8?q?=E7=90=86=E6=97=A0=E7=94=A8=E4=BE=9D=E8=B5=96=E5=92=8C=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IpcPipe 使用 ReadExactly 保证读取完整数据,提升数据读取安全性 - JsonParser 用 RuntimeHelpers.GetUninitializedObject 替换 FormatterServices,增强兼容性 - 修复 Menu.xaml.cs 粘贴操作可能的空引用异常 - ShellContextMenu 调整 QueryInterface 参数为 in,适配新版 .NET - 移除不再需要的 NuGet 分析器依赖和无用文件/目录引用 # --- Business/IpcPipe.cs | 2 +- Helpers/Updater/JsonParser.cs | 3 ++- Packaging/Packaging.wapproj | 2 -- SystemTrayMenu.csproj | 4 ---- UserInterface/Menu.xaml.cs | 2 +- UserInterface/ShellContextMenu.cs | 4 ++-- 6 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Business/IpcPipe.cs b/Business/IpcPipe.cs index 9e51d459..d9060aa3 100644 --- a/Business/IpcPipe.cs +++ b/Business/IpcPipe.cs @@ -141,7 +141,7 @@ internal string ReadString() // Receive message byte[] inBuffer = new byte[len]; - ioStream.Read(inBuffer, 0, len); + ioStream.ReadExactly(inBuffer, 0, len); return streamEncoding.GetString(inBuffer); } diff --git a/Helpers/Updater/JsonParser.cs b/Helpers/Updater/JsonParser.cs index 3e169740..e0147b2a 100644 --- a/Helpers/Updater/JsonParser.cs +++ b/Helpers/Updater/JsonParser.cs @@ -29,6 +29,7 @@ namespace SystemTrayMenu.Helpers.Updater using System.Collections; using System.Collections.Generic; using System.Reflection; + using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; @@ -450,7 +451,7 @@ private static Dictionary CreateMemberNameDictionary(T[] members) private static object ParseObject(Type type, string json) { - object instance = FormatterServices.GetUninitializedObject(type); + object instance = RuntimeHelpers.GetUninitializedObject(type); // The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON List elems = Split(json); diff --git a/Packaging/Packaging.wapproj b/Packaging/Packaging.wapproj index 379eaa07..0a110e8c 100644 --- a/Packaging/Packaging.wapproj +++ b/Packaging/Packaging.wapproj @@ -69,7 +69,6 @@ Designer - @@ -125,7 +124,6 @@ - \ No newline at end of file diff --git a/SystemTrayMenu.csproj b/SystemTrayMenu.csproj index 597ef1ef..c5995260 100644 --- a/SystemTrayMenu.csproj +++ b/SystemTrayMenu.csproj @@ -87,10 +87,6 @@ EXIT 0 - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - all diff --git a/UserInterface/Menu.xaml.cs b/UserInterface/Menu.xaml.cs index f23b95be..af99de2c 100644 --- a/UserInterface/Menu.xaml.cs +++ b/UserInterface/Menu.xaml.cs @@ -169,7 +169,7 @@ internal Menu(RowData? rowDataParent, string path) { if (Clipboard.ContainsText(TextDataFormat.Text)) { - textBoxSearch.SelectedText = Clipboard.GetData(DataFormats.Text).ToString(); + textBoxSearch.SelectedText = Clipboard.GetData(DataFormats.Text)?.ToString() ?? string.Empty; } }), }); diff --git a/UserInterface/ShellContextMenu.cs b/UserInterface/ShellContextMenu.cs index 50cd6291..7cef67c0 100644 --- a/UserInterface/ShellContextMenu.cs +++ b/UserInterface/ShellContextMenu.cs @@ -796,8 +796,8 @@ public void ShowContextMenu(Point pointScreen) CmdFirst, CmdLast, CMF.EXPLORE | CMF.NORMAL | ((Keyboard.Modifiers & ModifierKeys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0)); - Marshal.QueryInterface(iContextMenuPtr, ref iidIContextMenu2, out iContextMenuPtr2); - Marshal.QueryInterface(iContextMenuPtr, ref iidIContextMenu3, out iContextMenuPtr3); + Marshal.QueryInterface(iContextMenuPtr, in iidIContextMenu2, out iContextMenuPtr2); + Marshal.QueryInterface(iContextMenuPtr, in iidIContextMenu3, out iContextMenuPtr3); oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2)); oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3)); From 9902cd0383bee6585c2bdb7a9b5f6b819445b1fd Mon Sep 17 00:00:00 2001 From: calmripple Date: Sat, 28 Mar 2026 01:09:34 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E4=BC=98=E5=8C=96=20Packaging.wapproj=20?= =?UTF-8?q?=E6=89=93=E5=8C=85=E9=85=8D=E7=BD=AE=E5=8F=8A=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除 GenerateAppInstallerFile 配置,新增 NoWarn 忽略 NU1701 警告。为 AnyCPU 平台指定 PlatformTarget 为 x64,并在项目引用中强制使用 x64 平台。将目标框架调整为 net10.0-windows10.0.22000.0,SkipGetTargetFrameworkProperties 设为 true,清理多目标构建相关注释,提升打包兼容性与构建体验。 --- Packaging/Packaging.wapproj | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Packaging/Packaging.wapproj b/Packaging/Packaging.wapproj index 0a110e8c..876be721 100644 --- a/Packaging/Packaging.wapproj +++ b/Packaging/Packaging.wapproj @@ -52,19 +52,22 @@ en-US false ..\SystemTrayMenu.csproj - False True True x86|x64 https://github.com/Hofknecht/SystemTrayMenu/releases 0 Always + $(NoWarn);NU1701 + + + x64 - - - + Platform=x64 + TargetFramework=net10.0-windows10.0.22000.0 + true Designer From 0daaf9fb66bcb2ec5cd8c3eee2f0ba9d41071873 Mon Sep 17 00:00:00 2001 From: calmripple Date: Sat, 28 Mar 2026 01:16:00 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E4=B8=BB=E8=A6=81NuGet?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E5=8C=85=E8=87=B3=E6=9C=80=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 升级了 H.NotifyIcon 至 2.4.1,HidSharp 至 2.6.4,PixiEditor.ColorPicker 至 3.4.2.2,以获得新特性和修复已知问题。 --- SystemTrayMenu.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SystemTrayMenu.csproj b/SystemTrayMenu.csproj index c5995260..e01711da 100644 --- a/SystemTrayMenu.csproj +++ b/SystemTrayMenu.csproj @@ -85,9 +85,9 @@ EXIT 0 - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive