The various ways of sending a message

Date:November 19, 2004 / year-entry #399
Orig Link:
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)
  1. Nate says:

    What is the difference between SendNotifyMessage() and PostMessage()?

  2. asdf says:

    SendNotifyMessage will call the wndproc if the HWND is in the same thread otherwise it behaves just like PostMessage.

  3. Nate says:

    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.

  4. Raymond Chen says:

    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.

  5. Johan Ericsson says:

    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

    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.

    [Response. -Raymond]
  6. Mark says:

    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.

  7. Raymond Chen says:

    Please put suggestions into the suggestion box instead of hijacking an existing thread. Suggestions posted as normal comments tend to get lost.

  8. Dan Maas says:

    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.

  9. Leonardo Brondani Schenkel says:

    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?

  10. asdf says:

    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.

  11. Leonardo Brondani Schenkel says:

    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?

  12. Raymond Chen says:

    "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…)

  13. Leonardo Brondani Schenkel says:

    Thank you. I’m looking forward to this new series. :-)

    This means that even a thread is doing this:

    while(1) {



    Windows can "freeze" this loop, call the window procedure, and later continue the loop like standard C signals?

  14. Raymond Chen says:

    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.

  15. Leonardo Brondani Schenkel says:

    Yes, I know. Just kidding.

  16. Chris Becke says:

    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?

  17. ac says:

    Regarding the differences between PostMessage and SendMessage, I find that this article summarizes it pretty well (in an MFC context):

    Some of the other articles on the site are useful too.

  18. Jon Potter says:

    A busy loop like:

    while(1) {



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

  19. Raymond Chen says:

    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.

  20. Eric TF Bat says:

    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…

  21. Mike Dimmick says:

    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.

  22. carlso says:

    "Windows will not call the window procedure until I call some Win32 blocking API. Is that correct?"

    Raymond replies: That is incorrect.

    Perhaps what the original post meant was not "Win32 blocking API", but instead "Win32 yielding API".

    I’m going to go out on a limb here, but my understanding is that messages are only processed (i.e., a WndProc is called) when an application calls one of the "Yielding" APIs.

    There was a nice article written by Bob Gunderson at Microsoft back in the 16-bit, Win 3.x days called "Modules, Instances, and Tasks." In those days, Windows supported cooperative multitasking instead of today’s pre-emptive multitasking. In other words, a task would never lose control of the CPU until it explicitly called a function that could yield control. And Microsoft documented the list of functions that could do so. Win 3.x had a concept of “task” which then got extended to become a concept of a “thread” in Win32. My understanding is that the inter-thread messaging in Win32 tried to maintain the previous semantics of how tasks yielded to each other under the old 16-bit APIs. That is, today, within a Win32 thread (task), 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 (as mentioned below).

    Here’s the text from the Gunderson paper:



    A task can be thought of as a "logical CPU" with its own CS:IP, stack, and registers. A task can execute code from any number of modules. As execution enters a module (usually through an exported entry point), the current task handle remains unchanged, but the function’s prolog code sets the proper execution context, that is, the proper data segment.

    Task switching occurs when an application calls a Windows function that gives up control of the system, a procedure known as yielding. Because Windows is a nonpreemptive multitasking system, applications must periodically give up control of the system to allow other applications to run. The following functions can cause the calling task to yield:

    – DialogBox, DialogBoxParam, DialogBoxIndirect, DialogBoxIndirectParam

    – DeviceMode, ExtDeviceMode (These can display a dialog box.)

    – GetDC (Only if all device contexts [DCs] are in use.)

    – GetMessage, PeekMessage, WaitMessage

    – MessageBox

    – Yield

    Along with the functions on this list, any function that sends a message to another application (such as SendMessage) can cause a temporary task switch while the target application processes the message.

  23. carlso says:

    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.

  24. Jason Malinowski says:

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

  25. Raymond Chen says:

    SendMessage bypasses the queue. That’s what people are missing.

  26. Jon Potter says:

    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.

  27. Raymond Chen says:

    They don’t go into the message queue; they go into a separate place.

  28. Chris Becke says:

    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.

  29. Jon Potter says:

    Seems like you are splitting hairs here. They don’t go into the queue, but they go into a queue? :)

  30. Raymond Chen says:

    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.

  31. asdf says:

    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.

  32. Raymond Chen says:

    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.

  33. Jason Malinowski says:

    OK….I’m now beginning to get it.

    Anyways: here’s an interesting article that seems to discuss SendMessage vs. PostMessage:

  34. Jon Potter says:

    Maybe if it did then fewer people would fail to understand the distinction :)

  35. A says:

    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.


    A message sent by another thread or application is in the queue.

  36. Jon Potter says:

    Ooh, explain that Raymond :)

    (just kidding!)

  37. A says:

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

  38. About this "separate place"… does it guarantee that the order in which a window receives SendMessage calls is the same order they were sent?

  39. Raymond Chen says:

    You already know the answer based on information posted in this thread.

  40. Leonardo Brondani Schenkel says:

    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?

  41. cola says:

    How does PeekMessage’s wRemoveMsg argument affect this?

    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.

  42. carlso says:

    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…"

  43. Peter says:

    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?

  44. amit shrivastava says:


    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 if u know the answer or have ne idea on the matter.

    I would really appreciate your comments and suggestions.

    Thank you


  45. The pitfalls of broadcasting messages.

Comments are closed.

*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index