如何找到激活时打开给定HMENU的菜单项(如果有)?

Fre*_*abe 5 c c++ winapi mfc menu

我想用原型实现一个功能

/* 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 );
Run Code Online (Sandbox Code Playgroud)

给定一个HMENU句柄,我希望能够找出应用程序中打开了哪个菜单项(如果有)。这基本上是与GetSubMenu函数相反的。

我当前的方法是查看应用程序顶级窗口中的每个HMENU,并检查是否可以找到一个菜单项,该菜单项在激活时会打开给定的子菜单。我使用GetMenuItemCount / GetSubMenu递归执行此操作

但是,这效率很低,并且对于由上下文菜单项打开的菜单而言,它会失败。因此,我想知道:

有谁知道如何找到激活菜单后打开给定HMENU的菜单项(如果有)?

更新:我刚刚想到一个主意;应该有可能(使用SetWindowsHookEx函数)安装一个钩子,该钩子会通知菜单中发生的所有输入事件。每当检测到菜单项激活时,请记住该菜单项(由(HMENU,int)对标识)和将通过全局菜单中的菜单项打开的HMENU。然后,getParentMenuItem上面的函数可以简单地对地图进行查找。

更新的更新:上面的更新中描述的挂钩想法照旧是行不通的,因为它当然只会识别菜单项->菜单关联,这些菜单项已在某个时候被激活。

但是,这感觉有点难看,因为它要求我保持很多状态(地图);有没有更简单的可能性?

Ala*_*lan 4

您可以尝试MENUINFO.dwMenuData为您在应用程序中创建的所有菜单设置父菜单句柄:

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);
Run Code Online (Sandbox Code Playgroud)

dwMenuData那么你只需要在你的函数中查询这个字段:

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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果您无法控制所有菜单的创建方式,则可以WH_CALLWNDPROC在首次创建菜单时使用挂钩来捕获。 一篇好文章(带有源代码)描述了如何做到这一点 - 然后您可以尝试使用上述方法将父 HMENU 注入到创建的菜单中。