diff --git a/src/BizHawk.Client.EmuHawk/CustomControls/FolderBrowserDialogEx.cs b/src/BizHawk.Client.EmuHawk/CustomControls/FolderBrowserDialogEx.cs
index f20d40ddab..47e5bb2855 100644
--- a/src/BizHawk.Client.EmuHawk/CustomControls/FolderBrowserDialogEx.cs
+++ b/src/BizHawk.Client.EmuHawk/CustomControls/FolderBrowserDialogEx.cs
@@ -6,7 +6,7 @@ using System.Windows.Forms;
 
 using BizHawk.Common;
 
-using static BizHawk.Common.ShlobjImports;
+using static BizHawk.Common.Shell32Imports;
 
 namespace BizHawk.Client.EmuHawk
 {
diff --git a/src/BizHawk.Common/Win32/ShlobjImports.cs b/src/BizHawk.Common/Win32/Shell32Imports.cs
similarity index 77%
rename from src/BizHawk.Common/Win32/ShlobjImports.cs
rename to src/BizHawk.Common/Win32/Shell32Imports.cs
index cb830714ff..a80c493d90 100644
--- a/src/BizHawk.Common/Win32/ShlobjImports.cs
+++ b/src/BizHawk.Common/Win32/Shell32Imports.cs
@@ -2,14 +2,13 @@
 
 using System;
 using System.Runtime.InteropServices;
-using System.Text;
 
 // ReSharper disable FieldCanBeMadeReadOnly.Global
 // ReSharper disable UnusedMember.Global
 
 namespace BizHawk.Common
 {
-	public static class ShlobjImports
+	public static class Shell32Imports
 	{
 		public const int BFFM_INITIALIZED = 1;
 		public const int BFFM_SETSELECTIONW = 0x400 + 103;
@@ -63,5 +62,18 @@ namespace BizHawk.Common
 
 		[DllImport("shell32.dll", ExactSpelling = true)]
 		public static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, int nFolder, out IntPtr ppidl);
+
+		[DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
+		public static extern int SHCreateItemFromParsingName(
+			[In] string pszPath,
+			[In] IntPtr pbc,
+			[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
+			out IntPtr ppv);
+
+		[DllImport("shell32.dll", ExactSpelling = true)]
+		public static extern int SHGetIDListFromObject(IntPtr punk, out IntPtr ppidl);
+
+		[DllImport("shell32.dll", EntryPoint = "#16")]
+		public static extern IntPtr ILFindLastID(IntPtr pidl);
 	}
 }
diff --git a/src/BizHawk.Common/Win32/ShellLinkImports.cs b/src/BizHawk.Common/Win32/ShellLinkImports.cs
index 3deabfaefa..2e0502d155 100644
--- a/src/BizHawk.Common/Win32/ShellLinkImports.cs
+++ b/src/BizHawk.Common/Win32/ShellLinkImports.cs
@@ -1,6 +1,7 @@
 #nullable disable
 
 using System;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 // ReSharper disable FieldCanBeMadeReadOnly.Global
@@ -48,30 +49,24 @@ namespace BizHawk.Common
 
 			public void GetPath(out string pszFile, int cch, uint fFlags)
 			{
-				fixed (IShellLinkW* _this = &this)
+				var _pszFile = Marshal.AllocCoTaskMem(cch * sizeof(char));
+				try
 				{
-					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);
-					}
+					var hr = lpVtbl->GetPath((IShellLinkW*)Unsafe.AsPointer(ref this), _pszFile, cch, IntPtr.Zero, fFlags);
+					Marshal.ThrowExceptionForHR(hr);
+					pszFile = Marshal.PtrToStringUni(_pszFile);
+				}
+				finally
+				{
+					Marshal.FreeCoTaskMem(_pszFile);
 				}
 			}
 
 #if false
 			public void Resolve(IntPtr hwnd, int fFlags)
 			{
-				fixed (IShellLinkW* _this = &this)
-				{
-					var hr = lpVtbl->Resolve(_this, hwnd, fFlags);
-					Marshal.ThrowExceptionForHR(hr);
-				}
+				var hr = lpVtbl->Resolve((IShellLinkW*)Unsafe.AsPointer(ref this), hwnd, fFlags);
+				Marshal.ThrowExceptionForHR(hr);
 			}
 #endif
 		}
@@ -102,18 +97,15 @@ namespace BizHawk.Common
 
 			public void Load(string pszFileName, uint dwMode)
 			{
-				fixed (IPersistFile* _this = &this)
+				var _pszFileName = Marshal.StringToCoTaskMemUni(pszFileName);
+				try
 				{
-					var _pszFileName = Marshal.StringToCoTaskMemUni(pszFileName);
-					try
-					{
-						var hr = lpVtbl->Load(_this, _pszFileName, dwMode);
-						Marshal.ThrowExceptionForHR(hr);
-					}
-					finally
-					{
-						Marshal.FreeCoTaskMem(_pszFileName);
-					}
+					var hr = lpVtbl->Load((IPersistFile*)Unsafe.AsPointer(ref this), _pszFileName, dwMode);
+					Marshal.ThrowExceptionForHR(hr);
+				}
+				finally
+				{
+					Marshal.FreeCoTaskMem(_pszFileName);
 				}
 			}
 		}
diff --git a/src/BizHawk.Common/Win32/Win32Imports.cs b/src/BizHawk.Common/Win32/Win32Imports.cs
index 351bd5d707..980f43702c 100644
--- a/src/BizHawk.Common/Win32/Win32Imports.cs
+++ b/src/BizHawk.Common/Win32/Win32Imports.cs
@@ -1,8 +1,12 @@
 #nullable disable
 
+using System;
 using System.IO;
 using System.Runtime.InteropServices;
-using System.Text;
+
+// ReSharper disable UnusedMember.Global
+
+#pragma warning disable CA1069 // This warning is just dumb
 
 namespace BizHawk.Common
 {
@@ -13,9 +17,40 @@ namespace BizHawk.Common
 	{
 		public const int MAX_PATH = 260;
 
+		[Flags]
+		public enum TPM
+		{
+			LEFTBUTTON = 0x0000,
+			RIGHTBUTTON = 0x0002,
+			LEFTALIGN = 0x0000,
+			CENTERALIGN = 0x000,
+			RIGHTALIGN = 0x000,
+			TOPALIGN = 0x0000,
+			VCENTERALIGN = 0x0010,
+			BOTTOMALIGN = 0x0020,
+			HORIZONTAL = 0x0000,
+			VERTICAL = 0x0040,
+			NONOTIFY = 0x0080,
+			RETURNCMD = 0x0100,
+			RECURSE = 0x0001,
+			HORPOSANIMATION = 0x0400,
+			HORNEGANIMATION = 0x0800,
+			VERPOSANIMATION = 0x1000,
+			VERNEGANIMATION = 0x2000,
+			NOANIMATION = 0x4000,
+			LAYOUTRTL = 0x8000,
+		}
+
+		[DllImport("user32.dll", ExactSpelling = true)]
+		public static extern IntPtr CreatePopupMenu();
+
 		[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
 		public static extern bool DeleteFileW(string lpFileName);
 
+		[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public static extern bool DestroyMenu(IntPtr hMenu);
+
 		[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
 		public static extern uint MapVirtualKeyW(uint uCode, uint uMapType);
 
@@ -27,5 +62,8 @@ namespace BizHawk.Common
 
 		[DllImport("winmm.dll", ExactSpelling = true)]
 		public static extern uint timeBeginPeriod(uint uMilliseconds);
+
+		[DllImport("user32.dll", ExactSpelling = true)]
+		public static extern int TrackPopupMenuEx(IntPtr hmenu, TPM fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);
 	}
-}
+}
\ No newline at end of file
diff --git a/src/BizHawk.Common/Win32/Win32ShellContextMenu.cs b/src/BizHawk.Common/Win32/Win32ShellContextMenu.cs
index d879ffa638..fb4e4fbb29 100644
--- a/src/BizHawk.Common/Win32/Win32ShellContextMenu.cs
+++ b/src/BizHawk.Common/Win32/Win32ShellContextMenu.cs
@@ -1,246 +1,169 @@
 using System;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
-using System.Text;
 
-// ReSharper disable FieldCanBeMadeReadOnly.Global
-// ReSharper disable UnusedMember.Global
+// ReSharper disable UnusedMember.Local
 
 namespace BizHawk.Common
 {
-	public class Win32ShellContextMenu
+	public unsafe class Win32ShellContextMenu : IDisposable
 	{
-		[ComImport]
-		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-		[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
-		public interface IShellItem
+		[StructLayout(LayoutKind.Sequential)]
+		private struct IShellItem
 		{
-			IntPtr BindToHandler(IntPtr pbc,
-				[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
-				[MarshalAs(UnmanagedType.LPStruct)] Guid riid);
+			public static readonly Guid Guid = new("43826d1e-e718-42ee-bc55-a1e261c37bfe");
 
-			[PreserveSig]
-			int GetParent(out IShellItem ppsi);
-
-			IntPtr GetDisplayName(uint sigdnName);
-
-			uint GetAttributes(uint sfgaoMask);
-
-			int Compare(IShellItem psi, uint hint);
-		}
-
-
-		[ComImport]
-		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-		[Guid("000214F2-0000-0000-C000-000000000046")]
-		public interface IEnumIDList
-		{
-			[PreserveSig]
-			int Next(uint celt, out IntPtr rgelt, out uint pceltFetched);
-
-			[PreserveSig]
-			int Skip(uint celt);
-
-			[PreserveSig]
-			int Reset();
-
-			IEnumIDList Clone();
-		}
-
-		[ComImport]
-		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-		[Guid("000214E6-0000-0000-C000-000000000046")]
-		public interface IShellFolder
-		{
-			void ParseDisplayName(
-				[In] IntPtr hwnd,
-				[In] IntPtr pbc,
-				[In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
-				[Out] out uint pchEaten,
-				[Out] out IntPtr ppidl,
-				[In, Out] ref uint pdwAttributes);
-
-			[PreserveSig]
-			int EnumObjects(
-				[In] IntPtr hwnd,
-				[In] SHCONTF grfFlags,
-				[Out] out IEnumIDList ppenumIDList);
-
-			void BindToObject(IntPtr pidl, IntPtr pbc,
-							  [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
-							  out IntPtr ppv);
-
-			void BindToStorage(IntPtr pidl, IntPtr pbc,
-							   [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
-							   out IntPtr ppv);
-
-			[PreserveSig]
-			short CompareIDs(uint lParam, IntPtr pidl1, IntPtr pidl2);
-
-			IntPtr CreateViewObject(IntPtr hwndOwner,
-				[MarshalAs(UnmanagedType.LPStruct)] Guid riid);
-
-			void GetAttributesOf(uint cidl,
-				[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] apidl,
-				ref uint rgfInOut);
-
-			void GetUIObjectOf(IntPtr hwndOwner, uint cidl,
-				[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] IntPtr[] apidl,
-				[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
-				uint rgfReserved,
-				out IntPtr ppv);
-
-			void GetDisplayNameOf(IntPtr pidl, int uFlags, out STRRET pName);
-
-			void SetNameOf(IntPtr hwnd, IntPtr pidl, string pszName, SHCONTF uFlags, out IntPtr ppidlOut);
-
-			public enum SHCONTF
+			[StructLayout(LayoutKind.Sequential)]
+			public struct IShellItemVtbl
 			{
-				FOLDERS = 0x0020,
-				NONFOLDERS = 0x0040,
-				INCLUDEHIDDEN = 0x0080,
-				INIT_ON_FIRST_NEXT = 0x0100,
-				NETPRINTERSRCH = 0x0200,
-				SHAREABLE = 0x0400,
-				STORAGE = 0x0800
+				// IUnknown functions
+				public delegate* unmanaged[Stdcall]<IShellItem*, in Guid, out IntPtr, int> QueryInterface;
+				public delegate* unmanaged[Stdcall]<IShellItem*, uint> AddRef;
+				public delegate* unmanaged[Stdcall]<IShellItem*, uint> Release;
+				// IShellItem functions
+				public delegate* unmanaged[Stdcall]<IShellItem*, IntPtr, in Guid, in Guid, out IntPtr, int> BindToHandler;
+				public delegate* unmanaged[Stdcall]<IShellItem*, out IShellItem*, int> GetParent;
+				public delegate* unmanaged[Stdcall]<IShellItem*, int, out IntPtr, int> GetDisplayName;
+				public delegate* unmanaged[Stdcall]<IShellItem*, uint, out uint, int> GetAttributes;
+				public delegate* unmanaged[Stdcall]<IShellItem*, IShellItem*, uint, out int, int> Compare;
 			}
 
-			[StructLayout(LayoutKind.Explicit, Size = 264)]
-			public struct STRRET
+			public IShellItemVtbl* lpVtbl;
+
+			public void BindToHandler(IntPtr pbc, Guid bhid, Guid riid, out IntPtr ppv)
 			{
-				[FieldOffset(0)]
-				public uint uType;
-				[FieldOffset(4)]
-				public IntPtr pOleStr;
-				[FieldOffset(4)]
-				public IntPtr pStr;
-				[FieldOffset(4)]
-				public uint uOffset;
-				[FieldOffset(4)]
-				public IntPtr cStr;
+				var hr = lpVtbl->BindToHandler((IShellItem*)Unsafe.AsPointer(ref this), pbc, in bhid, in riid, out ppv);
+				Marshal.ThrowExceptionForHR(hr);
+			}
+
+			public void GetParent(out IShellItem* ppsi)
+			{
+				var hr = lpVtbl->GetParent((IShellItem*)Unsafe.AsPointer(ref this), out ppsi);
+				Marshal.ThrowExceptionForHR(hr);
 			}
 		}
 
-#pragma warning disable CA1069
-		[Flags]
-		public enum TPM
+		[StructLayout(LayoutKind.Sequential)]
+		private struct IShellFolder
 		{
-			TPM_LEFTBUTTON = 0x0000,
-			TPM_RIGHTBUTTON = 0x0002,
-			TPM_LEFTALIGN = 0x0000,
-			TPM_CENTERALIGN = 0x000,
-			TPM_RIGHTALIGN = 0x000,
-			TPM_TOPALIGN = 0x0000,
-			TPM_VCENTERALIGN = 0x0010,
-			TPM_BOTTOMALIGN = 0x0020,
-			TPM_HORIZONTAL = 0x0000,
-			TPM_VERTICAL = 0x0040,
-			TPM_NONOTIFY = 0x0080,
-			TPM_RETURNCMD = 0x0100,
-			TPM_RECURSE = 0x0001,
-			TPM_HORPOSANIMATION = 0x0400,
-			TPM_HORNEGANIMATION = 0x0800,
-			TPM_VERPOSANIMATION = 0x1000,
-			TPM_VERNEGANIMATION = 0x2000,
-			TPM_NOANIMATION = 0x4000,
-			TPM_LAYOUTRTL = 0x8000,
-		}
-#pragma warning restore CA1069
+			public static readonly Guid Guid = new("000214E6-0000-0000-C000-000000000046");
 
-		[Flags]
-		public enum CMF : uint
-		{
-			NORMAL = 0x00000000,
-			DEFAULTONLY = 0x00000001,
-			VERBSONLY = 0x00000002,
-			EXPLORE = 0x00000004,
-			NOVERBS = 0x00000008,
-			CANRENAME = 0x00000010,
-			NODEFAULT = 0x00000020,
-			INCLUDESTATIC = 0x00000040,
-			EXTENDEDVERBS = 0x00000100,
-			RESERVED = 0xffff0000,
+			[StructLayout(LayoutKind.Sequential)]
+			public struct IShellFolderVtbl
+			{
+				// IUnknown functions
+				public delegate* unmanaged[Stdcall]<IShellFolder*, in Guid, out IntPtr, int> QueryInterface;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, uint> AddRef;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, uint> Release;
+				// IShellFolder functions
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, IntPtr, IntPtr, uint*, out IntPtr, uint*, int> ParseDisplayName;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, uint, out IntPtr, int> EnumObjects;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, IntPtr, in Guid, out IntPtr, int> BindToObject;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, IntPtr, in Guid, out IntPtr, int> BindToStorage;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, IntPtr, IntPtr, int> CompareIDs;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, in Guid, out IntPtr, int> CreateViewObject;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, uint, IntPtr*, ref uint, int> GetAttributesOf;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, uint, IntPtr*, in Guid, uint*, out IntPtr, int> GetUIObjectOf;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, uint, IntPtr, int> GetDisplayNameOf;
+				public delegate* unmanaged[Stdcall]<IShellFolder*, IntPtr, IntPtr, IntPtr, uint, out IntPtr, int> SetNameOf;
+			}
+
+			public IShellFolderVtbl* lpVtbl;
+
+			public void GetUIObjectOf(IntPtr hwndOwner, uint cidl, IntPtr* apidl, Guid riid, out IntPtr ppv)
+			{
+				var hr = lpVtbl->GetUIObjectOf((IShellFolder*)Unsafe.AsPointer(ref this), hwndOwner, cidl, apidl, in riid, null, out ppv);
+				Marshal.ThrowExceptionForHR(hr);
+			}
 		}
 
-		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
-		public struct CMINVOKECOMMANDINFO
+		[StructLayout(LayoutKind.Sequential)]
+		private struct IContextMenu
 		{
-			public int cbSize;
-			public int fMask;
-			public IntPtr hwnd;
-			public string lpVerb;
-			public string lpParameters;
-			public string lpDirectory;
-			public int nShow;
-			public int dwHotKey;
-			public IntPtr hIcon;
+			public static readonly Guid Guid = new("000214e4-0000-0000-c000-000000000046");
+
+			[Flags]
+			public enum CMF : uint
+			{
+				NORMAL = 0x00000000,
+				DEFAULTONLY = 0x00000001,
+				VERBSONLY = 0x00000002,
+				EXPLORE = 0x00000004,
+				NOVERBS = 0x00000008,
+				CANRENAME = 0x00000010,
+				NODEFAULT = 0x00000020,
+				INCLUDESTATIC = 0x00000040,
+				EXTENDEDVERBS = 0x00000100,
+				RESERVED = 0xffff0000,
+			}
+
+			[StructLayout(LayoutKind.Sequential)]
+			public struct CMINVOKECOMMANDINFO
+			{
+				public uint cbSize;
+				public uint fMask;
+				public IntPtr hwnd;
+				public IntPtr lpVerb;
+				public IntPtr lpParameters;
+				public IntPtr lpDirectory;
+				public int nShow;
+				public uint dwHotKey;
+				public IntPtr hIcon;
+			}
+
+			[StructLayout(LayoutKind.Sequential)]
+			public struct IContextMenuVtbl
+			{
+				// IUnknown functions
+				public delegate* unmanaged[Stdcall]<IContextMenu*, in Guid, out IntPtr, int> QueryInterface;
+				public delegate* unmanaged[Stdcall]<IContextMenu*, uint> AddRef;
+				public delegate* unmanaged[Stdcall]<IContextMenu*, uint> Release;
+				// IContextMenu functions
+				public delegate* unmanaged[Stdcall]<IContextMenu*, IntPtr, uint, uint, uint, CMF, int> QueryContextMenu;
+				public delegate* unmanaged[Stdcall]<IContextMenu*, CMINVOKECOMMANDINFO*, int> InvokeCommand;
+				public delegate* unmanaged[Stdcall]<IContextMenu*, UIntPtr, uint, uint*, IntPtr, uint, int> GetCommandString;
+			}
+
+			public IContextMenuVtbl* lpVtbl;
+
+			public void QueryContextMenu(IntPtr hmenu, uint indexMenu, uint idCmdFirst, uint idCmdLast, CMF uFlags)
+			{
+				var hr = lpVtbl->QueryContextMenu((IContextMenu*)Unsafe.AsPointer(ref this), hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
+				Marshal.ThrowExceptionForHR(hr);
+			}
 		}
 
-		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
-		public struct CMINVOKECOMMANDINFO_ByIndex
+		[StructLayout(LayoutKind.Sequential)]
+		private struct IContextMenu2
 		{
-			public int cbSize;
-			public int fMask;
-			public IntPtr hwnd;
-			public int iVerb;
-			public string lpParameters;
-			public string lpDirectory;
-			public int nShow;
-			public int dwHotKey;
-			public IntPtr hIcon;
+			public static readonly Guid Guid = new("000214f4-0000-0000-c000-000000000046");
+
+			[StructLayout(LayoutKind.Sequential)]
+			public struct IContextMenu2Vtbl
+			{
+				// IUnknown functions
+				public delegate* unmanaged[Stdcall]<IContextMenu2*, in Guid, out IntPtr, int> QueryInterface;
+				public delegate* unmanaged[Stdcall]<IContextMenu2*, uint> AddRef;
+				public delegate* unmanaged[Stdcall]<IContextMenu2*, uint> Release;
+				// IContextMenu functions
+				public delegate* unmanaged[Stdcall]<IContextMenu2*, IntPtr, uint, uint, uint, IContextMenu.CMF, int> QueryContextMenu;
+				public delegate* unmanaged[Stdcall]<IContextMenu2*, IContextMenu.CMINVOKECOMMANDINFO*, int> InvokeCommand;
+				public delegate* unmanaged[Stdcall]<IContextMenu2*, UIntPtr, uint, uint*, IntPtr, uint, int> GetCommandString;
+				// IContextMenu2 functions
+				public delegate* unmanaged[Stdcall]<IContextMenu2*, uint, IntPtr, IntPtr, int> HandleMenuMsg;
+			}
+
+			public IContextMenu2Vtbl* lpVtbl;
+
+			public void InvokeCommand(IContextMenu.CMINVOKECOMMANDINFO* pici)
+			{
+				var hr = lpVtbl->InvokeCommand((IContextMenu2*)Unsafe.AsPointer(ref this), pici);
+				Marshal.ThrowExceptionForHR(hr);
+			}
 		}
 
-		[ComImport]
-		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-		[Guid("000214e4-0000-0000-c000-000000000046")]
-		public interface IContextMenu
-		{
-			[PreserveSig]
-			int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, CMF uFlags);
-
-			void InvokeCommand(ref CMINVOKECOMMANDINFO pici);
-
-			[PreserveSig]
-			int GetCommandString(int idcmd, uint uflags, int reserved,
-				[MarshalAs(UnmanagedType.LPStr)] StringBuilder commandstring,
-				int cch);
-		}
-
-		[ComImport]
-		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-		[Guid("000214f4-0000-0000-c000-000000000046")]
-		public interface IContextMenu2 : IContextMenu
-		{
-			[PreserveSig]
-			new int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, CMF uFlags);
-
-			void InvokeCommand(ref CMINVOKECOMMANDINFO_ByIndex pici);
-
-			[PreserveSig]
-			new int GetCommandString(int idcmd, uint uflags, int reserved,
-				[MarshalAs(UnmanagedType.LPStr)] StringBuilder commandstring,
-				int cch);
-
-			[PreserveSig]
-			int HandleMenuMsg(int uMsg, IntPtr wParam, IntPtr lParam);
-		}
-
-		[DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
-		public static extern IShellItem SHCreateItemFromParsingName(
-			[In] string pszPath,
-			[In] IntPtr pbc,
-			[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);
-
-		[DllImport("shell32.dll", ExactSpelling = true, PreserveSig = false)]
-		public static extern IntPtr SHGetIDListFromObject([In, MarshalAs(UnmanagedType.IUnknown)] object punk);
-
-		[DllImport("shell32.dll", EntryPoint = "#16", ExactSpelling = true)]
-		public static extern IntPtr ILFindLastID(IntPtr pidl);
-
-		[DllImport("user32.dll", ExactSpelling = true)]
-		public static extern int TrackPopupMenuEx(IntPtr hmenu, TPM fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);
-
-		private IContextMenu ComInterface { get; }
-		private IContextMenu2 ComInterface2 { get; }
+		private IContextMenu* CMI;
+		private IContextMenu2* CM2I;
 
 		private static readonly Guid SFObject = new("3981e224-f559-11d3-8e3a-00c04f6837d5");
 
@@ -254,38 +177,88 @@ namespace BizHawk.Common
 				throw new NotSupportedException("Non-file Uri schemes are unsupported");
 			}
 
-			var shellItem = SHCreateItemFromParsingName(uri.LocalPath, IntPtr.Zero, typeof(IShellItem).GUID);
+			var hr = Shell32Imports.SHCreateItemFromParsingName(uri.LocalPath, IntPtr.Zero, IShellItem.Guid, out var psi);
+			Marshal.ThrowExceptionForHR(hr);
+			var sii = (IShellItem*)psi;
 
-			var pidls = new IntPtr[1];
-			pidls[0] = ILFindLastID(SHGetIDListFromObject(shellItem));
-			shellItem.GetParent(out var parent);
+			IntPtr pidls;
+			IShellItem* psii;
+			try
+			{
+				hr = Shell32Imports.SHGetIDListFromObject(psi, out var ppidl);
+				Marshal.ThrowExceptionForHR(hr);
 
-			var result = parent.BindToHandler(IntPtr.Zero, SFObject, typeof(IShellFolder).GUID);
+				pidls = Shell32Imports.ILFindLastID(ppidl);
+				sii->GetParent(out psii);
+			}
+			finally
+			{
+				sii->lpVtbl->Release(sii);
+			}
 
-			var shellFolder = (IShellFolder)Marshal.GetObjectForIUnknown(result);
-			shellFolder.GetUIObjectOf(IntPtr.Zero, 1, pidls, typeof(IContextMenu).GUID, 0, out result);
+			IShellFolder* sfi;
+			try
+			{
+				psii->BindToHandler(IntPtr.Zero, SFObject, IShellFolder.Guid, out var psf);
+				sfi = (IShellFolder*)psf;
+			}
+			finally
+			{
+				psii->lpVtbl->Release(psii);
+			}
 
-			ComInterface = (IContextMenu)Marshal.GetObjectForIUnknown(result);
-			ComInterface2 = (IContextMenu2)ComInterface;
+			IContextMenu* cmi;
+			try
+			{
+				sfi->GetUIObjectOf(IntPtr.Zero, 1, &pidls, IContextMenu.Guid, out var pcm);
+				cmi = (IContextMenu*)pcm;
+			}
+			finally
+			{
+				sfi->lpVtbl->Release(sfi);
+			}
+
+			IContextMenu2* cm2i;
+			try
+			{
+				cmi->lpVtbl->QueryInterface(cmi, in IContextMenu2.Guid, out var pcm2);
+				cm2i = (IContextMenu2*)pcm2;
+			}
+			catch
+			{
+				cmi->lpVtbl->Release(cmi);
+				throw;
+			}
+
+			CMI = cmi;
+			CM2I = cm2i;
+		}
+
+		public void Dispose()
+		{
+			if (CM2I != null)
+			{
+				CM2I->lpVtbl->Release(CM2I);
+				CM2I = null;
+			}
+
+			if (CMI != null)
+			{
+				CMI->lpVtbl->Release(CMI);
+				CMI = null;
+			}
 		}
 
 		private ref struct TempMenu
 		{
-			[DllImport("user32.dll", ExactSpelling = true)]
-			private static extern IntPtr CreatePopupMenu();
-
-			[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
-			[return: MarshalAs(UnmanagedType.Bool)]
-			private static extern bool DestroyMenu(IntPtr hMenu);
-
 			public IntPtr Handle { get; private set; }
 
 			public TempMenu()
 			{
-				Handle = CreatePopupMenu();
+				Handle = Win32Imports.CreatePopupMenu();
 				if (Handle == IntPtr.Zero)
 				{
-					throw new InvalidOperationException($"{nameof(CreatePopupMenu)} returned NULL!");
+					throw new InvalidOperationException($"{nameof(Win32Imports.CreatePopupMenu)} returned NULL!");
 				}
 			}
 
@@ -293,7 +266,7 @@ namespace BizHawk.Common
 			{
 				if (Handle != IntPtr.Zero)
 				{
-					_ = DestroyMenu(Handle);
+					_ = Win32Imports.DestroyMenu(Handle);
 					Handle = IntPtr.Zero;
 				}
 			}
@@ -301,19 +274,21 @@ namespace BizHawk.Common
 
 		public static void ShowContextMenu(string path, IntPtr parentWindow, int x, int y)
 		{
-			var ctxMenu = new Win32ShellContextMenu(path);
+			using var ctxMenu = new Win32ShellContextMenu(path);
 			using var menu = new TempMenu();
+
 			const int CmdFirst = 0x8000;
-			ctxMenu.ComInterface.QueryContextMenu(menu.Handle, 0, CmdFirst, int.MaxValue, CMF.EXPLORE);
-			var command = TrackPopupMenuEx(menu.Handle, TPM.TPM_RETURNCMD, x, y, parentWindow, IntPtr.Zero);
+			ctxMenu.CMI->QueryContextMenu(menu.Handle, 0, CmdFirst, uint.MaxValue, IContextMenu.CMF.EXPLORE);
+
+			var command = Win32Imports.TrackPopupMenuEx(menu.Handle, Win32Imports.TPM.RETURNCMD, x, y, parentWindow, IntPtr.Zero);
 			if (command > 0)
 			{
 				const int SW_SHOWNORMAL = 1;
-				CMINVOKECOMMANDINFO_ByIndex invoke = default;
-				invoke.cbSize = Marshal.SizeOf(invoke);
-				invoke.iVerb = command - CmdFirst;
+				IContextMenu.CMINVOKECOMMANDINFO invoke = default;
+				invoke.cbSize = (uint)Marshal.SizeOf<IContextMenu.CMINVOKECOMMANDINFO>();
+				invoke.lpVerb = new(command - CmdFirst);
 				invoke.nShow = SW_SHOWNORMAL;
-				ctxMenu.ComInterface2.InvokeCommand(ref invoke);
+				ctxMenu.CM2I->InvokeCommand(&invoke);
 			}
 		}
 	}