From 086aeab6c05f4b2ab13e6d0a8239db7d83c588b1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 27 May 2025 14:36:09 +0800 Subject: [PATCH] Use PInvoke to improve code quality --- .../NativeMethods.txt | 4 + Flow.Launcher.Infrastructure/Win32Helper.cs | 31 ++++++++ Flow.Launcher/PublicAPIInstance.cs | 76 ++++--------------- 3 files changed, 50 insertions(+), 61 deletions(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index 0e50420b0..2591506c8 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -57,3 +57,7 @@ LOCALE_TRANSIENT_KEYBOARD1 LOCALE_TRANSIENT_KEYBOARD2 LOCALE_TRANSIENT_KEYBOARD3 LOCALE_TRANSIENT_KEYBOARD4 + +SHParseDisplayName +SHOpenFolderAndSelectItems +CoTaskMemFree diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 783ade14e..4952eec98 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading; @@ -17,6 +18,7 @@ using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.Dwm; using Windows.Win32.UI.Input.KeyboardAndMouse; +using Windows.Win32.UI.Shell.Common; using Windows.Win32.UI.WindowsAndMessaging; using Point = System.Windows.Point; using SystemFonts = System.Windows.SystemFonts; @@ -753,5 +755,34 @@ namespace Flow.Launcher.Infrastructure } #endregion + + #region Explorer + + public static unsafe void OpenFolderAndSelectFile(string filePath) + { + ITEMIDLIST* pidlFolder = null; + ITEMIDLIST* pidlFile = null; + + var folderPath = Path.GetDirectoryName(filePath); + + try + { + var hrFolder = PInvoke.SHParseDisplayName(folderPath, null, out pidlFolder, 0, null); + if (hrFolder.Failed) throw new COMException("Failed to parse folder path", hrFolder); + + var hrFile = PInvoke.SHParseDisplayName(filePath, null, out pidlFile, 0, null); + if (hrFile.Failed) throw new COMException("Failed to parse file path", hrFile); + + var hrSelect = PInvoke.SHOpenFolderAndSelectItems(pidlFolder, 1, &pidlFile, 0); + if (hrSelect.Failed) throw new COMException("Failed to open folder and select item", hrSelect); + } + finally + { + if (pidlFile != null) PInvoke.CoTaskMemFree(pidlFile); + if (pidlFolder != null) PInvoke.CoTaskMemFree(pidlFolder); + } + } + + #endregion } } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 58dbd3ff0..c06c56039 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -8,11 +8,9 @@ using System.IO; using System.Linq; using System.Net; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows; -using System.Windows.Input; using System.Windows.Media; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core; @@ -320,88 +318,44 @@ namespace Flow.Launcher ((PluginJsonStorage)_pluginJsonStorages[type]).Save(); } - - [DllImport("shell32.dll", CharSet = CharSet.Unicode)] - private static extern int SHParseDisplayName( - [MarshalAs(UnmanagedType.LPWStr)] string name, - IntPtr bindingContext, - out IntPtr pidl, - uint sfgaoIn, - out uint psfgaoOut - ); - - [DllImport("shell32.dll")] - private static extern int SHOpenFolderAndSelectItems( - IntPtr pidlFolder, - uint cidl, - [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, - uint dwFlags - ); - - [DllImport("ole32.dll")] - private static extern void CoTaskMemFree(IntPtr pv); - - private void OpenFolderAndSelectItem(string filePath) - { - IntPtr pidlFolder = IntPtr.Zero; - IntPtr pidlFile = IntPtr.Zero; - uint attr; - - string folderPath = Path.GetDirectoryName(filePath); - - try - { - SHParseDisplayName(folderPath, IntPtr.Zero, out pidlFolder, 0, out attr); - SHParseDisplayName(filePath, IntPtr.Zero, out pidlFile, 0, out attr); - - if (pidlFolder != IntPtr.Zero && pidlFile != IntPtr.Zero) - { - SHOpenFolderAndSelectItems(pidlFolder, 1, new[] { pidlFile }, 0); - } - } - finally - { - if (pidlFile != IntPtr.Zero) - CoTaskMemFree(pidlFile); - if (pidlFolder != IntPtr.Zero) - CoTaskMemFree(pidlFolder); - } - } public void OpenDirectory(string directoryPath, string fileNameOrFilePath = null) { try { - string targetPath = fileNameOrFilePath is null + var explorerInfo = _settings.CustomExplorer; + var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant(); + var targetPath = fileNameOrFilePath is null ? directoryPath : Path.IsPathRooted(fileNameOrFilePath) ? fileNameOrFilePath : Path.Combine(directoryPath, fileNameOrFilePath); - var explorerInfo = _settings.CustomExplorer; - var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant(); - if (Path.GetFileNameWithoutExtension(explorerPath) == "explorer") { + // Windows File Manager if (fileNameOrFilePath is null) { - // 폴더만 열기 - Process.Start(new ProcessStartInfo + // Only Open the directory + using var explorer = new Process(); + explorer.StartInfo = new ProcessStartInfo { FileName = directoryPath, UseShellExecute = true - })?.Dispose(); + }; + explorer.Start(); } else { - // SHOpenFolderAndSelectItems 방식 - OpenFolderAndSelectItem(targetPath); + // Open the directory and select the file + Win32Helper.OpenFolderAndSelectFile(targetPath); } } else { - // 커스텀 파일 관리자 - var shellProcess = new ProcessStartInfo + // Custom File Manager + using var explorer = new Process(); + explorer.StartInfo = new ProcessStartInfo { FileName = explorerInfo.Path.Replace("%d", directoryPath), UseShellExecute = true, @@ -411,7 +365,7 @@ namespace Flow.Launcher .Replace("%d", directoryPath) .Replace("%f", targetPath) }; - Process.Start(shellProcess)?.Dispose(); + explorer.Start(); } } catch (Win32Exception ex) when (ex.NativeErrorCode == 2)