Unlike many other common controls, a menu is not a child window but usually saved as a resource, even though menus can be created dynamically at runtime. Despite there differences, handling menus in screen reading doesn't appear to be that different from handling buttons. A menu sends out messages to it's parent just like a push button does. When the user moves in a menu it's indicated by a WM_MENUSELECT message (which is handled in the HWNDCALLPROC hook).
In a WM_MENUSELECT message lParam is the handle (HMENU) to the currently open menu. In addition the highword of wParam lists some style flags for the active menu item and the lowword gives a representation of an index of this menu command in the menu. There are two approaches to indexing both of which are used. If a menu has a sub-menu associated to it, it is recognized by a unique command ID. Otherwise the lowword gives the index to the menu directly. To make things more complicated, certain fields in the WM_MENUSELECT message may indicate that a menu is closed. It's staited well in MSDN: If the fuFlags parameter contains 0xFFFF and the hmenu parameter contains NULL, the system has closed the menu. (Microsoft, 1999,
The parameters in a WM_MENUSELECT can be saved in local variables as follows. Notice saving the indexing method in a variable, too:
HMENU handle = (HMENU) lParam;
UINT offset = LOWORD(wParam);
UINT flags = HIWORD(wParam);
if(flags == 0xFFFF && handle == NULL)
{ // The menu is closed.
lstrcat(textOut, "Menu closed\r\n");
return;
} // if
UINT offsetStyle; // Search by id or index.
if(flags & MF_POPUP)
offsetStyle = MF_BYPOSITION; // If it's got a popup, by index then.
else
offsetStyle = MF_BYCOMMAND; // By id.
The statement if(flags & MF_POPUP) checks if the style flag exists. One can combine the menu styles with a bitwise or, so comparing the flags can be done directly with a bit and. MF_POPUP signals that a menu does have a sub-menu. Other general styles include MF_GRAYED (you cannot select the menu item) and MF_CHECKED (there's a tickmark in this menu item).
GetMenuString gives the text of a menu item, though in MSDN they recommend using the newer and more extensive function GetMenuItemInfo. All in all, GetMenuString takes a handle to the menu, a string for the menu text, the maximum length for the string and a flag determining whether a command ID or index was given. Most of the parameters are passed in a WM_MENU_SELECT so the actual function call is:
GetMenuString(handle, offset, textBuf, MAX_TEXT_LENGTH, offsetStyle);