One important concept in Windows development is the message. It is possible to get a better understanding of the Windows program by making sure that the message is delivered and processed.
First divide the message into Class 3: Send Message (incomingsent messages), post message (post messages), input message . Where the sending message is a non-queue message , the latter two are queue messages . Non-queue messages are not included in the thread's message queue, and only queue messages are queued in the thread's message queue.
The above classification can also tell why the input action cannot be simulated by the PostMessage function. Because the delivery message goes into the delivery message queue, the input message is entered into the input message queue, and the two message queues are processed at different times.
First, send a message
SendMessage function Families (Sendnotifymessage,sendmessagecallback and SendMessageTimeout), the behavior of all functions is the same in terms of how messages are handled: if The sender and receiver are in the same thread , then the receiver's window procedure will be called directly, and if the sender and receiver are in different threads , then the message will be added to the receiver's sending message queue, and the "wake-up" recipient will be processed for the message.
PostMessage and PostThreadMessage These two functions add messages to the receiver's and deliver the message queue, and wake the recipient.
The messages generated by user input (including keyboard input, mouse input, or input generated through the SendInput function) are added to the input message queue, and the recipient is also awakened.
Such as:
Receiver Wake means that if the recipient is blocked by GetMessage, WaitMessage, msgwaitmultiplieobjects, or other similar functions, the receiving thread will unblock so it can process the new message. It is as if the message added to the queue is the message that the receiving thread is waiting for.
Second, receive the message
At the receiving end of the message, there are three ways to receive messages. Although there are slightly different approaches, these methods follow the same basic rules:
1. The sending message will be submitted directly to the window during the process.
2. Receive the delivery message (via GetMessage or PeekMessage function).
3. Receive input messages (via GetMessage or PeekMessage functions).
The message needs to be submitted during the processing of the message, which might look like this:
LRESULT delivermessage (HWND hwnd,uint umsg,wparam wparam,lparam LPARAM) {//Get the corresponding window procedure WNDPROC Lpfnwndproc = (WNDPROC) getwindowlongptr (HWND,GWLP_WNDPROC);//Call window procedure to process the message return CallWindowProc (Lpfnwndproc, Hwnd,umsg,wparam,lparam);}
One of the principles of message processing is to submit a message for delivery. The process of this function is as follows:
void deliverincomingsentmessages () { while (with a send message) { MSG msg = this message; Delete this message from the sending message queue; If (this is a special pseudo-message) { process this pseudo-message; } else{ delivermessage (Msg.hwnd, Msg.message, Msg.wparam, Msg.lparam); Give the return value to the sender;}}}
Based on the previous functions, we can begin to analyze the functions that receive the message.
The pseudo code of PeekMessage is shown below:
BOOL PeekMessage (lpmsg pmsg,hwnd hwnd,uint wmsgfiltermin,uint wmsgfiltermax,uint flags) { Deliverincomingsentmessages (); If (there is a post message that satisfies the filter) { *pmsg = this message; if (Flags & Pm_remove) deletes the message from the delivery message queue; return TRUE; } if (an input message satisfies the filter condition) { *pmsg = this message; if (Flags & pm_remove) deletes this message from the input message queue; return TRUE; } return FALSE;}
The PeekMessage function first submits all outgoing messages waiting to be processed, if any. After this is done, the function looks for the corresponding message in the delivery message queue based on the filter conditions set (wmsgfiltermin and parameter Wmsgfiltermax, respectively, to set the minimum and maximum values of the retrieved message), if not found, The search continues in the input message queue based on the filtering criteria. If a message is found, the message is received (not submitted) and the message is removed from the corresponding message queue (if the flags parameter contains the PM_REMOVE flag). The PeekMessage function returns False if there are no messages that meet the filter criteria.
From the above, the strategies used to process various types of messages are different. It is not possible to filter out the sending messages, which will certainly be processed. Only post messages and input messages can be filtered. The sending message is distributed inside the PeekMessage function, and the delivery message and input message are returned to the caller via the pmsg parameter, and the caller decides what to do with the message (the usual processing is "distribute this message", but it is not possible to do so).
The process of GetMessage functions is similar to the PeekMessage function, except that GetMessage is returned only if a delivery message is obtained or a message is entered. If you do not get such a message, GetMessage will wait until a delivery message or input message comes in:
BOOL GetMessage (lpmsg pmsg,hwnd hwnd,uint wmsgfiltermin,uint wmsgfiltermax) {while (! PeekMessage (Pmsg,hwnd,wmsgfiltermin,wmsgfiltermax,pm_remove)) { waitmessage (); } return pmsg->message! = Wm_quit;}
Another scenario is the dispatch of messages between threads.
Sendtoanotherthread (...) { adds a message to the receiver's send message queue; These two functions will wait for the receiver to respond if (function = = SendMessage | | Function = = sendmessagetimeout) { while (! Received message &&! Timeout) { deliverincomingsentmessage (); Wait for new message or timeout (if sendmessagetimeout);}}}
The message is added to the sending message queue of the thread in the destination window, and in the case of SendMessage and SendMessageTimeout, the sending thread waits for the target window to return a result (or a message time-out) after dispatching the message.
To sum up, only in three cases to distribute the sending message: 1. in PeekMessage; 2. in GetMessage; 3. SendMessage between threads.
Iii. Message life cycle
1. send a message
As mentioned earlier, if a thread sends a message to one of its own windows, the window procedure that receives the window is called directly (the message does not go into the message queue or into the message pump).
Sends a message between threads, the sent message is added to the sending message queue in the destination window. This message waits in the sending message queue until the target window is on the thread that is executing the peekmessage,getmessage or SendMessage between the threads. When the thread that receives the message is returned from the window procedure, the processing result of the message is returned to the sending thread. The sending thread will continue to execute after the returned result is obtained.
If the Replymessage function is used, the message life cycle may change. If the receiving thread calls Replymessage while processing the sending message, the parameter values passed to the Replymessage function are returned to the sending thread as if the receiving thread were to return from the window procedure. Therefore, the send thread and the receive thread are executed concurrently. The send thread executes because the thread will no longer need to wait for the result of the message, while the receiving thread is executing because the thread is still not returned from the window procedure (the final return value of the window procedure is ignored because the receiving thread has returned a value to the sending thread, And the program cannot go back to that moment to change the value that has been returned.
2. post a message
The post message is added to the drop message queue of the thread on which the target window resides. This message will continue to wait in the delivery message queue until the receiving thread calls GetMessage or the PeekMessage function assigns the message to the MSG structure provided by the program. The next action will depend on the object that receives the message.
In theory, though, a program can do anything to deliver a message. But the most likely scenario is to get the message in the main message pump, which might be the code for the main message pump:
while (GetMessage (&msg, NULL, 0,0)) { if (! TranslateAccelerator (hwnd,hacc,&msg)) { translatemessage (&msg); DispatchMessage (&msg); }}
If this is the case, then the message will be compared to the accelerator key table first, and if a matching accelerator key is found, a wm_command (or wm_syscommand) message will be submitted to the HWND window. In this case, the processing of the message ends, so the message will never be posted to the window.
If no matching accelerator key is found, this message will normally be submitted by the DispatchMessage function to the window procedure, but there are exceptions:
0 if it is a thread message, then there is no corresponding target window. Therefore, thread messages are not distributed.
0 if it is a WM_TIMER message, and the lparam parameter of the message is not NULL, then LPARAM will be treated as a timeproc callback function, so this function will be called directly.
3. generated post messages
The first three types of messages don't cover all of the messages, and some of them, we'll call them "special types of messages."
The WM_MOUSEMOVE message is one of the special messages. When the mouse moves, the message is not added to the input message queue as an input message, but instead a "mouse has moved" flag is set. When the window manager looks for the input message, if it finds that the "mouse has moved" flag is set, the window manager clears the flag and dynamically generates a WM_MOUSEMOVE message and then adds the message to the queue of the input message (or with an existing wm_ MouseMove messages are merged together).
Other special messages belonging to this "dynamically generated" are: WM_PAINT, Wm_timer, and Wm_quit. The first two messages can be generated even after the message lookup process is complete, and both messages are generated when no available input message is found and the message is explicitly indicated in the message filter (the time to generate the Wm_quit message is even later than when the build window draws the message and timer message. This message is generated only if the delivery message queue is empty. In addition, the WM_QUIT message ignores the setting of the message filter, which means that it will be processed as soon as the message appears.
Taking into account the various situations previously mentioned, the PeekMessage is written in a more complex form:
BOOL PeekMessage (lpmsg pmsg, HWND hwnd, UINT wmsgfiltermin,uint Wmsgfiltermax, uint flags) {deliverincomingsentmessage (); if ( There is a delivery message that satisfies the filter condition) {*pmsg = this message; if (Flags & pm_remove) Deletes this message from the delivery message queue: Return TURE;} The Wm_quit message ignores the filter setting if (there is a wm_quit message waiting to be processed and no message is posted) {clears the "there is a wm_quit message waiting to be processed" flag; *pmsg = Wm_quit message; return TRUE;} if (the mouse moves and the input message satisfies the filter) {Clears the "mouse has moved" flag; Add the WM_MOUSEMOVE message to the input message queue;} if (an input message satisfies the filter condition) {*pmsg = this message; if (Flags & pm_remove) Deletes this message from the input message queue; return TURE;} if (the window needs to be drawn and the WM_PAINT message satisfies the filter condition) {*pmsg = WM_PAINT message; return TRUE;} If (the timer is triggered and the WM_TIMER message satisfies the filter condition) {A WM_TIMER message is added to the delivery message queue; *pmsg = This message; if (Flags & pm_remove) Deletes this message from the delivery message queue; return TRUE;} return FALSE;}
Wm_mousemove and Wm_timer messages are interesting: they become true messages in the queue when they need to be generated. If the program uses the PM_NOREMOVE flag when calling the PeekMessage function, this can cause some subtle problems. These messages will stay in the message queue, and the subsequent mouse move messages will be merged with the mouse move message that resides.
Windows message sending and receiving