diff --git a/src/BizHawk.Client.EmuHawk/EmuHawkUtil.cs b/src/BizHawk.Client.EmuHawk/EmuHawkUtil.cs
index 13ccda5eb9..d67834a070 100644
--- a/src/BizHawk.Client.EmuHawk/EmuHawkUtil.cs
+++ b/src/BizHawk.Client.EmuHawk/EmuHawkUtil.cs
@@ -23,16 +23,19 @@ namespace BizHawk.Client.EmuHawk
using var link = new ShellLinkImports.ShellLink();
- const uint STGM_READ = 0;
- link.Load(filename, STGM_READ);
+ unsafe
+ {
+ const uint STGM_READ = 0;
+ ((ShellLinkImports.IPersistFile*)link)->Load(filename, STGM_READ);
#if false
- // TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files.
- link.Resolve(hwnd, 0);
+ // TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files.
+ ((ShellLinkImports.IShellLinkW*)link)->Resolve(hwnd, 0);
#endif
- link.GetPath(out var path, Win32Imports.MAX_PATH + 1, out _, 0);
- return path;
+ ((ShellLinkImports.IShellLinkW*)link)->GetPath(out var path, Win32Imports.MAX_PATH + 1, 0);
+ return path;
+ }
}
}
}
diff --git a/src/BizHawk.Common/Win32/ShellLinkImports.cs b/src/BizHawk.Common/Win32/ShellLinkImports.cs
index 1ccd6eb089..3deabfaefa 100644
--- a/src/BizHawk.Common/Win32/ShellLinkImports.cs
+++ b/src/BizHawk.Common/Win32/ShellLinkImports.cs
@@ -10,33 +10,6 @@ namespace BizHawk.Common
{
public static class ShellLinkImports
{
- [StructLayout(LayoutKind.Sequential)]
- public struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public FILETIME ftCreationTime;
- public FILETIME ftLastAccessTime;
- public FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Win32Imports.MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- // Obsolete fields
- public uint dwFileType;
- public uint dwCreatorType;
- public int wFinderFlags;
-
- public struct FILETIME
- {
- public uint dwLowDateTime;
- public uint dwHighDateTime;
- }
- }
-
/// The IShellLink interface allows Shell links to be created, modified, and resolved
[StructLayout(LayoutKind.Sequential)]
public unsafe struct IShellLinkW
@@ -72,25 +45,35 @@ namespace BizHawk.Common
}
public IShellLinkWVtbl* lpVtbl;
- }
- [StructLayout(LayoutKind.Sequential)]
- public unsafe struct IPersist
- {
- public static readonly Guid Guid = new("0000010c-0000-0000-C000-000000000046");
-
- [StructLayout(LayoutKind.Sequential)]
- public struct IPersistVtbl
+ public void GetPath(out string pszFile, int cch, uint fFlags)
{
- // IUnknown functions
- public delegate* unmanaged[Stdcall] QueryInterface;
- public delegate* unmanaged[Stdcall] AddRef;
- public delegate* unmanaged[Stdcall] Release;
- // IPersist functions
- public delegate* unmanaged[Stdcall] GetClassID;
+ fixed (IShellLinkW* _this = &this)
+ {
+ var _pszFile = Marshal.AllocCoTaskMem(cch * sizeof(char));
+ try
+ {
+ var hr = lpVtbl->GetPath(_this, _pszFile, cch, IntPtr.Zero, fFlags);
+ Marshal.ThrowExceptionForHR(hr);
+ pszFile = Marshal.PtrToStringUni(_pszFile);
+ }
+ finally
+ {
+ Marshal.FreeCoTaskMem(_pszFile);
+ }
+ }
}
- public IPersistVtbl* lpVtbl;
+#if false
+ public void Resolve(IntPtr hwnd, int fFlags)
+ {
+ fixed (IShellLinkW* _this = &this)
+ {
+ var hr = lpVtbl->Resolve(_this, hwnd, fFlags);
+ Marshal.ThrowExceptionForHR(hr);
+ }
+ }
+#endif
}
[StructLayout(LayoutKind.Sequential)]
@@ -116,12 +99,31 @@ namespace BizHawk.Common
}
public IPersistFileVtbl* lpVtbl;
+
+ public void Load(string pszFileName, uint dwMode)
+ {
+ fixed (IPersistFile* _this = &this)
+ {
+ var _pszFileName = Marshal.StringToCoTaskMemUni(pszFileName);
+ try
+ {
+ var hr = lpVtbl->Load(_this, _pszFileName, dwMode);
+ Marshal.ThrowExceptionForHR(hr);
+ }
+ finally
+ {
+ Marshal.FreeCoTaskMem(_pszFileName);
+ }
+ }
+ }
}
/// CLSID_ShellLink from ShlGuid.h
public unsafe class ShellLink : IDisposable
{
public static readonly Guid Guid = new("00021401-0000-0000-C000-000000000046");
+ public static explicit operator IShellLinkW*(ShellLink link) => link.SLI;
+ public static explicit operator IPersistFile*(ShellLink link) => link.PFI;
private IShellLinkW* SLI;
private IPersistFile* PFI;
@@ -132,7 +134,7 @@ namespace BizHawk.Common
Marshal.ThrowExceptionForHR(hr);
var sli = (IShellLinkW*)psl;
- hr = sli->lpVtbl->QueryInterface(sli, in IPersist.Guid, out var ppf);
+ hr = sli->lpVtbl->QueryInterface(sli, in IPersistFile.Guid, out var ppf);
var hrEx = Marshal.GetExceptionForHR(hr);
if (hrEx != null)
{
@@ -158,44 +160,6 @@ namespace BizHawk.Common
SLI = null;
}
}
-
- public void GetPath(out string pszFile, int cch, out WIN32_FIND_DATAW pfd, uint fFlags)
- {
- var pszFile_ = Marshal.AllocCoTaskMem(cch * sizeof(char));
-#if false // should we do this? we don't need pfd (NULL is valid), and we could delete the WIN32_FIND_DATAW definition by doing this
- var hr = SLI->lpVtbl->GetPath(SLI, pszFile_, cch, IntPtr.Zero, fFlags);
-#else
- var pfd_ = Marshal.AllocCoTaskMem(Marshal.SizeOf());
- var hr = SLI->lpVtbl->GetPath(SLI, pszFile_, cch, pfd_, fFlags);
-#endif
- try
- {
- Marshal.ThrowExceptionForHR(hr);
- pszFile = Marshal.PtrToStringUni(pszFile_);
- pfd = Marshal.PtrToStructure(pfd_);
- }
- finally
- {
- Marshal.FreeCoTaskMem(pszFile_);
- Marshal.FreeCoTaskMem(pfd_);
- }
- }
-
-#if false
- public void Resolve(IntPtr hwnd, int fFlags)
- {
- var hr = SLI->lpVtbl->Resolve(SLI, hwnd, fFlags);
- Marshal.ThrowExceptionForHR(hr);
- }
-#endif
-
- public void Load(string pszFileName, uint dwMode)
- {
- var pszFileName_ = Marshal.StringToCoTaskMemUni(pszFileName);
- var hr = PFI->lpVtbl->Load(PFI, pszFileName_, dwMode);
- Marshal.FreeCoTaskMem(pszFileName_);
- Marshal.ThrowExceptionForHR(hr);
- }
}
}
}