SendmessagePostmessage Principle
This article describes the implementation principles of sendmessage and postmessage functions in three steps.ProgramThe three steps are as follows:
1. Running Mechanism of sendmessage and postmessage.
2. Running details of sendmessage and postmessage.
3. Internal Implementation of sendmessage and postmessage.
Note: Understand this articleArticleBefore that, you must first understand the message Loop Mechanism in windows.
1Running Mechanism of sendmessage and postmessage
Let's take a look at the simplest one.
Sendmessage can be understood as the sendmessage function that sends a message. Only sendmessage is returned after the message processing is complete. A little deeper, the sendmessage is returned after the window processing function returns.
Postmessage can be understood as a postmessage function that sends a message and returns immediately without waiting for the message to be processed. A little deeper, postmessage only sends the message, and does not care if the message is sent or not. As long as the message is sent, it is immediately returned.
This is sufficient for programmers who write General Windows programs. But does sendmessage and postmessage really mean waiting for a message to be sent and not waiting for a message to be sent? For more information, see the following section 2nd.
2Running insider of sendmessage and postmessage
When writing a general windows program, as mentioned at, it is sufficient to handle it. In fact, we can look at msdn to determine the running details of sendmessage and postmessage.
In msdn, sendmessage is interpreted as:SendmessageFunction sends the specified message to a window or windows. It callthe window procedure for the specified window and does not return until the window procedure has processed the message.
The sendmessage function sends the specified message to the window. It calls the window processing function of a specific window and does not return immediately until the window processing function processes the message.
Let's take a look at the postmessage explanation:PostmessageFunction places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.
The postmessage function puts a message into the thread related to the Message Queue that created the window, and immediately returns the message without waiting for the thread to process the message.
After carefully reading the msdn explanation, we know that sendmessage is indeed sending a message, and then waiting for processing to complete the response, but the method for sending the message isDirectly call the message processing function (that is, the wndproc function)According to the function call rules, sendmessage is returned only after the message processing function is returned. However, postmessage does not send a message. postmessage puts the message into the message queue and immediately returns the message. postmessage does not know when the message is processed, at this time, only the message loop knows when the message to be postmessage is processed.
So far, we have opened a level of doubt. Originally, sendmessage only calls our message processing function, and postmessage only places the message in the message queue. The next section will go deeper into these two functions to see how Microsoft implements them.
3Internal Implementation of sendmessage and postmessage
The operating principles and mechanisms of windows are often something we are interested in, and these things are not documented, so we can only use the tools provided by Microsoft to study them on our own.
First, in the basic Win32 ProjectCode, We can directly see the message processing function, message loop, so create a basic Win32 Project (this article uses vs2005), in order to see more information, we need to set, let vs2005 load the Microsoft symbol (PDB) file [1]. In order to facilitate the removal of unnecessary code, two menus are added: idm_sendmessage and idm_postmessage. The following lists the simplified code.
Message loop:
Ln000: While (getmessage (& MSG, null, 0, 0 ))
Ln001 :{
Ln002: translatemessage (& MSG );
Ln003: dispatchmessage (& MSG );
Ln004 :}
Message Processing functions:
Ln100: lresult callback wndproc (hwnd, uint message, wparam, lparam)
Ln101 :{
Ln102: int wmid, wmevent;
Ln103: Switch (Message)
Ln104 :{
Ln105: Case wm_command:
Ln106: wmid = loword (wparam );
Ln107: wmevent = hiword (wparam );
Ln108: Switch (wmid)
Ln109 :{
Ln110: Case idm_exit:
Ln111: destroywindow (hwnd );
Ln112: break;
Ln113: Case idm_sendmessage:
Ln114: sendmessage (hwnd, wm_sendmessage, 0, 0 );
Ln115: break;
Ln116: Case idm_postmessage:
Ln117: postmessage (hwnd, wm_postmessage, 0, 0 );
Ln118: break;
Ln119: default:
Ln120: Return defwindowproc (hwnd, message, wparam, lparam );
Ln121 :}
Ln122: break;
Ln123:
Ln124: Case wm_sendmessage:
Ln125: MessageBox (hwnd, l "sendmessage", l "prompt", mb_ OK );
Ln126: break;
Ln127:
Ln128: Case wm_postmessage:
Ln129: MessageBox (hwnd, l "postmessage", l "prompt", mb_ OK );
Ln130: break;
Ln131:
Ln132: Case wm_destroy:
Lnqueue: postquitmessage (0 );
Ln134:
Ln135: default:
Ln136: Return defwindowproc (hwnd, message, wparam, lparam );
Lnbench :}
Ln138: Return 0;
Ln139 :}
Next, we will analyze the internal situation of the two functions step by step and discuss sendmessage first.
The first step is to debug F5 at the next breakpoint of the dispatchmessage (ln003) function. After the program runs to the breakpoint, check the callstack window and obtain the following results:
#003: myproj.exe! Wwinmain (hinstance _ * hinstance = 0x00400000, hinstance _ * hprevinstance = 0x00000000, wchar_t * lpcmdline = 0x000208e0, int ncmdshow = 0x00000001) line 49 C ++
#002: myproj.exe! _ Tmaincrtstartup () line 589 + 0x35 bytes C
#001: myproj.exe! Wwinmaincrtstartup () line 414 C
#000: kernel32.dll! _ Baseprocessstart @ 4 () + 0x23 bytes
We can see that the process first calls the baseprocessstart function in kernel32.dll, then calls the startup code function wwinmaincrtstartup, then calls the _ tmaincrtstartup function, and finally calls our wwinmain function, our program is running.
Step 2: remove the breakpoint in step 1. at the entrance of the wndproc (ln101) function, run F5 to the next breakpoint and view the callstack window. The following results are available:
#008: myproj.exe! Wndproc (hwnd _ * hwnd = 0x00050860, unsigned int message = 0x00000101, unsigned int wparam = 0x00000074, long lparam = 0xc03f0001) line 122 C ++
#007: user32.dll! _ Internalcallwinproc @ 20 () + 0x28 bytes
#006: user32.dll! _ Usercallwinproccheckwow @ 32 () + 0xb7 bytes
#005: user32.dll! _ Dispatchmessageworker @ 8 () + 0xdc bytes
#004: user32.dll! _ Dispatchmessagew @ 4 () + 0xf bytes
#003: myproj.exe! Wwinmain (hinstance _ * hinstance = 0x00400000, hinstance _ * hprevinstance = 0x00000000, wchar_t * lpcmdline = 0x000208e0, #000: int ncmdshow = 0x00000001) line 49 + 0xc bytes C ++
#002: myproj.exe! _ Tmaincrtstartup () line 589 + 0x35 bytes C
#001: myproj.exe! Wwinmaincrtstartup () line 414 C
#000: kernel32.dll! _ Baseprocessstart @ 4 () + 0x23 bytes
#000 ~ #003 is the same as step 1 and will not be explained. At #004 and #005, we can see that the function runs inside the dispatchmessage. dispatchmessagew and dispatchmessageworker are functions everywhere in user32.dll, and the front strings of the functions are equal, this conjecture should be the internal processing of dispatchmessage. #008 is our message processing function, so we can imagine that #006 and #007 are the code prepared to call our message processing function.
Step 3: remove the breakpoint in step 2. Place the breakpoint at ln003, ln114, ln115, and ln125 respectively. Select the corresponding item from the menu so that the program runs until ln114 and F10, we can see that it has not run to break (ln115) and directly jumped to ln125. We can see that sendmessage is currently waiting. Check the callstack window and the following results are available:
#013: myproj.exe! Wndproc (hwnd _ * hwnd = 0x00050860, unsigned int message = 0x00000500, unsigned int wparam = 0x00000000, long lparam = 0x00000000) line 147 C ++
#012: user32.dll! _ Internalcallwinproc @ 20 () + 0x28 bytes
#011: user32.dll! _ Usercallwinproccheckwow @ 32 () + 0xb7 bytes
#010: user32.dll! _ Sendmessageworker @ 20 () + 0xc8 bytes
#009: user32.dll! _ Sendmessagew @ 16 () + 0x49 bytes
#008: myproj.exe! Wndproc (hwnd _ * hwnd = 0x00050860, unsigned int message = 0x00000111, unsigned int wparam = 0x00008003, long lparam = 0x00000000) line 136 + 0x15 bytes C ++
#007: user32.dll! _ Internalcallwinproc @ 20 () + 0x28 bytes
#006: user32.dll! _ Usercallwinproccheckwow @ 32 () + 0xb7 bytes
#005: user32.dll! _ Dispatchmessageworker @ 8 () + 0xdc bytes
#004: user32.dll! _ Dispatchmessagew @ 4 () + 0xf bytes
#003: myproj.exe! Wwinmain (hinstance _ * hinstance = 0x00400000, hinstance _ * hprevinstance = 0x00000000, wchar_t * lpcmdline = 0x000208e0, #000: int ncmdshow = 0x00000001) line 49 + 0xc bytes C ++
#002: myproj.exe! _ Tmaincrtstartup () line 589 + 0x35 bytes C
#001: myproj.exe! Wwinmaincrtstartup () line 414 C
#000: kernel32.dll! _ Baseprocessstart @ 4 () + 0x23 bytes
#000 ~ #008 is the same as above and will not be explained. At #009 and #010, we can see that the function is called inside sendmessage. Here we guess it should be the internal processing of sendmessage. #011 and #012 are the same as #006 and #007 in step 2. In the second part, these two functions are the code prepared to call the message processing function, #013 is also our message processing function, so the functions of the two lines of code are equal.
So far, we have proved that sendmessage does call the message processing function directly. Before the message processing function returns, sendmessage waits. In all operations, the ln003 breakpoint is not delivered, proving that sendmessage will not put the message into the Message Queue (in the postmessage analysis, this breakpoint will run and will be described later ).
Step 4: Run F5 again. In the displayed dialog box, click OK in the dialog box and run at the breakpoint ln115. View the callstack window. The following results are available:
#008: myproj.exe! Wndproc (hwnd _ * hwnd = 0x00050860, unsigned int message = 0x00000111, unsigned int wparam = 0x00008003, long lparam = 0x00000000) line 137 C ++
#007: user32.dll! _ Internalcallwinproc @ 20 () + 0x28 bytes
#006: user32.dll! _ Usercallwinproccheckwow @ 32 () + 0xb7 bytes
#005: user32.dll! _ Dispatchmessageworker @ 8 () + 0xdc bytes
#004: user32.dll! _ Dispatchmessagew @ 4 () + 0xf bytes
#003: myproj.exe! Wwinmain (hinstance _ * hinstance = 0x00400000, hinstance _ * hprevinstance = 0x00000000, wchar_t * lpcmdline = 0x000208e0, int ncmdshow = 0x00000001) line 49 + 0xc bytes C ++
#002: myproj.exe! _ Tmaincrtstartup () line 589 + 0x35 bytes C
#001: myproj.exe! Wwinmaincrtstartup () line 414 C
#000: kernel32.dll! _ Baseprocessstart @ 4 () + 0x23 bytes
#000 ~ 008 is exactly the same as step 2. At this time, sendmessage is returned and the called Stack is cleared.
So far, we have completely opened the challenge cloud of sendmessage and understood the running mechanism of the sendmessage function. In summary, sendmessage internally calls the sendmessagew and sendmessageworker functions for internal processing, then, call usercallwinproccheckwow and internalcallwinproc to call the message processing function in our code. After the message processing function is complete, the sendmessage function returns.
After sendmessage is discussed, we will discuss postmessage, delete all the above breakpoints, and disable debugging.
Step 1: Debug F5 at the next breakpoint of the dispatchmessage (ln003) function. The result here is the same as that of sendmessage.
Step 2: remove the breakpoint in step 1 and start the next breakpoint at the entrance of the wndproc (ln101) function. F5 continues to run. The result here is the same as sendmessage.
Step 3: remove the breakpoint in step 2. Place the breakpoint at ln003, ln117, ln118, and ln129 respectively. Select the corresponding item from the menu so that the program runs to ln117 and F10, we can see that it has been run to break, and the postmessage function returns. At this time, the callstack does not change.
Step 4: F5 continues to run. At this time, the program runs to ln003, And the callstack is the same as the first step.
Step 5: F5 continues to run (due to multiple messages, you may have to press it multiple times) and run the program to ln129. At this time, the callstack is the same as step 2. For convenience, the following is a list again:
#008: myproj.exe! Wndproc (hwnd _ * hwnd = 0x00070874, unsigned int message = 0x00000501, unsigned int wparam = 0x00000000, long lparam = 0x00000000) line 151 C ++
#007: user32.dll! _ Internalcallwinproc @ 20 () + 0x28 bytes
#006: user32.dll! _ Usercallwinproccheckwow @ 32 () + 0xb7 bytes
#005: user32.dll! _ Dispatchmessageworker @ 8 () + 0xdc bytes
#004: user32.dll! _ Dispatchmessagew @ 4 () + 0xf bytes
#003: myproj.exe! Wwinmain (hinstance _ * hinstance = 0x00400000, hinstance _ * hprevinstance = 0x00000000, wchar_t * lpcmdline = 0x000208e0, int ncmdshow = 0x00000001) line 49 + 0xc bytes C ++
#002: myproj.exe! _ Tmaincrtstartup () line 589 + 0x35 bytes C
#001: myproj.exe! Wwinmaincrtstartup () line 414 C
#000: kernel32.dll! _ Baseprocessstart @ 4 () + 0x23 bytes
We can see that this call is called from the message loop. dispatchmessagew and dispatchmessageworker are the internal processing of dispatchmessage, and usercallwinproccheckwow and internalcallwinproc are the code prepared to call our message processing function.
So far, we have completely switched off the problem cloud of postmessage and understood the running mechanism of the postmessage function. In summary, postmessage puts the message into the message queue and returns it immediately, the getmessage in the message loop (peekmessage is also available, as shown in this example) is processed after the message is sent, it is processed according to the common message processing method.