如何遍历IContextMenu的所有项目和子项并列出所有可用的动词?到目前为止,我从JCL中提取了这个工作代码:
function DisplayContextMenuPidl(const Handle: THandle; const Folder: IShellFolder; Item: PItemIdList; Pos: TPoint): Boolean;
var
Cmd: Cardinal;
ContextMenu: IContextMenu;
ContextMenu2: IContextMenu2;
Menu: HMENU;
CommandInfo: TCMInvokeCommandInfo;
CallbackWindow: THandle;
vteste : string;
begin
Result := False;
if (Item = nil) or (Folder = nil) then
Exit;
Folder.GetUIObjectOf(Handle, 1, Item, IID_IContextMenu, nil,
Pointer(ContextMenu));
if ContextMenu <> nil then
begin
Menu := CreatePopupMenu;
if Menu <> 0 then
begin
if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then
begin
CallbackWindow := 0;
if Succeeded(ContextMenu.QueryInterface(IContextMenu2, ContextMenu2)) then
begin
CallbackWindow := CreateMenuCallbackWnd(ContextMenu2);
end;
ClientToScreen(Handle, Pos);
Cmd := Cardinal(TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, Pos.X, Pos.Y, 0, CallbackWindow, nil));
if Cmd <> 0 then
begin
ResetMemory(CommandInfo, SizeOf(CommandInfo));
CommandInfo.cbSize := SizeOf(TCMInvokeCommandInfo);
CommandInfo.hwnd := Handle;
CommandInfo.lpVerb := MakeIntResourceA(Cmd - 1);
CommandInfo.nShow := SW_SHOWNORMAL;
Result := Succeeded(ContextMenu.InvokeCommand(CommandInfo));
end;
if CallbackWindow <> 0 then
DestroyWindow(CallbackWindow);
end;
DestroyMenu(Menu);
end;
end;
end;
此代码工作正常,它显示上下文菜单。我需要调整它以便它可以列出(可能是一个日志文件)所有菜单和子菜单动词。
修改
为了澄清,我假设我有这个上下文菜单:
我想记录这样的事情:
open = open
properties = properties
发送到=发送到
发送到bluetooh = xxx
修改
如果某人有其他方式获取动词或通过显示文字调用项目,我也会很感激。
答案 0 :(得分:5)
要枚举上下文菜单中的项目,您可以使用Windows Menu functions
:GetMenuItemCount,GetMenuItemInfo,GetSubMenu。
使用这些函数我写了这个函数
uses
JclShell,
ShlObj;
function DisplayContextMenuInfo( const Folder: IShellFolder; Item: PItemIdList; List :TStrings): Boolean;
function GetMenuItemCaption(const hSubMenu: HMENU; const MenuId: Integer): string;
var
MenuItemInfo: TMenuItemInfo;
begin
MenuItemInfo.cbSize := SizeOf(MenuItemInfo);
MenuItemInfo.fMask := MIIM_STRING;
SetLength(Result, 1024*Sizeof(Char));
MenuItemInfo.dwTypeData := PChar(Result);
MenuItemInfo.cch := Length(Result)-1;
if not GetMenuItemInfo(hSubMenu, MenuId, False, MenuItemInfo) then
RaiseLastOSError;
SetLength(Result, MenuItemInfo.cch*Sizeof(Char));
end;
Procedure LogGetMenuInfo(Menu: HMENU);
var
i : Integer;
ItemsCount : Integer;
MenuId : Cardinal;
Caption : string;
begin
ItemsCount:=GetMenuItemCount(Menu);
List.Add(Format('Number of items %d ',[ItemsCount]));
for i:= 0 to ItemsCount - 1 do
begin
MenuId:=GetMenuItemID(Menu,i);
case MenuId of
Cardinal(-1) : begin
List.Add('');
List.Add(Format('Sub Menu',[]));
LogGetMenuInfo(GetSubMenu(Menu,i));
end;
0 :
else
begin
Caption:=GetMenuItemCaption(Menu, MenuId);
List.Add(Format('MenuId (Cmd) %d Caption %s ',[MenuId,Caption]))
end;
end;
end;
end;
var
ContextMenu: IContextMenu;
Menu: HMENU;
begin
Result := False;
if (Item = nil) or (Folder = nil) then Exit;
Folder.GetUIObjectOf(0, 1, Item, IID_IContextMenu, nil, Pointer(ContextMenu));
if ContextMenu <> nil then
begin
Menu := CreatePopupMenu;
try
if Menu <> 0 then
if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then
LogGetMenuInfo(Menu);
finally
DestroyMenu(Menu);
end;
end;
end;
以这种方式打电话
var
ItemIdList: PItemIdList;
Folder : IShellFolder;
FileName : string;
begin
FileName:= 'C:\Users\Dexter\Downloads\VirtualTreeview.pdf';
ItemIdList := PathToPidlBind(FileName, Folder);
if ItemIdList <> nil then
begin
DisplayContextMenuInfo( Folder, ItemIdList, Memo1.lines);
PidlFree(ItemIdList);
end;
end;
这将填充作为参数传递的TStrings,其信息如下:
Number of items 26
MenuId (Cmd) 141 Caption Open with Adobe Reader X
MenuId (Cmd) 142 Caption &Open
MenuId (Cmd) 143 Caption &Print
MenuId (Cmd) 146 Caption Run &Sandboxed
MenuId (Cmd) 140 Caption Analizar con &AVG
Sub Menu
Number of items 28
MenuId (Cmd) 105 Caption Add To Send To
MenuId (Cmd) 106 Caption Add To Templates
MenuId (Cmd) 107 Caption Change Date && Time
MenuId (Cmd) 108 Caption Change Extension: pdf
MenuId (Cmd) 109 Caption Choose Program
MenuId (Cmd) 110 Caption Command Prompt
MenuId (Cmd) 111 Caption Copy/Move To Folder
MenuId (Cmd) 112 Caption Copy Path
MenuId (Cmd) 113 Caption Delete On Reboot
MenuId (Cmd) 114 Caption Duplicate File
MenuId (Cmd) 115 Caption Encrypt File
MenuId (Cmd) 116 Caption Explore Rooted
MenuId (Cmd) 117 Caption Extended Delete
MenuId (Cmd) 118 Caption Extended Search && Replace
现在使用此功能,您可以传递要执行的menuid(cmd)
function InvokeContextMenuCommand(const Comnand: Cardinal; const Folder: IShellFolder; Item: PItemIdList): Boolean;
var
ContextMenu : IContextMenu;
CommandInfo : TCMInvokeCommandInfo;
Menu : HMENU;
CallbackWindow: THandle;
begin
Result := False;
if Comnand=0 then exit;
if (Item = nil) or (Folder = nil) then Exit;
Folder.GetUIObjectOf(0, 1, Item, IID_IContextMenu, nil, Pointer(ContextMenu));
if ContextMenu <> nil then
begin
Menu := CreatePopupMenu;
try
if Menu <> 0 then
if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then
begin
CallbackWindow:=0;
TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, 0, 0, 0, CallbackWindow, nil);
ZeroMemory(@CommandInfo, SizeOf(CommandInfo));
CommandInfo.cbSize := SizeOf(TCMInvokeCommandInfo);
CommandInfo.hwnd := 0;
CommandInfo.lpVerb := MakeIntResourceA(Comnand - 1);
CommandInfo.nShow := SW_SHOWNORMAL;
Result := Succeeded(ContextMenu.InvokeCommand(CommandInfo));
end;
finally
DestroyMenu(Menu);
end;
end;
end;
以这种方式打电话
var
ItemIdList: PItemIdList;
Folder : IShellFolder;
FileName : string;
begin
FileName:= 'C:\Users\Dexter\Downloads\VirtualTreeview.pdf';
ItemIdList := PathToPidlBind(FileName, Folder);
if ItemIdList <> nil then
begin
//calling the 141 Menuid = `Open with Adobe Reader X`
InvokeContextMenuCommand(141,Folder, ItemIdList);
PidlFree(ItemIdList);
end;
end;
答案 1 :(得分:2)
致电QueryContextMenu
后,您的菜单将主要填充。您知道菜单的句柄,因此可以迭代其项目并获取所需的信息。
function DisplayContextMenuPidl(const Handle: THandle; const Folder: IShellFolder; Item: PItemIdList; Pos: TPoint): Boolean;
//++
procedure RecurseItems(const Menu: HMENU; Strings: TStrings; Indent: Integer = 0);
function GetItemString(Parent: HMENU; Item: Integer): string;
begin
SetLength(Result, GetMenuString(Parent, Item, nil, 0, MF_BYPOSITION) + 1);
GetMenuString(Parent, Item, PChar(Result), Length(Result), MF_BYPOSITION);
end;
var
i: Integer;
ItemInfo: TMenuItemInfo;
begin
for i := 0 to GetMenuItemCount(Menu) - 1 do begin
FillChar(ItemInfo, SizeOf(ItemInfo), 0);
ItemInfo.cbSize := SizeOf(ItemInfo);
ItemInfo.fMask := MIIM_SUBMENU or MIIM_TYPE;
GetMenuItemInfo(Menu, i, True, ItemInfo);
if ItemInfo.fType <> MFT_SEPARATOR then
Strings.Add(StringOfChar('-', Indent * 2) + GetItemString(Menu, i));
if ItemInfo.hSubMenu <> 0 then
RecurseItems(ItemInfo.hSubMenu, Strings, Indent + 1);
end;
end;
//--
var
Cmd: Cardinal;
ContextMenu: IContextMenu;
ContextMenu2: IContextMenu2;
...
begin
Menu := CreatePopupMenu;
if Menu <> 0 then
begin
if Succeeded(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)) then
//++
Memo1.Clear;
RecurseItems(Menu, Memo1.Lines);
//--
begin
CallbackWindow := 0;
..
如果你在检索'IContextMenu2'界面之后得到了物品的文字,那真的没有任何区别,因为在他们的父母之前不会填充像'发送到'或'新'这样的子菜单菜单项已被选中。在该例程中无法您可以访问它们。请注意以下两个在上述代码的示例输出中未能扩展的项目:
&Open Run as &administrator Troubleshoot compatibilit&y 7-Zip --Open archive --Extract files... --Extract Here --Test archive --Add to archive... S&hare with -- Pin to Tas&kbar Pin to Start Men&u Restore previous &versions Se&nd to -- Cu&t &Copy Create &shortcut &Delete P&roperties
显示子项的消息将通过您的CallbackWindow的WndProc,如WM_INITMENUPOPUP,WM_ENTERIDLE,WM_MEASUREITEM,WM_DRAWITEM。但我认为试图提取信息根本没有任何意义..