C++ Q&A: Sending Messages in Windows, Adding Ho...

We were unable to locate this content in de-de.

Here is the same content in en-us.

This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
MSDN Magazine
Sending Messages in Windows, Adding Hot Keys to your Application
Paul DiLascia
Download the code for this article: CQA1200.exe (57KB)
Browse the code for this article at Code Center: HotKey Demo

Q
I'm somewhat confused about the difference between PostMessage and SendMessage. I've seen code that uses both functions. Can you tell me when I should use PostMessage versus SendMessage?

A
There are a few subtle differences in the ways you can send messages in Windows®, but the basic difference between PostMessage and SendMessage is that SendMessage sends a message to another window immediately by calling that window's procedure and waiting for it to return, whereas PostMessage queues the message in an MSG structure and returns immediatelyâ€"without waiting. MSG is short for message, not monosodium glutamate.
      With SendMessage, the receiving app processes the message immediately, rather than at some later time, by fetching it from its queue. For example, suppose you write:
CString s;
pWnd->SendMessage(WM_SETTEXT, 0, "Fooblitzky");
pWnd->GetWindowText(&s); 
// s is "Fooblitzky"
This example sends WM_SETTEXT to whatever window is represented by pWnd. Windows calls that window's procedure with WM_SETTEXT as the message ID, and zero and "Fooblitzky" as WPARAM and LPARAM. The message proc handles the message and returns; control returns to the next line, which calls GetWindowText. As you'd expect, s is now set to the value "Fooblitzky". SendMessage behaves like a function call, where WM_SETTEXT is the function.
      What happens if you use PostMessage instead?
CString s;
pWnd->PostMessage(WM_SETTEXT, 0, "Fooblitzky");
pWnd->GetWindowText(&s); 
// s is ????
PostMessage doesn't call the window procedure. Instead, it adds an MSG structure to the message queue of the thread or process that owns pWnd, and returns. The MSG holds the message ID and parameters. The thread or application processes the message when it gets around to it. That is, when its main dispatch loop calls GetMessage and WM_SETTEXT's turn comes up. (There could be other messages already waiting before WM_SETTEXT.) In any event, PostMessage returns immediately without waiting for any of this, so when the next line (GetWindowText) executes, s won't be "Fooblitzky", unless that's what the window text happened to already be before PostMessage was called. (If pWnd belongs to another thread or process, it is of course theoretically possible that Windows could interrupt your thread exactly between PostMessage and GetWindowText, and give the other thread enough of a time slice to process WM_SETTEXT. But that's about as likely as all the molecules in your body suddenly shifting to the left one inch due to a rare confluence of random fluctuationsâ€"which is to say, quite unlikely. Well, OK, maybe not that unlikely.)
      So there are two ways to deliver a message to a window: SendMessage calls the window proc directly; PostMessage uses the queue. Figure 1 illustrates the difference.

Figure 1 SendMessage versus PostMessage
Figure 1 SendMessage versus PostMessage

      With all that in mind, let's get back to the original question: when should you use SendMessage versus PostMessage? Most of the time, SendMessage does what you want. It calls a window to perform some action immediately. You want to set the text or change a bitmap or get some property or whatever, and you want to do it now because the next line of code depends on the result. MFC is full of wrapper functions that do nothing but call SendMessage. For example:
// typical MFC wrapper
inline void CEdit::Cut()
{ 
    ::SendMessage(m_hWnd, WM_CUT, 0, 0); 
}
One benefit of such wrapper functions is they make SendMessage look more like the function call it is (the other benefit is that there's less to type). These wrappersâ€"and SendMessageâ€"are typically used by parent/child windows to communicate.
      When should you use PostMessage? Typically you post a message when the action requested is not urgent and possibly lengthy, or you don't want to interrupt current processing to wait on it. These messages have the characteristic of a notification: "Hey, something just happenedâ€"in case you care." For example, when you call InvalidateRect or InvalidateRgn to inform Windows that a particular area needs painting, Windows doesn't repaint the area immediately; instead, it adds the area to a list and posts a WM_PAINT message (if one hasn't been posted already). If your app then calls InvalidateRect again, the second region is added to the list. The window doesn't get painted until later, when WM_PAINT is processed. In this way, multiple regions get updated in a single paint operation.
      A similar situation arises when a worker thread notifies its UI thread that new data is waitingâ€"by posting a message. The worker goes on working, and the UI processes the message when it gets to it. Asynchronous update is a common programming paradigm, and a clear candidate for PostMessage. In general, PostMessage is safer when you want to send a message to another process or thread, because SendMessage can block. More on this in a moment.
      Another time to use PostMessage is when you want to finish processing the current message before processing the new one. For example, suppose you're handling a message and you determine it's time to quit the application (perhaps the message is an Exit command). You don't want to send WM_QUIT via SendMessage; that would call the message proc and quit immediately in the middle of whatever you were doing. Better to post WM_QUIT, so your app can process all the bye-bye messages like WM_CLOSE, WM_DESTROY, and WM_POSTNCDESTROY before quitting gracefully. This example is so commonplace there's a function called PostQuitMessage to post WM_QUIT.
      PostMessage usually works better when you want to simulate a command or input event by posting WM_COMMAND or one of the keyboard or mouse messages (which is always dicey, by the way). This holds true because "real" input events usually come in sequences of related messages (such as keydown/keyup pairs) and your app may get befuddled if you try to process a new input message in the middle of one of these sequences. Post works better when simulating input.
      Sometimes you have to use PostMessage to get around a quirk or bug to avoid infinite recursion. For example, suppose your WM_SETFOCUS handler (OnSetFocus) determines that the new focus window is not good for some reason and you have to change the focus to a different window. If you call SetFocus from within your OnSetFocus handler, Windows immediately sends another WM_SETFOCUS messageâ€"while you're still processing the first one! The result is infinite regress until your stack blows up. To avoid this infelicity, you can post a message to yourselfâ€"MYWM_SWITCHFOCUSâ€"so OnSetFocus can finish before you process the message to change the focus. This is one of those examples that's easier to understand in practice than on paper. The main thing to remember is that Windows won't let you SetFocus within a WM_SETFOCUS handler.
      Since SendMessage calls the window proc directly, it needs an HWND. How else can it know which message proc to call? But PostMessage adds the message to the message queue, which is associated with a thread or process, not a window. In theory, PostMessage doesn't need a window. And in fact, that's the case.
// post message to myself
PostMessage(NULL, WM_HI_THERE_HANDSOME, ...);
      If the HWND is NULL, PostMessage posts the message to the current running thread's message queue. In practice, this feature isn't terribly useful since most times you want to post a message to some other thread (perhaps with PostThreadMessage); but there are always rare situations when it's convenient to post to yourself without a window. (If you think of any, please let me know.)
      In case you think you're beginning to understand when to use SendMessage and PostMessage, there are three more message-sending functions you should know about: SendMessageCallback, SendNotifyMessage, and SendMessageTimeout. These functions are useful in the heady world of Win32® and multithreading. In Win32, if you call SendMessage your thread is blocked until the target thread processes the message. If the target thread is itself blocked for some other reason, SendMessage never returns. Oops.
      SendNotifyMessage, SendMessageTimeout, and SendMessageCallback were invented to work around this problem. SendNotifyMessage works like SendMessage if the target window belongs to (was created by) the current thread; it works like PostMessage if the window belongs to a different thread. SendMessageTimeout is similar, but it lets you specify a maximum time to wait for the other thread to respond. The Windows function ExitWindowsEx uses SendMessageTimeout to send WM_QUERYENDSESSION to all top-level apps. That is, it tries to be nice by giving each app a chance to die gracefully, but if an app doesn't respond soon enough, ExitWindowsEx kills the app anyway. Too bad, so sad. SendMessageTimeout waits, but not forever.
      As you might guess, SendMessageCallback takes a callback function. It sends the message and returns immediately; when the message has been processed, Windows calls your function. SendMessageCallback comes in handy when you'd like to use PostMessage, but you want to know when the message has been handled. Think of it as PostMessage with a return receipt.
      PostMessage, SendMessageTimeout, and SendNotifyMessage are all good candidates to use if you want to broadcast a message to all top-level windows by using HWND_TOPMOST as the HWND. It's a bad idea to use HWND_TOPMOST with SendMessage because one dead process can bring your app to a halt.
      Figure 2 summarizes the differences among the various message-sending functions. Whew!

Q
I wrote a dialog application that can be hidden. Now I want a hot key (like Ctrl+Alt+S) to show it. How can I do this?
Nicolas Le Corre

A
There are two ways to associate a hot key with your app: you can use WM_SETHOTKEY to set a single hot key that activates your app, or you can use RegisterHotKey to register any number of hot keys that can do whatever you want. With WM_SETHOTKEY, the key is associated with your top-level window and main thread; RegisterHotKey works with any window and thread. Since WM_SETHOTKEY is the easy approach, I'll show you the other oneâ€"RegisterHotKey.
      But before I do, here are some words of caution: a lot of people (myself included) use text editors like Emacs, which uses virtually every possible combination of Alt + Shift + Ctrl characters fathomable, and we folks get extremely irritated when some program comes along to take over even one of these keys. Imagineâ€"you press Ctrl+Alt+S expecting to invoke regex-search (regular expression search), but instead you get some dialog appearing in the middle of your screen. Sheesh! It's very annoying. So at the least you should provide a way for users to change the hot key or turn it off completely.
      OK, so you've decided to ignore my warning (how many people use Emacs, anyway?) and add a hot key to your app. How do you do it? To show you, I modified the FileType program from last month's column by adding a Hide button and hot key activation using Windows+A. (A safe key, since few programs use the Windows key for anythingâ€"but did you know Windows + E brings up Windows Explorer?) The new program is aptly called FileType2 (see Figure 3 and Figure 4).

Figure 3 FileType2
Figure 3 FileType2

      FileType2 is a typical dialog-based app. When Windows creates the dialog, it sends WM_INITDIALOG; OnInitDialog does several things, then registers the hot key.
// In CMyDialog::OnInitDialog
m_nIDHotKey = GlobalAddAtom("FileType2App");
RegisterHotKey(m_hWnd, m_nIDHotKey, MOD_WIN, 
               'A');
In this snippet, m_nIDHotKey is the hot key ID, a UINT in CMyDialog. You can use any ID you like as long as it's unique among all hot keys within your window. GlobalAddAtom is overkill; I could have used 17 or 3 as my ID. But I wanted to show you how to use GlobalAddAtom because in the rare event you're writing a DLL that's shared among many apps, you should use an atom to avoid ID conflicts. (An atom is a systemwide unique ID, named by a string like "FileType2App"â€"read the documentation for more info.)
      Once you've successfully registered your hot key, Windows sends a WM_HOTKEY message any time the user presses the key. CMyDialog handles it like so:
LRESULT CMyDialog::OnHotKey(WPARAM wp, LPARAM)
{
    if (wp==m_nIDHotKey && !IsWindowVisible()) {
        ShowWindow(SW_SHOWNORMAL);
    }
    return 0;
}
In English: if the dialog is hidden, show it. Pretty simple. The only hard part is there's no built-in ON_WM_HOTKEY macro in MFC; you have to use ON_MESSAGE.
ON_MESSAGE(WM_HOTKEY, OnHotKey)
      When you register a hot key, you don't get to keep it forever; you must return it before your app quits. If you don't, other apps won't be able to use it. To return the hot key, you must callâ€"what else?â€"UnregisterHotKey. The natural place to call it is in your WM_DESTROY handler.
// bye-bye me
void CMyDialog::OnDestroy()
{
    UnregisterHotKey(m_hWnd, m_nIDHotKey);
}
      That's all there is to it. There's only one potential bugaboo I can think of: what happens if Jane J. User runs another instance of your app? The second instance will fail when it tries to register the hot key, since the first instance has already registered it. What to do? Well, if you spend more than 10 seconds thinking about it, you'll discover it doesn't really make sense to have a hot key with multiple instances. Which instance should process the key? The best thing to do is disallow multiple instances using standard techniques (see C++ Q&A in the October 1997 issue of MSJ). Or if you really need multiple instances, don't use a hot key! Of course, the hot key might actually start another instanceâ€"as is the case in Windows Explorer when you press Windows+E!
      RegisterHotKey is totally flexible since it lets you associate the hot key with any thread or window. If all you want to do is activate your app, WM_SETHOTKEY is simpler. You don't have to register or unregister anything, just send WM_SETHOTKEY with the key you want. When the user presses it, Windows activates your app, and just to be nice, sends you a WM_SYSCOMMAND with subcode SC_HOTKEY.
      Warning: don't try to use someone else's hot key! As the documentation says: "If more than one window has the same hot key, the window that is activated by the hot key is random." What I want to know is: does Windows select a random window each time, so it's like Russian rouletteâ€"or did the author mean to say arbitrary? Readers who perform the experiment to find out will receive extra credit.
      Hot keys are a bit dangerous because if everyone uses them, programs are bound to clash. A hot key should be reserved for something really bigâ€"like halting Windows to enter a system debugger. Even then, you should let users turn the hot key off, or change the key. How do you provide a user interface to change your hot key? It's easy. Just use a Hot Key control. This special control lets users type the key directly into an edit control. For more info, see the documentation. Hey, I can't do everything!
Paul DiLascia is the author of Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992) and a freelance consultant and writer-at-large. He can be reached at askpd@pobox.com or http://www.dilascia.com.

From the December 2000 issue of MSDN Magazine

Page view tracker