Getting a menu name from its handle

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Getting a menu name from its handle

07 Jan 2016, 15:27

Hello all,

I am looking for a way to get a menu name (as used in the AHK command Menu, <name>, Add... etc.) from its handle as received from, say, WM_MENUSELECT.

Is this doable? I can't see anything in the Win32 API that looks promising. The only way I can think of is to start at the top of the menu tree with a known name and handle, and walk down all submenu routes, until I find the handle I have.

Thanks,

WPB
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Getting a menu name from its handle

07 Jan 2016, 22:31

No.

The Win32 API knows nothing about what name AutoHotkey calls the menu by. You cannot get a submenu's name from its parent menu either; only the menu item text or submenu handle.

You'll just have to record each menu handle and name.

Note that certain modifications (such as deleting menus or removing menu items which have submenus) can cause all connected Win32 menus to be "destroyed". They are (re)created automatically when the menu is shown or added to a GUI. When that happens, the handle will be different.
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

08 Jan 2016, 16:48

Thanks, lexikos.

Are the underlying Win23 menus created as soon as the first Menu, <name>, Add is encountered, or only after a Menu, <name>, Show?

Also, is there a way of specifying the Command ID of a menu item when you add it, or do you have to use SetMenuItemInfo?

TIA, WPB
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Getting a menu name from its handle

08 Jan 2016, 17:31

The menu is not created until it is shown or added to a GUI, but this is irrelevant because you have to do one of those things to get the handle anyway. MenuGetHandle in the latest test build also causes the menu to be created. Sub-menus are created when the parent menu is created.

Unless you are creating your own menus from scratch, you should not be making up command IDs. You do not know what IDs AutoHotkey uses and therefore how to avoid conflicts.
Shadowpheonix
Posts: 1259
Joined: 16 Apr 2015, 09:41

Re: Getting a menu name from its handle

09 Jan 2016, 03:09

wpb wrote:Hello all,

I am looking for a way to get a menu name (as used in the AHK command Menu, <name>, Add... etc.) from its handle as received from, say, WM_MENUSELECT.

Is this doable? I can't see anything in the Win32 API that looks promising. The only way I can think of is to start at the top of the menu tree with a known name and handle, and walk down all submenu routes, until I find the handle I have.

Thanks,

WPB
Do you just need to know the name of the menu, or do you specifically need to retrieve it via the handle for some reason? If all you need is the name, have you considered the built in A_ThisMenu variable? I am honestly not sure what you are trying to accomplish, so my apologies if my suggestion is not relevant.
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

09 Jan 2016, 06:56

Thanks, Shadowpheonix. Unforunately, I don't think A_ThisMenu will be set up at the point when I need it. I am adding tooltips to my menu, and trying to store the tooltip strings in an associative array keyed by menu name and menu position. I need to extract that data when I get a callback from WM_MENUSELECT - which only gives me the menu handle and the item ID. I can get the position from the item ID easily enough (though there's surprisingly no Win32 API for that), but getting the menu name from the handle looks to be impossible unless I keep a database of all current handles.
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

09 Jan 2016, 06:57

The menu is not created until it is shown or added to a GUI, but this is irrelevant because you have to do one of those things to get the handle anyway. MenuGetHandle in the latest test build also causes the menu to be created. Sub-menus are created when the parent menu is created.

Unless you are creating your own menus from scratch, you should not be making up command IDs. You do not know what IDs AutoHotkey uses and therefore how to avoid conflicts.
Okay, thanks, lexikos. So, what would be very useful is a way to know what command ID AHK has assigned an item in the menu at the time you add it. Then, as I construct a menu, I could simultaneously construct a table of IDs->my data. But if I have to fully construct the menu, then create it (by adding it to a GUI, like you say), I then have to walk the whole menu tree again figuring out the assigned command ID and creating my table.

Also, are command IDs guaranteed to be the same when a menu is re-created? If not, they're not much use for figuring out what was selected in the menu tree, I guess.

And would, for example, the command IDs be the same in a submenu that is attached to two different parent menu items?
Shadowpheonix
Posts: 1259
Joined: 16 Apr 2015, 09:41

Re: Getting a menu name from its handle

09 Jan 2016, 14:15

Looking through forum posts over the past decade, the consensus seems to be that it is not possible to do tooltips on a menu. The recommendations all essentially boil down to using a GUI instead of a Menu.
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

09 Jan 2016, 14:55

It's definitely possible - I have it working. Just ironing out the details and figuring the best way to specify the tooltip strings for each menu item. Atm I am autogenerating AHK code from an Excel file that defines the menus and submenus in an Excel sheet. The tooltip strings get saved in an associative array, like I described above. But when I come to wanting to display the toolip, I have only the menu handle and item command ID to work with. So it looks like just before I show the menu, I'm going to have to walk the tree and record all the submenu handles so I can look up the menu name when I need it...
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Getting a menu name from its handle

09 Jan 2016, 18:48

Majkinetor's MMenu library had tooltips, but it didn't use the Menu command at all.
wpb wrote:Okay, thanks, lexikos. So, what would be very useful is a way to know what command ID AHK has assigned an item in the menu at the time you add it.
That's easy; use GetMenuItemInfo. [Edit: GetMenuItemID is easier.]
But if I have to fully construct the menu, then create it (by adding it to a GUI, like you say), I then have to walk the whole menu tree again figuring out the assigned command ID and creating my table.
You don't need to fully construct the menu - you can add menu items after getting the handle.
Also, are command IDs guaranteed to be the same when a menu is re-created?
No. What's a command ID? There's no such thing in the documentation, therefore there are no guarantees about it.

If you delete the menu and create a new menu with the same name, it's just that; a new menu. It has nothing to do with the old menu. If you delete items from a menu and then add items back with the same names, those are different items. In the latest test build, you can even add multiple items with the same names.

Off the record, the ID starts at an arbitrary number and increments for each new item. You will get the same ID again only after creating (and optionally deleting) approximately 54000 items. The ID is assigned when the item is added, not when the Win32 menu is created, so even if the Win32 menu is destroyed and recreated, the menu item IDs will still be the same.
And would, for example, the command IDs be the same in a submenu that is attached to two different parent menu items?
The same as what? It's one menu used in two places, not two menus. For there to be two sets of IDs, there'd need to be two separate Win32 menus, which would mean two different handles.
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

11 Jan 2016, 14:55

Thank you, lexikos, for all your pointers and advice. My current implementation works on top of the Menu command - I like the simplicity of the AHK Menu command, and it suits my needs well. Majkinetor's MMenu library is great, but overkill for what I'm trying to achieve. So I think I'll stick with the way I have it, and just build a lookup table of (sub)menu handles just before I open the menu. Then everything should work fine. Thanks again,

WPB
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Getting a menu name from its handle

11 Jan 2016, 20:43

The next release was planned to have a MenuGetHandle function (and it is already in the last test build). This topic has demonstrated the need for the inverse function, MenuGetName(Handle), which I will add in the next release.

While trying to come up with an example for the documentation I came to the conclusion that very few will use it directly, since one or more workarounds are needed before you can handle WM_MENUSELECT or other messages while the menu is showing. How are you doing it?
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

12 Jan 2016, 02:08

I define the menu as normal, use the standard method for getting its handle (attaching it as a submenu to a fake menu attached to an unused GUI - which I believe you came up with first), then simply call TrackPopupMenu and handle the WM_MENUSELECT messages. Most of that came from various forum posts around the place, so I can't claim credit.

In terms of the tooltips, those are triggered off a SetTimer callback from the WM_MENUSELECT handler. But as I mentioned, that gives only the menu handle and the command ID. My array of tooltip strings (and other item-by-item menu metadata - I also store a "client"-specified string which gets passed to the menu handler function) is keyed by menu name and menu position, so I have to convert command ID to position (which I do by naively looping through the menu whose handle I have and comparing command IDs with the one given to WM_MENUSELECT - there appears to be no native API to do this), and menu handle to name (which I will do by constructing a lookup table just before I show the menu).

I'm considering changing the above so that my array of tooltip strings is keyed by menu name and item name (instead of position), so that it matches the way AHK itself specifies menu items. Then setting a menu item and its tooltip would just be a case of:

Code: Select all

Menu, <MenuName>, Add, <MenuItem>, MenuHandler
MenData["<MenuName"]["<MenuItem>"] := {Tooltip: "Tooltip string here", OtherClientData: "Here"}
(Slight shame I first need to do

Code: Select all

MenData := {}
and

Code: Select all

MenData["<MenuName>"] := {}
for the above to work, but it's not a big problem, as the menu definition is created by a VBA script anyway at the moment.)

Positioning the tooptip requires me to first get the rectangle of the highlighted menu item using GetMenuItemRect. If the mouse pointer is inside the rectangle, I let the tooltip go where it would naturally go with no coordinates specified, but if the pointer is outside the rectangle, it means keyboard navigation is in play, so I position the tooltip at a set offset from the top-left of the menu item rectangle. Seems to work pretty well.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Getting a menu name from its handle

12 Jan 2016, 21:54

wpb wrote:(attaching it as a submenu to a fake menu attached to an unused GUI - which I believe you came up with first)
Actually,
MI.ahk wrote:; Gets a menu handle from a menu name.
; Adapted from Shimanov's Menu_AssignBitmap()
; http://www.autohotkey.com/forum/topic7526.html
MI_GetMenuHandle(menu_name)
... then simply call TrackPopupMenu and handle the WM_MENUSELECT messages.
Do you also handle/block WM_ENTERMENULOOP as in SKAN's code? I'd suppose that you must if you're using OnMessage, otherwise AutoHotkey would detect that a menu is showing and would prevent any new threads from launching. I don't think it blocks RegisterCallback callbacks, though.
... I have to convert command ID to position (which I do by naively looping through the menu whose handle I have and comparing command IDs with the one given to WM_MENUSELECT - there appears to be no native API to do this), ...
A_ThisMenuItemPos also searches through the menu items to determine the position.
I'm considering changing the above so that my array of tooltip strings is keyed by menu name and item name (instead of position), so that it matches the way AHK itself specifies menu items.
It is possible to have two items with the same text using the Rename sub-command, although the documentation implies otherwise. The next update (as in the test build) will make it easier to create duplicates and more feasible to actually use them.

The name (and in the test build, position) of the item is used to identify it, but changes are tied to the item, not the item's text or position, both of which can change. By contrast, the item's ID never changes (but if you delete the item and create an identical one, it will have a different ID).
(Slight shame I first need to do MenData := {} and MenData["<MenuName>"] := {} for the above to work, but it's not a big problem, as the menu definition is created by a VBA script anyway at the moment.)
If you've initialized MenData := {}, MenData["<MenuName>", "<MenuItem>"] := {...} will automatically initialize MenData["<MenuName>"].
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Getting a menu name from its handle

13 Jan 2016, 05:27

@lexikos: I tried SKAN's code only for some short tests. So I don't know whether such 'modeless' menus will have some risky side-effects when used with AHK. If not, and because you plan to release some changes for the AHK menu code, what about using the P5 parameter of the Menu, ..., Show command as an option allowing to show 'modeless' menus?
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Getting a menu name from its handle

13 Jan 2016, 19:39

I don't know why SKAN used the term "modeless" - his script just uses normal menus. When you show the menu with TrackPopupMenu(Ex) or Menu Show, which uses TrackPopupMenu(Ex), or you click a menu bar on a GUI, the program enters into a menu message loop. If AutoHotkey detects this, it prevents new threads from launching. If a new thread launched, AutoHotkey would take over the message loop for the duration of that thread and the menu would stop functioning correctly.

There are other, possibly important, effects of the "menu is visible" flag AutoHotkey sets. I have not fully analyzed it.

AutoHotkey sets the flag when it receives WM_ENTERMENULOOP and also when Menu Show is called. SKAN's code prevents the flag from being set by overriding WM_ENTERMENULOOP and calling TrackPopupMenu directly.
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

14 Jan 2016, 08:45

Do you also handle/block WM_ENTERMENULOOP as in SKAN's code? I'd suppose that you must if you're using OnMessage, otherwise AutoHotkey would detect that a menu is showing and would prevent any new threads from launching. I don't think it blocks RegisterCallback callbacks, though.
Yes, I pick that up and just return True, nothing else.
It is possible to have two items with the same text using the Rename sub-command, although the documentation implies otherwise. The next update (as in the test build) will make it easier to create duplicates and more feasible to actually use them.
Interesting. I didn't realise that.
The name (and in the test build, position) of the item is used to identify it, but changes are tied to the item, not the item's text or position, both of which can change. By contrast, the item's ID never changes (but if you delete the item and create an identical one, it will have a different ID).
Yes, my instinct is to key my assoc. array of tooltip strings by menu name and item ID, but as we discussed above in this thread, item ID can change if the menu is recreated at some point (possibly by deleting an entry with a submenu), which would mean I'd have to totally recreate my array. I don't want that work. So for now I guess I'll impose the limitation that menu items must be unique as the current release version of AHK does.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Getting a menu name from its handle

14 Jan 2016, 22:10

No, as I said, an item's ID never changes. *Menu handles* change.
wpb wrote:So for now I guess I'll impose the limitation that menu items must be unique as the current release version of AHK does.
It's an imaginary limitation. The current version does not impose it, hence "It is possible to have two items with the same text".
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

15 Feb 2016, 01:30

Lexikos - if I'm reading the changelog correctly on the latest AHK release build, I think you added a function to look up a menu name from its handle. Thank you very much - that will tidy up my code no end! Your obvious hard work is much appreciated.
wpb
Posts: 146
Joined: 14 Dec 2015, 01:53

Re: Getting a menu name from its handle

01 Feb 2018, 07:04

Coming back to this after a long break. AHK's new (since this thread was started) MenuGetHandle() and MenuGetName() functions have really tidied up my code. Thank you for adding them!

Lexikos, is there a way of getting at the item ID assigned by AHK to items in a menu? I'm still keying my array of menu metadata by menu name and item position at the moment, but item ID would be more robust.

Thanks, WPB

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: marypoppins_1, mikeyww, Rohwedder, RussF and 141 guests