27.1 Message Queuing for Threads
(1) Windows user Object
① types: Icons, cursors, window classes, menus, accelerator tables, etc.
② when a thread creates an object, the object is owned by the process of that thread, and when the process ends, the operating system automatically deletes the object if the user does not explicitly delete the object.
the ③ window and hook are two user objects that are owned by the thread that created the window and installed the Hooks (note, not the process). If a thread builds a window or installs a hook. Then the thread ends and the operating system automatically deletes the window or uninstalls the hook.
The ④ of windows and threads makes it necessary for the window's thread to process all messages for its window. This means that if a thread establishes a window (or calls a function related to a graphical user interface), it is assigned a message queue that is used to dispatch (dispatch) messages to the window.
(2) Threadinfo internal data structure (note that it is associated with a thread)
27.2 post messages to the thread's message queue
27.2.1 BOOL PostMessage (Hwnd,umsg,wparam,lparam);
(1) When the function is called, the system first determines which thread establishes the HWND window, allocates a piece of memory, stores the message parameters in the memory, and then adds the memory to the Posted-message queue of the corresponding thread.
(2) After adding to the queue, PostMessage also sets the qs_postmessage wake-up bit of the wake flags variable.
(3) The function returns immediately after the message is delivered.
27.2.2 BOOL postthreadmessage (Dwthreadid,umsg,wparam,lparam)
(1) dwThreadID is the target thread ID, and when the message is posted, the HWND in the MSG struct is automatically set to null.
(2) in the main message loop of the target thread, when getmessage (or peekmessage) gets a message, first checks if the HWND is NULL, and if it is a one-line special processing of the message without sending it to a window procedure, So we don't call DispatchMessage to dispatch the message.
(3) Like PostMessage, PostThreadMessage also returns immediately. The calling thread cannot know whether the message is being processed.
(4) The return value of the thread Id:dword GetWindowThreadProcessId (HWND,PDWPROCESSID) that gets the creation window is the thread ID.
27.2.3 void postquitmessage (int nexitcode)
(1) Terminates the message loop. Similar (but not identical) to PostThreadMessage (GetCurrentThreadID (), wm_quit,nexitcode,0). PostQuitMessage does not actually deliver the message to the queue (that is, the wm_quit message is not sent, for the 27.4.3 algorithm for extracting messages from the thread's queue), but only the QS_QUIT flag bit and the Nexitcode exit code are set.
(2) because the function simply sets the QS_QUIT flag bit and Nexitcode, the call will always succeed, so the return value is void.
27.3 send a message to a window
27.3.1 LRESULT SendMessage (hwnd,umsg,wparam,lparam) ;
(1) SendMessage will not return until the message is processed.
(2) If the thread that calls SendMessage sends a message to a window established by the thread, the SendMessage process is simple, just invoking the specified window procedure as a child function. When the window procedure finishes processing the message, its return value is returned directly to the Sendmessage,sendmessage and returned to the calling thread.
(3) If you call SendMessage to another thread that contains a thread in another process, the process is more complex because Windows requires that the window procedure be called by the thread that created the window (not another thread), which works as follows:
① when SendMessage is called, the function adds the message to the "Send-message" queue of the receiving thread , which causes the QS_SENDMESSAGE flag bit to be turned on for the receiving thread .
② if the receive thread is executing "other code" , then This message will not be processed immediately . When the receiving thread begins to wait for the message, the system first checks whether the QS_SENDMESSAGE flag bit is set . If set, the system will find the first message from the "Send-message" queue (there may be many messages in the queue because there may be multiple threads calling SendMessage to add messages to this queue at the same time). (Note that the "other code" mentioned earlier does not contain functions such as calling GetMessage, Peekmeesage, or waitmessage, because these functions let the receiving thread take out the messages in the Send-message queue and begin processing)
③ when a receive thread takes a message from the "Send-message" queue and invokes the corresponding window procedure, after processing a message, GetMessage does not return , but then goes back to processing the message for that queue until there is no other message in the "Send-queue" queue , the system will turn off the qs_sendmessage flag bit . during a receive thread processing a message, the thread calling SendMessage (also known as the "calling thread" or "Send Thread") is set to "idle" to wait for the receiving thread to send a reply message to its own "reply-message" queue . When the receiving thread finishes processing the message, the return value of the window procedure is posted to the "Reply-message" queue of the sending thread (note that the return value is returned to the sending thread as the SendMessage return value) and the sending thread is woken up . The sending thread then continues to execute normally.
④ when the sending thread waits for SendMessage to return, he is usually set to "idle", but he is also allowed to perform a task: If another thread (B) sends a message to the thread that currently calls SendMessage (a), a thread must immediately process the message. Instead of calling functions such as GetMessage, PeekMessage, or waitmessage. Why deal with it now? For example a thread sendmessage to B, then a hangs wait B thread processing finished, during this period B also sendmessage gave a, if a is not immediately wake up to deal with B sent over the message, two processes will enter each other waiting for the deadlock state)
(4) Windows uses this method to handle SendMessage between threads, which causes the sending thread to hang, and if a bug in the receiving thread causes a dead loop, the sending thread cannot be awakened. This means that a bug in a process can affect another process. (You can call the following four functions to solve this problem)
27.3.2 SendMessageTimeout function
Parameters |
Meaning |
HWND hwnd |
The first four parameters are the same as the SendMessage meaning |
UINT umsg |
WPARAM WPARAM |
LPARAM LPARAM |
UINT Fuflags |
Flag: Can be a combination of the following ①smto_normal (0): Do not use any other flags, or remove the following flags or combinations thereof. ②smto_abortifhung: Returns immediately if the receive thread is suspended ③smto_block: One thread can be interrupted while waiting for sendmessage* to return, in order to process another sent message. Using the SMTO_BLOCK flag prevents the system from allowing such interrupts, but may cause deadlocks (see the analysis of the SendMessage section for reasons). ④smto_notimeoutifnothung: The time limit value is not considered if the receiving thread is not suspended. |
UINT Utimeout |
The maximum time to wait for another thread to answer the message we sent, in units of MS |
Pdword Pdwresult |
The result of processing the message. |
return value |
Success or failure, available GetLastError for more information |
Note: If you call SendMessageTimeout to send a message to a window established by the calling thread, the system simply invokes the window and assigns the return value to Pdwresult. Because all processing must occur in a thread, the code that appears after the function is called must wait until the message is processed before it is executed. |
27.3.3 Sendmessagecallback (Hwnd,umsg,wparam,lparam,pfnresultcallback,dwdata);
(1) When Sendmessagecallback is called, a message is added to the "Send-message" queue of the receiving thread , and the calling thread returns immediately. When the receiving thread finishes processing the message, a reply message is sent to the "Reply-message" queue of the sending thread . Then the system notifies the sending thread when it is appropriate to execute the callback function specified by Pfnresultcallback .
(2) prototype of the callback function: VOID CALLBACK resultcallback (Hwnd,umsg,dwdata,dwresult); When Sendmessagecallback is called, it passes its own dwdata parameter directly to the callback function, dwresult the result of the window procedure that processes the message.
(3) When a message is sent between threads,Sendmessagecallback returns immediately, but the callback function does not execute immediately . Even after the receiving thread finishes processing the message, the callback function does not necessarily execute immediately, because the receiving thread simply sends a reply to the sending thread informing him that he has finished processing the message. As to when the sending thread calls this callback function, it is up to the sending thread to make the call, usually when the sending thread calls GetMessage, PeekMessage, WaitMessage, and the callback function is executed when the message is fetched from the "Reply-message" queue.
(4) There is another way to use sendmessagecallback. Windows provides a way to broadcast messages that can be broadcast using all overlapping (Overlapped) windows in the system. Although it is possible to pass SendMessage, and Hwnd_broadcast (-1) to the HWND, the return value of this method is only a lresult value, and cannot be viewed after the window procedure of each overlapping window is processed by the returned result. However, if you call Sendmessagecallback, the callback function will be called once for each window procedure, so you can view the returned results by Dwresult.
(5) If Sendmessagecallback sends a message to a window created by the calling thread, the system calls the window procedure immediately, and the callback function is called after the message is processed. When the callback function returns, the system starts execution from the code after the call to Sendmessagecallback.
27.7.4 BOOL sendnotifymessage (Hwnd,umsg,wparam,lparam);
(1) SendNotifyMessage adds a message to the "Send-message" queue of the receiving thread and returns immediately, which is a bit like PostMessage, But he has two different points from PostMessage :
① If a message is sent to another thread's window, sendnotifymessage is adding a message to the receive thread's "Send-message" , and PostMessage is the "posted-message" to the receiving thread Queue to add messages . In the system's message mechanism, messages in the "Send-message" queue are always prioritized over messages in the "Posted-message" queue .
② second, when sending a message to a window created by the calling thread itself, SendNotifyMessage's work is like SendMessage, calling the window procedure directly while waiting for the window process to finish processing before returning.
(2) Many messages are only for notification purposes, to inform the application that a state has changed, so the sending thread does not have to wait for the receiving thread to finish processing before returning. (such as the system to the window to send Wm_size, wm_move, etc., the operating system does not need to stop waiting for users to process these messages before continuing.) But some messages, the system must wait, such as the operating system to send wm_create to a window, must wait, if the window procedure returns-1, then the system does not establish this window.
27.3.5 BOOL replymessage (LRESULT LRESULT)
(1) The receiving thread can add a reply message to the "Reply-message" of the thread that sent the message through SendMessage in the event that the window process has not finished processing the message, which wakes up the sending thread .
(2) The receiving thread passes the LRESULT as the message processing result to the sending thread. when Replymessage is called , the sending thread is awakened early. When the receiving thread actually returns from the window procedure, the system ignores the return value, which is no longer replying to the sending thread for the reply message that should have been sent at the normal end of the window procedure .
(3)replymessage must be called during the window that receives the message , and cannot be called by a thread that calls send* because he is the thread that is used to reply to the call to SendMessage. The 3 sendmessage* functions discussed earlier will return immediately . The return of the SendMessage function can be controlled by the implementation of the window procedure by invoking the Replymessage .
(4) Replymessage does not work if a message is not sent through SendMessage or if the message is sent by the same thread. This is also the return value that is indicated if Replymessage is called when a message is sent between processing threads to return true. Calling Replymessage when a message is sent within a processing thread returns FALSE.
(5) You can call Insendmessage (Ex) to determine whether a message is sent between threads or within a thread. If the thread sent between threads returns True, the line range send or post will return false.
"Sending a message example"
//wm_user+5 is a message sent by other thread Cheng. If the message is sent by another process, the process must first call the RegisterWindowMessage registered as a global message type . CaseWm_user +5:. ....//deal with something else . if(Insendmessage ())//is the message sent between threads, only the ability to reply between threadsreplymessage (TRUE);//the message has been processed almost, SendMessage thread can be awakened, because I have to do something else, such as //Pop-up dialog box (dialogbox), you don't have to wait for the silly. Note: Where to call Replymessage can be in that what //notifies the system to wake up the SendMessage threadDialogBox (HInst,"myDialogBox", Hwndmain, (Dlgproc) mydlgproc); Break;
27th. Windows and messages (1)