- Window Messages (Get Started with Win32 and C++)
- The Message Loop
- Posted Messages versus Sent Messages
- SendMessageA function (winuser.h)
- Syntax
- Parameters
- Return value
- Remarks
- Examples
- SendMessage function (winuser.h)
- Syntax
- Parameters
- Return value
- Remarks
- SendMessageW function (winuser.h)
- Syntax
- Parameters
- Return value
- Remarks
- Examples
Window Messages (Get Started with Win32 and C++)
A GUI application must respond to events from the user and from the operating system.
- Events from the user include all the ways that someone can interact with your program: mouse clicks, key strokes, touch-screen gestures, and so on.
- Events from the operating system include anything «outside» of the program that can affect how the program behaves. For example, the user might plug in a new hardware device, or Windows might enter a lower-power state (sleep or hibernate).
These events can occur at any time while the program is running, in almost any order. How do you structure a program whose flow of execution cannot be predicted in advance?
To solve this problem, Windows uses a message-passing model. The operating system communicates with your application window by passing messages to it. A message is simply a numeric code that designates a particular event. For example, if the user presses the left mouse button, the window receives a message that has the following message code.
Some messages have data associated with them. For example, the WM_LBUTTONDOWN message includes the x-coordinate and y-coordinate of the mouse cursor.
To pass a message to a window, the operating system calls the window procedure registered for that window. (And now you know what the window procedure is for.)
The Message Loop
An application will receive thousands of messages while it runs. (Consider that every keystroke and mouse-button click generates a message.) Additionally, an application can have several windows, each with its own window procedure. How does the program receive all these messages and deliver them to the correct window procedure? The application needs a loop to retrieve the messages and dispatch them to the correct windows.
For each thread that creates a window, the operating system creates a queue for window messages. This queue holds messages for all the windows that are created on that thread. The queue itself is hidden from your program. You cannot manipulate the queue directly. However, you can pull a message from the queue by calling the GetMessage function.
This function removes the first message from the head of the queue. If the queue is empty, the function blocks until another message is queued. The fact that GetMessage blocks will not make your program unresponsive. If there are no messages, there is nothing for the program to do. If you have to perform background processing, you can create additional threads that continue to run while GetMessage waits for another message. (See Avoiding Bottlenecks in Your Window Procedure.)
The first parameter of GetMessage is the address of a MSG structure. If the function succeeds, it fills in the MSG structure with information about the message. This includes the target window and the message code. The other three parameters let you filter which messages you get from the queue. In almost all cases, you will set these parameters to zero.
Although the MSG structure contains information about the message, you will almost never examine this structure directly. Instead, you will pass it directly to two other functions.
The TranslateMessage function is related to keyboard input. It translates keystrokes (key down, key up) into characters. You do not really have to know how this function works; just remember to call it before DispatchMessage. The link to the MSDN documentation will give you more information, if you are curious.
The DispatchMessage function tells the operating system to call the window procedure of the window that is the target of the message. In other words, the operating system looks up the window handle in its table of windows, finds the function pointer associated with the window, and invokes the function.
For example, suppose that the user presses the left mouse button. This causes a chain of events:
- The operating system puts a WM_LBUTTONDOWN message on the message queue.
- Your program calls the GetMessage function.
- GetMessage pulls the WM_LBUTTONDOWN message from the queue and fills in the MSG structure.
- Your program calls the TranslateMessage and DispatchMessage functions.
- Inside DispatchMessage, the operating system calls your window procedure.
- Your window procedure can either respond to the message or ignore it.
When the window procedure returns, it returns back to DispatchMessage. This returns to the message loop for the next message. As long as your program is running, messages will continue to arrive on the queue. Therefore, you must have a loop that continually pulls messages from the queue and dispatches them. You can think of the loop as doing the following:
As written, of course, this loop would never end. That is where the return value for the GetMessage function comes in. Normally, GetMessage returns a nonzero value. When you want to exit the application and break out of the message loop, call the PostQuitMessage function.
The PostQuitMessage function puts a WM_QUIT message on the message queue. WM_QUIT is a special message: It causes GetMessage to return zero, signaling the end of the message loop. Here is the revised message loop.
As long as GetMessage returns a nonzero value, the expression in the while loop evaluates to true. After you call PostQuitMessage, the expression becomes false and the program breaks out of the loop. (One interesting result of this behavior is that your window procedure never receives a WM_QUIT message. Therefore, you do not have to have a case statement for this message in your window procedure.)
The next obvious question is when to call PostQuitMessage. We’ll return to this question in the topic Closing the Window, but first we have to write our window procedure.
Posted Messages versus Sent Messages
The previous section talked about messages going onto a queue. Sometimes, the operating system will call a window procedure directly, bypassing the queue.
The terminology for this distinction can be confusing:
- Posting a message means the message goes on the message queue, and is dispatched through the message loop (GetMessage and DispatchMessage).
- Sending a message means the message skips the queue, and the operating system calls the window procedure directly.
For now, the difference is not very important. The window procedure handles all messages. However, some messages bypass the queue and go directly to your window procedure. However, it can make a difference if your application communicates between windows. You can find a more thorough discussion of this issue in the topic About Messages and Message Queues.
SendMessageA function (winuser.h)
Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread’s message queue and return immediately, use the PostMessage or PostThreadMessage function.
Syntax
Parameters
A handle to the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST ((HWND)0xffff), the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
Message sending is subject to UIPI. The thread of a process can send messages only to message queues of threads in processes of lesser or equal integrity level.
The message to be sent.
For lists of the system-provided messages, see System-Defined Messages.
Additional message-specific information.
Additional message-specific information.
Return value
The return value specifies the result of the message processing; it depends on the message sent.
Remarks
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function to obtain a unique message for inter-application communication.
The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling.
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more information on nonqueued messages, see Nonqueued Messages.
An accessibility application can use SendMessage to send WM_APPCOMMAND messages to the shell to launch applications. This functionality is not guaranteed to work for other types of applications.
Examples
The winuser.h header defines SendMessage as an alias which automatically selects the ANSI or Unicode version of this function based on the definition of the UNICODE preprocessor constant. Mixing usage of the encoding-neutral alias with code that not encoding-neutral can lead to mismatches that result in compilation or runtime errors. For more information, see Conventions for Function Prototypes.
SendMessage function (winuser.h)
Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread’s message queue and return immediately, use the PostMessage or PostThreadMessage function.
Syntax
Parameters
A handle to the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST ((HWND)0xffff), the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
Message sending is subject to UIPI. The thread of a process can send messages only to message queues of threads in processes of lesser or equal integrity level.
The message to be sent.
For lists of the system-provided messages, see System-Defined Messages.
Additional message-specific information.
Additional message-specific information.
Return value
The return value specifies the result of the message processing; it depends on the message sent.
Remarks
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function to obtain a unique message for inter-application communication.
The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling.
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more information on nonqueued messages, see Nonqueued Messages.
An accessibility application can use SendMessage to send WM_APPCOMMAND messages to the shell to launch applications. This functionality is not guaranteed to work for other types of applications.
SendMessageW function (winuser.h)
Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread’s message queue and return immediately, use the PostMessage or PostThreadMessage function.
Syntax
Parameters
A handle to the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST ((HWND)0xffff), the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
Message sending is subject to UIPI. The thread of a process can send messages only to message queues of threads in processes of lesser or equal integrity level.
The message to be sent.
For lists of the system-provided messages, see System-Defined Messages.
Additional message-specific information.
Additional message-specific information.
Return value
The return value specifies the result of the message processing; it depends on the message sent.
Remarks
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function to obtain a unique message for inter-application communication.
The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling.
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more information on nonqueued messages, see Nonqueued Messages.
An accessibility application can use SendMessage to send WM_APPCOMMAND messages to the shell to launch applications. This functionality is not guaranteed to work for other types of applications.
Examples
The winuser.h header defines SendMessage as an alias which automatically selects the ANSI or Unicode version of this function based on the definition of the UNICODE preprocessor constant. Mixing usage of the encoding-neutral alias with code that not encoding-neutral can lead to mismatches that result in compilation or runtime errors. For more information, see Conventions for Function Prototypes.