How to get or/and execute context menu verbs knowing path of item

123244 60 Reputation points
2024-10-17T17:25:50.0333333+00:00

Hello, can you please tell me how to get information about commands from the windows context menu, I need to get all the commands for an element by its path, and if it is possible to run the command (verb) as if you clicked on it in the context menu.

Windows
Windows
A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.
5,479 questions
Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,649 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,997 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 85,706 Reputation points
    2024-10-17T23:02:29.1633333+00:00

    This test searches for example the verb "properties" and executes it (for a file E:\test.jpg)

    (you can also just use ShellExecute(Ex) for standard verbs or Process.Start)

    You can uncomment the "TrackPopupMenu..." part to display the context menu (WM_INITMENUPOPUP is needed for submenus)

     IContextMenu2 pContextMenu2 = null;
    
    
            public const int WM_INITMENUPOPUP = 0x0117;
    
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_INITMENUPOPUP)
                {
                     if (pContextMenu2 != null)
                        pContextMenu2.HandleMenuMsg((uint)m.Msg, (int)m.WParam, m.LParam);
                    return;
                }
                else
                    base.WndProc(ref m);
            }
    
    
    
                        IntPtr pItemIDL = ILCreateFromPath("E:\\test.jpg");
                        IntPtr pcm = IntPtr.Zero;
                        Guid IID_IContextMenu = new Guid("000214E4-0000-0000-C000-000000000046");
                        HRESULT hr = SHGetUIObjectFromFullPIDL(pItemIDL, IntPtr.Zero, ref IID_IContextMenu, ref pcm);
                        if (hr == HRESULT.S_OK)
                        {
                            IContextMenu pContextMenu = Marshal.GetObjectForIUnknown(pcm) as IContextMenu;
                            IntPtr hMenu = CreatePopupMenu();
                            //IntPtr hSubmenu = IntPtr.Zero;
                            IntPtr hSubmenu = hMenu;
                            //hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE |CMF_ASYNCVERBSTATE | CMF_INCLUDESTATIC);
                            hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE);
                            if (hr == HRESULT.S_OK)
                            {
                                pContextMenu2 = (IContextMenu2)pContextMenu;
                                hSubmenu = hMenu;
                                //int nX = Cursor.Position.X, nY = Cursor.Position.Y;
                                //uint nCmd = TrackPopupMenu(hSubmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, nX, nY, 0, this.Handle, IntPtr.Zero);
                                //if (nCmd != 0)
                                //{
                                //    CMINVOKECOMMANDINFO cmi = new CMINVOKECOMMANDINFO();
                                //    cmi.cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFO));
                                //    cmi.fMask = 0;
                                //    cmi.hwnd = this.Handle;
                                //    cmi.lpVerb = (IntPtr)(nCmd - 1);
                                //    cmi.lpParameters = IntPtr.Zero;
                                //    cmi.lpDirectory = IntPtr.Zero;
                                //    cmi.nShow = SW_SHOWNORMAL;
                                //    cmi.dwHotKey = 0;
                                //    cmi.hIcon = IntPtr.Zero; ;
                                //    hr = pContextMenu.InvokeCommand(ref cmi);
                                //}
    
                                int nNbItems = GetMenuItemCount(hSubmenu);
                                for (int i = nNbItems - 1; i >= 0; i--)
                                {
                                    MENUITEMINFO mii = new MENUITEMINFO();
                                    mii.cbSize = (uint)Marshal.SizeOf(typeof(MENUITEMINFO));
                                    mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID | MIIM_SUBMENU | MIIM_DATA;                                
                                    if (GetMenuItemInfo(hMenu, i, true, ref mii))
                                    {
                                        if (mii.fType == MFT_STRING)
                                        {
                                            StringBuilder sbVerb = new StringBuilder(260);
                                            hr = pContextMenu2.GetCommandString(mii.wID - 1, GCS_VERBW, IntPtr.Zero, sbVerb, (uint)sbVerb.Capacity);
                                            if (hr == HRESULT.S_OK)
                                            {
                                                if (sbVerb.ToString() == "properties")
                                                {
                                                    CMINVOKECOMMANDINFO cmi = new CMINVOKECOMMANDINFO();
                                                    cmi.cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFO));
                                                    cmi.fMask = 0;
                                                    cmi.hwnd = this.Handle;
                                                    cmi.lpVerb = (IntPtr)(mii.wID - 1);
                                                    cmi.lpParameters = IntPtr.Zero;
                                                    cmi.lpDirectory = IntPtr.Zero;
                                                    cmi.nShow = SW_SHOWNORMAL;
                                                    cmi.dwHotKey = 0;
                                                    cmi.hIcon = IntPtr.Zero; ;
                                                    hr = pContextMenu.InvokeCommand(ref cmi);
                                                }
                                            }
                                        }
                                    }
                                }
                                pContextMenu2 = null;
                            }
                            Marshal.ReleaseComObject(pContextMenu);
                            DestroyMenu(hMenu);
                        }
                        ILFree(pItemIDL);
    
                        return;
                    }
    
    
    public enum HRESULT : int
    {
        S_OK = 0,
        S_FALSE = 1,
        E_NOINTERFACE = unchecked((int)0x80004002),
        E_NOTIMPL = unchecked((int)0x80004001),
        E_FAIL = unchecked((int)0x80004005),
        E_UNEXPECTED = unchecked((int)0x8000FFFF),
        E_OUTOFMEMORY = unchecked((int)0x8007000E)
    }
    
           [DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern IntPtr ILCreateFromPath([MarshalAs(UnmanagedType.LPWStr)]string pszPath);
           
     // From MSDN : https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shbrowseforfolderw
     private HRESULT SHGetUIObjectFromFullPIDL(IntPtr pidl, IntPtr hwnd, ref Guid riid, ref IntPtr ppv)
     {
         IntPtr pidlChild = IntPtr.Zero;
         IShellFolder psf = null;
         ppv = IntPtr.Zero;
         Guid IID_IShellFolder = new Guid("000214E6-0000-0000-C000-000000000046");
         HRESULT hr = SHBindToParent(pidl, ref IID_IShellFolder, ref psf, ref pidlChild);
         if (hr == HRESULT.S_OK)
         {
             uint rgfReserved = 0;
             hr = psf.GetUIObjectOf(hwnd, 1, ref pidlChild, riid, ref rgfReserved, out ppv);
             Marshal.ReleaseComObject(psf);
         }
         return hr;
     }
     
           [DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern void ILFree(IntPtr pidl);
    
           [DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern HRESULT SHBindToParent(IntPtr pidl, ref Guid riid, ref IShellFolder ppv, ref IntPtr ppidlLast);
    
            [ComImport]
            [Guid("000214e4-0000-0000-c000-000000000046")]
            [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            public interface IContextMenu
            {
                HRESULT QueryContextMenu(IntPtr hmenu, uint indexMenu, uint idCmdFirst, uint idCmdLast, uint uFlags);
                [PreserveSig()]
                HRESULT InvokeCommand(ref CMINVOKECOMMANDINFO pici);
    
                [PreserveSig()]
                HRESULT GetCommandString(uint idCmd, uint uType, IntPtr pReserved, StringBuilder pszName, uint cchMax);
            }
    
            [ComImport]
            [Guid("000214f4-0000-0000-c000-000000000046")]
            [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            public interface IContextMenu2 : IContextMenu
            {
                new HRESULT QueryContextMenu(IntPtr hmenu, uint indexMenu, uint idCmdFirst, uint idCmdLast, uint uFlags);
                [PreserveSig()]
                new HRESULT InvokeCommand(ref CMINVOKECOMMANDINFO pici);
    
                [PreserveSig()]
                new HRESULT GetCommandString(uint idCmd, uint uType, IntPtr pReserved, StringBuilder pszName, uint cchMax);
    
                [PreserveSig()]
                HRESULT HandleMenuMsg(uint uMsg, int wParam, IntPtr lParam);
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            public struct CMINVOKECOMMANDINFO
            {
                public int cbSize;
                public int fMask;
                public IntPtr hwnd;
                public IntPtr lpVerb;
                public IntPtr lpParameters;
                public IntPtr lpDirectory;
                public int nShow;
                public int dwHotKey;
                public IntPtr hIcon;
            }
    
            public const int CMF_NORMAL = 0x00000000;
            public const int CMF_DEFAULTONLY = 0x00000001;
            public const int CMF_VERBSONLY = 0x00000002;
            public const int CMF_EXPLORE = 0x00000004;
            public const int CMF_NOVERBS = 0x00000008;
            public const int CMF_CANRENAME = 0x00000010;
            public const int CMF_NODEFAULT = 0x00000020;
            public const int CMF_INCLUDESTATIC = 0x00000040;
            public const int CMF_ITEMMENU = 0x00000080;
            public const int CMF_EXTENDEDVERBS = 0x00000100;
            public const int CMF_DISABLEDVERBS = 0x00000200;
            public const int CMF_ASYNCVERBSTATE = 0x00000400;
            public const int CMF_OPTIMIZEFORINVOKE = 0x00000800;
            public const int CMF_SYNCCASCADEMENU = 0x00001000;
            public const int CMF_DONOTPICKDEFAULT = 0x00002000;
            public const int CMF_RESERVED = unchecked((int)0xffff0000);
    
            public const int SW_SHOWNORMAL = 1;
    
            public const int GCS_VERBA = 0x00000000;     // canonical verb
            public const int GCS_HELPTEXTA = 0x00000001;     // help text (for status bar)
            public const int GCS_VALIDATEA = 0x00000002;     // validate command exists
            public const int GCS_VERBW = 0x00000004;     // canonical verb (unicode)
            public const int GCS_HELPTEXTW = 0x00000005;     // help text (unicode version)
            public const int GCS_VALIDATEW = 0x00000006;     // validate command exists (unicode)
            public const int GCS_VERBICONW = 0x00000014;     // icon string (unicode)
            public const int GCS_UNICODE = 0x00000004;     // for bit testing - Unicode string
            
                   [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern IntPtr CreatePopupMenu();
    
           [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern uint TrackPopupMenu(IntPtr hMenu, uint uFlags, int x, int y, int nReserved, IntPtr hWnd, IntPtr prcRect);
    
           public const int TPM_LEFTBUTTON = 0x0000;
           public const int TPM_RIGHTBUTTON = 0x0002;
           public const int TPM_LEFTALIGN = 0x0000;
           public const int TPM_CENTERALIGN = 0x0004;
           public const int TPM_RIGHTALIGN = 0x0008;
           public const int TPM_TOPALIGN = 0x0000;
           public const int TPM_VCENTERALIGN = 0x0010;
           public const int TPM_BOTTOMALIGN = 0x0020;
           public const int TPM_HORIZONTAL = 0x0000;     /* Horz alignment matters more */
           public const int TPM_VERTICAL = 0x0040;     /* Vert alignment matters more */
           public const int TPM_NONOTIFY = 0x0080;     /* Don't send any notification msgs */
           public const int TPM_RETURNCMD = 0x0100;
           public const int TPM_RECURSE = 0x0001;
           public const int TPM_HORPOSANIMATION = 0x0400;
           public const int TPM_HORNEGANIMATION = 0x0800;
           public const int TPM_VERPOSANIMATION = 0x1000;
           public const int TPM_VERNEGANIMATION = 0x2000;
           public const int TPM_NOANIMATION = 0x4000;
           public const int TPM_LAYOUTRTL = 0x8000;
           public const int TPM_WORKAREA = 0x10000;
    
           [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern bool GetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, [In, Out] ref MENUITEMINFO lpmii);
    
           [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
           public struct MENUITEMINFO
           {
               public uint cbSize;
               public uint fMask;
               public uint fType;         // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0)
               public uint fState;        // used if MIIM_STATE
               public uint wID;           // used if MIIM_ID
               public IntPtr hSubMenu;      // used if MIIM_SUBMENU
               public IntPtr hbmpChecked;   // used if MIIM_CHECKMARKS
               public IntPtr hbmpUnchecked; // used if MIIM_CHECKMARKS
               public IntPtr dwItemData;   // used if MIIM_DATA
    
               public IntPtr dwTypeData;
               //[MarshalAs(UnmanagedType.LPWStr)]
               //public string dwTypeData;    // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0)
               public uint cch;           // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0)
               public IntPtr hbmpItem;      // used if MIIM_BITMAP
           }
    
           public const int MIIM_STATE = 0x00000001;
           public const int MIIM_ID = 0x00000002;
           public const int MIIM_SUBMENU = 0x00000004;
           public const int MIIM_CHECKMARKS = 0x00000008;
           public const int MIIM_TYPE = 0x00000010;
           public const int MIIM_DATA = 0x00000020;
    
           public const int MIIM_STRING = 0x00000040;
           public const int MIIM_BITMAP = 0x00000080;
           public const int MIIM_FTYPE = 0x00000100;
    
           [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern int GetMenuString(IntPtr hMenu, uint uIDItem, StringBuilder lpString, int cchMax, uint flags);
    
           public const int MF_BYCOMMAND = 0x00000000;
           public const int MF_BYPOSITION = 0x00000400;
    
           [DllImport("User32.dll", SetLastError = true)]
           public static extern IntPtr GetSubMenu(IntPtr hMenu, int nPos);
    
           [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern int GetMenuItemCount(IntPtr hMenu);
    
           [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern bool DestroyMenu(IntPtr hMenu);
    
    
    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.