Menus and Messages

Windows usually sends a window procedure several different messages when the user selects a menu item. In most cases your program can ignore many of these messages and simply pass them to DefWindowProc. Let's take a look at them anyway.

The first message your program receives when the user selects a menu item with the keyboard or mouse is a WM_SYSCOMMAND message. The values of wParam and lParam are shown below:

  wParam lParam

Mouse: F09x 0
Keyboard: F10x 0

The WINDOWS.H identifier SC_MOUSEMENU is equal to F090H; SC_KEYMENU is F100H, but the last digit in wParam (indicated by an x in the table above) can be anything. Use:

(wParam & 0xFFF0)

if you need to check this value. Most programs pass these messages to DefWindowProc.

The second message your program receives is a WM_INITMENU message with the following parameters:

wParam LOWORD (lParam) HIWORD (lParam)

Handle to main menu 0 0

The value of wParam is the handle to your main menu even if the user is selecting an item from the system menu. Windows programs generally ignore the WM_INITMENU message. Although the message exists to give you the opportunity to change the menu before an item is chosen, I suspect any changes to the top-level menu at this time would be very disconcerting to the user.

The next message your program receives is WM_MENUSELECT. A program can receive many WM_MENUSELECT messages as the user moves the cursor or mouse among the menu items. The parameters that accompany WM_SELECT are as follows:

wParam LOWORD (lParam) HIWORD (lParam)

Selected item: Menu ID or popup menu handle Selection flags Handle to menu containing selected item

WM_MENUSELECT is a menu-tracking message. The value of wParam tells you what item of the menu is currently selected (highlighted). The ”selection flags“ in the low word of lParam can be a combination of the following: MF_GRAYED, MF_DISABLED, MF_CHECKED, MF_BITMAP, MF_POPUP, MF_HELP, MF_SYSMENU, and MF_MOUSESELECT. You may want to use WM_MENUSELECT if you need to change something in the client area of your window based on the movement of the highlight among the menu items. Most programs pass this message to DefWindowProc.

When Windows is ready to display a popup menu, it sends the window procedure a WM_INITMENUPOPUP message with the following parameters:

wParam LOWORD (lParam) HIWORD (lParam)

Popup menu handle Popup index 1 for system menu, 0 otherwise

This message is important if you need to enable or disable items in a popup menu before it is displayed. For instance, suppose your program can copy text from the clipboard using the Paste command on a popup menu. When you receive a WM_INITMENUPOPUP message for that popup, you should determine if the clipboard has text in it. If it doesn't, you should gray the Paste menu item. We'll see an example of this in the revised POPPAD program shown toward the end of this chapter.

The most important menu message is WM_COMMAND. This message indicates that the user has chosen an enabled menu item from your window's menu. You'll recall from Chapter 6 that WM_COMMAND messages also result from child window controls. If you happen to use the same ID codes for menus and child window controls, you can differentiate between them by the low word of lParam, which will be 0 for a menu item:

  wParam LOWORD (lParam) HIWORD (lParam)

Menu: Menu ID 0 0
Control: Control ID Child window handle Notification code

The WM_SYSCOMMAND message is similar to the WM_COMMAND message except that WM_SYSCOMMAND signals that the user has chosen an enabled menu item from the system menu:

  wParam LOWORD (lParam) HIWORD (lParam)

System menu: Menu ID 0 0

The menu ID indicates which item on the system menu has been chosen. For the predefined system menu items, the bottom four bits should be masked out. The resultant value will be one of the following: SC_SIZE, SC_MOVE, SC_MINIMIZE, SC_MAXIMIZE, SC_NEXTWINDOW, SC_PREVWINDOW, SC_CLOSE, SC_VSCROLL, SC_HSCROLL, SC- ARRANGE, SC_RESTORE, and SC_TASKLIST. In addition, wParam can be SC_MOUSEMENU or SC_KEYMENU, as indicated earlier.

If you add menu items to the system menu, wParam will be the menu ID that you define. To avoid conflicts with the predefined menu IDs, use values below F000H. It is important that you pass normal WM_SYSCOMMAND messages to DefWindowProc. If you do not, you'll effectively disable the normal system menu commands.

The final message we'll discuss is WM_MENUCHAR, which isn't really a menu message at all. Windows sends this message to your window procedure in one of two circumstances: if the user presses Alt and a character key that does not correspond to a menu item, or, when a popup is displayed, if the user presses a character key that does not correspond to an item in the popup. The parameters that accompany the WM_MENUCHAR message are as follows:

wParam LOWORD (lParam) HIWORD (lParam)

ASCII code Selection code Handle to menu

The selection code is:

0—No popup is displayed.

MF_POPUP—Popup is displayed.

MF_SYSMENU—System menu popup is displayed.

Windows programs usually pass this message to DefWindowProc, which normally returns a 0 to Windows, which causes Windows to beep. We'll see a use for the WM_MENUCHAR message in the GRAFMENU program shown later in this chapter.