循环遍历 IContextMenu
如何循环遍历 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
属性=属性
发送至=发送至
发送到 bluetooh= xxx
编辑
如果有人有另一种获取动词或通过其显示文本调用项目的方法,我也将不胜感激。
How do I loop through all items and sub items of a IContextMenu and list all available verbs? So far, I have this working code extracted from 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;
This code works fine and it shows the context menu. I need to adapt it so it can list (maybe a log file) all the menu and submenus verbs.
EDIT
To clarify lets assume I have this context menu:
I want to log something like this:
Item verb
open= open
properties= properties
send to= sendto
send to bluetooh= xxx
EDIT
If somebody has another way of getting the verbs or call a item by its display text I would also appreciate it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
要枚举上下文菜单的项目,您可以使用 Windows
菜单功能
:GetMenuItemCount 、 GetMenuItemInfo、GetSubMenu 。使用这些函数,我编写了这个函数
并以这种方式调用,
这将用这样的信息填充作为参数传递的TString:
执行调用的menuid(cmd)
现在使用这个函数,您可以传递您想要以这种方式
To enumerate the items of the context menu you can use the Windows
Menu functions
: GetMenuItemCount , GetMenuItemInfo, GetSubMenu.using these functions i wrote this function
and call in this way
this will fill the TStrings passed as parameter with info like this :
now using this function you can pass the menuid (cmd) which you want execute
call in this way
调用
QueryContextMenu
后,您的菜单将大部分填充。您知道菜单的句柄,因此可以迭代其项目并获取所需的信息。如果您在检索“IContextMenu2”界面后获取项目的文本,则不会有任何区别,因为在选择其父菜单项之前,不会填充“发送到”或“新建”等子菜单。在该例程中您不可能能够访问它们。请注意以下在上述代码的示例输出中未能展开的两个项目:
显示子项目的消息将通过 CallbackWindow 的 WndProc 传递,如 WM_INITMENUPOPUP、WM_ENTERIDLE、WM_MEASUREITEM、WM_DRAWITEM。但我认为尝试提取那里的信息根本没有任何意义。
After you call
QueryContextMenu
your menu will be mostly populated. You know your menu's handle, so can iterate its items and get the information you need.It won't really make any difference if you get items' text after you retrieve an 'IContextMenu2' interface or not, because sub menus like 'Send To' or 'New' are not populated until their parent menu item is selected. There's no way in that routine you'll have access to them. Note below the two items that have failed to expand in the sample output of the above code:
Messages to show the sub-items will be passing through your CallbackWindow's WndProc, like WM_INITMENUPOPUP, WM_ENTERIDLE, WM_MEASUREITEM, WM_DRAWITEM. But I don't think trying to extract the information there would make any sense at all..