mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Explorer plugin native context menu: free all allocated unmanaged memory
This commit is contained in:
parent
ce5a38bc49
commit
ee64c259fc
1 changed files with 115 additions and 65 deletions
|
|
@ -156,92 +156,142 @@ public static class ShellContextMenuDisplayHelper
|
||||||
|
|
||||||
public static void ExecuteContextMenuItem(string fileName, uint menuItemId)
|
public static void ExecuteContextMenuItem(string fileName, uint menuItemId)
|
||||||
{
|
{
|
||||||
var malloc = GetMalloc();
|
IMalloc malloc = null;
|
||||||
var hr = SHParseDisplayName(fileName, IntPtr.Zero, out var pidl, 0, out _);
|
IntPtr originalPidl = IntPtr.Zero;
|
||||||
if (hr != 0) throw new Exception("SHParseDisplayName failed");
|
IntPtr pShellFolder = IntPtr.Zero;
|
||||||
|
IntPtr pContextMenu = IntPtr.Zero;
|
||||||
|
IntPtr hMenu = IntPtr.Zero;
|
||||||
|
IContextMenu contextMenu = null;
|
||||||
|
IShellFolder shellFolder = null;
|
||||||
|
|
||||||
var originalPidl = pidl;
|
try
|
||||||
|
|
||||||
var guid = typeof(IShellFolder).GUID;
|
|
||||||
hr = SHBindToParent(pidl, guid, out var pShellFolder, ref pidl);
|
|
||||||
if (hr != 0) throw new Exception("SHBindToParent failed");
|
|
||||||
|
|
||||||
var shellFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pShellFolder, typeof(IShellFolder));
|
|
||||||
hr = shellFolder.GetUIObjectOf(
|
|
||||||
IntPtr.Zero, 1, new[] { pidl }, typeof(IContextMenu).GUID, IntPtr.Zero, out var pContextMenu
|
|
||||||
);
|
|
||||||
if (hr != 0) throw new Exception("GetUIObjectOf failed");
|
|
||||||
|
|
||||||
var contextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(pContextMenu, typeof(IContextMenu));
|
|
||||||
|
|
||||||
var hMenu = CreatePopupMenu();
|
|
||||||
contextMenu.QueryContextMenu(hMenu, 0, ContextMenuStartId, ContextMenuEndId, (uint)ContextMenuFlags.Normal);
|
|
||||||
|
|
||||||
var directory = Path.GetDirectoryName(fileName);
|
|
||||||
var invokeCommandInfo = new CMINVOKECOMMANDINFO
|
|
||||||
{
|
{
|
||||||
cbSize = (uint)Marshal.SizeOf(typeof(CMINVOKECOMMANDINFO)),
|
malloc = GetMalloc();
|
||||||
fMask = (uint)ContextMenuInvokeCommandFlags.Unicode,
|
var hr = SHParseDisplayName(fileName, IntPtr.Zero, out var pidl, 0, out _);
|
||||||
hwnd = IntPtr.Zero,
|
if (hr != 0) throw new Exception("SHParseDisplayName failed");
|
||||||
lpVerb = (IntPtr)(menuItemId - ContextMenuStartId),
|
|
||||||
lpParameters = null,
|
|
||||||
lpDirectory = directory ?? "",
|
|
||||||
nShow = 1,
|
|
||||||
hIcon = IntPtr.Zero,
|
|
||||||
};
|
|
||||||
|
|
||||||
hr = contextMenu.InvokeCommand(ref invokeCommandInfo);
|
originalPidl = pidl;
|
||||||
if (hr != 0)
|
|
||||||
{
|
var guid = typeof(IShellFolder).GUID;
|
||||||
throw new Exception($"InvokeCommand failed with code {hr:X}");
|
hr = SHBindToParent(pidl, guid, out pShellFolder, ref pidl);
|
||||||
|
if (hr != 0) throw new Exception("SHBindToParent failed");
|
||||||
|
|
||||||
|
shellFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pShellFolder, typeof(IShellFolder));
|
||||||
|
hr = shellFolder.GetUIObjectOf(
|
||||||
|
IntPtr.Zero, 1, new[] { pidl }, typeof(IContextMenu).GUID, IntPtr.Zero, out pContextMenu
|
||||||
|
);
|
||||||
|
if (hr != 0) throw new Exception("GetUIObjectOf failed");
|
||||||
|
|
||||||
|
contextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(pContextMenu, typeof(IContextMenu));
|
||||||
|
|
||||||
|
hMenu = CreatePopupMenu();
|
||||||
|
contextMenu.QueryContextMenu(hMenu, 0, ContextMenuStartId, ContextMenuEndId, (uint)ContextMenuFlags.Normal);
|
||||||
|
|
||||||
|
var directory = Path.GetDirectoryName(fileName);
|
||||||
|
var invokeCommandInfo = new CMINVOKECOMMANDINFO
|
||||||
|
{
|
||||||
|
cbSize = (uint)Marshal.SizeOf(typeof(CMINVOKECOMMANDINFO)),
|
||||||
|
fMask = (uint)ContextMenuInvokeCommandFlags.Unicode,
|
||||||
|
hwnd = IntPtr.Zero,
|
||||||
|
lpVerb = (IntPtr)(menuItemId - ContextMenuStartId),
|
||||||
|
lpParameters = null,
|
||||||
|
lpDirectory = directory ?? "",
|
||||||
|
nShow = 1,
|
||||||
|
hIcon = IntPtr.Zero,
|
||||||
|
};
|
||||||
|
|
||||||
|
hr = contextMenu.InvokeCommand(ref invokeCommandInfo);
|
||||||
|
if (hr != 0)
|
||||||
|
{
|
||||||
|
throw new Exception($"InvokeCommand failed with code {hr:X}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (hMenu != IntPtr.Zero)
|
||||||
|
DestroyMenu(hMenu);
|
||||||
|
|
||||||
DestroyMenu(hMenu);
|
if (contextMenu != null)
|
||||||
Marshal.ReleaseComObject(contextMenu);
|
Marshal.ReleaseComObject(contextMenu);
|
||||||
Marshal.ReleaseComObject(shellFolder);
|
|
||||||
|
|
||||||
if (originalPidl != IntPtr.Zero)
|
if (pContextMenu != IntPtr.Zero)
|
||||||
malloc.Free(originalPidl);
|
Marshal.Release(pContextMenu);
|
||||||
|
|
||||||
Marshal.ReleaseComObject(malloc);
|
if (shellFolder != null)
|
||||||
|
Marshal.ReleaseComObject(shellFolder);
|
||||||
|
|
||||||
|
if (pShellFolder != IntPtr.Zero)
|
||||||
|
Marshal.Release(pShellFolder);
|
||||||
|
|
||||||
|
if (originalPidl != IntPtr.Zero)
|
||||||
|
malloc?.Free(originalPidl);
|
||||||
|
|
||||||
|
if (malloc != null)
|
||||||
|
Marshal.ReleaseComObject(malloc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<ContextMenuItem> GetContextMenuWithIcons(string filePath)
|
public static List<ContextMenuItem> GetContextMenuWithIcons(string filePath)
|
||||||
{
|
{
|
||||||
var malloc = GetMalloc();
|
IMalloc malloc = null;
|
||||||
var hr = SHParseDisplayName(filePath, IntPtr.Zero, out var pidl, 0, out _);
|
IntPtr originalPidl = IntPtr.Zero;
|
||||||
if (hr != 0) throw new Exception("SHParseDisplayName failed");
|
IntPtr pShellFolder = IntPtr.Zero;
|
||||||
|
IShellFolder shellFolder = null;
|
||||||
|
IntPtr pContextMenu = IntPtr.Zero;
|
||||||
|
IContextMenu contextMenu = null;
|
||||||
|
IntPtr hMenu = IntPtr.Zero;
|
||||||
|
|
||||||
var originalPidl = pidl;
|
try
|
||||||
|
{
|
||||||
|
malloc = GetMalloc();
|
||||||
|
var hr = SHParseDisplayName(filePath, IntPtr.Zero, out var pidl, 0, out _);
|
||||||
|
if (hr != 0) throw new Exception("SHParseDisplayName failed");
|
||||||
|
|
||||||
var guid = typeof(IShellFolder).GUID;
|
originalPidl = pidl;
|
||||||
hr = SHBindToParent(pidl, guid, out var pShellFolder, ref pidl);
|
|
||||||
if (hr != 0) throw new Exception("SHBindToParent failed");
|
|
||||||
|
|
||||||
var shellFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pShellFolder, typeof(IShellFolder));
|
var guid = typeof(IShellFolder).GUID;
|
||||||
hr = shellFolder.GetUIObjectOf(
|
hr = SHBindToParent(pidl, guid, out pShellFolder, ref pidl);
|
||||||
IntPtr.Zero, 1, new[] { pidl }, typeof(IContextMenu).GUID, IntPtr.Zero, out var pContextMenu
|
if (hr != 0) throw new Exception("SHBindToParent failed");
|
||||||
);
|
|
||||||
if (hr != 0) throw new Exception("GetUIObjectOf failed");
|
|
||||||
|
|
||||||
var contextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(pContextMenu, typeof(IContextMenu));
|
shellFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pShellFolder, typeof(IShellFolder));
|
||||||
|
hr = shellFolder.GetUIObjectOf(
|
||||||
|
IntPtr.Zero, 1, new[] { pidl }, typeof(IContextMenu).GUID, IntPtr.Zero, out pContextMenu
|
||||||
|
);
|
||||||
|
if (hr != 0) throw new Exception("GetUIObjectOf failed");
|
||||||
|
|
||||||
var hMenu = CreatePopupMenu();
|
contextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(pContextMenu, typeof(IContextMenu));
|
||||||
contextMenu.QueryContextMenu(hMenu, 0, ContextMenuStartId, ContextMenuEndId, (uint)ContextMenuFlags.Normal);
|
|
||||||
|
|
||||||
var menuItems = new List<ContextMenuItem>();
|
hMenu = CreatePopupMenu();
|
||||||
ProcessMenuWithIcons(hMenu, contextMenu, menuItems);
|
contextMenu.QueryContextMenu(hMenu, 0, ContextMenuStartId, ContextMenuEndId, (uint)ContextMenuFlags.Normal);
|
||||||
|
|
||||||
DestroyMenu(hMenu);
|
var menuItems = new List<ContextMenuItem>();
|
||||||
Marshal.ReleaseComObject(contextMenu);
|
ProcessMenuWithIcons(hMenu, contextMenu, menuItems);
|
||||||
Marshal.ReleaseComObject(shellFolder);
|
|
||||||
|
|
||||||
if (originalPidl != IntPtr.Zero)
|
return menuItems;
|
||||||
malloc.Free(originalPidl);
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (hMenu != IntPtr.Zero)
|
||||||
|
DestroyMenu(hMenu);
|
||||||
|
|
||||||
Marshal.ReleaseComObject(malloc);
|
if (contextMenu != null)
|
||||||
|
Marshal.ReleaseComObject(contextMenu);
|
||||||
|
|
||||||
return menuItems;
|
if (pContextMenu != IntPtr.Zero)
|
||||||
|
Marshal.Release(pContextMenu);
|
||||||
|
|
||||||
|
if (shellFolder != null)
|
||||||
|
Marshal.ReleaseComObject(shellFolder);
|
||||||
|
|
||||||
|
if (pShellFolder != IntPtr.Zero)
|
||||||
|
Marshal.Release(pShellFolder);
|
||||||
|
|
||||||
|
if (originalPidl != IntPtr.Zero)
|
||||||
|
malloc?.Free(originalPidl);
|
||||||
|
|
||||||
|
if (malloc != null)
|
||||||
|
Marshal.ReleaseComObject(malloc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue