我仍在寻找使用Windows API Code Pack
.
如果有人有兴趣使用这个通用解决方案,这个答案只是为了分享 @Simon Mourier 翻译成 VB.NET 的代码并添加文档。
归功于他。
''' <summary>
''' Exposes methods that retrieve information about a Shell item.
''' IShellItem and IShellItem2 are the preferred representations of items in any new code.
''' </summary>
<ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IShellItem
REM NOTE: This interface is only partially defined, don't use it in other contexts.
''' <summary>
''' Binds to a handler for an item as specified by the handler ID value (BHID).
''' </summary>
''' <param name="pbc">
''' A pointer to an IBindCtx interface on a bind context object.
''' Used to pass optional parameters to the handler.
''' The contents of the bind context are handler-specific.
''' For example, when binding to BHID_Stream, the STGM flags in the bind context indicate the
''' mode of access desired (read or read/write).</param>
''' <param name="bhid">
''' Reference to a GUID that specifies which handler will be created.
''' One of the following values defined in Shlguid.h.</param>
''' <param name="riid">
''' IID of the object type to retrieve.
''' </param>
''' <param name="ppv">
''' When this method returns,
''' contains a pointer of type riid that is returned by the handler specified by rbhid.
''' </param>
''' <returns>System.Int32.</returns>
<PreserveSig>
Function BindToHandler(
ByVal pbc As IntPtr,
<MarshalAs(UnmanagedType.LPStruct)> ByVal bhid As Guid,
<MarshalAs(UnmanagedType.LPStruct)> ByVal riid As Guid,
ByRef ppv As IContextMenu
) As Integer
End Interface
''' <summary>
''' Exposes methods that either create or merge a shortcut menu associated with a Shell object.
''' </summary>
<ComImport, Guid("000214e4-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IContextMenu
''' <summary>
''' Adds commands to a shortcut menu.
''' </summary>
''' <param name="hmenu">
''' A handle to the shortcut menu.
''' The handler should specify this handle when adding menu items.
''' </param>
''' <param name="iMenu">
''' The zero-based position at which to insert the first new menu item.
''' </param>
''' <param name="idCmdFirst">
''' The minimum value that the handler can specify for a menu item identifier.
''' </param>
''' <param name="idCmdLast">
''' The maximum value that the handler can specify for a menu item identifier.
''' </param>
''' <param name="uFlags">
''' Optional flags that specify how the shortcut menu can be changed.
''' The remaining bits of the low-order word are reserved by the system.
''' The high-order word can be used for context-specific communications.
''' The CMF_RESERVED value can be used to mask the low-order word.</param>
''' <returns>System.Int32.</returns>
<PreserveSig>
Function QueryContextMenu(
ByVal hmenu As IntPtr,
ByVal iMenu As Integer,
ByVal idCmdFirst As Integer,
ByVal idCmdLast As Integer,
ByVal uFlags As QueryContextMenuFlags
) As Integer
''' <summary>
''' Carries out the command associated with a shortcut menu item.
''' </summary>
''' <param name="pici">
''' A pointer to a CMINVOKECOMMANDINFO or CMINVOKECOMMANDINFOEX structure that contains
''' specifics about the command.</param>
''' <returns>System.Int32.</returns>
<PreserveSig>
Function InvokeCommand(
ByRef pici As CMINVOKECOMMANDINFO
) As Integer
''' <summary>
''' Gets information about a shortcut menu command,
''' including the help string and the language-independent, or canonical, name for the command.
''' </summary>
''' <param name="idCmd">
''' Menu command identifier offset.
''' </param>
''' <param name="uFlags">
''' Flags specifying the information to return.
''' </param>
''' <param name="pwReserved">
''' Reserved.
''' Applications must specify NULL when calling this method and
''' handlers must ignore this parameter when called.
''' </param>
''' <param name="pszName">
''' The address of the buffer to receive the null-terminated string being retrieved.
''' </param>
''' <param name="cchMax">
''' Size of the buffer, in characters, to receive the null-terminated string.
''' </param>
''' <returns>System.Int32.</returns>
<PreserveSig>
Function GetCommandString(
ByVal idCmd As Integer,
ByVal uFlags As GetCommandStringFlags,
ByVal pwReserved As IntPtr,
<MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As StringBuilder,
ByVal cchMax As Integer) As Integer
End Interface
''' <summary>
''' Determines the number of items in the specified menu.
''' </summary>
''' <param name="hMenu">A handle to the menu to be examined.</param>
''' <returns>
''' If the function succeeds, the return value specifies the number of items in the menu.
''' If the function fails, the return value is -1.</returns>
<DllImport("user32.dll")>
Public Shared Function GetMenuItemCount(
ByVal hMenu As IntPtr
) As Integer
End Function
''' <summary>
''' Retrieves the menu item identifier of a menu item located at the specified position in a menu.
''' </summary>
''' <param name="hMenu">
''' A handle to the menu that contains the item whose identifier is to be retrieved.
''' </param>
''' <param name="nPos">
''' The zero-based relative position of the menu item whose identifier is to be retrieved.
''' </param>
''' <returns>
''' The return value is the identifier of the specified menu item.
''' If the menu item identifier is NULL or if the specified item opens a submenu, the return value is -1.
''' </returns>
<DllImport("user32.dll")> _
Public Shared Function GetMenuItemID(
ByVal hMenu As IntPtr,
ByVal nPos As Integer
) As Integer
End Function
''' <summary>
''' Creates and initializes a Shell item object from a parsing name.
''' </summary>
''' <param name="path">
''' A pointer to a display name.
''' </param>
''' <param name="pbc">
''' Optional.
''' A pointer to a bind context used to pass parameters as inputs and outputs to the parsing function.
''' These passed parameters are often specific to the data source and are documented by the data source owners.
''' </param>
''' <param name="riid">
''' A reference to the IID of the interface to retrieve through ppv,
''' typically IID_IShellItem or IID_IShellItem2.
''' </param>
''' <param name="item">
''' When this method returns successfully, contains the interface pointer requested in riid.
''' This is typically IShellItem or IShellItem2.</param>
''' <returns>System.Int32.</returns>
<DllImport("shell32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> _
Public Shared Function SHCreateItemFromParsingName(
ByVal path As String,
ByVal pbc As IntPtr, <MarshalAs(UnmanagedType.LPStruct)>
ByVal riid As Guid,
ByRef item As IShellItem
) As Integer
End Function
''' <summary>
''' Optional flags that specify how a shortcut menu can be changed.
''' </summary>
<Description("'uFlags' parameter used in 'QueryContextMenu' function")>
Public Enum QueryContextMenuFlags As Integer
REM NOTE: This Enum is only partially defined, don't use it in other contexts.
''' <summary>
''' Indicates normal operation.
''' A shortcut menu extension, namespace extension, or drag-and-drop handler can add all menu items.
''' </summary>
CMF_NORMAL = &H0
End Enum
''' <summary>
''' Flags specifying the information to return.
''' </summary>
<Description("'uFlags' parameter used in 'GetCommandString' function")>
Public Enum GetCommandStringFlags As Integer
REM NOTE: This Enum is only partially defined, don't use it in other contexts.
''' <summary>
''' Sets pszName to a Unicode string containing the language-independent command name for the menu item.
''' </summary>
GCS_VERBW = &H4
End Enum
''' <summary>
''' Contains information needed by IContextMenu::InvokeCommand to invoke a shortcut menu command.
''' </summary>
<Description("'pici' parameter used in 'InvokeCommand' function")>
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
Structure CMINVOKECOMMANDINFO
''' <summary>
''' The size of this structure, in bytes.
''' </summary>
Public cbSize As Integer
''' <summary>
''' Zero, or one or more of the CMINVOKECOMMANDINFO flags.
''' </summary>
Public fMask As Integer
''' <summary>
''' A handle to the window that is the owner of the shortcut menu.
''' An extension can also use this handle as the owner of any message boxes or dialog boxes it displays.
''' </summary>
Public hwnd As IntPtr
''' <summary>
''' The address of a null-terminated string that specifies the language-independent name
''' of the command to carry out.
''' This member is typically a string when a command is being activated by an application.
''' The system provides predefined constant values for the following command strings.
''' </summary>
Public lpVerb As IntPtr
''' <summary>
''' An optional string containing parameters that are passed to the command.
''' The format of this string is determined by the command that is to be invoked.
''' This member is always NULL for menu items inserted by a Shell extension.
''' </summary>
Public lpParameters As String
''' <summary>
''' An optional working directory name.
''' This member is always NULL for menu items inserted by a Shell extension.
''' </summary>
Public lpDirectory As String
''' <summary>
''' A set of SW_ values to pass to the ShowWindow function if the command
''' displays a window or starts an application.
''' </summary>
Public nShow As Integer
''' <summary>
''' An optional keyboard shortcut to assign to any application activated by the command.
''' If the fMask parameter does not specify CMIC_MASK_HOTKEY, this member is ignored.
''' </summary>
Public dwHotKey As Integer
''' <summary>
''' An icon to use for any application activated by the command.
''' If the fMask member does not specify CMIC_MASK_ICON, this member is ignored.
''' </summary>
Public hIcon As IntPtr
End Structure
''' <summary>
''' Invokes a verb on a ShellObject item.
''' </summary>
''' <param name="ShellObject">
''' Indicates the item.
''' </param>
''' <param name="Verb">
''' Indicates the verb to invoke on the item.
''' </param>
''' <exception cref="System.ArgumentNullException">ParsingPath</exception>
''' <exception cref="System.ComponentModel.Win32Exception">
''' </exception>
Public Shared Sub InvokeItemVerb(ByVal [ShellObject] As ShellObject,
ByVal Verb As String)
Dim [ShellItem] As NativeMethods.IShellItem = Nothing
Dim menu As NativeMethods.IContextMenu = Nothing
Dim ci As New NativeMethods.CMINVOKECOMMANDINFO
Dim cm As New ContextMenu
Dim sb As New StringBuilder(256)
Dim hr As Integer = -1
Dim count As Integer = -1
Dim verbId As Integer = -1
Dim id As Integer = -1
Dim BHID_SFUIObject As Guid = Nothing
If Verb Is Nothing Then
Verb = "open"
End If
' Get an item from the item parsing-path
hr = NativeMethods.SHCreateItemFromParsingName([ShellObject].Properties.System.ParsingPath.Value,
IntPtr.Zero,
GetType(NativeMethods.IShellItem).GUID,
[ShellItem])
If hr < 0 Then
Throw New Win32Exception(hr)
End If
' Get the context menu from the item
BHID_SFUIObject = New Guid("{3981e225-f559-11d3-8e3a-00c04f6837d5}")
hr = [ShellItem].BindToHandler(IntPtr.Zero, BHID_SFUIObject,
GetType(NativeMethods.IContextMenu).GUID,
menu)
If hr < 0 Then
Throw New Win32Exception(hr)
End If
' Build a fake context menu so we can scan it for the verb's menu id.
hr = menu.QueryContextMenu(cm.Handle, 0, 0, -1,
NativeMethods.QueryContextMenuFlags.CMF_NORMAL)
If hr < 0 Then
Throw New Win32Exception(hr)
End If
count = NativeMethods.GetMenuItemCount(cm.Handle)
For i As Integer = 0 To count - 1
id = NativeMethods.GetMenuItemID(cm.Handle, i)
If id < 0 Then
Continue For
End If
hr = menu.GetCommandString(id, NativeMethods.GetCommandStringFlags.GCS_VERBW,
IntPtr.Zero, sb, sb.Capacity)
If sb.ToString().Equals(Verb, StringComparison.InvariantCultureIgnoreCase) Then
verbId = id
Exit For
End If
Next i
If verbId < 0 Then
Throw New Win32Exception(String.Format("Verb '{0}' is not supported by the item.", Verb))
End If
' Invoke the Verb.
With ci
.cbSize = Marshal.SizeOf(GetType(NativeMethods.CMINVOKECOMMANDINFO))
.lpVerb = New IntPtr(verbId)
End With
hr = menu.InvokeCommand(ci)
If hr < 0 Then
Throw New Win32Exception(hr)
End If
End Sub