When we send a message, "if the specified window was created by the calling thread, the window procedure is called immediately as a subroutine".
But "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." (taken from MSDN documentation for SendMessage).
Now, I don't understand how (or, more appropriately, when) the target windows procedure is called. Of course the target thread will not be preempted (the program counter is not changed). I presume that the call will happen during some wait function (like GetMessage or PeekMessage), it is true? That process is documented in detail somewhere?
Update: the rationale behind it is explained by the QS_SENDMESSAGE flag of GetQueueStatus() and MsgWaitForMultipleObjects():
QS_SENDMESSAGE
A message sent by another thread or application is in the queue.
This, along with additional remarks in MSDN documentation, means that a message sent by another thread is actually posted to the queue. Then, as soon as GetMessage or PeekMessage are called, it will be processed before any other posted message by being sent directly to the window procedure.
I see some confusion here.
According to the MSDN docs, when you touch the message queue of the current thread with the intent of message processing (e.g. if you call PeekMessage or GetMessage), all pending sent (i.e. non-queued) messages from other threads are handled - passed to the WndProc - and then the message queue is checked, so:
sent messages never go through DispatchMessage and are handled as soon as possible:
in the current thread, they are simply passed to WndProc
in another thread, they are handled before any posted message processing
to be able to handle sent messages, the target thread still needs a message pump
PostThreadMessage does just what it states - posts a message in a threads queue - such messages are not directed to any window and must be handled explixitly
the only messages handled by DispatchMessage are those created by PostMessage or some system facility (timers, events, user input, etc.)
to avoid deadlocks, use SendNotifyMessage, SendMessageTimeout or SendMessageCallback instead of plain SendMessage between different threads
For further reference, study the Remarks section of the MSDN PeekMessage entry.
Short answer: When the target thread calls GetMessage (or PeekMessage) followed by DispatchMessage, then the SendMessage from the other thread is received and handled.
I am not certain if the received SendMessage preempts other messages in the queue or not. Either way, a SendMessage from one thread to another is like saying: "Post this message to the other thread's message queue. Return when that thread has finished processing it".
An now for an answer you didn't ask for:
In general, when I program interactions between the main UI thread and a worker thread, I try to avoid using SendMessage. If you aren't careful, you can get into a situation where both threads are deadlocked on each other. (Think of the case where the main thread is calling WaitForSingleObject to wait for the worker thread to complete, but the worker thread is blocked on SendMessage back to the UI thread).
Every windows is associated with a thread. You can use GetWindowThreadProcessId to retrieves the thread of every window. If you send a message to a windows from the other thread with respect of PostThreadMessage the message will be placed in the thread's message queue. The thread must have a get-message loop (with GetMessage for example) to get the messages and dispatch there to the window procedure of the window.
It you call SendMessage instead of PostThreadMessage you call the Windows Procedure directly without placing it in the message queue. Some nonqueued messages are sent also immediately to the destination window procedure, bypassing the system message queue and thread message queue. (see http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages). The main reason to use SendMessage instead of PostThreadMessage if you want to give some information from another windows (control) like read a text from an another control during processing of another message. You should do this only if it really needed. So if you use SendMessage to send a message to a windows from another thread your current thread must be blocked for some time.
It can be a good idea to use PostThreadMessage or SendMessageCallback instead of SendMessage if it is possible.
Related
I'd like to confirm what I think to be true. When I use Windows SendMessage(), this is a deterministic call in that it will execute immediately (will not return until the message is processed) as opposed to PostMessage() which is non-deterministic as it can be preempted by any other message that happens to be in the queue at that moment in time (in fact it will not be executed until it hits the message loop).
Is this a fair assessment, or am I missing something?
That is essentially true for in-process calls. Cross-process SendMessage works similar, but processing of the message doesn't begin until the receiver process calls GetMessage (or its kin).
Your UI thread has a message pump that looks something like:
while (GetMessage(&msg))
DispatchMessage(&msg);
PostMessage causes the message to be put onto the message queue. GetMessage removes the oldest message from the queue (FIFO*).
DispatchMessage causes the WndProc associated with the message's target window to be called with the message.
SendMessage basically bypasses this chain and calls the WndProc directly (more or less).
A lot of standard window messages result in a chain of SendMessage calls where sending one message sends another which sends another. That chain is often referred to as "the current dispatch". If you need your message to be processed inside the chain, use SendMessage. If you need it to be processed after the current dispatch has completed, use PostMessage.
You can use a tool like Spy++ to see Windows messaging in action, or to debug problems you're having with message order of operations.
[*] It's not strictly a FIFO queue because certain kinds of messages (i.e. timer, mouse, keyboard) are not actually posted to the queue, but rather generated on the fly. For the sake of simplicity, you can think of it as a FIFO.
While handling WM_TIMER, I called MessageBox. As a result, a message box popped up with the frequency of the timer. So I believe that the application was trying to continue to process queued/non-queued messages even during MessageBox.
Am I right?
I know that according to MSDN, while an application is sending a message to a different thread from the sending thread, the sending thread will try to process non-queued messages it receives before SendMessage returns --- i.e. before the target thread replies.
Are there any other functions that could try to continue to process queued/non-queued messages before they return, besides MessageBox and SendMessage? I need to know about that to determine whether any functions called in the Window procedure should be reentrant.
Another two relevant questions are
1) Does DispatchMessage not return until the window procedure has returned?
2) Will GetMessage not be called again if the current DispatchMessage hasn't returned yet?
A modal dialog runs its own message loop internally, using the calling thread's message queue. You are calling MessageBox() inside your WM_TIMER handler, so the message loop inside of MessageBox() is receiving and dispatching subsequent WM_TIMER messages while the message box is running.
I don't quite understand how GetWindowText can work for a window on the same thread as the caller. If GetWindowText blocks until the message is processed, how can the thread call DispatchMessage? It's been blocked inside GetWindowText. Does this mean that GetWindowText must always be called from a separate thread from the one operating the message loop?
GetWindowText is just a thin wrapper for SendMessage(WM_GETTEXT).
Messages sent to a window are always processed in the thread which created the window (windows have "thread affinity"). Sent messages do not go through DispatchMessage, rather GetMessage (or PeekMessage or MsgWaitForMultipleObjects) will call the window procedure directly, for messages sent from another thread. If the message is sent from the same thread, SendMessage will call the window procedure.
The SendMessage documentation says:
The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
And the GetMessage documentation says:
Retrieves a message from the calling thread's message queue. The function dispatches incoming sent messages until a posted message is available for retrieval.
From the PeekMessage docs:
Dispatches incoming sent messages, checks the thread message queue for a posted message, and retrieves the message (if any exist).
The behavior of sending messages has previously been highlighted on Raymond Chen's excellent blog, The Old New Thing, which all Win32 developers ought to subscribe to:
If you use any of the above send-type functions to send a message to a window that belongs to the sending thread, the call is made synchronously.
http://blogs.msdn.com/b/oldnewthing/archive/2004/11/19/266664.aspx
Recall that SendMessage delivers the message directly to the window procedure; the message pump never sees it.
http://blogs.msdn.com/b/oldnewthing/archive/2008/12/23/9248851.aspx
And of course, there are related questions found here on StackOverflow:
SendMessage vs PostMessage + WaitForSingleObject
The general question, is if I post several messages to the windows message pump from a separate worker thread, will they appear at their destination in the order I sent? ie..
::PostMessage(m_hUsers, WM_BULKPROCESS, 0, 0);
// ... some processing here ...
::PostMessage(m_hUsers, WM_BULKDONE, 0, 0);
m_hUsers is a handle (HWND) to a window I'm sending the messages to from my worker thread. So, will WM_BULKPROCESS always show up first in the window (and therefore be processed by the handler in that dialog class), or is it possible for them to get out of order, ie WM_BULKDONE gets processed before WM_BULKPROCESS, even though it was sent last?
There are a few exceptions (like WM_PAINT), but generally, the order of messages is kept.
Imaging trying to make sense of mouse input if messages appeared in the wrong order!
Quote from GetMessage
During this call, the system delivers pending, nonqueued messages,
that is, messages sent to windows owned by the calling thread using
the SendMessage, SendMessageCallback, SendMessageTimeout, or
SendNotifyMessage function. Then the first queued message that matches
the specified filter is retrieved. The system may also process
internal events. If no filter is specified, messages are processed in
the following order:
Sent messages
Posted messages
Input (hardware) messages and system internal events
Sent messages (again)
WM_PAINT messages
WM_TIMER messages
Window messages are stored in a queue. So you can rely on FIFO mechanism.
They should be unless you have code in the message pump that specifically dispatch the messages (either intentionally or not) differently e.g. somehow pick two messages and dispatch them out of order. Normally programmers call DispatchMessage for each message in the order you get from the queue.
I suspect the issue is synchronization and not the message queue. If your code allows multitple invocations of the worker thread proc you have to manage this more tightly to know which "instance" of the worker thread is posting the messages.
Have you checked to make sure you only one worker thread executing at a time, or that the m_hUsers window handle is protected from being changed between BULKPROCESS and BULKDONE?
SendMessage can be useful for managing the BULKDONE because it will block until the message has been processed allowing the code invoking the worker thread to synchronize the invokation of worker threads and truely know that one worker thread has finsished before invoking another. Postmessage will not block but remember the time sensitive part of your worker thread is
`// ... some processing here ...
not sending the windows messages.
How precisely does windows decide that SendMessage should return- that is, how does it decide the receiving thread has finished processing the sent message?
Detailed scenario:
I've got thread A using SendMessage to send a thread to thread B. Obviously SendMessage doesn't return until thread B finishes processing the message. Thread B pops up a dialog box and starts pumping messages. In my scenario, there is a WM_KILLFOCUS message on the queue which gets pumped by thread B. This results is a WM_COMMAND message on thread B. Thread B passes this WM_COMMAND message to the default window proc. When it does this, SendMessage returns back to thread A, even though the original message hasn't finished processing yet! What is going on? It looks like somehow the default window proc is confusing windows into thinking the original sent message is finished.
So are there known scenarios where pumping messages and calling the default window proc can trick SendMessage into returning?
Thanks!
Phil
As long as processing of the message has started, the WindowProc processing the interthread message can call ReplyMessage to allow the calling thread to continue while processing continues.
Since SendMessage has a return value, it is always after the message is processed.
PostMessage on the other hand will not wait for the message to be processed.
From MSDN on SendMessage:
The SendMessage function calls the
window procedure for the specified
window and does not return until the
window procedure has processed the
message.
There is no case where it will return before the message is processed.
From the MSDN, it sounds like that the problem may be that displaying a dialog box in thread B may cause deadlocks. See Message Deadlocks.
Possibly it is because the message received by thread A was a nonqueued message. From MSDN:
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.
It sounds as if your original SendMessage has NOT returned but rather than the WindowProc in thread A has been called during the processing of the message sent. There is no requirement that a message handler must refrain from calling SendMessage in response to receipt of a message.
You should be able to see the original call to SendMessage in your callstack at the point where you receive the WM_COMMAND that you sent in response to the focus change message.