Windows Menu Resources

Creating a win32 menu resource in-memory is a somewhat non-trivial task, especially in a program that uses the SBCS or MBCS character sets. The difficulty comes from the alignment requirements and the fact that all the strings must be in Unicode. One reason a program might need to deal with menu resources is saving menus that were generated from program data. If the generation process is complicated, saving the final resouce can be a significant time saving step.

= Main article = There are some cases where a program might not be able to describe its menus at compile time. Such cases include programs that generate their menus from database enteries or other sources that might vary from one program run to another. One way a program can deal with this situation is via CreateMenu and manual insertion of each menu item in its proper position. This is both straightfoward and reasonably easy, however with complex menu structures it can also be very time consuming (in terms of actual program execution, to the point users may complain). Another approach is to build a menu resource whenever the data the menu is based on changes. The program would then use the LoadMenuIndirect API to generate a run time menu from the saved data.

Another complexity of this task is the handling of commands. Programs that need to create menus at run-time will ususually handle a significant number of the dynamic enteries in a very similiar fashion, for these items a command range can be helpful.

Calculating MENUEX_TEMPLATE_ITEM alignment
Because each MENUEX_TEMPLATE_ITEM must be aligned on a DWORD (4-byte) boundary and because the actual size of menu item descriptors vary, calculating the correct offset for each menu item requires care. The following snippet will calculate the correct number of DWORDs a given MENUEX_TEMPLATE_ITEM structure occupies, given the number of characters in the display string and whether the item opens a drop-down or submenu. Doing this calculation in number of DWORDs needed makes keeping everything aligned somewhat easier.
 * DWORD dwNeededDWORDs = sizeof(MENUEX_TEMPLATE_ITEM) + // Space for the menu item structure.
 * (sizeof(WCHAR) * nCharCount) + // Space for item text
 * (sizeof(WCHAR) * ((nCharCount % 2) == 0) ? 1 : 0)) + // Depending on the string length, one more word may be needed.
 * (sizeof(DWORD) * (bHasSubMenu ? 1 : 0)) // Space needed for dwHelpID?
 * / sizeof(DWORD); // Truncate to the correct number of DWORDs

Allocating a MENUEX_TEMPLATE_ITEM
One option for building the required buffer is to use a resizable array structure, such as std::vector, and then growing the allocated space by (dwNeededDWORDs * sizeof DWORD).

Other considerations
Building the menu resource is made much easier if the program can determine whether an item terminates its group (ie, the menu bar, a drop-down menu or a submenu) in advance then creating the overall resource is made much easier. Otherwise either offsets must be saved to various items in the overall structure or the structure must be traversed so that it correctly indicates branching information.

= Reference material =

API function(s)
The key API in this process is LoadMenuIndirect, it has the following prototype.
 * HMENU LoadMenuIndirect(MENUTEMPLATE const * pMenuTemplate);


 * pMenuTemplate : A pointer to a menu template or extended menu template. A menu template consists of a MENUITEMTEMPLATEHEADER followed by one or more  MENUITEMTEMPLATE structures.  An extended menu template consists of a MENUEX_TEMPLATE_HEADER followed by one or more MENUEX_TEMPLATE_ITEM structures.

Unfortunately, due to the nature of these structures, MENUEX_TEMPLATE_HEADER and MENUEX_TEMPLATE_ITEM are not defined by the Platform SDK headers.

MENUITEMTEMPLATEHEADER
typedef struct MENUITEMTEMPLATEHEADER { WORD versionNumber; WORD offset; } MENUITEMTEMPLATEHADER, *PMENUITEMTEMPLATEHADER;

Description:
 * versionNumber :For the MENUITEMTEMPLATEHEADER/MENUITEMTEMPLATE combination versionNumber needs to be set to 0.
 * offset : The number of bytes past the end of the header structure where the first MENUITEMTEMPLATE will be found. This member is usually zero, but allows for storing program specific information between the header and the first MENUITEMTEMPLATE.

MENUITEMTEMPLATE
typedef struct MENUITEMTEMPLATE { WORD mtOption; WORD mtID; WORD mtString[1]; } MENUITEMTEMPLATE, *PMENUITEMTEMPLATE;

Description:
 * mtOption : One or more of the following flags control how the item appears.
 * MF_CHECKED : Indicates that a check mark should be drawn with the menu item.
 * MF_GRAYED : Indicates that the item should appear grayed out.
 * MF_HELP : Indicates that a vertical seperator should appear to the left of the menu item.
 * MF_MENUBARBREAK : Indicates that the item begins a new column. A vertical seperator appears between the old and new column.
 * MF_MENUBREAK : Indicates that the item begins a new column.
 * MF_OWNERDRAW : Indicates that the owner window of the menu is responsible for drawing all aspects of the menu item, including highlight, select and inactive states. Not valid for an item in a menu bar (top level only).
 * MF_POPUP : Indicates that the menu item is one which opens a drop down menu.


 * mtID : The menu item identifier for a command item.
 * mtString : A NUL terminated Unicode string that provides the menu item text.

MENUEX_TEMPLATE_HEADER
typedef struct MENUEX_TEMPLATE_HEADER { WORD wVersion; WORD wOffset; DWORD dwHelpId; } MENUEX_TEMPLATE_HEADER;

Description:
 * wVersion : For the MENUEX_TEMPLATE_HEADER/MENUEX_TEMPLATE_ITEM combination wVersion 1.
 * wOffset : The number of bytes between the end of the header and the first MENUEX_TEMPLATE_ITEM structure. Usually 0, but can be more to allow program specific data to be stored as part of the menu resource.
 * dwHelpId : The help identifier for the entire menu bar.

Note that the MENUEX_TEMPLATE_HEADER needs to be DWORD aligned, and that all MENUEX_TEMPLATE_ITEM in the menu resource (including the first at wOffset) must be DWORD aligned as well.

MENUEX_TEMPLATE_ITEM
typedef struct MENUEX_TEMPLATE_ITEM { DWORD dwHelpId; DWORD dwType; DWORD dwState; WORD menuId; WORD bResInfo; WCHAR szText; } MENUEX_TEMPLATE_ITEM;

Description:
 * dwHelpId : The help identifier for the menu item. This member is only present in items that define drop-down or submenus.
 * dwType : Menu item type, this member can be a combination of the following types:
 * MFT_BITMAP : Displays the menu item using a bitmap.
 * MFT_MENUBARBREAK : Places the item in a new line (for a menu bar), or in a new column (for a drop-down, submenu, or shortcut menu). For a drop-down, subment, or shortcut menu a vertical bar seperates the old and new columns.
 * MFT_MENUBREAK : Places the item in a new line (for menu bars), or in a new column (for drop-down, submenus and shortcut menus). No seperator is included.
 * MFT_OWNERDRAW : The owner of the menu is responsible for drawing the item in all cases, including highlighting, selection, and inactive states. This type is not valid for menu bar items (only applies to items actually in the bar, not those in drop0-down or submenus).
 * MFT_RADIOCHECK : Display the item as a radio button rather than a normal check box.
 * MFT_RIGHTJUSTIFY : Right justify the menu item and all subsequent items. This value is only valid for items contained in a menu bar.
 * MFT_RIGHTORDER : Indicate that menus cascade right-to-left (the default is left-to-right).
 * MFT_SEPARATOR : Display the menu item as either a horizontal or vertical bar.
 * MFT_STRING - Display the menu as text.
 * Note that the MFT_BITMAP, MFT_SEPERATOR and MFT_STRING types can not be combined with each other.


 * dwState : Menu item state, this value can be one or more of the following values:
 * MFS_CHECKED : Display the item with a check box, and mark it as checked.
 * MFS_DEFAULT : The item is the default menu item. A menu can contain only one default menu item, which is displayed in bold text.
 * MFS_DISABLED : Display the item in gray text and make it non-selectable.
 * MFS_ENABLED : Display the item in normal text and make it selectable.
 * MFS_GRAYED : This state is the same as MFS_DISABLED.
 * MFS_HILITE : Highlight the menu item
 * MFS_UNCHECKED : Display the item with a check box, and mark it as unchecked.
 * MFS_UNHILITE : Unhighlight the menu item


 * menuId : Menu item identifier.
 * bResInfo : This member provides information needed to end menu bars, drop-down menus, submenus and shortcut menus as well as start new drop-down menus and submenus. For 32 bit applications, this member is a WORD, for 16 bit applications it uses one byte.  It can be zero, one or both of the following values:
 * 0x80 : This structure defines the last entry in a menu bar, drop-down menu, submenu or shortcut menu.
 * 0x01 : This structure defines an item that opens a drop-down menu or submenu.
 * For example, if the last item in a drow-down menu opens a submenu, then the definition for that item needs to set bResInfo to 0x81. The last item of the submenu would then set its bResInfo to 0x80.


 * szText : A NUL terminated Unicode string that provides the menu item text. This member must begin on a word boundary.

Each MENUEX_TEMPLATE_ITEM begins on the first DWORD boundary following the prior MENUEX_TEMPLATE_ITEM. If this alignment is not calculated correctly then the menu will fail to load.