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 );
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.
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:
Does anybody have a nice idea how to find the menu item (if any) which opens a given HMENU when activated?
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?
I just found the same need. I have my menus defined in the .rc file, and I want to gray out access to a popup menu if all of its subitems get grayed out. (You can argue that this inhibits discovery, but, in this particular case, it's what we need).
As previous responders mentioned, if you are creating menus programmatically, you can store an item's parent menu handle as ancillary information.
But for menus defined in the resource file using the POPUP keyword, you can't associate an ID with a POPUP and you can't easily climb up the menu tree programmatically. You have to recursively search down for a menu item, and keep track of the parents.
I wrote the following code to do this. EnableSubmenuItem works like EnableMenuItem to enable or disable a menu item by ID. It then checks the item's parent menu. If all items in its parent menu are disabled, the parent gets disabled. Conversely if any subitem is enabled, the parent gets enabled.
(BTW the original question, how to find parent hMenu of a menu item, is addressed by routine FindParentMenu, in the following code).
You could try setting
MENUINFO.dwMenuData
to the parent menu handle for all menus you create in your application:Then you only need to query this
dwMenuData
field in your function:Edit: 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.