11

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.

Community
  • 1
  • 1
lornova
  • 6,667
  • 9
  • 47
  • 74

3 Answers3

8

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.

nalzok
  • 14,965
  • 21
  • 72
  • 139
Viktor Svub
  • 1,451
  • 10
  • 15
  • 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). – lornova Jun 01 '10 at 12:00
  • 7
    GetMessage documentation says that it "dispatches incoming sent messages until a posted message is available for retrieval." That is why SendMessage says "messages sent between threads are processed only when the receiving thread executes message retrieval code". Sending a message to a different thread therefore requires the target thread to have a message loop. Sending a message on the same thread results in a direct window procedure call on the same thread. Sending a message to another thread results in a direct window procedure call on the target thread *from within a GetMessage call*. – Triynko Apr 24 '13 at 18:25
  • Now as far as the priority of sent vs posted messages go, it is very clear. If the target message loop is waiting on messages to be posted (i.e. it is blocking within a GetMessage call), then a sent message will be processed first if it arrives before a posted message. If the target message loop is actually processing a message (i.e. calling Translate or DispatchMessage), then a sent message will be processed before a posted message, even if it arrives later, as long as it arrives by the time the target message loop finishes processing whatever message it's in the middle of processing. – Triynko Apr 24 '13 at 18:28
1

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
  • 100,020
  • 15
  • 103
  • 173
  • 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). – lornova May 31 '10 at 10:35
  • Not sure what you are really trying to do, but if its for inter-process communications, then you should likely use COM. – selbie May 31 '10 at 10:43
  • 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. – lornova May 31 '10 at 11:26
  • It sounds like SendMessage always bypasses the message loop if sent from the window's owner thread, in which case the window procedure is called directly as a subroutine. – Triynko Apr 24 '13 at 18:11
  • On the other hand, if the calling thread does not own the window, then "the system switches to that thread and calls the appropriate window procedure". It's not clear whether the procedure is called directly or posted to the queue. It's also not clear whether (and if), once posted to the queue, it is fully processed by GetMessage (i.e. processed with priority), or its actually returned by GetMessage like normal messages. It just says "Messages sent between threads are processed only when the receiving thread executes message retrieval code." – Triynko Apr 24 '13 at 18:13
  • 1
    I suspect, as another answer claims, such messages are processed fully by GetMessage with priority, so they are never actually returned by GetMessage and never passed to DispatchMessage. That would explain why GetMessage must be called (i.e. the thread must have a message loop), in order for a cross-thread SendMessage to succeed. Specifically, GetMessage documentation says it "dispatches incoming sent messages until a posted message is available for retrieval." That pretty much settles it. – Triynko Apr 24 '13 at 18:18
  • 1
    @Triynko - Yes, on the same thread SendMessage is an immediate invocation of the WndProc function. Across a different threads, SendMessage blocks until the thread of the HWND gets around to calling GetMessage/DispatchMessage. Interesting point about GetMessage auto-invoking. It usually doesn't matter since DispatchMessage is nearly always called after GetMessage. I'll have to write some test code later to see if that's true. – selbie Apr 24 '13 at 18:38
1

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
  • 220,925
  • 34
  • 403
  • 798
  • 1
    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. – lornova May 31 '10 at 11:28