For example, a test on a Button Click with Notepad :
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
<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
<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
<DllImport("Shell32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function SHBindToParent(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(hwnd As IntPtr, pbc As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> pszDisplayName As String, <[In], Out> ByRef pchEaten As UInteger, <Out> ByRef ppidl As IntPtr, <[In], Out> ByRef pdwAttributes As SFGAO) As HRESULT
Function EnumObjects(hwnd As IntPtr, grfFlags As SHCONTF, <Out> ByRef ppenumIDList As IEnumIDList) As HRESULT
Function BindToObject(pidl As IntPtr, pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
Function BindToStorage(pidl As IntPtr, pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
Function CompareIDs(lParam As IntPtr, pidl1 As IntPtr, pidl2 As IntPtr) As HRESULT
Function CreateViewObject(hwndOwner As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
Function GetAttributesOf(cidl As UInteger, apidl As IntPtr, <[In], Out> ByRef rgfInOut As SFGAO) As HRESULT
Function GetUIObjectOf(hwndOwner As IntPtr, 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(pidl As IntPtr, uFlags As SHGDNF, <Out> ByRef pName As STRRET) As HRESULT
Function SetNameOf(hwnd As IntPtr, pidl As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> pszName As String, 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](celt As UInteger, <Out> ByRef rgelt As IntPtr, <Out> ByRef pceltFetched As Integer) As HRESULT
<PreserveSig()>
Function Skip(celt As UInteger) As HRESULT
Sub Reset()
Function Clone() As IEnumIDList
End Interface
<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
<DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function DestroyMenu(hMenu As IntPtr) As Boolean
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 SEE_MASK_ASYNCOK = &H100000
Public Const CMIC_MASK_ASYNCOK = SEE_MASK_ASYNCOK
Public Const SEE_MASK_UNICODE = &H4000
Public Const CMIC_MASK_UNICODE = SEE_MASK_UNICODE
Public Const WM_INITMENUPOPUP As Integer = &H117
Public Const WM_DRAWITEM As Integer = &H2B
Public Const WM_MEASUREITEM As Integer = &H2C
Private Function SHGetUIObjectFromFullPIDL(pidl As IntPtr, 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 hr As HRESULT = SHBindToParent(pidl, GetType(IShellFolder).GUID, 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
Public m_pContextMenu2 As IContextMenu2 = Nothing
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_INITMENUPOPUP Or m.Msg = WM_DRAWITEM Or m.Msg = WM_MEASUREITEM Then
If m_pContextMenu2 IsNot Nothing Then
If m_pContextMenu2 IsNot Nothing Then m_pContextMenu2.HandleMenuMsg(CUInt(m.Msg), CInt(m.WParam), m.LParam)
Return
End If
Else
MyBase.WndProc(m)
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sFilePath = "c:\Windows\System32\notepad.exe"
Dim pItemIDL As IntPtr = ILCreateFromPath(sFilePath)
If (pItemIDL <> IntPtr.Zero) Then
Dim pContextMenuPtr As IntPtr = IntPtr.Zero
Dim hr As HRESULT = SHGetUIObjectFromFullPIDL(pItemIDL, IntPtr.Zero, GetType(IContextMenu).GUID, pContextMenuPtr)
If (hr = HRESULT.S_OK) Then
Dim pContextMenu As IContextMenu = TryCast(Marshal.GetObjectForIUnknown(pContextMenuPtr), IContextMenu)
If (pContextMenu IsNot Nothing) Then
Dim hMenu As IntPtr = CreatePopupMenu()
hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, &H7FFF, CMF_EXPLORE Or CMF_EXTENDEDVERBS)
If (hr = HRESULT.S_OK) Then
m_pContextMenu2 = CType(pContextMenu, IContextMenu2)
Dim nX As Integer = Cursor.Position.X, nY = Cursor.Position.Y
Dim nCmd As UInteger = TrackPopupMenu(hMenu, 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.fMask = CMIC_MASK_ASYNCOK Or CMIC_MASK_UNICODE
cmi.hwnd = Me.Handle
'cmi.hwnd = GetDesktopWindow()
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
m_pContextMenu2 = Nothing
End If
Marshal.ReleaseComObject(pContextMenu)
DestroyMenu(hMenu)
End If
End If
ILFree(pItemIDL)
End If
End Sub
End Class