A detailed description of the Windows message delivery mechanism

Source: Internet
Author: User
Tags set background

Windows is a message-driven system. Windows messages provide a means of communicating between applications and between applications and Windows systems. The functionality the application wants to implement is triggered by the message, and is done by responding to and processing the message. It must be noted that the message is not preemptive, regardless of the urgency of the event, always follow the arrival of the party, in turn (some system messages excepted), which may cause some real-time external events can not be processed in time.

Windows applications typically include Windows, which primarily provide a visual way for users to interact, and windows are always created within a thread. Windows systems manage interactions through messaging mechanisms, messages are sent, saved, processed, and a thread maintains its own set of message queues (messages queue) to maintain exclusivity among threads. The characteristics of the queue are nothing more than FIFO, which can implement an asynchronous demand response process.


1. Message

2. Message type

3. Message Queuing (msg Queues)

4. Queue messages (Queued Messages) and non-queue messages (non-queued Messages)

5, PostMessage (postthreadmessage), SendMessage

6, GetMessage, PeekMessage

7, TranslateMessage, TranslateAccelerator

8, (Message deadlocks)

9, Broadcastsystemmessage

10. Handling of messages

11, MFC's message map

12. Message Reflection mechanism

1. Message

The message system is very important for a Win32 program, which is a source of power for a program to run. A message is a system-defined 32-bit value that uniquely defines an event that sends a notification to Windows informing the application that something has happened. For example, click the mouse, change the window size, press a key on the keyboard

will cause Windows to send a message to the application.

The message itself is passed to the application as a record that contains the type of message and other information. For example, for a message that is generated by clicking the mouse,

said that this record contains the coordinates when the mouse is clicked. This record type, called MSG,MSG, contains message information from the Windows Application Message queue, which is

Windows declares the following:
typedef struct TAGMSG
HWND hwnd; The window handle that accepts the message
UINT message; The message constant identifier, which is what we usually call the message number
WPARAM WPARAM; Specific additional information for a 32-bit message, which means that the exact meaning depends on the message value
LPARAM LPARAM; Specific additional information for a 32-bit message, which means that the exact meaning depends on the message value
DWORD time; Time when the message was created
Point pt; The position of the mouse/cursor in the screen coordinate system when the message was created
Messages can be generated by a system or application. The system generates a message when an input event occurs. For example, when the user strikes a key, move the mouse or click the control. The system also generates messages in response to changes made by the application, such as the application changing the system font and changing the size of the form. An application can generate messages to make a form perform tasks or communicate with a window in another application.

2. Message type

1) System Definition message (system-defined Messages)
Pre-defined messages in the SDK, which are not user-defined, range between [0x0000, 0x03ff] and can be divided into the following three categories:
1> window messages (Windows message)
Related to the internal workings of the window, such as creating Windows, drawing windows, destroying windows, etc. It can be a normal window, a dialog, a control, and so on.
such as: Wm_create, WM_PAINT, Wm_mousemove, Wm_ctlcolor, Wm_hscroll ...
2> Command Message
A command message is generated when a user request is processed, such as when a menu item or toolbar or control is clicked.
WM_COMMAND, LoWord (WParam) represents the ID of a menu item, toolbar button, or control. If it is a control, HiWord (WParam) represents the control message type
3> Control Notification (Notify Message)
The control notifies the message, which is the most flexible message format, with its messages, WParam, LPARAM, respectively: WM_NOTIFY, control ID, pointer to NMHDR. NMHDR contains the contents of the control notification and can be arbitrarily extended.
2) Program definition message (application-defined Messages)
User-defined messages have the following provisions for their scope:
Wm_user:0x0400-0x7fff (ex. wm_user+10)
Wm_app (winver> 4.0): 0x8000-0xbfff (ex. WM_APP+4)

3. Message Queuing (msg Queues)

There are two types of Message Queuing in Windows
1) System Message Queuing (systems messages queue)
This is a system-unique queue where the device driver (mouse, keyboard) translates the operation input into a message that exists in the system queue, which is then placed in the message queue of the thread on which the target window is located (thread-specific-message queues) Waiting for processing in
2) thread Message Queuing (thread-specific message queue)
Each GUI thread maintains such a thread message queue. (This queue is created only when the thread calls the GDI function and is not created by default). The message in the thread message queue is then sent to the appropriate window procedure (WNDPROC) for processing.
Note: In thread Message Queuing, Wm_paint,wm_timer is processed only when there are no other messages in the queue, and WM_PAINT messages are merged to improve efficiency. All other messages are processed in first-in, in-and-out (FIFO) mode.

4. Queue messages (Queued Messages) and non-queue messages (non-queued Messages)

1) Queue messages (Queued Messages)  
        messages are saved in the message queue first, the message loop takes messages from this queue and distributes them to each window processing  , such as mouse, keyboard messages.   
2) Non-queue messages (nonqueued Messages)  
        messages bypass system Message Queuing and thread Message Queuing send directly to a window procedure is processed   such as: Wm_activate, Wm_setfocus, Wm_setcursor, wm_windowposchanged  
Note: The message sent by PostMessage is a queue message. It will post the message to the message queue, and the message sent by SendMessage is sent to the window process directly.

Differences between queue messages and non-queue messages
From the way messages are sent, messages can be divided into 2 types: Queue messages and non-queue messages. Message Queuing can be divided into system Message Queuing and thread Message Queuing. System Message Queuing is maintained by Windows, thread Message Queuing is maintained by each GUI thread itself, to avoid creating message queues for Non-gui, all threads are generated without Message Queuing, and the system creates a message queue for the thread the first time the GDI function is called. Queue messages are sent to the system message queue and then to the thread message queue, and non-queue messages are sent directly to the destination window procedure.
For queue messages, the most common messages that are triggered by the mouse and keyboard, such as Wm_mousermove,wm_char, are other messages, such as WM_PAINT, Wm_timer, and Wm_quit. When the mouse, keyboard events are triggered, the corresponding mouse or keyboard driver will convert these events into corresponding messages, and then sent to the system message queue, by the Windows system to process. The Windows system takes a message from the system message queue at the appropriate time, determines that the message is to be sent to that window, according to the structure of the MSG message, and then takes the extracted message to the appropriate queue of the thread that created the window, and the following is what the thread message queue is about. Windows started to get busy with their own things. When a thread sees a message in its own message queue, it takes it out of the queue and sends it to the appropriate window process via the operating system.
In general, the system always posts the message at the end of the message queue. This ensures that the window receives the message in FIFO order. However, WM_PAINT is an exception, and multiple wm_paint of the same window are merged into a WM_PAINT message, merging all invalid areas into an invalid zone. The purpose of merging Wm_pain is to reduce the number of times the window is refreshed.

Non-queue messages will bypass system queues and message queues, sending messages directly to the window procedure. The system sends a non-queue message Notification window and the system sends a message notification window. For example, when a user activates a window The system sends Wm_activate, Wm_setfocus, and Wm_setcursor. These messages notify the window that it was activated. Non-queue messages can also be generated by system functions when the application calls. For example, when the program calls the SetWindowPos system, the wm_windowposchanged message is sent. Some functions also send non-queue messages, such as the ones we're going to talk about below.

5, PostMessage (postthreadmessage), SendMessage
PostMessage: Returns the message immediately after it is placed in the thread message queue where the specified window is located. PostThreadMessage: Returns the message immediately after it is placed in the message queue of the specified thread.
SendMessage: The message is sent directly to the window process processing, the process is finished before returning.

The difference between PostMessage (asynchronous) and SendMessage (synchronous)

A, PostMessage is asynchronous, SendMessage is synchronous.

PostMessage only puts the message in the queue, regardless of whether the message is processed or returned, the message may not be processed;

SendMessage waits for the message to be processed before returning, and if the message is not processed, the thread that sent the message will remain in a blocked state waiting for the message to be returned.

b, the same line range:

When SendMessage sends a message, the USER32.DLL module invokes the message handler of the target window and returns the result, SendMessage sends a message inside the same thread does not enter the thread message queue, and the message sent by the PostMessage is first placed in the message queue. The message loop is then dispatched to the target window (dispatchmessage).

C, Different threads:

SendMessage sends a message to the destination window of the message queue, and then sends the message to the thread in USER32. The DLL module monitors and waits for messages to be processed until the target window is processed back, and SendMessage needs to do a lot of work before returning, such as responding to a SendMessage () sent to it by another thread. It is best to use PostThreadMessage instead when Postmessge () to other threads. The HWND parameter of PostMessage () can be null, which is equivalent to PostThreadMessage () + Getcrrentthreadid.

D, the system processes the message.

The system only processes (marshal) system messages (0--wm_user), and users are required to process them themselves when sending user messages (defined by the user).

When sending a system message using an asynchronous function such as Postmessage,sendnotifymessage,sendmessagecallback, the parameter cannot use a pointer because the sender does not wait for the message to be processed and the receiver has not been processed, and the pointer may be released. , or the content changes.

E, in Windows 2000/XP, each message queue can hold up to a certain number of messages, more than will not be processed and discarded. The system defaults to 10000;:[hkey_local_machine\software\microsoft\windows NT\CurrentVersion\Windows] USERPostMessageLimit

6, GetMessage, PeekMessage
PeekMessage will return immediately to keep the message
GetMessage returns a message when there is a message

The main differences between the PeekMessage and GetMessage functions are:
A. The primary function of GetMessage is to "take out" messages from the message queue, remove them from the message queue after the message is taken out, and PeekMessage's primary function is to "peek" the message and return True if there is a message, otherwise false. You can also use PeekMessage to remove a message from the message queue, which uses one of its parameters (UINT wremovemsg), and if set to Pm_remove, the message is fetched and removed from the message queue, and if set to Pm_noremove, The message is not removed from the message queue.
B. If getmessage does not get a message from the message queue, the thread is suspended by the operating system, and when the OS re-dispatches the thread, the nature of the two is different: the use of the getmessage thread will still be suspended, and using the PeekMessage thread would give the CPU control. Run for some time.
C, GetMessage waits for a message each time, until the message is returned, and PeekMessage simply queries the message queue, returns without a message, and determines whether the message was taken from the return value.
We can also say that PeekMessage is a function with thread-asynchronous behavior, and the function returns immediately regardless of whether there is a message in the message queue. The GetMessage is a function that has thread synchronization behavior, and if there is no message in the message queue, the function waits until at least one message in the message queue is returned.
If there is no message in the message queue, PeekMessage can always return, which is equivalent to executing a loop, which enters a dead loop if the message queue is always empty. GetMessage is unlikely to enter a dead loop because the message queue is empty.


Inside windows, GetMessage and PeekMessage execute the same code, and both PeekMessage and getmessage get messages to the system's message queue and place them in the specified structure.


PeekMessage: Returns True when there is a message, no message returns false

GetMessage: Returns True if there is a message and the message is not wm_quit, if there is a message and returns false for Wm_quit, no message is returned.

GetMessage: After getting the message, delete the message except the WM_PAINT message.

PeekMessage: After getting the message, determine whether to delete the message according to the WREMOVEMSG parameter. Pm_remove is deleted, Pm_noremove is not deleted.

The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they is processed. However, if a WM_PAINT message has a null update region, PeekMessage does remove it from the queue.

You cannot delete a WM_PAINT message from a message queue by using PeekMessage, removing the WM_PAINT message from the queue can make the invalidated area of the window's display area effective (refreshing the window), and if the queue contains a WM_PAINT message program, it will always be the while loop.

7, TranslateMessage, TranslateAccelerator
TranslateMessage: Converts a virtual-key message into a character message (character message) and puts it into the message queue of the current thread, and the next fetch of the message loop.
TranslateAccelerator: The shortcut key corresponds to the corresponding menu command. It transforms the Wm_keydown or wm_syskeydown into the corresponding WM_COMMAND or Wm_syscommand message in the accelerator table, and then sends the converted WM_COMMAND or Wm_syscommand directly to the window process, It will not be returned until the processing is finished.

8, (message deadlocks)
Assuming the threads A and B, now have the following steps
1) thread A sendmessage to thread B, a waits for the message to be returned after process B is processed
2) thread B receives a message from thread A and processes it, B also sendmessgae to thread a during processing, and waits for a return from a. Because at this point, thread A is waiting to be returned from thread B, unable to process the message from B, which causes the thread A, b to wait for each other to form a deadlock. Multiple threads can also form ring deadlocks.
You can use SendNotifyMessage or sendmessagetimeout to avoid deadlocks.

9, Broadcastsystemmessage
We generally contact the message is sent to the window, in fact, the recipient of the message can be a variety of, it can be an application (applications), can install the driver (installable drivers), network equipment (networks drivers), System-Level device drivers (System-level devices drivers), etc.,
Broadcastsystemmessage This API can send messages to the above system components.

10. Handling of Messages
Next we talk about the processing of the message, first we look at the VC in the message pump:

while (GetMessage (&msg, NULL, 0, 0))
if (! TranslateAccelerator (Msg.hwnd, hacceltable, &msg))
TranslateMessage (&MSG);
DispatchMessage (&MSG);

TranslateMessage (Conversion message):

Used to convert a virtual key message to a character message. Because Windows uses a virtual key definition for all keyboard encodings, it is not a character message when the key is pressed, and a message that requires a keyboard mapping to convert to characters.

TranslateMessage function

Used to convert a virtual key message to a character message. The character message is posted to the calling thread's message queue and is removed the next time the GetMessage function is called. When we hit a character key on the keyboard, the system generates WM_KEYDOWN and WM_KEYUP messages. The additional parameters of these two messages (WPARAM and lparam) contain information such as the virtual key code and the scan code, and we often need to get the ASCII code of a character in the program, translatemessage this function can be wm_keydown and wm_ The combination of the KeyUp messages is converted to a WM_CHAR message (the wparam attached parameter of the message contains the ASCII code of the character) and the converted new message is posted to the calling thread's message queue. Note that the TranslateMessage function does not modify the original message, it simply generates a new message and posts it to the message queue.

That is to say, TranslateMessage will find the message there is a character key message, if there is a character key message, will produce a WM_CHAR message, if there is no message will be generated.

DispatchMessage (Dispatch message):

Sends the message of the TranslateMessage transformation to the window's message handler function, which was specified when the window was registered.

First, GetMessage gets a message from the message queue of the main thread of the process and copies it to the MSG structure, and if there is no message in the queue, the GetMessage function waits for a message to come back. If you pass a window handle to GetMessage as the second argument, only the message for the specified window can be obtained from the queue. GetMessage can also filter messages from the message queue to accept only messages that fall within the scope of the message queue. This is the time to use Getmessage/peekmessage to specify a message filter. This filter is a range of message identifiers or a form handle, or both. It is useful when an application is looking for a post-incoming message queue message. The Wm_keyfirst and Wm_keylast constants are used to accept all keyboard messages. The Wm_mousefirst and Wm_mouselast constants are used to accept all mouse messages.
Then TranslateAccelerator determines whether the message is a key message and is an accelerator key message, and if so, the function converts several key messages into a callback function that the accelerator key message is passed to the window. After processing the accelerator key, the function TranslateMessage will convert the two key message wm_keydown and Wm_keyup to a WM_CHAR, but note that the message wm_keydown,wm_keyup will still be passed to the window's callback function.
After processing, the DispatchMessage function sends this message to the callback function that has been set in the window specified by the message. If the message is Wm_quit, then GetMessage returns 0, which exits the loop body. An application can use PostQuitMessage to end its own message loop. Typically called in the Wm_destroy message of the main window. 11, MFC's message map
When using MFC programming, the nature and WIN32 of message sending and processing are the same, but it encapsulates message processing, simplifies the complexity of message processing when programmers program, it processes messages through message mapping mechanism, programmers do not have to design and implement their own window procedures.
Frankly speaking, the message mapping mechanism in MFC is essentially a huge message and its processing function table. The message map is basically divided into two parts:
There is a macro declare_message_map () in the header file (. h), which is placed at the end of the class, is a public property, and corresponds to the addition of a message map table in the Implementation section (. cpp), which reads as follows:
Begin_massage_map (The current class, the base class for the current Class)
{{Afx_msg_map (CMainFrame)
Entry entry for the message
End_message_map ()
But only these two are not enough to complete a message, if a message work, there must be the following 3 parts to collaborate:
1, add the corresponding function declaration in the definition of the class;
2, add the corresponding message map entry in the message map of the class;
3, in the realization of the class to add the corresponding function body;
Adding a message
(1), using the Class Wizard to implement auto-add
Select View-> from the menu Class Wizard activates the Class Wizard, select the message map tag, and choose the classes we want to add the message from in the Class name combo box. In the Object IDs list box, select the name of the class. At this point, the Messages list box displays the overloaded member functions and window messages for that class. An overloaded member function appears at the top of the list and is represented by the uppercase and lowercase letters of the actual imaginary member function. The other is a window message that appears in uppercase letters. Select the message we want to add, click the Add Funtion button, and the Class Wizard will automatically add the message.
Sometimes the message we want to add is not found in the message list, and we can use the class info tag on the Class wizard to extend the list of messages. In this page, locate the Message Filter combo box, which allows you to change the options in the Messages list box on the first page.
(2), adding messages manually
If the Messages list box does not have the message we want, we need to add it manually:
1) Add the declaration of the handler function in the. h file of the class, followed by the declaration after the//}}afx_msg line, and note that you must start with afx_msg.
In general, the best place to add a handler declaration is below the table maintained by the Class Wizard in the source code, outside of the {{}} brackets in which it marks its realm. Anything in these brackets can be destroyed by the Class Wizard.
2) Next, locate the//}}afx_msg_map line in the user class's. cpp file, and immediately after it, join the message entry. Also, put it outside {{}}.
3) Finally, add the entity of the message handler function to the file.
For messages that can be added using the Class wizard, use the Class Wizard to add as much as possible to reduce our workload; For messages and custom messages that cannot be added using the Class Wizard, you need to add them manually. In general, MFC's message programming is relatively simple for the user, which is no longer used for instance demonstrations.
12. Message Reflection mechanism
What do you mean message reflection?
The parent window sends the control to its notification message, reflecting back to the control for processing (that is, letting the control handle the message), which allows the control to handle its own mechanism called the message reflection mechanism.
Through the previous study we know that in general, the control sends a notification message to the parent window, which is processed by the parent window. In this way, the parent window (usually a dialog box) will process these messages, in other words, the control's message processing must be in the parent window class, and each time we add child controls, we will copy the code in the parent window class. Obviously, this is inconvenient for the maintenance and porting of code, and obviously deviates from the object programming principles of C + +.
Starting with version 4.0, MFC provides a message reflection mechanism (MSG Reflection) that can reflect control notification messages back to the control. Specifically, for a reflection message, if the control has a handler for the message, the control processes the message itself, and if the control does not process the message, the framework will continue to send the message to the parent window so that the parent window continues to process the message. It can be seen that the new message reflection mechanism does not disrupt the original notification message processing mechanism.
The message reflection mechanism is useful for providing the control with the opportunity to process notification messages. If the message is handled by the parent window in the traditional way, it aggravates the dependency of the control object on the parent window, which clearly violates the object-oriented principle. If the control handles the message itself, it makes the control object more independent and greatly facilitates the maintenance and porting of the code.
Example M8: Simply demonstrates the message reflection mechanism of MFC. (See attached source engineering M8)
Open VC + + 6.0, create a new dialog based project M8.
In this project, a new Cmyedit class is created, and the base class is CEdit. Next, add three variables to the class, as follows:
CBrush M_brbkgnd;
COLORREF M_clrbkgnd;
COLORREF M_clrtext;
In Cmyedit::cmyedit (), assign an initial value to these three variables:
M_clrbkgnd = RGB (255, 255, 0);
M_clrtext = RGB (0, 0, 0);
M_brbkgnd.createsolidbrush (RGB (150, 150, 150));
Open ClassWizard, with the class name Cmyedit,messages "=wm_ctlcolor" selected, do you notice that the WM_CTLCOLOR message is preceded by an equal sign, which indicates that the message is a reflection message, that is, The message preceded by an equal sign is a message that can be reflected.
The message reflection function code is as follows:
Hbrush Cmyedit::ctlcolor (cdc* PDC, UINT nCtlColor)
Todo:change any attributes of the DC
Pdc-> SetTextColor (M_clrtext);//Set text color
Pdc-> SetBkColor (M_CLRBKGND);//Set Background color
Note that before we overwrite the contents of the function, the function returns NULL, that is, return null;
A function that returns Null will execute the Ctlcolor function of the parent window without executing the control's Ctlcolor function
So, we let the function return the background brush without returning NULL in order to implement message reflection
return M_BRBKGND; Back to Background brush
Add an edit control to the Idd_m8_dialog dialog box, and use ClassWizard to add a cmyedit-type variable m_edit1 to the edit control, associating the edit control with the Cmyedit.

Lin Bingwen Evankaka Original works. Reprint please specify the source Http://blog.csdn.net/evankaka

A detailed description of the Windows message delivery mechanism

Related Article

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.