mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Replace DllImport & flags with CSWin32
This commit is contained in:
parent
ca01b25a39
commit
313f86b648
4 changed files with 82 additions and 133 deletions
|
|
@ -52,6 +52,10 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="NativeMethods.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||
|
|
@ -61,6 +65,10 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ini-parser" Version="2.5.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
10
Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt
Normal file
10
Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
SHGetLocalizedName
|
||||
LoadString
|
||||
LoadLibraryEx
|
||||
FreeLibrary
|
||||
ExpandEnvironmentStrings
|
||||
S_OK
|
||||
SLGP_FLAGS
|
||||
WIN32_FIND_DATAW
|
||||
SLR_FLAGS
|
||||
IShellLinkW
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>Retrieves the path and file name of a Shell link object</summary>
|
||||
void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, ref WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
|
||||
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
|
||||
void GetIDList(out IntPtr ppidl);
|
||||
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
|
||||
void SetIDList(IntPtr pidl);
|
||||
/// <summary>Retrieves the description string for a Shell link object</summary>
|
||||
void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
||||
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
|
||||
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
|
||||
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
|
||||
void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
||||
/// <summary>Sets the name of the working directory for a Shell link object</summary>
|
||||
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
|
||||
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
|
||||
void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
||||
/// <summary>Sets the command-line arguments for a Shell link object</summary>
|
||||
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
|
||||
/// <summary>Retrieves the hot key for a Shell link object</summary>
|
||||
void GetHotkey(out short pwHotkey);
|
||||
/// <summary>Sets a hot key for a Shell link object</summary>
|
||||
void SetHotkey(short wHotkey);
|
||||
/// <summary>Retrieves the show command for a Shell link object</summary>
|
||||
void GetShowCmd(out int piShowCmd);
|
||||
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
|
||||
void SetShowCmd(int iShowCmd);
|
||||
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
|
||||
void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
|
||||
int cchIconPath, out int piIcon);
|
||||
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
|
||||
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
||||
/// <summary>Sets the relative path to the Shell link object</summary>
|
||||
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
||||
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
|
||||
void Resolve(ref Accessibility._RemotableHandle hwnd, SLR_FLAGS fFlags);
|
||||
/// <summary>Sets the path and file name of a Shell link object</summary>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
|||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the localized name of a shell item.
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the shell item (e. g. shortcut 'File Explorer.lnk').</param>
|
||||
/// <returns>The localized name as string or <see cref="string.Empty"/>.</returns>
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue