The Microsoft Foundation Class Library provides a communications mechanism for connecting Windows messages to the message-handler member functions of your windows classes. This section describes the mechanism, emphasizing the message map.
This discussion does not instruct you to add any code to your files.
You write a Microsoft Foundation message map using macros from a set of predefined macros. The following sections discuss the parts of a message map, where the macros go, and how the message map connects your handlers to the Windows messages they handle.
To write the message map, use the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros. Between them, add an entry for each Windows message your main window (or dialog) will handle. The Microsoft Foundation Class Library predefines a set of macros to use for the entries, as discussed in the following sections.
You write the message-handler functions corresponding to your message map entries. The Microsoft Foundation Class Library specifies some rules for naming your message handlers and for specifying their argument signatures. The rules are discussed in the following sections.
Windows programs are spoken of as “event driven.” The user interacts with the windows, menus, and controls in the Windows user interface of your program. User-generated events, such as mouse clicks and keystrokes, place “messages,” each based on the MSG structure defined for Windows, in your application's message queue. Your application uses a message loop to get messages from the queue and send the messages to the appropriate window for handling.
A Windows program must have a mechanism for selecting the appropriate code to respond to Windows messages, such as WM_CREATE, WM_PAINT, or WM_COMMAND.
Traditional Windows programs define a window procedure for each registered “window class.” The window procedure, often called WndProc, typically contains a switch statement which uses the message information passed to the window procedure to select appropriate code to respond to the message.
The Microsoft Foundation Classes provide a mechanism for the same purpose called a message map. These message maps are similar to C++ “v-tables” but are more space efficient. The message map defines linkages between particular Windows messages and corresponding member functions of the window object.
Message Map Macros
Hello uses a message map with two entries, as described previously. ON_COMMAND, which is used to respond to commands such as WM_COMMAND messages, is only one of the macros available for associating messages with functions. The Microsoft Foundation Class Library provides many such macros, including, for example, ON_WM_PAINT, ON_WM_CREATE, and ON_WM_SIZE. For more information about the macros associated with message map entries, see the cookbook and the Class Libraries Reference. The ON_WM_PAINT macro is discussed further, in “Paint the Window” on page 101.
For instance, the example code for Hello defines a message map with an entry providing a connection between the constant IDM_ABOUT and the OnAbout member function. IDM_ABOUT represents the menu ID of the About menu command, as defined in the resource file associated with Hello.
When a window procedure receives a WM_COMMAND message for a menu command, the window procedure's wParam parameter contains a menu ID to identify which menu command was chosen. Hello's message map uses the ON_COMMAND macro to associate IDM_ABOUT with the OnAbout member function.
Logically, the message map is part of the main window class, so a good place to put it is with the CMainWindow code.
The macros create entries in a table. The message-processing mechanisms in the Microsoft Foundation Classes use the table to locate and call the function associated with a message. Figure 3.4 shows the process of routing messages to handlers via message maps.
What happens if there is no entry in the message map of your window class for a given message? Each window class in the class hierarchy (CWnd, CFrameWnd, and CMainWindow in the example) has its own message map. The message processing mechanism can move up the hierarchy of message maps in search of a message-to-function mapping.
Because default handlers are declared in class CWnd, a default handler will be found at the CWnd level of the hierarchy if nowhere else. If the default behavior for a given handler has been overridden at some level, the mechanism finds a function to execute and calls it. Because of this structure, it's a good idea to call the base class's version of your handler function, much as you call DefWindowProc in traditional Windows programming.
Rules for Message-Handler Functions
If you use the message-handling apparatus of the Microsoft Foundation Classes in your Windows program, there are some guidelines and requirements for the names and parameter signatures of your message handler functions, such as OnAbout and OnPaint. There are three main categories of messages that a window receives:
WM_COMMAND messages generated by user menu selections or menu-accelerator keys.
Notification messages from child windows, such as a message from a button to its parent window indicating that the button has been clicked: BN_CLICKED.
A notification message is a WM_COMMAND message in which the wParam parameter contains the control ID for the child window and the lParam parameter contains a notification control code in the high-order word and the control handle in the low-order word.
Other WM_XXX messages, such as WM_PAINT or WM_SIZE, generated by the system or by user input.
Note:
You can always get to the raw Windows MSG structure by calling the GetCurrentMsg function.
Your handler functions for menu messages and child window notification messages (the first two preceding categories) take no arguments and return no value. No arguments are needed because your main window object stores the message information needed to process the message. The two categories of messages use the information that Windows passes with the message differently, but the conventions for naming your handler functions are the same.
Your handler functions for messages in the third category above, however, do require various arguments, depending on the message, and can return a value. Because the Windows messages are all standard, the names and argument signatures required for these handler functions are predefined by the Microsoft Foundation Classes.
For example, your handler for the WM_PAINT message must be named OnPaint. It takes no arguments and returns no value.
Other message handlers do require arguments, and some return values. The OnSize handler function for a WM_SIZE message, for example, requires two arguments, one of type UINT and one of type CPoint. OnSize returns no value. An OnEraseBkgnd handler for the WM_ERASEBKGND message requires one argument, a pointer to a device context class object, and returns a BOOL.
To determine the correct argument signature and return type for your message- handler functions, see the Class Libraries Reference. The signatures are also listed as function prototypes in the CWnd class declaration in file AFXWIN.H. Each prototype is preceded by the afx_msg identifier. You should copy and paste these prototypes into your own code as needed. See the additional information in the box “Default Message Handlers” on page 100.
For more information about message maps, see the cookbook. For more examples, see the next chapter.
The next several sections examine how to write the message handler member functions for Hello's main window class. These functions correspond to the two entries in Hello's message map above. They handle:
Responding to an application request to paint or repaint a window's contents.
Displaying an About dialog box.
Default Message Handlers
The Microsoft Foundation Classes supply default message handlers, as function prototypes, for all standard Windows messages. All of the Microsoft Foundation's window classes also have their own message maps. Because of this, the Microsoft Foundation provides good default message handling equivalent to the use of DefWindowProc and its relatives in traditional Windows programming.
The default message handler functions work through the message maps and are not actually virtual functions, although their behavior appears to be like that of virtual functions. To override the default behavior for any Windows message, you must provide your own handler function for the message in your window class, and you must make an entry in your message map for the function. The function must follow the prototype for its message, given in class CWnd. For example, in CWnd, the prototype for OnPaint is
afx_msg void OnPaint()
Your function declaration for CMainWindow's OnPaint member function looks like this:
afx_msg void OnPaint();
If you do override the default handler by supplying your own, it is a good practice to call your base class's version of the handler. You can do this at any appropriate point in the body of your handler. For example, in a function that draws a graphic, you might call the base class version to get the default processing, then add your own processing. In another case, you might do your processing first, then call the base class version to add the default processing. Calling the base class version of your function is optional. You will certainly want to do it for any handler that augments rather than replaces the behavior of the base class's version of the handler.