private static void EnumMenuItems( Shell32.IContextMenu cMenu, HMENU hMenu, List <Win32ContextMenuItem> menuItemsResult, Func <string, bool> itemFilter = null) { var itemCount = User32.GetMenuItemCount(hMenu); var mii = new User32.MENUITEMINFO(); mii.cbSize = (uint)Marshal.SizeOf(mii); mii.fMask = User32.MenuItemInfoMask.MIIM_BITMAP | User32.MenuItemInfoMask.MIIM_FTYPE | User32.MenuItemInfoMask.MIIM_STRING | User32.MenuItemInfoMask.MIIM_ID | User32.MenuItemInfoMask.MIIM_SUBMENU; for (uint ii = 0; ii < itemCount; ii++) { var menuItem = new ContextMenuItem(); var container = new SafeCoTaskMemString(512); mii.dwTypeData = (IntPtr)container; mii.cch = (uint)container.Capacity - 1; // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 var retval = User32.GetMenuItemInfo(hMenu, ii, true, ref mii); if (!retval) { container.Dispose(); continue; } menuItem.Type = (MenuItemType)mii.fType; menuItem.ID = (int)(mii.wID - 1); // wID - idCmdFirst if (menuItem.Type == MenuItemType.MFT_STRING) { Debug.WriteLine("Item {0} ({1}): {2}", ii, mii.wID, mii.dwTypeData); menuItem.Label = mii.dwTypeData; menuItem.CommandString = GetCommandString(cMenu, mii.wID - 1); if (itemFilter != null && (itemFilter(menuItem.CommandString) || itemFilter(menuItem.Label))) { // Skip items implemented in UWP container.Dispose(); continue; } if (mii.hbmpItem != HBITMAP.NULL && !Enum.IsDefined(typeof(HBITMAP_HMENU), ((IntPtr)mii.hbmpItem).ToInt64())) { var bitmap = GetBitmapFromHBitmap(mii.hbmpItem); if (bitmap != null) { menuItem.Icon = bitmap; } } if (mii.hSubMenu != HMENU.NULL) { Debug.WriteLine("Item {0}: has submenu", ii); var subItems = new List <Win32ContextMenuItem>(); try { (cMenu as Shell32.IContextMenu2)?.HandleMenuMsg((uint)User32.WindowMessage.WM_INITMENUPOPUP, (IntPtr)mii.hSubMenu, new IntPtr(ii)); } catch (NotImplementedException) { // Only for dynamic/owner drawn? (open with, etc) } EnumMenuItems(cMenu, mii.hSubMenu, subItems, itemFilter); menuItem.SubItems = subItems; Debug.WriteLine("Item {0}: done submenu", ii); } } else { Debug.WriteLine("Item {0}: {1}", ii, mii.fType.ToString()); } container.Dispose(); menuItemsResult.Add(menuItem); } }
private static ContextMenuPackage[] FetchContextMenuCore(Shell32.IContextMenu Context, HMENU Menu, string[] RelatedPath, bool IncludeExtensionItem) { int MenuItemNum = User32.GetMenuItemCount(Menu); List <ContextMenuPackage> MenuItems = new List <ContextMenuPackage>(MenuItemNum); for (uint i = 0; i < MenuItemNum; i++) { IntPtr DataHandle = Marshal.AllocCoTaskMem(BufferSize); try { User32.MENUITEMINFO Info = new User32.MENUITEMINFO { cbSize = Convert.ToUInt32(Marshal.SizeOf(typeof(User32.MENUITEMINFO))), fMask = User32.MenuItemInfoMask.MIIM_ID | User32.MenuItemInfoMask.MIIM_SUBMENU | User32.MenuItemInfoMask.MIIM_FTYPE | User32.MenuItemInfoMask.MIIM_STRING | User32.MenuItemInfoMask.MIIM_STATE | User32.MenuItemInfoMask.MIIM_BITMAP, dwTypeData = DataHandle, cch = CchMax }; if (User32.GetMenuItemInfo(Menu, i, true, ref Info)) { if (Info.fType.IsFlagSet(User32.MenuItemType.MFT_STRING) && !Info.fState.IsFlagSet(User32.MenuItemState.MFS_DISABLED)) { IntPtr VerbWHandle = IntPtr.Zero; IntPtr VerbAHandle = IntPtr.Zero; string Verb = null; try { VerbWHandle = Marshal.AllocCoTaskMem(BufferSize); if (Context.GetCommandString(new IntPtr(Info.wID), Shell32.GCS.GCS_VERBW, IntPtr.Zero, VerbWHandle, CchMax).Succeeded) { Verb = Marshal.PtrToStringUni(VerbWHandle); } if (string.IsNullOrEmpty(Verb)) { VerbAHandle = Marshal.AllocCoTaskMem(BufferSize); if (Context.GetCommandString(new IntPtr(Info.wID), Shell32.GCS.GCS_VERBA, IntPtr.Zero, VerbAHandle, CchMax).Succeeded) { Verb = Marshal.PtrToStringAnsi(VerbAHandle); } } } catch (AccessViolationException AVE) { Verb = null; LogTracer.Log(AVE, "Could not get verb from context menu item"); } finally { if (VerbAHandle != IntPtr.Zero) { Marshal.FreeCoTaskMem(VerbAHandle); } if (VerbWHandle != IntPtr.Zero) { Marshal.FreeCoTaskMem(VerbWHandle); } } Verb ??= string.Empty; if (!VerbFilterHashSet.Contains(Verb.ToLower())) { try { string Name = Marshal.PtrToStringUni(DataHandle); if (!string.IsNullOrEmpty(Name) && !NameFilterHashSet.Contains(Name)) { ContextMenuPackage Package = new ContextMenuPackage { Name = Regex.Replace(Name, @"\(&\S*\)|&", string.Empty), Id = Convert.ToInt32(Info.wID), Verb = Verb, IncludeExtensionItem = IncludeExtensionItem, RelatedPath = RelatedPath }; if (Info.hbmpItem != HBITMAP.NULL && ((IntPtr)Info.hbmpItem).ToInt64() != -1) { using (Bitmap OriginBitmap = Info.hbmpItem.ToBitmap()) { BitmapData OriginData = OriginBitmap.LockBits(new Rectangle(0, 0, OriginBitmap.Width, OriginBitmap.Height), ImageLockMode.ReadOnly, OriginBitmap.PixelFormat); try { using (Bitmap ArgbBitmap = new Bitmap(OriginBitmap.Width, OriginBitmap.Height, OriginData.Stride, PixelFormat.Format32bppArgb, OriginData.Scan0)) using (MemoryStream Stream = new MemoryStream()) { ArgbBitmap.Save(Stream, ImageFormat.Png); Package.IconData = Stream.ToArray(); } } finally { OriginBitmap.UnlockBits(OriginData); } } } else { Package.IconData = Array.Empty <byte>(); } if (Info.hSubMenu != HMENU.NULL) { Package.SubMenus = FetchContextMenuCore(Context, Info.hSubMenu, RelatedPath, IncludeExtensionItem); } else { Package.SubMenus = Array.Empty <ContextMenuPackage>(); } MenuItems.Add(Package); } } catch { continue; } } } } } catch (Exception ex) { LogTracer.Log(ex, "Exception was threw when fetching the context menu item"); } finally { Marshal.FreeCoTaskMem(DataHandle); } } return(MenuItems.ToArray()); }
public static List <(string, string, string)> FetchContextMenuItems(IEnumerable <string> Path, bool FetchExtensionMenu = false) { ShellItem[] ItemCollecion = Array.Empty <ShellItem>(); try { ItemCollecion = Path.Where((Item) => File.Exists(Item) || Directory.Exists(Item)).Select((Item) => ShellItem.Open(Item)).ToArray(); Context = new ShellContextMenu(ItemCollecion); using (User32.SafeHMENU NewMenu = User32.CreatePopupMenu()) { Context.ComInterface.QueryContextMenu(NewMenu, 0, 0, ushort.MaxValue, FetchExtensionMenu ? (Shell32.CMF.CMF_VERBSONLY | Shell32.CMF.CMF_EXTENDEDVERBS) : Shell32.CMF.CMF_VERBSONLY); int MaxCount = User32.GetMenuItemCount(NewMenu); List <(string, string, string)> ContextMenuItemList = new List <(string, string, string)>(MaxCount); for (uint i = 0; i < MaxCount; i++) { IntPtr DataPtr = Marshal.AllocHGlobal(BufferSize); try { User32.MENUITEMINFO Info = new User32.MENUITEMINFO { fMask = User32.MenuItemInfoMask.MIIM_STRING | User32.MenuItemInfoMask.MIIM_ID | User32.MenuItemInfoMask.MIIM_FTYPE | User32.MenuItemInfoMask.MIIM_BITMAP | User32.MenuItemInfoMask.MIIM_STATE, dwTypeData = DataPtr, cch = Convert.ToUInt32(BufferSize - 1), cbSize = Convert.ToUInt32(Marshal.SizeOf(typeof(User32.MENUITEMINFO))) }; if (User32.GetMenuItemInfo(NewMenu, i, true, ref Info)) { if (Info.fType == User32.MenuItemType.MFT_STRING && Info.fState == User32.MenuItemState.MFS_ENABLED) { IntPtr VerbPtr = Marshal.AllocHGlobal(BufferSize); try { Context.ComInterface.GetCommandString(new IntPtr(Info.wID), Shell32.GCS.GCS_VERBW, IntPtr.Zero, VerbPtr, Convert.ToUInt32(BufferSize - 1)); string Verb = Marshal.PtrToStringUni(VerbPtr); switch (Verb.ToLower()) { case "open": case "opennewprocess": case "pintohome": case "cut": case "copy": case "paste": case "delete": case "properties": case "openas": case "link": case "runas": case "rename": { break; } default: { IntPtr HelpTextPtr = Marshal.AllocHGlobal(BufferSize); try { Context.ComInterface.GetCommandString(new IntPtr(Info.wID), Shell32.GCS.GCS_HELPTEXTW, IntPtr.Zero, HelpTextPtr, Convert.ToUInt32(BufferSize - 1)); string HelpText = Marshal.PtrToStringUni(HelpTextPtr); if (Info.hbmpItem != HBITMAP.NULL) { using (MemoryStream Stream = new MemoryStream()) { Bitmap OriginBitmap = Info.hbmpItem.ToBitmap(); BitmapData OriginData = OriginBitmap.LockBits(new Rectangle(0, 0, OriginBitmap.Width, OriginBitmap.Height), ImageLockMode.ReadOnly, OriginBitmap.PixelFormat); Bitmap ArgbBitmap = new Bitmap(OriginBitmap.Width, OriginBitmap.Height, OriginData.Stride, PixelFormat.Format32bppArgb, OriginData.Scan0); ArgbBitmap.Save(Stream, ImageFormat.Png); ContextMenuItemList.Add((HelpText, Verb, Convert.ToBase64String(Stream.ToArray()))); } } else { ContextMenuItemList.Add((HelpText, Verb, string.Empty)); } } finally { Marshal.FreeHGlobal(HelpTextPtr); } break; } } } catch { continue; } finally { Marshal.FreeHGlobal(VerbPtr); } } } } finally { Marshal.FreeHGlobal(DataPtr); } } return(ContextMenuItemList); } } catch { return(new List <(string, string, string)>(0)); } finally { Array.ForEach(ItemCollecion, (Item) => Item.Dispose()); } }
public static List <ContextMenuPackage> FetchContextMenuItems(string Path, bool FetchExtensionMenu = false) { try { if (File.Exists(Path) || Directory.Exists(Path)) { using (ShellItem Item = ShellItem.Open(Path)) { Shell32.IContextMenu Context = Item.GetHandler <Shell32.IContextMenu>(); try { using (User32.SafeHMENU NewMenu = User32.CreatePopupMenu()) { Context.QueryContextMenu(NewMenu, 0, 0, ushort.MaxValue, FetchExtensionMenu ? (Shell32.CMF.CMF_NORMAL | Shell32.CMF.CMF_EXTENDEDVERBS) : Shell32.CMF.CMF_NORMAL); int MaxCount = User32.GetMenuItemCount(NewMenu); List <ContextMenuPackage> ContextMenuItemList = new List <ContextMenuPackage>(MaxCount); for (uint i = 0; i < MaxCount; i++) { IntPtr DataPtr = Marshal.AllocHGlobal(BufferSize); try { User32.MENUITEMINFO Info = new User32.MENUITEMINFO { fMask = User32.MenuItemInfoMask.MIIM_STRING | User32.MenuItemInfoMask.MIIM_ID | User32.MenuItemInfoMask.MIIM_FTYPE | User32.MenuItemInfoMask.MIIM_BITMAP | User32.MenuItemInfoMask.MIIM_STATE, dwTypeData = DataPtr, cch = Convert.ToUInt32(BufferSize - 1), cbSize = Convert.ToUInt32(Marshal.SizeOf(typeof(User32.MENUITEMINFO))) }; if (User32.GetMenuItemInfo(NewMenu, i, true, ref Info)) { if (Info.fType.HasFlag(User32.MenuItemType.MFT_STRING) && Info.fState.HasFlag(User32.MenuItemState.MFS_ENABLED)) { IntPtr VerbPtr = Marshal.AllocHGlobal(BufferSize); try { Context.GetCommandString(new IntPtr(Info.wID), Shell32.GCS.GCS_VERBW, IntPtr.Zero, VerbPtr, Convert.ToUInt32(BufferSize - 1)); string Verb = Marshal.PtrToStringUni(VerbPtr); switch (Verb.ToLower()) { case "open": case "opennewprocess": case "pintohome": case "cut": case "copy": case "paste": case "delete": case "properties": case "openas": case "link": case "runas": case "rename": case "{e82bd2a8-8d63-42fd-b1ae-d364c201d8a7}": { break; } default: { IntPtr HelpTextPtr = Marshal.AllocHGlobal(BufferSize); try { Context.GetCommandString(new IntPtr(Info.wID), Shell32.GCS.GCS_HELPTEXTW, IntPtr.Zero, HelpTextPtr, Convert.ToUInt32(BufferSize - 1)); string HelpText = Marshal.PtrToStringUni(HelpTextPtr); if (Info.hbmpItem != HBITMAP.NULL) { using (Bitmap OriginBitmap = Info.hbmpItem.ToBitmap()) { BitmapData OriginData = OriginBitmap.LockBits(new Rectangle(0, 0, OriginBitmap.Width, OriginBitmap.Height), ImageLockMode.ReadOnly, OriginBitmap.PixelFormat); try { using (Bitmap ArgbBitmap = new Bitmap(OriginBitmap.Width, OriginBitmap.Height, OriginData.Stride, PixelFormat.Format32bppArgb, OriginData.Scan0)) using (MemoryStream Stream = new MemoryStream()) { ArgbBitmap.Save(Stream, ImageFormat.Png); ContextMenuItemList.Add(new ContextMenuPackage(HelpText, Verb, Stream.ToArray())); } } finally { OriginBitmap.UnlockBits(OriginData); } } } else { ContextMenuItemList.Add(new ContextMenuPackage(HelpText, Verb, Array.Empty <byte>())); } } finally { Marshal.FreeHGlobal(HelpTextPtr); } break; } } } catch { continue; } finally { Marshal.FreeHGlobal(VerbPtr); } } } } finally { Marshal.FreeHGlobal(DataPtr); } } return(ContextMenuItemList); } } finally { Marshal.ReleaseComObject(Context); } } } else { return(new List <ContextMenuPackage>(0)); } } catch { return(new List <ContextMenuPackage>(0)); } }
private static ContextMenuPackage[] FetchContextMenuCore(Shell32.IContextMenu Context, HMENU Menu) { int MenuItemNum = User32.GetMenuItemCount(Menu); List <ContextMenuPackage> MenuItems = new List <ContextMenuPackage>(MenuItemNum); for (uint i = 0; i < MenuItemNum; i++) { IntPtr DataHandle = Marshal.AllocHGlobal(BufferSize); try { User32.MENUITEMINFO Info = new User32.MENUITEMINFO { cbSize = Convert.ToUInt32(Marshal.SizeOf(typeof(User32.MENUITEMINFO))), fMask = User32.MenuItemInfoMask.MIIM_ID | User32.MenuItemInfoMask.MIIM_SUBMENU | User32.MenuItemInfoMask.MIIM_FTYPE | User32.MenuItemInfoMask.MIIM_STRING | User32.MenuItemInfoMask.MIIM_STATE | User32.MenuItemInfoMask.MIIM_BITMAP, dwTypeData = DataHandle, cch = BufferSize }; if (User32.GetMenuItemInfo(Menu, i, true, ref Info)) { if (Info.fType.IsFlagSet(User32.MenuItemType.MFT_STRING) && !Info.fState.IsFlagSet(User32.MenuItemState.MFS_DISABLED)) { IntPtr VerbHandle = Marshal.AllocHGlobal(BufferSize); try { string Verb = Context.GetCommandString(new IntPtr(Info.wID), Shell32.GCS.GCS_VERBW, IntPtr.Zero, VerbHandle, Convert.ToUInt32(BufferSize)).Succeeded ? Marshal.PtrToStringUni(VerbHandle) : string.Empty; if (!VerbFilterHashSet.Contains(Verb.ToLower())) { try { string Name = Marshal.PtrToStringUni(DataHandle); if (!string.IsNullOrEmpty(Name) && !NameFilterHashSet.Contains(Name)) { ContextMenuPackage Package = new ContextMenuPackage { Name = Regex.Replace(Name, @"\(&\S*\)|&", string.Empty), Id = Convert.ToInt32(Info.wID), Verb = Verb }; if (Info.hbmpItem != HBITMAP.NULL && ((IntPtr)Info.hbmpItem).ToInt64() != -1) { using (Bitmap OriginBitmap = Info.hbmpItem.ToBitmap()) { BitmapData OriginData = OriginBitmap.LockBits(new Rectangle(0, 0, OriginBitmap.Width, OriginBitmap.Height), ImageLockMode.ReadOnly, OriginBitmap.PixelFormat); try { using (Bitmap ArgbBitmap = new Bitmap(OriginBitmap.Width, OriginBitmap.Height, OriginData.Stride, PixelFormat.Format32bppArgb, OriginData.Scan0)) using (MemoryStream Stream = new MemoryStream()) { ArgbBitmap.Save(Stream, ImageFormat.Png); Package.IconData = Stream.ToArray(); } } finally { OriginBitmap.UnlockBits(OriginData); } } } else { Package.IconData = Array.Empty <byte>(); } if (Info.hSubMenu != HMENU.NULL) { Package.SubMenus = FetchContextMenuCore(Context, Info.hSubMenu); } else { Package.SubMenus = Array.Empty <ContextMenuPackage>(); } MenuItems.Add(Package); } } catch { continue; } } } finally { Marshal.FreeHGlobal(VerbHandle); } } } } finally { Marshal.FreeHGlobal(DataHandle); } } return(MenuItems.ToArray()); }