menu shell

jenCarlos 141 Reputation points
2022-02-08T01:03:08.547+00:00

Hello...
What I want is to get the "New" context menu along with its submenus, so that I can use it in an application.

Example:
172083-new-menu.jpg

172039-vb8nta7.jpg

have searched the internet and there are no good references about this, so I turn to you.
I have tried to do, but could not solve.

Dim CLSID_NewMenu As New Guid("{D969A300-E7FF-11d0-A93B-00A0C90F2719}")  
   Dim iContextMenuPtr As IntPtr = IntPtr.Zero  
        Dim pContextMenu As IContextMenu = Nothing  
  
        If CoCreateInstance(CLSID_NewMenu, IntPtr.Zero, CLSCTX.INPROC_SERVER, IID_IContextMenu, iContextMenuPtr) = 0 Then  
            Dim hMenu As IntPtr  
            pContextMenu = DirectCast(Marshal.GetObjectForIUnknown(iContextMenuPtr), IContextMenu)  
            
                 hMenu = CreatePopupMenu()  
                pContextMenu.QueryContextMenu(hMenu, 0, 1, &H7FFF, CMF.NORMAL)  
  
                Dim sbMenuItem As StringBuilder = New StringBuilder(260)  
                GetMenuString(hMenu, 0, sbMenuItem, sbMenuItem.Capacity, MF_BYPOSITION)  
                MsgBox(sbMenuItem.ToString)  
  
              
  
        End If  
  

I hope you can help me thanks.

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,578 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 81,741 Reputation points
    2022-02-09T00:26:40.523+00:00

    I just tested on Windows 7 and it worked with an older method, more complicated

    The whole test (with a Button for the click) =>
    (I let the first method and skipped it with "If False Then...")

    I cannot paste it, then a link : VB_IContextMenu_New

    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. Castorix31 81,741 Reputation points
    2022-02-08T10:23:46.807+00:00

    This works for me (test in C:\Temp folder) =>

    172188-icontextmenu.gif

            Dim sPath As String = "C:\Temp"  
            Dim pItemIDL As IntPtr = ILCreateFromPath(sPath)  
    
            Dim pContextMenu As IContextMenu = Nothing  
            Dim CLSID_NewMenu As New Guid("D969A300-E7FF-11d0-A93B-00A0C90F2719")  
            Dim NewMenuType As Type = Type.GetTypeFromCLSID(CLSID_NewMenu, True)  
            Dim NewMenu As Object = Activator.CreateInstance(NewMenuType)  
            pContextMenu = DirectCast(NewMenu, IContextMenu)  
            If pContextMenu IsNot Nothing Then  
                pContextMenu2 = CType(pContextMenu, IContextMenu2)  
                Dim hMenu As IntPtr = CreatePopupMenu()  
                Dim hr As HRESULT = pContextMenu.QueryContextMenu(hMenu, 0, 1, 256, 0)  
                If (hr = HRESULT.S_OK) Then  
                    Dim psei As IShellExtInit = Nothing  
                    psei = DirectCast(pContextMenu, IShellExtInit)  
                    hr = psei.Initialize(pItemIDL, Nothing, IntPtr.Zero)  
                    If (hr = HRESULT.S_OK) Then                          
                        Dim nX As Integer = Cursor.Position.X, nY = Cursor.Position.Y  
                        Dim hPopupMenu As IntPtr = GetSubMenu(hMenu, 0)  
                        Dim nCmd As UInteger = TrackPopupMenu(hPopupMenu, TPM_LEFTALIGN Or TPM_LEFTBUTTON Or TPM_RIGHTBUTTON Or TPM_RETURNCMD, nX, nY, 0, Me.Handle, IntPtr.Zero)  
                        If (nCmd <> 0) Then  
                            Dim cmi As CMINVOKECOMMANDINFO = New CMINVOKECOMMANDINFO()  
                            cmi.cbSize = Marshal.SizeOf(GetType(CMINVOKECOMMANDINFO))  
                            cmi.fMask = 0  
                            cmi.hwnd = Me.Handle  
                            cmi.lpVerb = CType((nCmd - 1), IntPtr)  
                            cmi.lpParameters = IntPtr.Zero  
                            cmi.lpDirectory = IntPtr.Zero  
                            cmi.nShow = SW_SHOWNORMAL  
                            cmi.dwHotKey = 0  
                            cmi.hIcon = IntPtr.Zero  
                            hr = pContextMenu.InvokeCommand(cmi)  
                        End If  
                        pContextMenu2 = Nothing  
                    End If  
                End If  
                Marshal.ReleaseComObject(pContextMenu)  
                DestroyMenu(hMenu)  
            End If  
            If (pItemIDL <> IntPtr.Zero) Then ILFree(pItemIDL)  
    

    HandleMenuMsg to build the context menu :

        Public pContextMenu2 As IContextMenu2 = Nothing  
        Public Const WM_INITMENUPOPUP As Integer = &H117  
      
        Protected Overrides Sub WndProc(ByRef m As Message)  
            If m.Msg = WM_INITMENUPOPUP Then  
                If pContextMenu2 IsNot Nothing Then pContextMenu2.HandleMenuMsg(CUInt(m.Msg), CInt(m.WParam), m.LParam)  
                Return  
            Else  
                MyBase.WndProc(m)  
            End If  
        End Sub  
    

    Declarations :

    Public Enum HRESULT As Integer  
        S_OK = 0  
        S_FALSE = 1  
        E_NOINTERFACE = &H80004002  
        E_NOTIMPL = &H80004001  
        E_FAIL = &H80004005  
        E_UNEXPECTED = &H8000FFFF  
        E_OUTOFMEMORY = &H8007000E  
    End Enum  
    
    <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>  
    Public Shared Function ILCreateFromPath(<MarshalAs(UnmanagedType.LPWStr)> pszPath As String) As IntPtr  
    End Function  
    
    <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>  
    Public Shared Sub ILFree(pidl As IntPtr)  
    End Sub  
    
    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>  
    Public Shared Function CreatePopupMenu() As IntPtr  
    End Function  
    
    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>  
    Public Shared Function TrackPopupMenu(hMenu As IntPtr, uFlags As UInteger, x As Integer, y As Integer, nReserved As Integer, hWnd As IntPtr, prcRect As IntPtr) As UInteger  
    End Function  
    
    Public Const TPM_LEFTBUTTON As Integer = &H0  
    Public Const TPM_RIGHTBUTTON As Integer = &H2  
    Public Const TPM_LEFTALIGN As Integer = &H0  
    Public Const TPM_CENTERALIGN As Integer = &H4  
    Public Const TPM_RIGHTALIGN As Integer = &H8  
    Public Const TPM_TOPALIGN As Integer = &H0  
    Public Const TPM_VCENTERALIGN As Integer = &H10  
    Public Const TPM_BOTTOMALIGN As Integer = &H20  
    Public Const TPM_HORIZONTAL As Integer = &H0  
    Public Const TPM_VERTICAL As Integer = &H40  
    Public Const TPM_NONOTIFY As Integer = &H80  
    Public Const TPM_RETURNCMD As Integer = &H100  
    Public Const TPM_RECURSE As Integer = &H1  
    Public Const TPM_HORPOSANIMATION As Integer = &H400  
    Public Const TPM_HORNEGANIMATION As Integer = &H800  
    Public Const TPM_VERPOSANIMATION As Integer = &H1000  
    Public Const TPM_VERNEGANIMATION As Integer = &H2000  
    Public Const TPM_NOANIMATION As Integer = &H4000  
    Public Const TPM_LAYOUTRTL As Integer = &H8000  
    Public Const TPM_WORKAREA As Integer = &H10000  
    
    <DllImport("User32.dll", SetLastError:=True)>  
    Public Shared Function GetSubMenu(hMenu As IntPtr, nPos As Integer) As IntPtr  
    End Function  
    
    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>  
    Public Shared Function GetMenuItemCount(hMenu As IntPtr) As Integer  
    End Function  
    
    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>  
    Public Shared Function DestroyMenu(hMenu As IntPtr) As Boolean  
    End Function  
    
    <ComImport>  
    <Guid("000214e4-0000-0000-c000-000000000046")>  
    <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>  
    Interface IContextMenu  
        Function QueryContextMenu(hmenu As IntPtr, indexMenu As UInteger, idCmdFirst As UInteger, idCmdLast As UInteger, uFlags As UInteger) As HRESULT  
        <PreserveSig()>  
        Function InvokeCommand(ByRef pici As CMINVOKECOMMANDINFO) As HRESULT  
        <PreserveSig()>  
        Function GetCommandString(idCmd As UInteger, uType As UInteger, pReserved As IntPtr, pszName As StringBuilder, cchMax As UInteger) As HRESULT  
    End Interface  
    
    <ComImport>  
    <Guid("000214f4-0000-0000-c000-000000000046")>  
    <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>  
    Interface IContextMenu2  
        Inherits IContextMenu  
    
        Overloads Function QueryContextMenu(hmenu As IntPtr, indexMenu As UInteger, idCmdFirst As UInteger, idCmdLast As UInteger, uFlags As UInteger) As HRESULT  
        <PreserveSig()>  
        Overloads Function InvokeCommand(ByRef pici As CMINVOKECOMMANDINFO) As HRESULT  
        <PreserveSig()>  
        Overloads Function GetCommandString(idCmd As UInteger, uType As UInteger, pReserved As IntPtr, pszName As StringBuilder, cchMax As UInteger) As HRESULT  
        <PreserveSig()>  
        Function HandleMenuMsg(uMsg As UInteger, wParam As Integer, lParam As IntPtr) As HRESULT  
    End Interface  
    
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>  
    Public Structure CMINVOKECOMMANDINFO  
        Public cbSize As Integer  
        Public fMask As Integer  
        Public hwnd As IntPtr  
        Public lpVerb As IntPtr  
        Public lpParameters As IntPtr  
        Public lpDirectory As IntPtr  
        Public nShow As Integer  
        Public dwHotKey As Integer  
        Public hIcon As IntPtr  
    End Structure  
    
    Public Const CMF_NORMAL As Integer = &H0  
    Public Const CMF_DEFAULTONLY As Integer = &H1  
    Public Const CMF_VERBSONLY As Integer = &H2  
    Public Const CMF_EXPLORE As Integer = &H4  
    Public Const CMF_NOVERBS As Integer = &H8  
    Public Const CMF_CANRENAME As Integer = &H10  
    Public Const CMF_NODEFAULT As Integer = &H20  
    Public Const CMF_INCLUDESTATIC As Integer = &H40  
    Public Const CMF_ITEMMENU As Integer = &H80  
    Public Const CMF_EXTENDEDVERBS As Integer = &H100  
    Public Const CMF_DISABLEDVERBS As Integer = &H200  
    Public Const CMF_ASYNCVERBSTATE As Integer = &H400  
    Public Const CMF_OPTIMIZEFORINVOKE As Integer = &H800  
    Public Const CMF_SYNCCASCADEMENU As Integer = &H1000  
    Public Const CMF_DONOTPICKDEFAULT As Integer = &H2000  
    Public Const CMF_RESERVED As Integer = &HFFFF0000  
    Public Const SW_SHOWNORMAL As Integer = 1  
    Public Const GCS_VERBA As Integer = &H0  
    Public Const GCS_HELPTEXTA As Integer = &H1  
    Public Const GCS_VALIDATEA As Integer = &H2  
    Public Const GCS_VERBW As Integer = &H4  
    Public Const GCS_HELPTEXTW As Integer = &H5  
    Public Const GCS_VALIDATEW As Integer = &H6  
    Public Const GCS_VERBICONW As Integer = &H14  
    Public Const GCS_UNICODE As Integer = &H4  
    
    
    <ComImport>  
    <Guid("000214E8-0000-0000-C000-000000000046")>  
    <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>  
    Interface IShellExtInit  
        Function Initialize(pidlFolder As IntPtr, pdtobj As IDataObject, hkeyProgID As IntPtr) As HRESULT  
    End Interface  
    
    1 person found this answer helpful.

  2. Jiachen Li-MSFT 26,671 Reputation points Microsoft Vendor
    2022-02-08T07:12:09.107+00:00

    Hi @jenCarlos ,
    You can try to use ContextMenuStrip Control to implement the "New" context menu along with its submenus.
    Add a new ContextMenuStrip control, add menu items to it in design view and implement the function for each menu item.
    Then set the form's ContextMenuStrip property.

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
            MyBase.ContextMenuStrip = ContextMenuStrip1  
        End Sub  
    

    Hope this could be helpful.
    Best Regards.
    Jiachen Li

    ----------

    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.