如何找到激活时打开给定 HMENU 的菜单项(如果有)?
我想用原型实现一个函数
I'd like to implement a function with the prototype
/* Locates the menu item of the application which caused the given menu 'mnu' to
* show up.
* @return true if the given menu 'mnu' was opened by another menu item, false
* if not.
*/
bool getParentMenuItem( HMENU mnu, HMENU *parentMenu, int *parentMenuIdx );
给定一个 HMENU 句柄,我希望能够找出应用程序中的哪个菜单项(如果有)打开了它.这基本上是 GetSubMenu 的反面功能.
Given a HMENU handle, I'd like to be able to find out which menu item (if any) in the application opened it. This is basically the reverse of the GetSubMenu function.
我目前的方法是查看应用程序顶层窗口的每个 HMENU,并检查是否可以找到一个菜单项,该菜单项在激活时会打开给定的子菜单.我使用 GetMenuItemCount/递归地执行此操作GetSubMenu.
My current approach is to look into each HMENU of the top level windows of the application and check for whether I can find a menu item which would open the given sub menu when activated. I do this recursively, using GetMenuItemCount/GetSubMenu.
不过,这相当低效,并且对于由上下文菜单项打开的菜单会失败.因此,我想知道:
This is rather inefficient though, and it fails for menus which are opened by context menu items. Hence, I'm wondering:
有人知道如何找到在激活时打开给定 HMENU 的菜单项(如果有的话)吗?
Does anybody have a nice idea how to find the menu item (if any) which opens a given HMENU when activated?
更新:我刚刚想到的一个想法;应该可以(使用 SetWindowsHookEx函数)来安装一个钩子,该钩子会通知菜单中发生的所有输入事件.每当检测到菜单项激活时,记住菜单项(由 (HMENU,int) 对标识)和将由全局映射中的菜单项打开的 HMENU.然后,上面的 getParentMenuItem
函数可以简单地执行对地图的查找.
UPDATE: An idea which just came to my mind; it should be possible (using the SetWindowsHookEx function) to install a hook which gets notified of all input events which happened in a menu. Whenever a menu item activation is detected, memorize the menu item (identified by a (HMENU,int) pair) and the HMENU which will get opened by the menu item in a global map. The getParentMenuItem
function above could then simply perform a lookup into the map.
更新更新: 上面更新中描述的挂钩想法不会按原样起作用,因为它当然只会识别菜单项 -> 已激活的项目的菜单关联一点.
UPDATE to the update: The hooking idea described in the update above won't work as it is since it will of course only recognize menu item -> menu associations for items which have been activated at some point.
这感觉有点难看,因为它要求我保持很多状态(地图);还有更简单的可能性吗?
This feels a bit ugly though since it reqiures me to keep a lot of state (the map); are there any easier possibilities?
推荐答案
您可以尝试将 MENUINFO.dwMenuData
设置为您在应用程序中创建的所有菜单的父菜单句柄:
You could try setting MENUINFO.dwMenuData
to the parent menu handle for all menus you create in your application:
MENUINFO mi;
mi.cbSize = sizeof(MENUINFO);
mi.dwMenuData = (ULONG_PTR)<parent HMENU if this is a sub menu>
mi.fMask = MIM_MENUDATA;
SetMenuInfo(hCreatedMenu, &mi);
那么你只需要在你的函数中查询这个dwMenuData
字段:
Then you only need to query this dwMenuData
field in your function:
bool getParentMenuItem(HMENU mnu, HMENU *parentMenu, int *parentMenuIdx)
{
MENUINFO mi;
mi.cbSize = sizeof(MENUINFO);
mi.fMask = MIM_MENUDATA;
if (!GetMenuInfo(mnu,&mi) || mi.dwMenuData == 0)
return false;
*parentMenu = (HMENU)mi.dwMenuData;
// not sure how or why you need the parentMenuIdx, but you should be able
// to derive that from the parent HMENU
return true;
}
<小时>
如果您无法控制所有菜单的创建方式,您可以使用 WH_CALLWNDPROC
挂钩来捕获首次创建菜单的时间.一篇好文章(附源代码)描述了如何做到这一点 - 你然后可以尝试使用上述方法将父 HMENU 注入到创建的菜单中.
If you don't have control over how all menus are created, you could use a WH_CALLWNDPROC
hook to trap when a menu is first created. A good article (with source code) describes how this can be done - you could then look at trying to inject the parent HMENU into the created menu using the method described above.
相关文章