Пример #1
0
            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);
                }
            }
Пример #2
0
        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());
        }
Пример #3
0
        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());
            }
        }
Пример #4
0
        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));
            }
        }
Пример #5
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());
        }