33.1.3 Message Handling

A application is responsible for removing and processing messages posted to its threads' message queues. An single-threaded application typically uses a message loop in its WinMain function to remove and pass messages to the appropriate window procedures for processing. Applications with multiple threads can include a message loop in each thread that creates a window. The following sections describe how a message loop works and explains the role of a window procedure.

33.1.3.1 Message Loop

A simple message loop consists of three function calls: one to the GetMessage function, one to the TranslateMessage function, and one to the DispatchMessage function. The GetMessage function retrieves a message from the queue and copies it to an MSG structure. GetMessage returns TRUE except when it encounters the WM_QUIT message, in which case it returns FALSE and ends the loop. In a single-threaded application, terminating the message loop is typically the first step in terminating the application. An application can terminate its own loop by using the PostQuitMessage function, typically in the response to the WM_DESTROY message in the window procedure of the application's main window.

If you specify a window handle in the GetMessage function, only messages for the specified window will be retrieved from the queue. Also, the GetMessage function allows you to filter messages in the queue, retrieving only those messages that fall within a specified range. For more information, see Section 0.1.6, “Message Filtering.”

A thread's message loop must include the TranslateMessage function if the thread needs to receive character input from the keyboard. Windows generates virtual-key messages (WM_KEYDOWN and WM_KEYUP) each time the user presses a keyboard key. A virtual-key message contains a virtual-key code that identifies which key was pressed, but the message does not contain the character value of that key. To retrieve the character value, the message loop must contain the TranslateMessage function. This function translates the virtual-key message into a character message (WM_CHAR) and places it back into the application message queue. The character message can then be removed on a subsequent iteration of the message loop and dispatched to a window procedure.

The DispatchMessage function passes a message to the window procedure associated with the window handle specified in the MSG structure. If the window handle is 0xFFFFFFFF (-1), DispatchMessage passes the message to the window procedures of all top-level windows in the system. If the window handle is NULL, DispatchMessage does nothing with the message.

An application's main thread starts its message loop after initializing the application and creating at least one window. Once started, the message loop continues to retrieve messages from the thread's message queue and dispatch them to the appropriate windows. The message loop terminates when the GetMessage function removes the WM_QUIT message from the message queue.

Only one message loop is needed for a message queue, even if the application contains many windows. Because each message in the queue is an MSG structure that contains the handle of the window to which the message belongs, DispatchMessage always dispatches a message to the proper window.

An application can modify its message loop in a variety of ways. For example, it can retrieve messages from the queue without dispatching them to a window. This is useful for applications that post messages that do not specify a window. (These messages apply to the application rather than to a specific window; they have NULL window handles.) An application can also direct the GetMessage function to search for specific messages, leaving other messages in the queue. This is useful for applications that temporarily need to bypass the usual first-in, first-out order of the message queue.

An application that uses accelerators must include a call to the TranslateAccelerator function in a message loop to translate keyboard messages into command messages. For more information about accelerator keys, see Chapter 48, “Keyboard Accelerators.”

33.1.3.2 Window Procedures

A window procedure is a function that receives and processes all messages passed to the window. Every window class has a window procedure, and every window created using that class uses that same window procedure to respond to messages.

The system passes a message to a window procedure by passing the message data as arguments to the window procedure. The window procedure carries out an appropriate action for the given message. A window procedure typically checks the message identifier, then uses the information specified by the message parameters while processing the message.

A window procedure usually does not ignore a message. If it does not process a message, it must pass the message back to the system for default processing. The window procedure does this by calling the DefWindowProc function. This function carries out a default action and returns the message result. The window procedure must then return this value as its own message result. Most window procedures process just a few types of messages and pass the others on to the system by calling DefWindowProc.

Because a window procedure is shared by all windows belonging to the same class, a window procedure can process messages for several different windows. A window procedure can examine the window handle passed with a message to identify the specific window affected by the message. For more information about window procedures, see Chapter 35, “Window Procedures.”