The Windows Programming Model
Programs written for traditional operating environments use a procedural programming model in which programs execute from top to bottom in an orderly fashion. The path taken from start to finish may vary with each invocation of the program depending on the input it receives or the conditions under which it is run, but the path remains fairly predictable. In a C program, execution begins with the first line in the function named main and ends when main returns. In between, main might call other functions and these functions might call even more functions, but ultimately it is the program—not the operating system—that determines what gets called and when.
Windows programs operate differently. They use the event-driven programming model illustrated in Figure 1-1, in which applications respond to events by processing messages sent by the operating system. An event could be a keystroke, a mouse click, or a command for a window to repaint itself, among other things. The entry point for a Windows program is a function named WinMain, but most of the action takes place in a function known as the window procedure. The window procedure processes messages sent to the window. WinMain creates that window and then enters a message loop, alternately retrieving messages and dispatching them to the window procedure. Messages wait in a message queue until they are retrieved. A typical Windows application performs the bulk of its processing in response to the messages it receives, and in between messages, it does little except wait for the next message to arrive.
The message loop ends when a WM_QUIT message is retrieved from the message queue, signaling that it's time for the application to end. This message usually appears because the user selected Exit from the File menu, clicked the close button (the small button with an X in the window's upper right corner), or selected Close from the window's system menu. When the message loop ends, WinMain returns and the application terminates.
Figure 1-1. The Windows programming model.
The window procedure typically calls other functions to help process the messages it receives. It can call functions local to the application, or it can call API functions provided by Windows. API functions are contained in special modules known as dynamic-link libraries, or DLLs. The Win32 API includes hundreds of functions that an application can call to perform various tasks such as creating a window, drawing a line, and performing file input and output. In C, the window procedure is typically implemented as a monolithic function containing a large switch statement with cases for individual messages. The code provided to process a particular message is known as a message handler. Messages that an application doesn't process are passed on to an API function named DefWindowProc, which provides default responses to unprocessed messages.
Messages, Messages, and More Messages
Where do messages come from, and what kinds of information do they convey? Windows defines hundreds of different message types. Most messages have names that begin with the letters "WM" and an underscore, as in WM_CREATE and WM_PAINT. These messages can be classified in various ways, but for the moment classification is not nearly as important as realizing the critical role messages play in the operation of an application. The following table shows 10 of the most common messages. A window receives a WM_PAINT message, for example, when its interior needs repainting. One way to characterize a Windows program is to think of it as a collection of message handlers. To a large extent, it is a program's unique way of responding to messages that gives it its personality.
Common Windows Messages
Message
Sent When
WM_CHAR
A character is input from the keyboard.
WM_COMMAND
The user selects an item from a menu, or a control sends a notification to its parent.
WM_CREATE
A window is created.
WM_DESTROY
A window is destroyed.
WM_LBUTTONDOWN
The left mouse button is pressed.
WM_LBUTTONUP
The left mouse button is released.
WM_MOUSEMOVE
The mouse pointer is moved.
WM_PAINT
A window needs repainting.
WM_QUIT
The application is about to terminate.
WM_SIZE
A window is resized.
A message manifests itself in the form of a call to a window's window procedure. Bundled with the call are four input parameters: the handle of the window to which the message is directed, a message ID, and two 32-bit parameters known as wParam and lParam. The window handle is a 32-bit value that uniquely identifies a window. Internally, the value references a data structure in which Windows stores relevant information about the window such as its size, style, and location on the screen. The message ID is a numeric value that identifies the message type: WM_CREATE, WM_PAINT, and so on. wParam and lParam contain information specific to the message type. When a WM_LBUTTONDOWN message arrives, for example, wParam holds a series of bit flags identifying the state of the Ctrl and Shift keys and of the mouse buttons. lParam holds two 16-bit values identifying the location of the mouse pointer when the click occurred. Together, these parameters provide the window procedure with all the information it needs to process the WM_LBUTTONDOWN message.