47.2.1 Using a Menu-Template Resource

A Windows developer typically includes a menu in an application by defining a menu template in the application's resource-definition file and then loading the menu at run time. This section describes how to define and load a menu-template resource.

47.2.1.1 Defining a Menu-Template Resource

A menu-template resource represents an application's menu bar and all the related pop-up menus. The MENU statement marks the beginning of a menu template and provides the identifier used to load the menu. The identifier must be either a unique string or a unique integer.

The POPUP statement defines a pop-up item. A top-level pop-up item appears in the menu bar and invokes a pop-up menu when it is selected. A nested pop-up item appears in a pop-up menu and invokes a cascaded pop-up menu when it is selected.

The MENUITEM statement defines a command item. A top-level command item appears in the menu bar and invokes a command message when it is selected. A nested command item appears in a pop-up menu and also invokes a command message.

The string for a pop-up item or command item must appear in quotation marks immediately to the right of the POPUP statement. You should use include an ampersand (&) in the string to specify the mnemonic for the menu item. Also, you should include the accelerator, if applicable, and use the “\t” escape character to separate the accelerator text from the menu-item text.

The command identifier for a command item must appear immediately to the right of the menu-item string. You should use a named constant as the identifier and define the constant in your application's header file.

You can specify a number of options that control the appearance and behavior of pop-up and command items. You specify these options to the right of the menu-item string (for a pop-up item) or to the right of the menu-item identifier (for a command item). The menu-item options are described in the following list:

Option Description

CHECKED Item has a check mark next to it. This option is not valid for a top-level pop-up menu.
GRAYED Item is disabled and its string appears on the menu in a dimmed (grayed) shade of the menu-text color.
INACTIVE Item is disabled and its string appears in the normal menu-text color.
MENUBARBREAK Same as MF_MENUBREAK except that in pop-up menus, it separates the new column from the old column with a vertical line.
MENUBREAK Menu-bar item is placed on a new line. An item in a pop-up menu is placed in a new column with no dividing line between the columns.

You can use the bitwise OR operator to combine these options. The INACTIVE and GRAYED options cannot be used together.

The following source code from a resource-definition file defines a menu bar that includes three pop-up items: File, Edit, and Font. Each pop-up item invokes a pop-up menu that has several command items, and the Font pop-up menu has two other pop-up menus within it.

MyMenuResource MENU

BEGIN

POPUP "&File"

BEGIN

MENUITEM "&Open...", IDM_FI_OPEN

MENUITEM "&Close\tF3", IDM_FI_CLOSE, GRAYED

MENUITEM "&Quit", IDM_FI_QUIT

MENUITEM SEPARATOR

MENUITEM "&About Sample...", IDM_FI_ABOUT

END

POPUP "&Edit"

BEGIN

MENUITEM "&Undo", IDM_ED_UNDO, GRAYED

MENUITEM SEPARATOR

MENUITEM "&Cut", IDM_ED_CUT

MENUITEM "C&opy", IDM_ED_COPY

MENUITEM "&Paste", IDM_ED_PASTE

MENUITEM "C&lear", IDM_ED_ABOUT

END

POPUP "Fo&nt"

BEGIN

POPUP "&Style"

BEGIN

MENUITEM "&Regular\tF5", IDM_FNT_STY_REGULAR

MENUITEM SEPARATOR

MENUITEM "&Bold\tCtrl+B", IDM_FNT_STY_BOLD

MENUITEM "&Italic\tCtrl+I", IDM_FNT_STY_ITALIC

MENUITEM "&Underline\tCtrl+U", IDM_FNT_STY_ULINE

END

POPUP "Si&ze"

BEGIN

MENUITEM "10", IDM_FNT_SZ_10

MENUITEM "12", IDM_FNT_SZ_12

MENUITEM "14", IDM_FNT_SZ_14

END

END

END

47.2.1.2 Loading a Menu-Template Resource

You can load a menu-template resource by calling the LoadMenu function, specifying the handle of the module that contains the resource and the menu-template's identifier. LoadMenu returns a menu handle that you can use to assign the menu to a window. This window becomes the menu's owner window, receiving all the messages generated by the menu.

You can use the SetMenu function to assign the menu to a window, or you can specify the menu's handle in the hmenu parameter of the CreateWindowEx function when you create a window. Alternatively, you can identify a menu template when you register a window class. This identifies the menu as the class menu for the given window class. Whenever you create a window of the given class, Windows automatically assigns the given menu to the window.

You create a class menu by including the identifier of the menu-template resource as the lpszMenuName member of an WNDCLASS structure, then passing the address of the structure to the RegisterClass function.

47.2.1.3 Example: Creating a Class Menu

The following example shows how to create a class menu for an application, how to create a window that uses the class menu, and how to process menu commands in the window procedure.

HANDLE hinst;

int APIENTRY WinMain(hinstance, hPrevInstance, lpCmdLine, nCmdShow)

HANDLE hinstance;

HANDLE hPrevInstance;

LPSTR lpCmdLine;

int nCmdShow;

{

MSG msg; /* message */

WNDCLASS wc; /* window-class data */

HWND hwnd; /* handle of main window */

/*

* Create the window class for the main window. Specify

* the identifier of the menu-template resource as the

* lpszMenuName member of the WNDCLASS structure to create

* the class menu.

*/

wc.style = 0;

wc.lpfnWndProc = (WNDPROC) MainWndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hinstance;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = GetStockObject(WHITE_BRUSH);

wc.lpszMenuName = "MyMenuResource";

wc.lpszClassName = "MainWClass";

if (!RegisterClass(&wc))

return FALSE;

hinst = hinstance;

/*

* Create the main window. Set the hmenu parameter to NULL so

* that Windows uses the class menu for the window.

*/

hwnd = CreateWindow("MainWClass", "Sample Application",

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance,

NULL);

if (hwnd == NULL)

return (FALSE);

/*

* Make the window visible and send a WM_PAINT message to the

* window procedure.

*/

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

/* Start the main message loop. */

while (GetMessage(&msg, NULL, 0, 0)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return (msg.wParam);

UNREFERENCED_PARAMETER(hPrevInstance);

}

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

switch (uMsg) {

.

. /* Process other window messages. */

.

case WM_COMMAND:

/* Test for the identifier of a command item. */

switch(LOWORD(wParam)) {

case IDM_FI_OPEN:

DoFileOpen(); /* application-defined */

break;

case IDM_FI_CLOSE:

DoFileClose(); /* application-defined */

break;

.

. /* Process other menu commands. */

.

default:

break;

}

return 0;

.

. /* Process other window messages. */

.

default:

return (DefWindowProc(hwnd, uMsg, wParam, lParam));

}

return NULL;

}