From 313f86b6485e6f32f1d23e58fcd09692ae322e8c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 10 Dec 2024 15:09:06 +0800 Subject: [PATCH] Replace DllImport & flags with CSWin32 --- .../Flow.Launcher.Plugin.Program.csproj | 8 ++ .../NativeMethods.txt | 10 ++ .../Programs/ShellLinkHelper.cs | 130 +++++------------- .../Programs/ShellLocalization.cs | 67 +++++---- 4 files changed, 82 insertions(+), 133 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index c0ad63cfe..99c1a12e9 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -52,6 +52,10 @@ PreserveNewest + + + + @@ -61,6 +65,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt b/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt new file mode 100644 index 000000000..ecd547dff --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt @@ -0,0 +1,10 @@ +SHGetLocalizedName +LoadString +LoadLibraryEx +FreeLibrary +ExpandEnvironmentStrings +S_OK +SLGP_FLAGS +WIN32_FIND_DATAW +SLR_FLAGS +IShellLinkW \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index 78c66d604..fae9c84c9 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -1,97 +1,17 @@ using System; -using System.Text; using System.Runtime.InteropServices; -using Accessibility; using System.Runtime.InteropServices.ComTypes; using Flow.Launcher.Plugin.Program.Logger; +using Windows.Win32.Foundation; +using Windows.Win32.UI.Shell; +using Windows.Win32.Storage.FileSystem; namespace Flow.Launcher.Plugin.Program.Programs { class ShellLinkHelper { - [Flags()] - public enum SLGP_FLAGS - { - SLGP_SHORTPATH = 0x1, - SLGP_UNCPRIORITY = 0x2, - SLGP_RAWPATH = 0x4 - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct WIN32_FIND_DATAW - { - public uint dwFileAttributes; - public long ftCreationTime; - public long ftLastAccessTime; - public long ftLastWriteTime; - public uint nFileSizeHigh; - public uint nFileSizeLow; - public uint dwReserved0; - public uint dwReserved1; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string cFileName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public string cAlternateFileName; - } - - [Flags()] - public enum SLR_FLAGS - { - SLR_NO_UI = 0x1, - SLR_ANY_MATCH = 0x2, - SLR_UPDATE = 0x4, - SLR_NOUPDATE = 0x8, - SLR_NOSEARCH = 0x10, - SLR_NOTRACK = 0x20, - SLR_NOLINKINFO = 0x40, - SLR_INVOKE_MSI = 0x80 - } - - + // Reference : http://www.pinvoke.net/default.aspx/Interfaces.IShellLinkW - /// The IShellLink interface allows Shell links to be created, modified, and resolved - [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")] - interface IShellLinkW - { - /// Retrieves the path and file name of a Shell link object - void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, ref WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags); - /// Retrieves the list of item identifiers for a Shell link object - void GetIDList(out IntPtr ppidl); - /// Sets the pointer to an item identifier list (PIDL) for a Shell link object. - void SetIDList(IntPtr pidl); - /// Retrieves the description string for a Shell link object - void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); - /// Sets the description for a Shell link object. The description can be any application-defined string - void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); - /// Retrieves the name of the working directory for a Shell link object - void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); - /// Sets the name of the working directory for a Shell link object - void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); - /// Retrieves the command-line arguments associated with a Shell link object - void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); - /// Sets the command-line arguments for a Shell link object - void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - /// Retrieves the hot key for a Shell link object - void GetHotkey(out short pwHotkey); - /// Sets a hot key for a Shell link object - void SetHotkey(short wHotkey); - /// Retrieves the show command for a Shell link object - void GetShowCmd(out int piShowCmd); - /// Sets the show command for a Shell link object. The show command sets the initial show state of the window. - void SetShowCmd(int iShowCmd); - /// Retrieves the location (path and index) of the icon for a Shell link object - void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, - int cchIconPath, out int piIcon); - /// Sets the location (path and index) of the icon for a Shell link object - void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); - /// Sets the relative path to the Shell link object - void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); - /// Attempts to find the target of a Shell link, even if it has been moved or renamed - void Resolve(ref Accessibility._RemotableHandle hwnd, SLR_FLAGS fFlags); - /// Sets the path and file name of a Shell link object - void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); - } - [ComImport(), Guid("00021401-0000-0000-C000-000000000046")] public class ShellLink { @@ -102,29 +22,40 @@ namespace Flow.Launcher.Plugin.Program.Programs public string arguments = string.Empty; // Retrieve the target path using Shell Link - public string retrieveTargetPath(string path) + public unsafe string retrieveTargetPath(string path) { var link = new ShellLink(); const int STGM_READ = 0; ((IPersistFile)link).Load(path, STGM_READ); - var hwnd = new _RemotableHandle(); - ((IShellLinkW)link).Resolve(ref hwnd, 0); + var hwnd = new HWND(IntPtr.Zero); + ((IShellLinkW)link).Resolve(hwnd, 0); const int MAX_PATH = 260; - StringBuilder buffer = new StringBuilder(MAX_PATH); + char[] buffer = new char[MAX_PATH]; var data = new WIN32_FIND_DATAW(); - ((IShellLinkW)link).GetPath(buffer, buffer.Capacity, ref data, SLGP_FLAGS.SLGP_SHORTPATH); - var target = buffer.ToString(); + var target = string.Empty; + fixed (char* bufferChar = buffer) + { + ((IShellLinkW)link).GetPath((PWSTR)bufferChar, MAX_PATH, &data, (uint)SLGP_FLAGS.SLGP_SHORTPATH); + int validLength = Array.IndexOf(buffer, '\0'); + if (validLength < 0) validLength = MAX_PATH; + target = new string(buffer, 0, validLength); + } // To set the app description - if (!String.IsNullOrEmpty(target)) + if (!string.IsNullOrEmpty(target)) { try { - buffer = new StringBuilder(MAX_PATH); - ((IShellLinkW)link).GetDescription(buffer, MAX_PATH); - description = buffer.ToString(); + char[] buffer1 = new char[MAX_PATH]; + fixed (char* buffer1Char = buffer1) + { + ((IShellLinkW)link).GetDescription((PWSTR)buffer1Char, MAX_PATH); + int validLength = Array.IndexOf(buffer1, '\0'); + if (validLength < 0) validLength = MAX_PATH; + description = new string(buffer1, 0, validLength); + } } catch (COMException e) { @@ -134,9 +65,14 @@ namespace Flow.Launcher.Plugin.Program.Programs e); } - buffer.Clear(); - ((IShellLinkW)link).GetArguments(buffer, MAX_PATH); - arguments = buffer.ToString(); + char[] buffer2 = new char[MAX_PATH]; + fixed (char* buffer2Char = buffer2) + { + ((IShellLinkW)link).GetArguments((PWSTR)buffer2Char, MAX_PATH); + int validLength = Array.IndexOf(buffer2, '\0'); + if (validLength < 0) validLength = MAX_PATH; + arguments = new string(buffer2, 0, validLength); + } } // To release unmanaged memory diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs index 4f344d89e..e36618b0d 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs @@ -1,8 +1,8 @@ using System; using System.IO; -using System.Runtime.InteropServices; -using System.Text; - +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.System.LibraryLoader; namespace Flow.Launcher.Plugin.Program.Programs { @@ -13,51 +13,46 @@ namespace Flow.Launcher.Plugin.Program.Programs /// public static class ShellLocalization { - internal const uint DONTRESOLVEDLLREFERENCES = 0x00000001; - internal const uint LOADLIBRARYASDATAFILE = 0x00000002; - - [DllImport("shell32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] - internal static extern int SHGetLocalizedName(string pszPath, StringBuilder pszResModule, ref int cch, out int pidsRes); - - [DllImport("user32.dll", EntryPoint = "LoadStringW", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] - internal static extern int LoadString(IntPtr hModule, int resourceID, StringBuilder resourceValue, int len); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadLibraryExW")] - internal static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); - - [DllImport("kernel32.dll", ExactSpelling = true)] - internal static extern int FreeLibrary(IntPtr hModule); - - [DllImport("kernel32.dll", EntryPoint = "ExpandEnvironmentStringsW", CharSet = CharSet.Unicode, ExactSpelling = true)] - internal static extern uint ExpandEnvironmentStrings(string lpSrc, StringBuilder lpDst, int nSize); - /// /// Returns the localized name of a shell item. /// /// Path to the shell item (e. g. shortcut 'File Explorer.lnk'). /// The localized name as string or . - public static string GetLocalizedName(string path) + public static unsafe string GetLocalizedName(string path) { - StringBuilder resourcePath = new StringBuilder(1024); - StringBuilder localizedName = new StringBuilder(1024); - int len, id; - len = resourcePath.Capacity; + int capacity = 1024; + char[] resourcePathBuffer = new char[capacity]; // If there is no resource to localize a file name the method returns a non zero value. - if (SHGetLocalizedName(path, resourcePath, ref len, out id) == 0) + fixed (char* resourcePath = resourcePathBuffer) { - _ = ExpandEnvironmentStrings(resourcePath.ToString(), resourcePath, resourcePath.Capacity); - IntPtr hMod = LoadLibraryEx(resourcePath.ToString(), IntPtr.Zero, DONTRESOLVEDLLREFERENCES | LOADLIBRARYASDATAFILE); - if (hMod != IntPtr.Zero) + var result = PInvoke.SHGetLocalizedName(path, (PWSTR)resourcePath, (uint)capacity, out var id); + if (result == HRESULT.S_OK) { - if (LoadString(hMod, id, localizedName, localizedName.Capacity) != 0) + int validLength = Array.IndexOf(resourcePathBuffer, '\0'); + if (validLength < 0) validLength = capacity; + var resourcePathStr = new string(resourcePathBuffer, 0, validLength); + _ = PInvoke.ExpandEnvironmentStrings(resourcePathStr, resourcePath, (uint)capacity); + var handle = PInvoke.LoadLibraryEx(resourcePathStr, + LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE); + IntPtr safeHandle = handle.DangerousGetHandle(); + if (safeHandle != IntPtr.Zero) { - string lString = localizedName.ToString(); - _ = FreeLibrary(hMod); - return lString; - } + char[] localizedNameBuffer = new char[capacity]; + fixed (char* localizedName = localizedNameBuffer) + { + if (PInvoke.LoadString(handle, (uint)id, (PWSTR)localizedName, capacity) != 0) + { + validLength = Array.IndexOf(localizedNameBuffer, '\0'); + if (validLength < 0) validLength = capacity; + var lString = new string(localizedNameBuffer, 0, validLength); + PInvoke.FreeLibrary(new(safeHandle)); + return lString; + } + } - _ = FreeLibrary(hMod); + PInvoke.FreeLibrary(new(safeHandle)); + } } }