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));
+ }
}
}