none
Contextual menu RRS feed

  • Question

  • Hello programmers ...

    What I want is to obtain, the option "Send to", the standard contextual menu, to be able to use in my application.


    Send to the menu in NSE:

    Is there any way to carry out this operation?
    If so, could you help me with an example please

    First of all, Thanks

    Sunday, December 8, 2019 4:47 AM

Answers

  • Can you pass me the complete code please
    Castorix31


    I am working on windows 7

    The code, tested with a file "e:\test.jpg" (change it) on Windows 10 FR (the localized string of the menu is not "Send To" in FR, I hope it will work on EN-US OS...)

    (add a button on an empty form for the click...)

    I added a few comments to explain briefly what I did... =>

    Option Strict On
    Imports System.Runtime.InteropServices
    Imports System.Text
    
    Public Class Form1
        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
    
        <ComImport>
        <Guid("000214e4-0000-0000-c000-000000000046")>
        <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Interface IContextMenu
            Function QueryContextMenu(ByVal hmenu As IntPtr, ByVal indexMenu As UInteger, ByVal idCmdFirst As UInteger, ByVal idCmdLast As UInteger, ByVal uFlags As UInteger) As HRESULT
            <PreserveSig()>
            Function InvokeCommand(ByRef pici As CMINVOKECOMMANDINFO) As HRESULT
            <PreserveSig()>
            Function GetCommandString(ByVal idCmd As UInteger, ByVal uType As UInteger, ByVal pReserved As IntPtr, ByVal pszName As StringBuilder, ByVal cchMax As UInteger) 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 = &HFFFF0000
    
    
        <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 GetMenuString(ByVal hMenu As IntPtr, ByVal uIDItem As UInteger, ByVal lpString As StringBuilder, ByVal cchMax As Integer, ByVal flags As UInteger) As Integer
        End Function
    
        Public Const MF_BYCOMMAND As Integer = &H0
        Public Const MF_BYPOSITION As Integer = &H400
    
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function GetMenuItemCount(ByVal hMenu As IntPtr) As Integer
        End Function
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function DestroyMenu(ByVal hMenu As IntPtr) As Boolean
        End Function
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function TrackPopupMenu(ByVal hMenu As IntPtr, ByVal uFlags As UInteger, ByVal x As Integer, ByVal y As Integer, ByVal nReserved As Integer, ByVal hWnd As IntPtr, ByVal 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
    
        Public Const SW_SHOWNORMAL = 1
    
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function GetMenuItemInfo(ByVal hMenu As IntPtr, ByVal uItem As Integer, ByVal fByPosition As Boolean, <[In], Out> ByRef lpmii As MENUITEMINFO) As Boolean
        End Function
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
        Public Structure MENUITEMINFO
            Public cbSize As UInteger
            Public fMask As UInteger
            Public fType As UInteger
            Public fState As UInteger
            Public wID As UInteger
            Public hSubMenu As IntPtr
            Public hbmpChecked As IntPtr
            Public hbmpUnchecked As IntPtr
            Public dwItemData As IntPtr
            <MarshalAs(UnmanagedType.LPWStr)>
            Private dwTypeData As String
            Public cch As UInteger
            Public hbmpItem As IntPtr
        End Structure
    
        Public Const MIIM_STATE As Integer = &H1
            Public Const MIIM_ID As Integer = &H2
            Public Const MIIM_SUBMENU As Integer = &H4
            Public Const MIIM_CHECKMARKS As Integer = &H8
            Public Const MIIM_TYPE As Integer = &H10
            Public Const MIIM_DATA As Integer = &H20
            Public Const MIIM_STRING As Integer = &H40
            Public Const MIIM_BITMAP As Integer = &H80
            Public Const MIIM_FTYPE As Integer = &H100
    
    
        <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function ILCreateFromPath(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszPath As String) As IntPtr
        End Function
    
        <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Sub ILFree(ByVal pidl As IntPtr)
        End Sub
    
    
        <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function SHBindToParent(ByVal pidl As IntPtr, ByRef riid As Guid, ByRef ppv As IShellFolder, ByRef ppidlLast As IntPtr) As HRESULT
        End Function
    
        <ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214E6-0000-0000-C000-000000000046")>
        Interface IShellFolder
            Function ParseDisplayName(ByVal hwnd As IntPtr, ByVal pbc As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal pszDisplayName As String, <[In], Out> ByRef pchEaten As UInteger, <Out> ByRef ppidl As IntPtr, <[In], Out> ByRef pdwAttributes As SFGAO) As HRESULT
            Function EnumObjects(ByVal hwnd As IntPtr, ByVal grfFlags As SHCONTF, <Out> ByRef ppenumIDList As IEnumIDList) As HRESULT
            Function BindToObject(ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
            Function BindToStorage(ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
            Function CompareIDs(ByVal lParam As IntPtr, ByVal pidl1 As IntPtr, ByVal pidl2 As IntPtr) As HRESULT
            Function CreateViewObject(ByVal hwndOwner As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
            Function GetAttributesOf(ByVal cidl As UInteger, ByVal apidl As IntPtr, <[In], Out> ByRef rgfInOut As SFGAO) As HRESULT
            Function GetUIObjectOf(ByVal hwndOwner As IntPtr, ByVal cidl As UInteger, ByRef apidl As IntPtr, <[In]> ByRef riid As Guid, <[In], Out> ByRef rgfReserved As UInteger, <Out> ByRef ppv As IntPtr) As HRESULT
            Function GetDisplayNameOf(ByVal pidl As IntPtr, ByVal uFlags As SHGDNF, <Out> ByRef pName As STRRET) As HRESULT
            Function SetNameOf(ByVal hwnd As IntPtr, ByVal pidl As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, ByVal uFlags As SHGDNF, <Out> ByRef ppidlOut As IntPtr) As HRESULT
        End Interface
    
        Public Enum SHCONTF
            SHCONTF_CHECKING_FOR_CHILDREN = &H10
            SHCONTF_FOLDERS = &H20
            SHCONTF_NONFOLDERS = &H40
            SHCONTF_INCLUDEHIDDEN = &H80
            SHCONTF_INIT_ON_FIRST_NEXT = &H100
            SHCONTF_NETPRINTERSRCH = &H200
            SHCONTF_SHAREABLE = &H400
            SHCONTF_STORAGE = &H800
            SHCONTF_NAVIGATION_ENUM = &H1000
            SHCONTF_FASTITEMS = &H2000
            SHCONTF_FLATLIST = &H4000
            SHCONTF_ENABLE_ASYNC = &H8000
        End Enum
    
        Public Enum SFGAO
            CANCOPY = &H1
            CANMOVE = &H2
            CANLINK = &H4
            STORAGE = &H8
            CANRENAME = &H10
            CANDELETE = &H20
            HASPROPSHEET = &H40
            DROPTARGET = &H100
            CAPABILITYMASK = &H177
            ENCRYPTED = &H2000
            ISSLOW = &H4000
            GHOSTED = &H8000
            LINK = &H10000
            SHARE = &H20000
            [READONLY] = &H40000
            HIDDEN = &H80000
            DISPLAYATTRMASK = &HFC000
            STREAM = &H400000
            STORAGEANCESTOR = &H800000
            VALIDATE = &H1000000
            REMOVABLE = &H2000000
            COMPRESSED = &H4000000
            BROWSABLE = &H8000000
            FILESYSANCESTOR = &H10000000
            FOLDER = &H20000000
            FILESYSTEM = &H40000000
            HASSUBFOLDER = &H80000000
            CONTENTSMASK = &H80000000
            STORAGECAPMASK = &H70C50008
            PKEYSFGAOMASK = &H81044000
        End Enum
    
        Public Enum SHGDNF
            SHGDN_NORMAL = 0
            SHGDN_INFOLDER = &H1
            SHGDN_FOREDITING = &H1000
            SHGDN_FORADDRESSBAR = &H4000
            SHGDN_FORPARSING = &H8000
        End Enum
    
    
        <StructLayout(LayoutKind.Explicit, Size:=264)>
        Public Structure STRRET
            <FieldOffset(0)>
            Public uType As UInteger
            <FieldOffset(4)>
            Public pOleStr As IntPtr
            <FieldOffset(4)>
            Public uOffset As UInteger
            <FieldOffset(4)>
            Public cString As IntPtr
        End Structure
    
        <ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F2-0000-0000-C000-000000000046")>
        Interface IEnumIDList
            <PreserveSig()>
            Function [Next](ByVal celt As UInteger, <Out> ByRef rgelt As IntPtr, <Out> ByRef pceltFetched As Integer) As HRESULT
            <PreserveSig()>
            Function Skip(ByVal celt As UInteger) As HRESULT
            Sub Reset()
            Function Clone() As IEnumIDList
        End Interface
    
        'Add a button to test
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Get the localized string for "Send To"
            Dim hr As HRESULT = HRESULT.E_FAIL
            Dim sSendTo As String = Nothing
            Dim pContextMenu As IContextMenu
            Dim CLSID_SendToMenu As New Guid("7BA4C740-9E81-11CF-99D3-00AA004AE837")
            Dim SendToMenuType As Type = Type.GetTypeFromCLSID(CLSID_SendToMenu, True)
            Dim SendToMenu As Object = Activator.CreateInstance(SendToMenuType)
            pContextMenu = DirectCast(SendToMenu, IContextMenu)
            If (pContextMenu IsNot Nothing) Then
                Dim hMenu As IntPtr = CreatePopupMenu()
                Dim sbMenuItem As StringBuilder = New StringBuilder(260)
                hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, &H7FFF, CMF_EXPLORE)
                If (hr = HRESULT.S_OK) Then
                    GetMenuString(hMenu, 0, sbMenuItem, sbMenuItem.Capacity, MF_BYPOSITION)
                    sSendTo = sbMenuItem.ToString()
                End If
                DestroyMenu(hMenu)
            End If
            Marshal.ReleaseComObject(pContextMenu)
    
            ' Test on a given file
            Dim pItemIDL As IntPtr = ILCreateFromPath("E:\test.jpg")
    
            ' Display the context menu and find the localized string (in french : "Envo&yer vers") to get the submenu handle
            Dim pcm As IntPtr = IntPtr.Zero
            Dim IID_IContextMenu As Guid = New Guid("000214E4-0000-0000-C000-000000000046")
            hr = SHGetUIObjectFromFullPIDL(pItemIDL, IntPtr.Zero, IID_IContextMenu, pcm)
            If (hr = HRESULT.S_OK) Then
                Dim pContextMenuShell As IContextMenu = TryCast(Marshal.GetObjectForIUnknown(pcm), IContextMenu)
                Dim hMenu As IntPtr = CreatePopupMenu()
                Dim hSubmenu As IntPtr = hMenu
                hr = pContextMenuShell.QueryContextMenu(hMenu, 0, 1, &H7FFF, CMF_EXPLORE)
                If (hr = HRESULT.S_OK) Then
                    Dim nNbItems As Integer = GetMenuItemCount(hMenu)
                    For i As Integer = nNbItems - 1 To 0 Step -1
                        Dim sbMenuItem As StringBuilder = New StringBuilder(260)
                        GetMenuString(hMenu, CUInt(i), sbMenuItem, sbMenuItem.Capacity, MF_BYPOSITION)
                        If (sbMenuItem.ToString() = sSendTo) Then
                            Dim mii As MENUITEMINFO = New MENUITEMINFO()
                            mii.cbSize = CType(Marshal.SizeOf(GetType(MENUITEMINFO)), UInteger)
                            mii.fMask = (MIIM_FTYPE Or MIIM_ID Or MIIM_SUBMENU Or MIIM_DATA)
                            If GetMenuItemInfo(hMenu, i, True, mii) Then
                                hSubmenu = mii.hSubMenu
                                Exit For
                            End If
                        End If
                    Next
                End If
    
                'Display the "Send To" context menu
                Dim nX As Integer = Cursor.Position.X, nY As Integer = Cursor.Position.Y
                Dim nCmd As UInteger = TrackPopupMenu(hSubmenu, TPM_LEFTALIGN Or TPM_LEFTBUTTON Or TPM_RIGHTBUTTON Or TPM_RETURNCMD, nX, nY, 0, Me.Handle, IntPtr.Zero)
    
                'Execute the chosen item
                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 = pContextMenuShell.InvokeCommand(cmi)
                End If
    
                Marshal.ReleaseComObject(pContextMenuShell)
                DestroyMenu(hMenu)
            End If
    
            ILFree(pItemIDL)
        End Sub
    
        Private Function SHGetUIObjectFromFullPIDL(ByVal pidl As IntPtr, ByVal hwnd As IntPtr, ByRef riid As Guid, ByRef ppv As IntPtr) As HRESULT
            Dim pidlChild As IntPtr = IntPtr.Zero
            Dim psf As IShellFolder = Nothing
            ppv = IntPtr.Zero
            Dim IID_IShellFolder As Guid = New Guid("000214E6-0000-0000-C000-000000000046")
            Dim hr As HRESULT = SHBindToParent(pidl, IID_IShellFolder, psf, pidlChild)
            If hr = HRESULT.S_OK Then
                Dim rgfReserved As UInteger = 0
                hr = psf.GetUIObjectOf(hwnd, 1, pidlChild, riid, rgfReserved, ppv)
                Marshal.ReleaseComObject(psf)
            End If
            Return hr
        End Function
    End Class
    

    • Marked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Unmarked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Marked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Unmarked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Marked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    Sunday, December 8, 2019 6:37 PM
  • Hello,

    Let' call the following the "cheap and dirty" method to add your application to the "Send to" menu.

    Create your application, add the following code which is done from project properties, Application tab, click the button "View Application Events" and replace the default code with this code.

    Namespace My
        Partial Friend Class MyApplication
            Public ReadOnly Property CommandLineArguments As String()
                Get
                    Dim arguments = Environment.
                            GetCommandLineArgs.
                            ToList().
                            Select(Function(argument) argument.ToUpper()).
                            ToList()
    
                    arguments.RemoveAt(0)
    
                    Return arguments.ToArray()
    
                End Get
            End Property
            ''' <summary>
            ''' Used to get command argument count
            ''' </summary>
            ''' <returns>Count of command arguments sent on startup of application</returns>
            Public ReadOnly Property HasCommandLineArguments As Boolean
                Get
                    Return CommandLineArguments.Length = 1
                End Get
            End Property
        End Class
    End Namespace
    

    Build the project, from Windows Explorer copy the executable and paste as shortcut to 

    %AppData%\Microsoft\Windows\SendTo

    e.g.

    C:\Users\UserName\AppData\Roaming\Microsoft\Windows\SendTo

    Give the shortcut a meaningful name e.g. for this demo my executable name is WindowsApp1.exe and the shortcut name is Karen Demo

    Now all that is left is to add code to perform actions. For a simple example we want to only work on .VB files, adjust the code as per below.

    Imports Microsoft.VisualBasic.ApplicationServices
    
    Namespace My
        Partial Friend Class MyApplication
            Public ReadOnly Property CommandLineArguments As String()
                Get
                    Dim arguments = Environment.
                            GetCommandLineArgs.
                            ToList().
                            Select(Function(argument) argument.ToUpper()).
                            ToList()
    
                    arguments.RemoveAt(0)
    
                    Return arguments.ToArray()
    
                End Get
            End Property
            ''' <summary>
            ''' Used to get command argument count
            ''' </summary>
            ''' <returns>Count of command arguments sent on startup of application</returns>
            Public ReadOnly Property HasCommandLineArguments As Boolean
                Get
                    Return CommandLineArguments.Length = 1
                End Get
            End Property
    
            Private Sub MyApplication_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
    
                If HasCommandLineArguments Then
    
                    If CommandLineArguments.FirstOrDefault().ToLower().EndsWith(".vb") Then
                        MessageBox.Show("Do something")
                    Else
                        MessageBox.Show("Closing")
                        e.Cancel = True
                    End If
                End If
            End Sub
        End Class
    End Namespace
    

    Or if you want to open the main form

    Imports Microsoft.VisualBasic.ApplicationServices
    
    Namespace My
        Partial Friend Class MyApplication
            Public ReadOnly Property CommandLineArguments As String()
                Get
                    Dim arguments = Environment.
                            GetCommandLineArgs.
                            ToList().
                            Select(Function(argument) argument.ToUpper()).
                            ToList()
    
                    arguments.RemoveAt(0)
    
                    Return arguments.ToArray()
    
                End Get
            End Property
            ''' <summary>
            ''' Used to get command argument count
            ''' </summary>
            ''' <returns>Count of command arguments sent on startup of application</returns>
            Public ReadOnly Property HasCommandLineArguments As Boolean
                Get
                    Return CommandLineArguments.Length = 1
                End Get
            End Property
    
            Private Sub MyApplication_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
    
                If HasCommandLineArguments Then
                    If Not CommandLineArguments.FirstOrDefault().ToLower().EndsWith(".vb") Then
                        e.Cancel = True
                    End If
                End If
            End Sub
        End Class
    End Namespace
    
    Hopefully this makes sense. The main drawback is it will always show in the "Send to" while more advance code which uses API could have logic to not show on some cases.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    • Marked as answer by JenCarlos Wednesday, June 3, 2020 10:18 PM
    Sunday, December 8, 2019 5:00 PM
    Moderator

All replies

  • Hi JenCarlos,

    I hope this article will be helpful.
    Context Menu and Event Handling in Visual Basic .NET
    Regards,

    Ashidacchi -- http://hokusosha.com

    Sunday, December 8, 2019 6:50 AM
  • Hi thanks.
    What I want is the context menu "send to" using shell functions.

    I found this example, the bad thing is that it is written in delphi, which I am not familiar with this language.

    function TMenuWithSentTo.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult;
    const
      SendToCLSID: TGUID = '{7BA4C740-9E81-11CF-99D3-00AA004AE837}';
    var
      ShellExtInit: IShellExtInit;
    begin
      Result := 0;
    
      // Add you menu items here
    
      CoCreateInstance(SendToCLSID, nil, CLSCTX_INPROC_SERVER, IContextMenu, FSendToMenu);
      FSendToMenu.QueryInterface(IShellExtInit, ShellExtInit);
      ShellExtInit.Initialize(nil, FDataObject, 0); // your IDataObject with CFSTR_SHELLIDLIST format 
      Result := Result + FSendToMenu.QueryContextMenu(Menu, indexMenu, idCmdFirst, idCmdLast, uFlags);
    
      // Add you menu items here
    end;
    
    function TMenuWithSentTo.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
    begin
      if IsMyCommand(lpici) then
        begin
          // Process your command here
          Result := S_OK;
        end
      else
        Result := FSendToMenu.InvokeCommand(lpici);
    end;
    
    function TMenuWithSentTo.GetCommandString(idCmd: UINT_PTR; uFlags: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult;
    begin
      if IsMyCommandID(idCmd) then
        begin
          // Process your command here
          Result := S_OK;
        end
      else
        FSendToMenu.GetCommandString(idCmd);
    end;
    
    function TMenuWithSentTo.HandleMenuMsg(uMsg: UINT; WParam: WPARAM; LParam: LPARAM): HResult;
    var
      SendToMenu2: IContextMenu2;
    begin
      if IsMyMessage(uMsg, WParam, LParam) then
        begin
          // Process your command here
          Result := S_OK;
        end
      else
        begin
          FSendToMenu.QueryInterface(IContextMenu2, SendToMenu2);
          Result := SendToMenu2.HandleMenuMsg(uMsg, WParam, LParam);
        end;
    end;
    
    function TMenuWithSentTo.HandleMenuMsg2(uMsg: UINT; wParam: WPARAM; lParam: LPARAM; var lpResult: LRESULT): HResult;
    var
      SendToMenu3: IContextMenu3;
    begin
      if IsMyMessage(uMsg, WParam, LParam) then
        begin
          // Process your command here
          Result := S_OK;
        end
      else
        begin
          FSendToMenu.QueryInterface(IContextMenu3, SendToMenu3);
          Result := SendToMenu3.HandleMenuMsg(uMsg, WParam, LParam);
        end;
    end;

    I found in this link: https://stackoverflow.com/questions/22990080/how-to-addenable-standard-send-to-context-menu-option-in-a-namespace-extensi

    can someone please help me with an example in visual basic


    Sunday, December 8, 2019 3:08 PM
  • Hello,

    Let' call the following the "cheap and dirty" method to add your application to the "Send to" menu.

    Create your application, add the following code which is done from project properties, Application tab, click the button "View Application Events" and replace the default code with this code.

    Namespace My
        Partial Friend Class MyApplication
            Public ReadOnly Property CommandLineArguments As String()
                Get
                    Dim arguments = Environment.
                            GetCommandLineArgs.
                            ToList().
                            Select(Function(argument) argument.ToUpper()).
                            ToList()
    
                    arguments.RemoveAt(0)
    
                    Return arguments.ToArray()
    
                End Get
            End Property
            ''' <summary>
            ''' Used to get command argument count
            ''' </summary>
            ''' <returns>Count of command arguments sent on startup of application</returns>
            Public ReadOnly Property HasCommandLineArguments As Boolean
                Get
                    Return CommandLineArguments.Length = 1
                End Get
            End Property
        End Class
    End Namespace
    

    Build the project, from Windows Explorer copy the executable and paste as shortcut to 

    %AppData%\Microsoft\Windows\SendTo

    e.g.

    C:\Users\UserName\AppData\Roaming\Microsoft\Windows\SendTo

    Give the shortcut a meaningful name e.g. for this demo my executable name is WindowsApp1.exe and the shortcut name is Karen Demo

    Now all that is left is to add code to perform actions. For a simple example we want to only work on .VB files, adjust the code as per below.

    Imports Microsoft.VisualBasic.ApplicationServices
    
    Namespace My
        Partial Friend Class MyApplication
            Public ReadOnly Property CommandLineArguments As String()
                Get
                    Dim arguments = Environment.
                            GetCommandLineArgs.
                            ToList().
                            Select(Function(argument) argument.ToUpper()).
                            ToList()
    
                    arguments.RemoveAt(0)
    
                    Return arguments.ToArray()
    
                End Get
            End Property
            ''' <summary>
            ''' Used to get command argument count
            ''' </summary>
            ''' <returns>Count of command arguments sent on startup of application</returns>
            Public ReadOnly Property HasCommandLineArguments As Boolean
                Get
                    Return CommandLineArguments.Length = 1
                End Get
            End Property
    
            Private Sub MyApplication_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
    
                If HasCommandLineArguments Then
    
                    If CommandLineArguments.FirstOrDefault().ToLower().EndsWith(".vb") Then
                        MessageBox.Show("Do something")
                    Else
                        MessageBox.Show("Closing")
                        e.Cancel = True
                    End If
                End If
            End Sub
        End Class
    End Namespace
    

    Or if you want to open the main form

    Imports Microsoft.VisualBasic.ApplicationServices
    
    Namespace My
        Partial Friend Class MyApplication
            Public ReadOnly Property CommandLineArguments As String()
                Get
                    Dim arguments = Environment.
                            GetCommandLineArgs.
                            ToList().
                            Select(Function(argument) argument.ToUpper()).
                            ToList()
    
                    arguments.RemoveAt(0)
    
                    Return arguments.ToArray()
    
                End Get
            End Property
            ''' <summary>
            ''' Used to get command argument count
            ''' </summary>
            ''' <returns>Count of command arguments sent on startup of application</returns>
            Public ReadOnly Property HasCommandLineArguments As Boolean
                Get
                    Return CommandLineArguments.Length = 1
                End Get
            End Property
    
            Private Sub MyApplication_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
    
                If HasCommandLineArguments Then
                    If Not CommandLineArguments.FirstOrDefault().ToLower().EndsWith(".vb") Then
                        e.Cancel = True
                    End If
                End If
            End Sub
        End Class
    End Namespace
    
    Hopefully this makes sense. The main drawback is it will always show in the "Send to" while more advance code which uses API could have logic to not show on some cases.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    • Marked as answer by JenCarlos Wednesday, June 3, 2020 10:18 PM
    Sunday, December 8, 2019 5:00 PM
    Moderator

  • What I want is the context menu "send to" using shell functions.

    I did it with IContextMenu interface

    but there are a lot of declarations (P/Invoke)

    If you don't find a simpler method, I could post it.

    I tested on Windows 10 (french) =>

    Sunday, December 8, 2019 6:13 PM
  • ok, thank you
    Sunday, December 8, 2019 6:15 PM
  • Can you pass me the complete code please
    Castorix31


    I am working on windows 7

    • Edited by JenCarlos Sunday, December 8, 2019 6:24 PM
    Sunday, December 8, 2019 6:23 PM
  • Can you pass me the complete code please
    Castorix31


    I am working on windows 7

    The code, tested with a file "e:\test.jpg" (change it) on Windows 10 FR (the localized string of the menu is not "Send To" in FR, I hope it will work on EN-US OS...)

    (add a button on an empty form for the click...)

    I added a few comments to explain briefly what I did... =>

    Option Strict On
    Imports System.Runtime.InteropServices
    Imports System.Text
    
    Public Class Form1
        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
    
        <ComImport>
        <Guid("000214e4-0000-0000-c000-000000000046")>
        <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Interface IContextMenu
            Function QueryContextMenu(ByVal hmenu As IntPtr, ByVal indexMenu As UInteger, ByVal idCmdFirst As UInteger, ByVal idCmdLast As UInteger, ByVal uFlags As UInteger) As HRESULT
            <PreserveSig()>
            Function InvokeCommand(ByRef pici As CMINVOKECOMMANDINFO) As HRESULT
            <PreserveSig()>
            Function GetCommandString(ByVal idCmd As UInteger, ByVal uType As UInteger, ByVal pReserved As IntPtr, ByVal pszName As StringBuilder, ByVal cchMax As UInteger) 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 = &HFFFF0000
    
    
        <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 GetMenuString(ByVal hMenu As IntPtr, ByVal uIDItem As UInteger, ByVal lpString As StringBuilder, ByVal cchMax As Integer, ByVal flags As UInteger) As Integer
        End Function
    
        Public Const MF_BYCOMMAND As Integer = &H0
        Public Const MF_BYPOSITION As Integer = &H400
    
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function GetMenuItemCount(ByVal hMenu As IntPtr) As Integer
        End Function
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function DestroyMenu(ByVal hMenu As IntPtr) As Boolean
        End Function
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function TrackPopupMenu(ByVal hMenu As IntPtr, ByVal uFlags As UInteger, ByVal x As Integer, ByVal y As Integer, ByVal nReserved As Integer, ByVal hWnd As IntPtr, ByVal 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
    
        Public Const SW_SHOWNORMAL = 1
    
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function GetMenuItemInfo(ByVal hMenu As IntPtr, ByVal uItem As Integer, ByVal fByPosition As Boolean, <[In], Out> ByRef lpmii As MENUITEMINFO) As Boolean
        End Function
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
        Public Structure MENUITEMINFO
            Public cbSize As UInteger
            Public fMask As UInteger
            Public fType As UInteger
            Public fState As UInteger
            Public wID As UInteger
            Public hSubMenu As IntPtr
            Public hbmpChecked As IntPtr
            Public hbmpUnchecked As IntPtr
            Public dwItemData As IntPtr
            <MarshalAs(UnmanagedType.LPWStr)>
            Private dwTypeData As String
            Public cch As UInteger
            Public hbmpItem As IntPtr
        End Structure
    
        Public Const MIIM_STATE As Integer = &H1
            Public Const MIIM_ID As Integer = &H2
            Public Const MIIM_SUBMENU As Integer = &H4
            Public Const MIIM_CHECKMARKS As Integer = &H8
            Public Const MIIM_TYPE As Integer = &H10
            Public Const MIIM_DATA As Integer = &H20
            Public Const MIIM_STRING As Integer = &H40
            Public Const MIIM_BITMAP As Integer = &H80
            Public Const MIIM_FTYPE As Integer = &H100
    
    
        <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function ILCreateFromPath(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszPath As String) As IntPtr
        End Function
    
        <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Sub ILFree(ByVal pidl As IntPtr)
        End Sub
    
    
        <DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function SHBindToParent(ByVal pidl As IntPtr, ByRef riid As Guid, ByRef ppv As IShellFolder, ByRef ppidlLast As IntPtr) As HRESULT
        End Function
    
        <ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214E6-0000-0000-C000-000000000046")>
        Interface IShellFolder
            Function ParseDisplayName(ByVal hwnd As IntPtr, ByVal pbc As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal pszDisplayName As String, <[In], Out> ByRef pchEaten As UInteger, <Out> ByRef ppidl As IntPtr, <[In], Out> ByRef pdwAttributes As SFGAO) As HRESULT
            Function EnumObjects(ByVal hwnd As IntPtr, ByVal grfFlags As SHCONTF, <Out> ByRef ppenumIDList As IEnumIDList) As HRESULT
            Function BindToObject(ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
            Function BindToStorage(ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
            Function CompareIDs(ByVal lParam As IntPtr, ByVal pidl1 As IntPtr, ByVal pidl2 As IntPtr) As HRESULT
            Function CreateViewObject(ByVal hwndOwner As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
            Function GetAttributesOf(ByVal cidl As UInteger, ByVal apidl As IntPtr, <[In], Out> ByRef rgfInOut As SFGAO) As HRESULT
            Function GetUIObjectOf(ByVal hwndOwner As IntPtr, ByVal cidl As UInteger, ByRef apidl As IntPtr, <[In]> ByRef riid As Guid, <[In], Out> ByRef rgfReserved As UInteger, <Out> ByRef ppv As IntPtr) As HRESULT
            Function GetDisplayNameOf(ByVal pidl As IntPtr, ByVal uFlags As SHGDNF, <Out> ByRef pName As STRRET) As HRESULT
            Function SetNameOf(ByVal hwnd As IntPtr, ByVal pidl As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, ByVal uFlags As SHGDNF, <Out> ByRef ppidlOut As IntPtr) As HRESULT
        End Interface
    
        Public Enum SHCONTF
            SHCONTF_CHECKING_FOR_CHILDREN = &H10
            SHCONTF_FOLDERS = &H20
            SHCONTF_NONFOLDERS = &H40
            SHCONTF_INCLUDEHIDDEN = &H80
            SHCONTF_INIT_ON_FIRST_NEXT = &H100
            SHCONTF_NETPRINTERSRCH = &H200
            SHCONTF_SHAREABLE = &H400
            SHCONTF_STORAGE = &H800
            SHCONTF_NAVIGATION_ENUM = &H1000
            SHCONTF_FASTITEMS = &H2000
            SHCONTF_FLATLIST = &H4000
            SHCONTF_ENABLE_ASYNC = &H8000
        End Enum
    
        Public Enum SFGAO
            CANCOPY = &H1
            CANMOVE = &H2
            CANLINK = &H4
            STORAGE = &H8
            CANRENAME = &H10
            CANDELETE = &H20
            HASPROPSHEET = &H40
            DROPTARGET = &H100
            CAPABILITYMASK = &H177
            ENCRYPTED = &H2000
            ISSLOW = &H4000
            GHOSTED = &H8000
            LINK = &H10000
            SHARE = &H20000
            [READONLY] = &H40000
            HIDDEN = &H80000
            DISPLAYATTRMASK = &HFC000
            STREAM = &H400000
            STORAGEANCESTOR = &H800000
            VALIDATE = &H1000000
            REMOVABLE = &H2000000
            COMPRESSED = &H4000000
            BROWSABLE = &H8000000
            FILESYSANCESTOR = &H10000000
            FOLDER = &H20000000
            FILESYSTEM = &H40000000
            HASSUBFOLDER = &H80000000
            CONTENTSMASK = &H80000000
            STORAGECAPMASK = &H70C50008
            PKEYSFGAOMASK = &H81044000
        End Enum
    
        Public Enum SHGDNF
            SHGDN_NORMAL = 0
            SHGDN_INFOLDER = &H1
            SHGDN_FOREDITING = &H1000
            SHGDN_FORADDRESSBAR = &H4000
            SHGDN_FORPARSING = &H8000
        End Enum
    
    
        <StructLayout(LayoutKind.Explicit, Size:=264)>
        Public Structure STRRET
            <FieldOffset(0)>
            Public uType As UInteger
            <FieldOffset(4)>
            Public pOleStr As IntPtr
            <FieldOffset(4)>
            Public uOffset As UInteger
            <FieldOffset(4)>
            Public cString As IntPtr
        End Structure
    
        <ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F2-0000-0000-C000-000000000046")>
        Interface IEnumIDList
            <PreserveSig()>
            Function [Next](ByVal celt As UInteger, <Out> ByRef rgelt As IntPtr, <Out> ByRef pceltFetched As Integer) As HRESULT
            <PreserveSig()>
            Function Skip(ByVal celt As UInteger) As HRESULT
            Sub Reset()
            Function Clone() As IEnumIDList
        End Interface
    
        'Add a button to test
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Get the localized string for "Send To"
            Dim hr As HRESULT = HRESULT.E_FAIL
            Dim sSendTo As String = Nothing
            Dim pContextMenu As IContextMenu
            Dim CLSID_SendToMenu As New Guid("7BA4C740-9E81-11CF-99D3-00AA004AE837")
            Dim SendToMenuType As Type = Type.GetTypeFromCLSID(CLSID_SendToMenu, True)
            Dim SendToMenu As Object = Activator.CreateInstance(SendToMenuType)
            pContextMenu = DirectCast(SendToMenu, IContextMenu)
            If (pContextMenu IsNot Nothing) Then
                Dim hMenu As IntPtr = CreatePopupMenu()
                Dim sbMenuItem As StringBuilder = New StringBuilder(260)
                hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, &H7FFF, CMF_EXPLORE)
                If (hr = HRESULT.S_OK) Then
                    GetMenuString(hMenu, 0, sbMenuItem, sbMenuItem.Capacity, MF_BYPOSITION)
                    sSendTo = sbMenuItem.ToString()
                End If
                DestroyMenu(hMenu)
            End If
            Marshal.ReleaseComObject(pContextMenu)
    
            ' Test on a given file
            Dim pItemIDL As IntPtr = ILCreateFromPath("E:\test.jpg")
    
            ' Display the context menu and find the localized string (in french : "Envo&yer vers") to get the submenu handle
            Dim pcm As IntPtr = IntPtr.Zero
            Dim IID_IContextMenu As Guid = New Guid("000214E4-0000-0000-C000-000000000046")
            hr = SHGetUIObjectFromFullPIDL(pItemIDL, IntPtr.Zero, IID_IContextMenu, pcm)
            If (hr = HRESULT.S_OK) Then
                Dim pContextMenuShell As IContextMenu = TryCast(Marshal.GetObjectForIUnknown(pcm), IContextMenu)
                Dim hMenu As IntPtr = CreatePopupMenu()
                Dim hSubmenu As IntPtr = hMenu
                hr = pContextMenuShell.QueryContextMenu(hMenu, 0, 1, &H7FFF, CMF_EXPLORE)
                If (hr = HRESULT.S_OK) Then
                    Dim nNbItems As Integer = GetMenuItemCount(hMenu)
                    For i As Integer = nNbItems - 1 To 0 Step -1
                        Dim sbMenuItem As StringBuilder = New StringBuilder(260)
                        GetMenuString(hMenu, CUInt(i), sbMenuItem, sbMenuItem.Capacity, MF_BYPOSITION)
                        If (sbMenuItem.ToString() = sSendTo) Then
                            Dim mii As MENUITEMINFO = New MENUITEMINFO()
                            mii.cbSize = CType(Marshal.SizeOf(GetType(MENUITEMINFO)), UInteger)
                            mii.fMask = (MIIM_FTYPE Or MIIM_ID Or MIIM_SUBMENU Or MIIM_DATA)
                            If GetMenuItemInfo(hMenu, i, True, mii) Then
                                hSubmenu = mii.hSubMenu
                                Exit For
                            End If
                        End If
                    Next
                End If
    
                'Display the "Send To" context menu
                Dim nX As Integer = Cursor.Position.X, nY As Integer = Cursor.Position.Y
                Dim nCmd As UInteger = TrackPopupMenu(hSubmenu, TPM_LEFTALIGN Or TPM_LEFTBUTTON Or TPM_RIGHTBUTTON Or TPM_RETURNCMD, nX, nY, 0, Me.Handle, IntPtr.Zero)
    
                'Execute the chosen item
                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 = pContextMenuShell.InvokeCommand(cmi)
                End If
    
                Marshal.ReleaseComObject(pContextMenuShell)
                DestroyMenu(hMenu)
            End If
    
            ILFree(pItemIDL)
        End Sub
    
        Private Function SHGetUIObjectFromFullPIDL(ByVal pidl As IntPtr, ByVal hwnd As IntPtr, ByRef riid As Guid, ByRef ppv As IntPtr) As HRESULT
            Dim pidlChild As IntPtr = IntPtr.Zero
            Dim psf As IShellFolder = Nothing
            ppv = IntPtr.Zero
            Dim IID_IShellFolder As Guid = New Guid("000214E6-0000-0000-C000-000000000046")
            Dim hr As HRESULT = SHBindToParent(pidl, IID_IShellFolder, psf, pidlChild)
            If hr = HRESULT.S_OK Then
                Dim rgfReserved As UInteger = 0
                hr = psf.GetUIObjectOf(hwnd, 1, pidlChild, riid, rgfReserved, ppv)
                Marshal.ReleaseComObject(psf)
            End If
            Return hr
        End Function
    End Class
    

    • Marked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Unmarked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Marked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Unmarked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    • Marked as answer by JenCarlos Sunday, December 8, 2019 9:40 PM
    Sunday, December 8, 2019 6:37 PM
  • I cannot say exactly how to achieve this, but I can say that I added a contextmenu to Explorer for GIMP. You can probably follow the logic, if you want.

    Check out the reg file here.


    George Frias - AWWshop, Wiki1978


    • Edited by GeoFrias Sunday, December 8, 2019 8:29 PM
    Sunday, December 8, 2019 8:29 PM
  • It works very well 

    Castorix31

    Many thanks



    • Edited by JenCarlos Sunday, December 8, 2019 9:39 PM
    Sunday, December 8, 2019 9:37 PM
  • Thank you
    Sunday, December 8, 2019 9:42 PM