Date: | November 19, 2004 / year-entry #399 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20041119-00/?p=37243 |
Comments: | 51 |
Summary: | There are several variations on the SendMessage function, but some are special cases of others. The simplest version is SendMessage itself, which sends a message and waits indefinitely for the response. The next level up is SendMessageTimeout which sends a message and waits for the response or until a certain amount of time has elapsed.... |
There are several variations on the SendMessage function, but some are special cases of others. The simplest version is SendMessage itself, which sends a message and waits indefinitely for the response. The next level up is SendMessageTimeout which sends a message and waits for the response or until a certain amount of time has elapsed. SendMessage is just SendMessageTimeout with an INFINITE timeout. Another version of SendMessage is SendNotifyMessage, which is like SendMessage except that it doesn't wait for the response. It returns immediately and ignores the result produced by the receiving window. The last SendMessage-style functions is SendMessageCallback. This sends a message and then returns immediately. When the recipient finally returns a response, the callback is called. SendNotifyMessage is SendMessageCallback with a callback that does nothing. That's how the four message-sending functions fit together. Bonus remark: 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. |
Comments (51)
Comments are closed. |
What is the difference between SendNotifyMessage() and PostMessage()?
SendNotifyMessage will call the wndproc if the HWND is in the same thread otherwise it behaves just like PostMessage.
Ok then, call me stupid but I’ve always thought that posting a message merely constituted an asynchronous send. Apparently I must be missing something.
asdf: No, SendNotifyMessage does not behave just like PostMessage. Sent messages are not queued. Obviously, I need to dedicate a future entry to explaining the difference between posting and sending messages since people appear not to grasp it.
Thanks for the discussion on SendMessage. And, I would also learn something from a discussion of the difference between posting and sending messages (as I thought it only had to do with the asynchronous nature of PostMessage)
On the SendMessage issue, any chance you can shed some light on this error: RPC_E_CANTCALLOUT_ININPUTSYNCCALL
http://support.microsoft.com/kb/q131056/
We ran into this problem when doing inter-thread SendMessage calls. Our work-around was to implement our own “SendMessage” by combining a PostMessage with a semaphore. We haven’t had any deadlocks; but I still don’t really understand why we got the error in the first place.
Thanks again for your postings! They are always interesting.
I believe the difference is SendMessage calls the WndProc directly, bypassing the message quere, while PostMessage posts the message on the end of the queue, where it will get processed in turn.
Please put suggestions into the suggestion box instead of hijacking an existing thread. Suggestions posted as normal comments tend to get lost.
I was always uneasy with the usage of the word "Send" in these functions. My first impression was that "send" always implied use of a queue – it took me a long time to understand that this is not the case.
For that matter I was also uneasy with the use of a single WndProc function for handling both synchronous same-thread function calls and asynchronous queued events.
(not coincidentally I’ve spent a lot of time finding bugs in my Win32 code that occur when WndProcs are re-entered by a SendMessage – it takes careful code sometimes to handle re-entrant calls gracefully).
Oh well, water under the bridge.
It’s not clear to me how this works: thread A can SendMessage() to another thread B, but thread B is busy doing other work (or blocked by some kind of synchronization). How does Windows call the window procedure of thread B without disrupting the thread’s flow of execution?
I already discussed this.
http://weblogs.asp.net/oldnewthing/archive/2004/06/08/150929.aspx
Eh? It’s my understanding that if you send a message to a HWND in the same thread, it calls the wndproc before the function returns. If the window is in another thread, it gets posted in the dest thread’s message queue at a higher priority than the posted messages and when the Get/Wait/PeekMessage function of the dest thread receives it, it calls the wndproc, notifies the caller of the LRESULT, and then tries to pull more messages out until it finds a posted message (minus a crap-load of details I left out). The SendMessage/Timeout functions will wait for the reply before returning and SendMessageCallback will make the src thread respond to the reply via the callback in its Get/Wait/PeekMessage code.
It’s not like PostMessage in the sense that GetMessage will return it (not to mention it’s at a higher priority) but it certainly puts it in the thread’s message queue.
Ok, what if my thread is busy doing some work? I think Windows will not call the window procedure until I call some Win32 blocking API. Is that correct?
Or, in another terms: does SendMessage() always bypass the message queue? If the thread does not have a message loop, is the window procedure called anyway?
"Windows will not call the window procedure until I call some Win32 blocking API. Is that correct?"
That is incorrect. Clearly there is much misinformation on this subject that cannot be cleared up in a simple comment. It looks like another multi-part series is in the cards. (I dread the multi-part series… they take months to write…)
Thank you. I’m looking forward to this new series. :-)
This means that even a thread is doing this:
while(1) {
whatever++;
}
Windows can "freeze" this loop, call the window procedure, and later continue the loop like standard C signals?
Assuming I write it at all. I may decide not to because it’s too much work. I don’t get paid to do this you know.
Yes, I know. Just kidding.
I have never recieved a message unless I called a Win32… well User32 function of some type.
If the thread that is needed to process messages is stuck in a while(1); Im pretty sure its not going to get any sent messages. Surely?
Regarding the differences between PostMessage and SendMessage, I find that this article summarizes it pretty well (in an MFC context):
http://www.flounder.com/messaging.htm
Some of the other articles on the site are useful too.
A busy loop like:
while(1) {
whatever++;
}
will never retrieve a message, Sent or Posted. Messages Sent from out of thread or out of process are dispatched by calls to GetMessage or PeekMessage – but they are automatically dispatched to the window procedure. That is, GetMessage() will never return with the MSG structure filled with a ‘sent’ message – instead, the window procedure is called from within the GetMessage() function.
That’s also why you can’t Send a message to a thread that doesn’t have a window, whereas you can Post a message to a thread without a window.
At least that’s my understanding of it :)
Apples and oranges. SendMessage *sends* a message, while PostMessage *posts* it. The purpose of this entry was to discuss the various ways of *sending* a message.
You’re not being paid to do this? Here you are, generating more good will among the serious geeks of the planet than anyone else in Microsoft, and they’re not paying you for it? Insane.
Still, maybe this way you don’t attract the attention of the lawyers… though, gods know, anything that would divert them from their usual job of patenting everything that’s not nailed down would be a good thing…
The places that I’m aware of sent messages (sent from another thread) being handled are in GetMessage, PeekMessage and WaitMessage. MsgWaitForMultipleObjects[Ex] returns if a sent message is queued, but does not process it – you need to PeekMessage. Remember that other APIs may call one of these APIs for you – for example, when making a COM call to another thread from a thread marked COINIT_APARTMENTTHREADED. COM uses Windows messaging to communicate to/from apartment threads for compatibility with 16-bit Windows. This is where Johan’s issue arises: while in the COM message filter, where COM is waiting for an outbound call to return, a sent message has been processed – perhaps a call back from the server to the client. In the window procedure, the thread has tried to make a second outbound call (perhaps to a different thread). This is illegal in COM so it fails the second call with the error above. I had to deal with similar problems with the use of DoEvents in a VB6 COM server – an earlier author had tried to improve concurrency by adding it, but it caused more problems than it solved (mainly due to unexpected re-entrancy!)
The difference between SendNotifyMessage and PostMessage is that sent messages have a higher priority than posted messages. Also, sent messages cannot be filtered since the application first sees them when they arrive at the window procedure. The application can choose whether or not to dispatch a posted message to the window procedure.
I’ll have to admit I don’t understand why the documentation for GetMessage lists sent messages twice, both top priority and after input messages.
A good reference for this stuff is Jeff Richter’s "Programming Applications for Microsoft Windows, Fourth Edition", which should be compulsory reading for any Windows developer, IMO.
After reading my previous post, I’m not sure if I made the point clear.
Consider this example back in the Win 3.x cooperative multitasking days:
Task A has control of the CPU and calls one of the yielding APIs.
Windows notices that Task B has messages pending in the queue and passes control of the CPU to Task B.
Task B now runs (processing a message via a WndProc call), and subsequently sends a message to Task A.
Control of the CPU is immediately given back to Task A to process the message. And note that because the only way Task A could have lost control of the CPU in the first place is by calling a yielding API (which it is now waiting in), the only way execution can resume within Task A is at the point of its last yielding call.
If those semantics still hold in Win32, then you might conclude that the only time a receiving thread can process a message from another thread is when the receiving thread has called one of those yielding APIs – which is my understanding.
I’m not sure if my understanding of this entire messaging thing, but I’m going to throw it in for either 1) people to ignore, 2) people to correct, or 3) people to say it’s right. :-)
I guess the way I always understood it is that each thread has a message queue, and GUI messages (at least) get added to that queue. However, messages don’t get processed until you expliclity remove them from the queue (through either GetMessage or PeekMessage), and dispatch them (which is what DispatchMessage does, right?) GetMessage doesn’t really do anything else (well, maybe it does) then wait for a message (until there is one), without the thread consuming 100% CPU (well, in a cooperative kernel, it would make sense what carlso is saying in his posts above mine.)
If I do SendMessage to another thread (or another process, for that matter), it will block the calling thread until the receving thread removes the message from the queue and processes it, at which point it returns the value back to the calling thread. PostMessage (and maybe SendNotifyMessage too?) posts it, but returns immediatly (which is why you can’t send pointers: since your code has continued, there’s no guarentee that the pointers will be valid when the thread receving the message finally gets it.) Still, I’ve understood it that you should never use SendMessage on another window in another app if you can get away with it: if that app has locked up, so will you (since it will never process or message.) Same idea with ShowWindowAysnc.
Now, like Raymond said in his bonus remark, any calls to SendMessage to windows belonging to the same thread are called directly, as if it was put onto the thread queue, SendMessage would block, waiting for you to respond to a message that you can’t get. :-)
Am I right here? My understanding seems to explain all the behavior I’ve ever run into with Win32, including one very nasty reentrancy problem where I called MessageBox in response to a winsock message, but I’m not sure if it’s 100% correct. Am I even close? (a yes or no is fine)
Raymond: and even if you don’t write the week-long article, you still do a great job here. :-)
SendMessage bypasses the queue. That’s what people are missing.
It doesn’t strictly though, does it? I mean if a thread is busy doing something, and 10 other threads all try to send it a message, those messages all get "queued". It’s just that those messages are automatically dispatched by a call to GetMessage or similar function, rather than being returned by GetMessage to be dispatched later by DispatchMessage.
They don’t go into the message queue; they go into a separate place.
Well, strictly it does bypass "the queue". Each UI thread has a queue of posted messages in which GetMessage and PeekMessage check. That queue is bypassed.
Multiple threads simultaneously calling SendMessage will be executed in a queued fashion, but as a result of Win32’s thread synchronization functions, not the destination threads message queue. Which could result in very un-queue like behaviour :- I dont think that Win32 guarantees that mutexes are signalled on a first come first served type basis.
Seems like you are splitting hairs here. They don’t go into the queue, but they go into a queue? :)
It’s a very important hair to split because many functions operate on "the message queue" – since sent messages do not go into "the message queue", they are unaffected by those functions. There are queued messages (which go into "the message queue") and non-queued messages (which do not go into "the message queue"). From the comments here, it appears that many people fail to understand this distinction.
Well, that’s an implementation detail. They could be stuck into one queue but marked as "sent message" so the messages that operate on posted messages skip over them. Which is how I’ve always conceptualized it seeing as how sent messages have higher priority over the posted ones anyway.
It’s an implementation detail that impacts the documentation. If you think of them as "in the queue but marked as sent" then documentation for functions that operate on message queues (eg PeekMessage) would have to say "except sent messages" everywhere.
OK….I’m now beginning to get it.
Anyways: here’s an interesting article that seems to discuss SendMessage vs. PostMessage:
http://msdn.microsoft.com/msdnmag/issues/1200/c/default.aspx
Maybe if it did then fewer people would fail to understand the distinction :)
The docs already allude to the fact that messages sent between threads get queued:
The GetQueueStatus function indicates the type of messages found in the calling thread’s message queue.
…
QS_SENDMESSAGE
A message sent by another thread or application is in the queue.
Ooh, explain that Raymond :)
(just kidding!)
Let me see if I have this straight:
When you post messages to another thread using PostMessage, they go into "the message queue".
When you send messages to another thread using SendNotifyMessage, they don’t technically go into "the message queue" but rather a "separate place".
When PeekMessage is called on the receiving end, it first checks if there are any messages in the "separate place" and dispatches them all automatically. It then checks "the message queue" and returns the first matching message.
And just because GetQueueStatus() will tell you whether sent messages are pending doesn’t mean those messages actually reside in "the message queue". QS_SENDMESSAGE is just a quirk they added because they didn’t want to add a separate function for it (?).
Yes that’s it.
About this "separate place"… does it guarantee that the order in which a window receives SendMessage calls is the same order they were sent?
You already know the answer based on information posted in this thread.
My understanding of it:
When SendMessage() is used to send a message to a window in *this* thread, the window procedure is called immediately by SendMessage().
When SendMessage() is used to send a message to a window is *another* thread, the message goes to a "separate place" that is not the message queue. But the message will only be sent (i.e., the window procedure will only be called) when the thread that owns the window calls a Win32 API function that directly or indirectly looks at this "separate place" for queued messages and automatically calls the window procedure.
Am I missing something?
How does PeekMessage’s wRemoveMsg argument affect this?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/messagesandmessagequeuesreference/messagesandmessagequeuesfunctions/peekmessage.asp
Can I retrieve sent messages as if they were posted messages, and then dispatch them? I would like to be able to filter out, for example, Shatter attacks.
For the record, I just wanted to correct some statements I previously made in "# re: The various ways of sending a message 11/20/2004 4:42 PM carlso"
(sorry, must have been the cold medicine I was on at the time ;-)
The confusion was due to my incorrect assumption that DispatchMessage() was listed among the yielding functions (it is not). Of course, messages are processed (i.e., WndProc is called) during DispatchMessage as well. Sorry for any confusion.
These statements are incorrect:
"…my understanding is that messages are only processed (i.e., a WndProc is called) when an application calls one of the "Yielding" APIs."
— and —
"…the only time a WndProc can be called (even from the result of another thread sending you a message), is when you execute one on the "yielding" functions…"
Here are the corrections:
In the first one, delete the word "only":
"…my understanding is that messages are processed (i.e., a WndProc is called) when an application calls one of the "Yielding" APIs."
And, in the second, rewrite:
"…when a thread sends (i.e., not posts) a message to another thread, the WndProc to process that message within the receiving thread can only be called when the receiving thread executes one of the "yielding" functions…"
I was just wondering, sometimes I find with Visual Studio 2003 that I cannot switch back to it. I then try and run a program called MessageSender found on Code Project (by Dmytro Ivanchykhin) and get it to send a WM_MDIACTIVATE, to the VStudio window. I have tried SendMessage,PostMessage and SendMessageTimeout and also used both the MessageSender and Target window thread contexts (the app that the message will seem to have come from)
But whatever I do, VStudio just crashes instead of being switched over to.
Why would this be?
Hi,
I am trying to stop a window from crashing through api. A window crashes when some operation on that window is done many times within a fraction of second. Can anybody tell me how to send windows O/s a message that tells O/s to stop closing the window whenever required.
please email me at amits@vt.edu if u know the answer or have ne idea on the matter.
I would really appreciate your comments and suggestions.
Thank you
Amit
The pitfalls of broadcasting messages.
PingBack from http://blogs.msdn.com/oldnewthing/archive/2007/10/01/5216600.aspx
PingBack from http://www.hilpers.com/956225-sendnotifymessage-vs-sendmessage