tags:

views:

72

answers:

3

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.

+1  A: 

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).

selbie
OK, so doing a SendMessage from a different thread (actually even a different process in my case) is like using a "blocking PostMessage"?My problem is that I have to create a secondary message loop using MsgWaitForMultipleObjectsEx and PeekMessage (on Windows CE).
Lorenzo
Not sure what you are really trying to do, but if its for inter-process communications, then you should likely use COM.
selbie
I have to workaround some limitations of the system I'm working on, I have to emulate a synchronous scenario by blocking waiting for a message (which is of course asynchronous). In the meantime, I have to be responsive to messages sent by the shell. For some reason in some circumstances our custom shell hangs until I received that message, and I can't figure why... However, your answer on SendMessage is satisfactory for the doubt I had.
Lorenzo
A: 

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.

Oleg
Thank you for the answer, but the question was actually about was happens internally when SendMessage is called on a different thread, more precisely how the target window procedure is called.
Lorenzo
+1  A: 

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 SendMessageCallbacks instead of plain SendMessage between different threads

For further reference, study the Remarks section of the MSDN PeekMessage entry.

Viktor Svub
Thank you, this definitely answers my doubt. Unfortunately on the Get/PeekMessage documentation of Windows CE 6 that part was missing from the "Remarks" section (I wonder if WinCE GWES has a subtle different behavior than Win32 USER).
Lorenzo