Message APIs

Home
Back To Tips Page

I have been asked recently to discuss the various message APIs and the situations in which they are used. This is not a complete discussion of the messaging APIs, but a survey of those I use in common practice. Esoteric ones such as BroadcastSystemMessage[Ex], InSendMessage[Ex], ReplyMessage, SendMessageCallback, SendNotifyMessage, or WaitMessage, for example, are not APIs I've ever used, and therefore I'm not really qualified to write about them extensively.

The set of messaging APIs and related topics I will discuss in this essay are shown below; you can click on one of them to go directly to that topic. 

Messages or Methods?

When creating a class, one of the questions comes up is how to communicate to the parent window. Often, a natural tendency is to somehow pass in a pointer to the parent class and simply call methods in the parent class. This is often done with dialogs and modeless dialogs.

The problem with this approach is that the dialog is not reusable in any way. It is intimately coupled to the structure in which you have created it. It also suggests that the dialog knows something about the context in which it is called. This inevitably leads to gratuitous complexity in development and maintenance. Therefore, I always construct dialogs with a very simple rule: the dialog knows nothing about variables which are not member variables of its class. It never uses global variables, with the rare exception of constant tables which might be compiled in (although I tend more to declare these as static member variable, usually in the protected part). If you use a global variable, or manipulate anything outside the member variables of the dialog, my opinion is that you have a deeply flawed design. Object-oriented programming is not assembly programming. For example, when programming in assembler, the most important part of the listing was the cross-reference table, so we could see what parts of the program modified global variables. I have never needed to use a cross-reference tool in my Windows programming, because the interfaces are so clear that I know exactly what modules are modifying state. Hence a cross-reference listing is relatively useless.

When communicating with a parent, there are only two acceptable methods, in my design methodology. Member variables are set when the dialog is created, and retrieved when the dialog terminates. Until the dialog terminates, it has absolutely no effect on any part of the program state. To send information to the parent of the dialog, which is usually query-only (it is very rare that any modification is made from a modal dialog; in almost all cases this represents a design failure, and I haven't done it in years), and I do this by doing a SendMessage to the parent.

When using a modeless dialog, the idea is that the modeless dialog reflects and can modify program state. It does this by some combination of three methods: 

The nice thing about this architecture is that it completely decouples the dialog from the rest of the program behavior. For example, I can create a "toolbox" for a view which is sent state information when the view is activated, and receives notifications that the view is deactivated. If it is view-specific, it will be notified as each view gets activated, so it always is correctly displaying the context for the view. It doesn't need to know what the view is; it sends its notifications to the main window that handles the dispatch.

When building child controls, particularly purely-MFC-based controls, I will choose the method approach to allow the parent to communicate with the child. I could use messages, but this is usually only important if you plan to use the controls in a pure-C environment, which I haven't done in years. However, the only way a child can notify its parent is by sending, or posting, a message to that parent. It must never know anything about the parent structure.

For example, if you have a dialog-based app which has a control, and you want to invoke a subdialog, one of the absolutely worst methods to query the control in the parent is to do something like

((CMyAppDlg *)GetParent())->c_Data.GetWindowText(s);

This is so horrible that it is almost inconceivable that it would ever be considered. It assumes the type of the parent, it assumes the name of the member variable, and it assumes that the member variable has a specific type. The equivalent horror is

(CEdit *)(((CMyAppDlg *)GetParent()->GetDlgItem(IDC_TEXT))->GetWindowText(s);

The only thing that makes this even worst than the previous example is that it is syntactically even uglier; it is so rare to use GetDlgItem in a proper MFC program that I consider this, unless there are compelling reasons, to be a deep programming error. (For my reasons, see my companion essays on Avoiding GetDlgItem and, for the counterexample of when it is actually useful, my essay on Who Owns the GUI).

First, you should never do such a dynamic inquiry. The values, if needed, should be set in member variables. But if you must do an inquiry, you should do a SendMessage to the parent. This is a well-defined interface; any recipient of this query will know what to do with it. Furthermore, you know what to expect from it. You don't need to know how the parent derives the value. You only have to know the value comes to you via either the result of the SendMessage or via something pointed to by the WPARAM or LPARAM.

Notifications of events in a child control should be sent to the parent. There are several ways of doing this. One of the most common is to use WM_NOTIFY. This has several advantages. First, it is a well-defined interface. You can easily add message handlers for it. You can communicate arbitrary information. It allows you to have several instances of the child control. You can also use custom user-defined messages. These are a bit harder to deal with when you have multiple instances. I will discuss both of these methods later.

Notifications from a modeless dialog should be sent via messages. My own preference is to use SendMessage to the main window. The main window undertakes to distribute this message to the other windows. There is a slight unpleasantness here, caused by Microsoft's decision to route only WM_COMMAND, WM_NOTIFY, and WM_UPDATE_COMMAND_UI messages, but not allow message routing for other types of messages. We'll talk about that later.

For the subsequent discussion, I will assume that you have already read my companion essay on Message Management, which discusses how to create and handle user-defined messages. Examples which rely on this essay will be presented without further explanation.

What is a Message?

A number of beginners want to know, "What is a message?", "Where do they come from?". A "message" is something that is detected by the GetMessage operation (or its related calls, such as PeekMessage and the like, but we don't need to concern ourselves with the details because the message pumps are buried in MFC). Whatever it is that GetMessage detects is a message. In addition, if it is a window message, we typically do a TranslateMessage and DispatchMessage. The DispatchMessage is, in MFC, always to the AfxWndProc message handler. Once you are in this handler, if you have read Petzold, or Rector & Newcomer, or some similar book on "basic Win32 Programming concepts", forget most of what those books talk about. They are talking about the pure Win32 API. MFC largely isolates you from this. You rarely if ever need to do switch statements or decode the messages.

So, now that we've established what a message is, where do they come from?

Many messages are created by the system. For example, a message that indicates the mouse has moved, or the system would like to know what cursor should be set, or the mouse has been clicked, and so on. These messages are always processed in FIFO (first-in-first-out) order.

For some kinds of windows, messages are the way their parent communicates requests to them, and the means by which they communicate to their parent window. 

For example, a window of the BUTTON class can receive messages such as WM_SETWINDOWTEXT and WM_SETFONT, which pass information in which it then stores. In MFC, you use the CButton class and use the methods SetWindowText and SetFont, but if you single-step through these calls you will find that underlying them is a SendMessage call which sends the message to the button window. 

In addition, the BUTTON class will send WM_COMMAND messages to its parent window. These messages tell what event happened, for example, the BN_CLICKED event. You create handlers for these messages by selecting the control in the ClassWizard, choosing the event type you want to intercept (such as BN_CLICKED), and the ClassWizard creates an entry in the MESSAGE_MAP which will route this event to a handler for that button event.

Most controls use either WM_COMMAND or WM_NOTIFY messages to their parents to communicate events. But there are many other kinds of messages. For example, many of the standard controls will send a WM_CTLCOLOR**** message to their parent to determine what color they should use for the control background, and perhaps have the text color, font, or other characteristics for drawing changed. "Owner-Draw" controls will send a WM_DRAWITEM message to the parent window, which will then undertake to draw the child window contents. However, if you handle a WM_CTLCOLOR, WM_DRAWITEM, WM_MEASUREITEM, or a few other messages in your dialog, you are probably doing the wrong thing. Instead, you should reflect these messages back to the child. This will be discussed in a separate section.

In addition, there are messages which you, the programmer, can define. These are called "user-defined messsages", and they form a completely separate essay which describes their use.

There are some messages, however, which are not as simple. For example, when a WM_KEYDOWN message is received, the TranslateMessage call will cause certain key combinations to be translated to WM_CHAR messages. The WM_CHAR message is placed at the front of the queue so it is the next message received. When a timer fires, it does not place a WM_TIMER message in the queue! Instead, it sets a status bit in the kernel's window descriptor. Whenver GetMessage goes to the message queue and finds it empty, it then checks this bit to see if there is a pending timer message. If there is, a WM_TIMER message is created and returned. Note the implication of this. There can be at most one pending event per timer in the pseudo-queue, so if you go off to do some lengthy computation and the timer ticks two or three times, there will be only one WM_TIMER event to notify you

And finally there is WM_PAINT. This is a very important message, since it notifies your window that its pixels are all messed up, or at least not representing the current truth. When it is received, the window is supposed to repaint itself. The built-in windows handle this themselves, but if you create a window class of your own, you must implement your own WM_PAINT (OnPaint) handler. If you do not, Bad Things Happen. The most common one is that your program appears to hang. This is because Windows says "This window is messed up, please redraw it". But there is no OnPaint handler, so it isn't redrawn. So Windows looks at the window and says "This window is messed up, please redraw it". But there is no OnPaint handler, so it isn't redrawn. So Windows looks...you get the idea. When you generate an OnPaint handler with the ClassWizard, the first line in it is 

CPaintDC dc(this);

The creation of a CPaintDC requires the execution of the BeginPaint API call, which says to Windows, "Whatever you believe is messed up, I'm going to fix up, so you can trust me that the contents of the window will be correct when I return". If you don't redraw everything, too bad. Windows assumes you have.

Like WM_TIMER, WM_PAINT is not a "real" message, but synthesized. Whenever any area of the window is invalidated, that is, marked as needing redrawing, a bit is set in the kernel's window descriptor for that window. When GetMessage is called, and the queue is empty, and there is no pending WM_TIMER message, and the invalidated bit is set, a WM_PAINT message is synthesized.

There are many messages which you, the programmer, should not send, and many that you must not send. If you are going to "fake out" the system by simulating an event, such as a mouse click, you must make sure that everything is correct. For example, if you want to simulate a WM_LBUTTONDOWN event, it is essential that not only you supply the correct parameters, but all the rest of the system state is correct. This means the cursor must be on the screen at the exact position you indicate in the client. To do this, you must also remember that the window coordinates are in client coordinates and the cursor is always set in screen coordinates. It is fairly certain that, if you are trying to fake out the system by sending such a message, you are probably ignoring some crucial piece of state essential to the proper functioning of the message. If you think you need to fake out a message, you should think again. The correct way to handle this, in nearly all cases, is to use a user-defined message to perform the notification of the parent window, and have a subroutine common to the system message and the user-defined message if you need to share code.

You must never send a WM_PAINT message. There is more to this message than its message code. There are many side effects such as computing the clipping region, the invalidation rectangle, and other state that would not be done if you ever did SendMessage(WM_PAINT). Instead, use UpdateWindow.

You must never send a WM_SETFOCUS or WM_KILLFOCUS message. These messages do not change the focus. These are messages sent to your window, by the system, to indicate that focus is changing! And while sending these messages may give the illusion that you have successfully changed focus, don't believe it. If you want to change focus to a window, call the SetFocus method on the window you want to set focus to. As a side effect, the messages will be generated.

You must never send a WM_DESTROY message. This is not a request to destroy a window; it is a notification that the window is being destroyed as the consequence of a DestroyWindow call. Sending it will cause various parts of your program to think and act as if the window is destroyed, but in fact it is not destroyed.

These are the most common errors I have seen. It is important to understand the documentation. If you can send a message, it will say something about "an application sends this message to...". If it says something like "this message is sent to...", it almost certainly is a message you must not send yourself.

Some Danger Signs

A number of people, particularly those who come from pure C/Win32 API programming often fall into serious traps. I have a number of predicates that I apply to decisions about approaches taken all too frequently. The probabilities that you are wrong decrease as your MFC experience increases. Most of the times I see these techniques used they are by people writing their first, or first complex, MFC program.

Experienced MFC programmers tend to avoid doing these things. If you are new to MFC, there is probably a much better, natural paradigm you should be using.

Hint: I've been writing MFC programs for six years (and pure Windows for five years before that), and I hardly ever use PreTranslateMessage, I wrote my own OnCmdMsg handlers in exactly one application that was designed to test command routing as part of developing a curriculum. That application is illustrated later in the command routing discussion, and is downloadable. I've never overridden Run or RunModalLoop. These latter are not for beginners. And even most experts don't need them (unless they are doing some really esoteric programming).

When to use or not use PreTranslateMessage

PreTranslateMessage is a frequently-misused call. This is a virtual method you can override in your classes, and it appears in the message pump as illustrated below (the Real Truth is more complex; for example, examine the CWinThread::PumpMessage method in thrdcore.cpp in the MFC source files)

while(GetMessage(&msg, 0, 0, NULL))
   {
     if(!PreTranslateMessage(&msg))
       {
         ::TranslateMessage(&msg);
         ::DispatchMessage(&msg);
       }
   }

So if you handle the message and don't want it to follow the regular dispatch, you must return TRUE from your PreTranslateMessage handler, and if don't handle it, you return FALSE to let the normal message dispatching work.

Generally, if you are trying to intercept a keystroke to a control, and the keystroke is intended for that control, you are using PreTranslateMessage incorrectly. You should be handling the message in the control itself. This means that if you want to handle something in a CEdit control, don't put something in your PreTranslateMessage handler such as

BOOL CMyDialog::PreTranslateMessage(LPMSG msg)
    {
      if(msg.message == WM_CHAR && 
         msg.wParam == VK_whatever && 
         msg.hwnd == c_MyEdit.m_hWnd)
          { /* do something here */
          } /* do something here */
    }

Instead, subclass the CEdit, put an OnChar handler in that control, and handle it there!

There is frequently a response "But I did that and I never got the WM_CHAR messages!" This is correct, particularly in a CDialog. This is because the CDialog "superclass" is really implemented in a funny way such that it gets the messages first, and tries to handle them itself. However, this is trivially fixed by adding a WM_GETDLGCODE handler to your subclassed control. In this handler you indicate which keys you want to get.

When you create the WM_GETDLGCODE handler, it appears as

UINT CMyEdit::OnGetDlgCode()
   {
     return CEdit::OnGetDlgCode();
   }

However, you may modify this value in any way you want. The most common way to handle this is to OR into the result one or more of the following flags (this is not an exhaustive set, just the most interesting ones for everyday usage)

Code Meaning
DLGC_WANTALLKEYS Gets WM_CHAR, WM_KEYDOWN, and WM_KEYUP messages for all keystrokes
DLGC_WANTARROWS Gets WM_KEYDOWN and WM_KEYUP messages for the keys.
DLGC_WANTCHARS Gets WM_CHAR messages for all keystrokes that generate characters.
DLGC_WANTTAB WM_CHAR messages for VK_TAB

For example, if I want to get the Tab key in my edit control, I would do

UINT CMyEdit::OnGetDlgCode()
   {
     return CEdit::OnGetDlgCode() | DLGC_WANTTAB;
   }

There are a few interesting cases where PreTranslateMessage makes sense. One is in intercepting the F1 key for help, or detecting some other application-wide keystroke. Another is to deal with some intrinsic limitations of MFC and Windows. A particularly nasty problem exists in dealing with editing labels in a TreeView or ListView from within a CPropertyPage. Hitting Escape or Return would close the property sheet instead of terminating the editing. This fix is documented in KB article Q125645. In 1997, when I wrote Win32 Programming, I pointed out that this KB article introduces more bugs than it fixes and in fact in practice does not work! I submitted the correct code to Microsoft, and they have not yet fixed this article. Don't trust Q125645 as it stands.

#define dim(x) ((sizeof(x)/(sizeof((x)[0])))

BOOL CMyPropertyPage::PreTranslateMessage(MSG *pMsg)
    {
    if(pMsg->message==WM_KEYDOWN && 
       (pMsg->wParam==VK_RETURN ||
        pMsg->wParam==VK_ESCAPE))
        {
        static const TCHAR szEdit[] = _T("edit");
        TCHAR szCompare[dim(szEdit)+1];
        HWND hFocus = ::GetFocus();

        // Check for "edit" controls which want the RETURN key.
        // If it doesn't want the return key then let it be
        // translated by just calling
        // CPropertyPage::PreTranslateMessage
        ::GetClassName(hFocus, szCompare, dim(szCompare));
        if (lstrcmpi(szCompare, szEdit) == 0)
            {
            if(::GetWindowLong(hFocus, GWL_STYLE) & ES_WANTRETURN)
                return FALSE;    // Don't translate...just send on
                                 // to control
            else
                return CPropertyPage::PreTranslateMessage(pMsg);
            }

        // Check for other controls which want the return key
        if (::SendMessage(hFocus,WM_GETDLGCODE,0,0) &
           (DLGC_WANTALLKEYS | DLGC_WANTMESSAGES | DLGC_WANTCHARS))
            return FALSE;        // Don't translate it
        };

    return CPropertyPage::PreTranslateMessage(pMsg);
    } 

The key to understanding PreTranslateMessage is that if the operation you are intercepting is not a generic operation which can apply to many controls, equally, within the CWnd class you are putting it in, you are probably in trouble. A fairly good predicate for this is if the ID of any control appears in your PreTranslateMessage handler.

Again, there are many cases in which PreTranslateMessage makes sense. But only if the alternatives cannot accomplish the task.

Cross-Process Messaging

A very important consideration is that when you are sending a message across a window boundary, you must not include an address in your address space as part of the message. There are a few exceptions to this, dealing with the built-in base controls. But for all practical purposes, you cannot pass an address in as an argument to any call that crosses a process boundary. 

One of the most common questions in this regard goes something like "I am writing a program that will capture all messages to an application, and I want to play them back". The answer is, stop what you are doing and go off and do something else. This is so hard to get right that it is almost certainly not worth the effort. I would turn down any job that had this as a requirement. And I have over a decade of Windows programming experience (perhaps that's exactly why I know to turn it down!)

The side effect of sending an address across a process boundary is that the receiving process will crash with a memory exception, or produce gibberish. The first option is far more likely than the second.

For most purposes, you can assume in Win32 that you have a 64-bit-wide path between processes, just what can be encoded in WPARAM and LPARAM. If you need more bandwidth, there are several solutions

All of these are beyond the scope of this essay. There is an accompanying essay on WM_COPYDATA.

The Messaging APIs

SendMessage

SendMessage is the most venerable message-transmission mechanism. The message is sent to the main processing loop for the thread. The message is dispatched to the appropriate handler, which processes it immediately and returns a value.

I use SendMessage directly under the following circumstances

I do not use SendMessage

HWND_BROADCAST

You can broadcast a message to all top-level windows in your current desktop (this does not work across desktops). There are times when you must do a message broadcast. The value HWND_BROADCAST is the window handle 0xFFFFFFFF.

If you broadcast a message, you should broadcast only one of the special Windows notification messages, or a Registered Window Message. Broadcasting other kinds of messages can lead to serious problems. For example, I was done in by someone broadcasting a WM_COPYDATA message, which led to my solution for protecting against this hazard.

Messages you might typically broadcast, or receive as a broadcast, or very importantly never broadcast, include those in the following list. This is not intended to be comprehensive.

Message Reason to Broadcast If you receive one
WM_COMPACTING Never You should try to free up memory because system resources are low.
WM_COPYDATA Never Be afraid. Be very afraid.
WM_DEVICECHANGE Never Deal with the condition should you have some interest in the device.
WM_DEVMODECHANGE If you change the device settings. Use SendMessageTimeout to HWND_BROADCAST. Deal with the changes in the device settings.
WM_DISPLAYCHANGE Never Deal with the fact that you could have either more or less screen area. Pull modeless dialogs back to visiblitiy. 
WM_ENDSESSION Never Prepare to shut down. The system is going away.
WM_FONTCHANGE When you add or remove a font Update any lists of fonts you have to account for the changes. Re-enumerate the fonts.
WM_HIBERNATE (CE only!) Never Clean up resources; the system is running out of resources.
WM_INPUTLANGUAGECHANGE Never Deal with any resource reloads you need to deal with the change in language.
WM_PALETTECHANGED Never Paletted systems only: take note of the fact that your colors may no longer be the same.
WM_PALETTEISCHANGING Never
WM_POWERBROADCAST Never The system is about to power down or has just powered back up. Deal with it.
WM_QUERYENDSESSION Never Decide if you are willing to let the session finish; if so, deal with what you need to shut down cleanly.
WM_QUERYNEWPALETTE Never If you need to change the palette, this is your notification that you should do so.
WM_SETTINGCHANGE Whenever you change system parameters via SystemParametersInfo If you were depending on any parameters retrieved by SystemParametersInfo, this is a good time to reexamine them.
WM_SYSCOLORCHANGE Never If you have been using ::GetSysColor and initialized values based on what color you found, you need to re-examine the settings.
WM_TIMECHANGE Whenever you change the system time If you were using the system time, deal with the fact that it has changed.
WM_USERCHANGED (Win9x only) Never The logged-in user has changed. Deal with it.
WM_WININICHANGE Obsolete Obsolete

Using WM_NOTIFY messages

You can define any structure you want to to create your own notifications. The basic structure must be

typedef struct {
    NMHDR hdr;
    anything you want for your control
   } MYHEADER, * LPMYHEADER;

or, if you don't care about C compatibility

class MYHEADER {
    public:
       NMHDR hdr;
       anything you want for your control
    };
typedef MYHEADER * LPMYHEADER;

The key here is that you must put an NMHDR structure as the very first member. You must also not introduce any virtual methods to the class. Virtual methods introduce a virtual method pointer (vtable pointer) which sits in the first location of the object and will make it incompatible with the expected structure of a WM_NOTIFY object.

You should never PostMessage or PostThreadMessage a WM_NOTIFY message, because you must pass a pointer to an object and the object must be deleted. This is not possible with Post[Thread]Message.

The NMHDR structure is defined as

typedef struct tagNMHDR { HWND hwndFrom; 
                          UINT idFrom; 
                          UINT code; } NMHDR;

The hwndFrom is the window handle of the child control; the idFrom is the control ID, and the code is the notification code.

void CMyCustomControl::OnLButtonDown(UINT nFlags, CPoint point)
    {
     MYHEADER myhdr;
     
     myhdr.hdr.hwndFrom = m_hWnd;
     myhdr.hdr.idFrom = GetDlgCtrlID();
     myhdr.hdr.code = MYN_CLICK;

     mydhr.pt = point;
     myhdr.whatever = ...:
     myhdr.something = ...;
     GetParent()->SendMessage(WM_NOTIFY, 0, (LPARAM)&myhdr);
    }

The WPARAM value is specified as identifying the control from which the message came, but the implication seems to be that this is not the control ID, because the Microsoft documentation says to use the idFrom and hwndFrom members of the NMHDR structure.

When the parent is an MFC class, you have to add a handler request of the form shown below. The ClassWizard cannot add this for you, because it only has knowledge of the built-in controls.

ON_NOTIFY(code, controlID, handler)

for example, to intercept the MYN_CLICK notification, I would write

ON_NOTIFY(MYN_CLICK, IDC_MY_CONTROL, OnMyControlClicked)

If I had more than one, I would add

ON_NOTIFY(MYN_CLICK, IDC_MY_OTHER_CONTROL, OnMyOtherControlClicked)

SendDlgItemMessage

This is just a convenient packaging of SendMessage when it is used in pure-C code that is implementing a dialog. It has such little relevance in MFC programming that its use is almost certainly indicative of a misunderstanding of MFC. It is implemented as

LRESULT SendDlgItemMessage(HWND hDlg, UINT id, UINT msg, WPARAM wParam, LPARAM lParam)
   {
     return SendMessage(GetDlgItem(hDlg, id), msg, wParam, lParam);
   }

Thus, it falls under the same rationale as GetDlgItem, (see my essay on Avoiding GetDlgItem), and is even more useless because there is no way that using this can make sense in MFC; instead, writing object methods based on the CWnd-derived class obtained from GetDlgItem is as far as you need to go.

PostMessage

PostMessage is convenient for many purposes, because all it does is enqueue a message for later processing. It can be used as a convenient substitute for building your own queuing mechanism. But it is absolutely necessary for handling inter-thread and some forms of inter-process communication.

PostMessage is delivered asynchronously. This means that under no circumstances can you pass the address of a local variable as a WPARAM or LPARAM, because not only is there no guarantee that the address will be valid when the message is finally processed, there is in fact quite the opposite. It is almost certain beyond any doubt that the address passed will not be valid when the message is processed. 

You can pass the address of a global variable across a thread boundary, but this is almost always a bad idea, because the global variable is shared among all threads; there is no guarantee what value it will hold when the message is processed. The most common "global address" passed is the address of a string literal. However, this is almost always a bad idea, because someday you will decide you need to pass a computed string, at which point the whole mechanism collapses.

The safest way to pass information is to create a new heap-based object to hold the information, and pass its address in the WPARAM or LPARAM of the posted message. It is the responsibility of the receiver of the message to delete this object when it has finished with it. In some cases, this is immediately upon handling the message; in other cases, the contents are placed in some other structure, which inherits the responsibility for disposing of the object when it is no longer required. This is described in detail in my companion essay on worker threads

The reason for doing a PostMessage is that you have no guarantee that the receiving thread is not blocked. If the receiving thread is blocked, you can end up in a deadlock situation, in which the two threads are mutually blocking on each other. This is a key reason a worker thread must never manipulate a GUI object. The chances of deadlock are significant, and detecting and debugging such problems is very difficult, particularly if you have never encountered them before.

PostThreadMessage

This call is virtually useless except in one restricted context, where it is very powerful. The case where it is useful is where you have a UI thread for a "worker" thread. You need UI threads to deal with PostThreadMessage. Sometimes, when I need some sort of queuing mechanism to communicate to a worker thread, I'll create a UI thread and use PostThreadMessage to post user-defined messages to the thread. To handle a message of this type, put an entry in the Message Map of your UI thread of the form:

ON_THREAD_MESSAGE(message, handler)
ON_REGISTERED_THREAD_MESSAGE(message, handler)

Like any handler for a user-defined message, the handler has the prototype

LRESULT handler(WPARAM, LPARAM)

and it is essential that you use exactly this prototype; if you don't need WPARAM or LPARAM, it doesn't matter, you have to include them.

DO NOT USE PostThreadMessage to your main GUI thread! The reason is that your main GUI thread, or any thread that has a visible window associated with it, can enter message loops which are not the main application message pump. For example, any MessageBox or menu action is handled out of a message loop embedded deep in the handlers for these objects. These message loops are clueless as to what to do with a thread message, because it has no HWND value (the value is NULL). So the DispatchMessage simply discards the message, and it is lost.

SendMessageTimeout

This API is particularly useful for interprocess communication, particularly when you have no idea what process you are communicating with. If you do a SendMessage to a thread, the sender remains blocked until the thread processes the message. If the receiving thread is blocked, the SendMessage cannot be processed, and the sender waits until the thread unblocks; if the receiver thread is blocked on some infrequent event, the sender thread appears to block interminably.

SendMessageTimeout allows you to get a thread timeout, and in fact you even have the option of returning immediately if the receiver thread is blocked. In most applications I have done, choosing a very small timeout interval, such as 100ms, is usually satisfactory.

For example, the way I find a process I'm interested in is to enumerate all the top-level windows and do a SendMessageTimeout to each window I find. If the window is one that I can talk to, it will return a meaningful value.

I used to just return TRUE, since every other program should pass the message on to DefWindowProc, which is defined to return 0 for any message it does not understand. This worked fine until Microsoft totally screwed up; one of the components of Personal Web Server (PWS) stupidly returns 1 for every message it receives, even if it doesn't understand the message. As far as I can tell, when this product was getting a design review, everyone was asleep, or a blunder like this would never have been permitted. But there it is, and we have to live with it. What I do now is return the code which is my Registered Window Message. 

Note that for interprocess communication, you must never use WM_APP+n style messages. (Of course, WM_USER is dead, so we will ignore it). You must always use a Registered Window Message. Otherwise, you have the opportunity to totally destroy applications that never heard of you. Since there is never a justification for using WM_APP+n messages for interprocess communication, if you don't want to "go through the additional effort" of using Registered Window Messages you are missing the whole point here: no fixed-integer message is safe for interprocess communication.

I use the GUID-based technique discussed in my companion essay to create a Registered Window Message UWM_QUERY.

My searching code looks something like I show below. In the class, I declare a static member function:

static BOOL findOther(HWND hWnd, LPARAM lParam);

When I want to find the other application, I call a method that looks much like this:

void CMyApplication::locateOther()
   {
    EnumData data;
    EnumWindows(findOther, (LPARAM)&data);
    if(data.hwnd != NULL)
       { /* found it */
        ... whatever...
       } /* found it */
    else
       { /* didn't find it */
        ...whatever else...
       } /* didn't find it */
   }

The enumerator function looks like the following. Note that because this is a static class member it has no access to any members of the class. If you need more general access, you could pass in this or put this in the EnumData structure. Note that I could have simply passed, for the simple code below, a reference to an HWND, and done

*((HWND *)lParam) = hWnd;

but the code is extracted from something more general and I used a more complex EnumData structure.

BOOL CMyApplication::findOther(HWND hWnd, LPARAM lParam)
   {
    if(!::IsWindow(hWnd))
      return TRUE; // keep on trekking
    DWORD result;
    BOOL ok = SendMessageTimeout(hWnd, UWM_QUERY, 0, 0, 
                                 SMTO_ABORTIFHUNG,
                                 100,
                                 &result);
    if(!ok)
      return TRUE;  // failed, keep on trekking
    if(!::IsWindow(hWnd))
      return TRUE;
    if(result == UWM_QUERY)
       { /* found it */
        EnumData * data = (EnumData *)lParam;
        data->hwnd = hWnd;
        return FALSE;
       } /* found it */
    return TRUE;
   }

UpdateAllViews

Actually, this is not a messaging API, but it is a very nice way to do a limited form of broadcasting. This is particularly convenient when you have several views on a single document. One example of this is when you have a splitter-window application where the splitter views interact. For example, selecting something in the left CTreeView panel should have some effect on the display in the right panel.

In any document/view app, there is an OnUpdate method associated with each view. This is automatically called by MFC whenever the document changes, and is called as a consequence of the default OnInitialUpdate handler.

OnUpdate takes three arguments: the sender view, which may be NULL, the lHint, which is an integer which is either 0 (the default case), or nonzero (for special updates of your choice), and the pHint, which is documented as being a CObject *, which is foolish, because it should have been simply an LPVOID but for reasons lost in the mists of time is declared to be a CObject *. So we're stuck with this silly decision.

You must always be prepared to deal with the case lHint == 0, pHint == NULL, which is the initial update request and may also be generated at other times. However, any specific view may, at any time of your choosing, send a nonzero lHint and an optional pHint. The interpretation of these is entirely up to you.

For example, in one treeview/graphic application, selecting an object in the left panel is supposed to highlight it in the right panel. So I have a handler for the selection-change event which does

GetDocument()->UpdateAllViews(this, UPDATE_SELECTION_CHANGED, (CObject *)data);

where data is some piece of information I want to pass over to the view (in this case, it is the ItemData of the tree view entry). The constant UPDATE_SELECTION_CHANGED is a constant of my choice, which I happened to define as 1.

In the graphics view, I used ClassWizard to add an OnUpdate handler.

void CGraphicsView::OnUpdate(CView * sender, UINT lHint, CObject * pHint)
   {
     GraphicalData * data = (GraphicalData *)pHint;
     switch(lHint)
       { /* lHint */
        case UPDATE_SELECTION_CHANGED:
           data->Highlight();
           return;
        case UPDATE_WHATEVER_ELSE:
           ...do whatever here...
           return;
        case UPDATE_BORING_EVENT:
           ... something boring here...
           return;
       } /* lHint */
     CView::OnUpdate(sender, lHint, pHint);
   }

Any time you make a change in the document (which in my case, is implied by the change of selection in the CTreeView) you can invoke UpdateAllViews to force all the views to do whatever is appropriate. Sometimes, all that happens is that the view repaints itself. Sometimes, you pass a pointer to an invalidation rectangle so all views know what to invalidate. For example, a splitter with two CScrollViews on the document. In this case, the view in which you make the change (assume a graphical view) computes the invalidation rectangle in view-relative coordinates and sends it, via UpdateAllViews, to each view. Each view, in turn, determines where in its scrolled view this view-relative rectangle is, maps it to a window-relative rectangle (in client window coordinates) and does an InvalidateRect (for more details, check out the Scribble Tutorial that comes with VC++).

SendMessageToDescendants

This is a convenient way to notify all your MDI views of something interesting, no matter what document they are involved in. It is often a nice tradeoff if you are feeling lazy, and it is an excellent intraprocess "broadcast".

void SendMessageToDescendants( UINT message, 
                               WPARAM wParam = 0, 
                               LPARAM lParam = 0, 
                               BOOL bDeep = TRUE, 
                               BOOL bOnlyPerm = FALSE );

The simple explanation is that it walks the tree from your current window (the one which is sending it) and passes the message, WPARAM and LPARAM to every descendant. If bDeep is TRUE, it recursively walks the tree and sends the message to every descendant, and if bDeep is FALSE, it only sends the message to immediate descendants. We will shortly show that this latter setting, bDeep==FALSE, is mostly useless. Similarly, the bOnlyPerm is almost always defaulted to its FALSE value, and deals with whether or not the message is sent to temporary window objects or only those which are permanent. Since most child windows are in the permanent map, this has little value; I've never used it.

I often use this from the mainframe window to broadcast information to all the views, no matter what document they are associated with (use UpdateAllViews if you care only about the views associated with a particular document). When you do this, you must use a Registered Window Message. This is because any other message might be interpreted by some descendant window that you've never really paid attention to. For example, I had been doing this using WM_USER+1 (this was back in the days before WM_USER was declared obsolete), and it worked fine until one day when I added a modeless dialog as one of the windows. This particular code is the DM_SETDEFID message which is used to change the default button, and all sorts of things started going wrong. I saw a similar problem with a piece of code I received that did a WM_USER+101, which blew sky-high when I added an IP address control to a tabbed dialog in a CFormView. It turns out that WM_USER+101 is the code to set the IP address. At least I can say that I didn't write this one, which postdated the declaration that WM_APP is now the accepted constant. But the correct approach is to always use a Registered Window Message.

Note that since this is sent to every child window, if you have heavily-populated CFormView windows, this is not necessarily the best-performing approach. Use it sparingly in such situations. Note, however, that it may be precisely some custom control you have created that wants this message!

All you need to do is create a handler in each window that cares about this message and do whatever you want. This is straightforward.

There are two useful tricks involved here. First, don't think you can optimize the performance by setting bDeep to FALSE. Second, what if you care to know if some window processed the message, or know how many windows processed the message, or need to know if no windows processed the message.

If you set bDeep to FALSE, it only sends the message to the immediate descendants of the window. Since this is most commonly the mainframe window, it would go only to the direct descendants of the mainframe. This is not going to get it to the views. In fact, in an MDI app, it will go to the toolbar, the status bar, and the MDI client window. Those are the only direct descendants of the mainframe. Below the MDI client window you have all the MDI child frames, and within each MDI child frame there is a view window. Mostly, you want the messages you broadcast to go to the view windows, so these are well below being "immediate descendants".

To see if any window has received the message, or to count the number of windows that processed the message, the trick is to pass down a reference to a BOOL or UINT; every window that processes the message will monotonically modify the value. For example, suppose I want to query, from my view, if any view on any document currently is using a resource that is exclusive access. For example, I might send a UWM_QUERY_AVAILABILITY message to the mainframe and expect to get, as a return value, a TRUE or a count. I would implement this as

BOOL result = AfxGetMainWnd()->SendMessage(UWM_QUERY_AVAILABILITY);

or 

UINT count = AfxGetMainWnd()->SendMessage(UWM_QUERY_AVAILABILITY);

in the mainframe, I would have a handler

LRESULT CMainFrame::OnQueryAvailability(WPARAM, LPARAM)
   {
    BOOL found = FALSE;
    SendMessageToDescendants(UWM_QUERY_AVAILABILITY, (WPARAM)&found);
    return (LRESULT)found;
   }

or

LRESULT CMainFrame::OnQueryAvailability(WPARAM, LPARAM)
   {
     UINT count = 0;
     SendMessageToDescendants(UWM_QUERY_AVAILABILITY, (WPARAM)&count);
     return (LRESULT)count;
   } 

Note that I use a form of polymorphism here: the UWM_QUERY_AVAILABILITY is interpreted differently by the mainframe and the views.

A view which wanted to handle this message and notify that it had done so, or indicate the resource is in use, or increment the count, would do something like

LRESULT CMyView::OnQueryAvailability(WPARAM wParam, LPARAM)
   {
    BOOL * seen = (BOOL *)wParam;
    ...maybe some stuff here...
    *seen |= (something > value); // for example...
    ...and maybe more stuff here...
   }

Note the use of |= so if the expression evaluates to TRUE the Boolean value becomes TRUE, but if it evaluates to FALSE the Boolean value remains unchanged.

LRESULT CMyView::OnQueryAvailability(WPARAM wParam, LPARAM)
   {
    ...maybe some stuff here...
    UINT * count = (UINT *)wParam;
    (*count)++;
    ...and maybe more stuff here...
   }

PostQuitMessage

This is a message which should never be used in the main GUI thread. There are frequently questions of the form "How do I stop my application" and someone invariably answers "Use PostQuitMessage". This is always an erroneous answer in MFC. This immediately shuts down the main message pump. If there is other cleanup to do, if a document was changed and the user needs to be prompted to save the changes, etc., too bad! This has shut down the message loop. You lose big. To shut down an application, do

AfxGetMainWnd()->SendMessage(WM_CLOSE);

However, there is a valid use of PostQuitMessage. If you are using a UI thread, particularly using one to handle some sort of queuing using PostThreadMessage, this is the right way to shut down your worker thread. You can call PostQuitMessage from within the worker thread to have it shut itself down. This is because, unlike a pure worker thread, there is no "top-level" function to return from. Of course, you can also call ExitThread, but I find that PostQuitMessage to be somewhat more correct, since it allows the CWinThread's ExitInstance handler to be called. When you call ExitThread in the UI thread, the thread stops immediately (but any DLLs that have been loaded will receive the appropriate DLL_THREAD_DETACH notification). Do NOT call TerminateThread!

If your main thread wants to shut down the "worker" UI thread, it can do a

thread->PostThreadMessage(WM_QUIT)

and the thread will be terminated cleanly, not only in the Win32 API sense but in the MFC sense, calling the ExitInstance handler.

Reflected Messages

When Windows was designed, it was decided that it was a Good Idea to allow for certain parameterization of the behavior of the built-in controls. So the controls were designed to query the parent window for some actions, or request the parent window to take actions on their behalf. These were messages like WM_CTLCOLOR (which doesn't exist in Win32; instead there are WM_CTLCOLORSTATIC, WM_CTLCOLORBTN, and a whole lot more. But MFC collapses all of these, for legacy reasons, into a single pseudo-WM_CTLCOLOR event, and designates a single handler for them, the OnCtlColor handler.

Now, on the surface, this seems like a Good Idea. Unfortunately, the implementation is very poor. This is because it requires the parent window to know how to color, draw, size, or otherwise treat a child! This is lousy modularity. Perhaps it works when people are writing trivial dialogs with simple control arrangements, but from the viewpoint of an object-oriented model, it is horrible. If I give you my control, you also have to have the code from my dialog window that tells how to paint, size, or color it! This is insane!

The designers of MFC saw this, and incorporated into MFC a very nice mechanism to replace the "owner-draw" methods and similar owner responsibilities. When MFC gets one of several messages, it first checks the child window that sent them to see if there is a handler within the child window that knows how to handle the request. This puts the responsibility back where it belongs: in the subclass that implements the window. Thus, the former "owner-draw" class of controls now become "self-draw" controls. What amuses me is that I was doing this back in the days of pure C code, by calling the FORWARD_ message cracker macros to route the message to my subclass.

The way you do this is to first create a subclass for the control. For example, my validating edit control does this. The messages you can handle by reflection appear in the list of methods as messages preceded by an =, that is =WM_CTLCOLOR. If is very important to note that this is not the same as creating a handler for WM_CTLCOLOR! If you create a handler for WM_CTLCOLOR, it means that any child window of the edit control (in my case) would have the edit control handle its color information. But =WM_CTLCOLOR means that the edit control subclass will receive a notification whenever the embedded EDIT control sends a WM_CTLCOLORxxx message to the parent of the window.

Note there are often several different notifications you can have reflected; for example, I could get a notification if focus was set to this edit control, one if the control were scrolled, etc. Note that the reflection handlers always appear before the regular handlers.

In this case, I want to additionally set the text background to be the same color as the background brush for the window; otherwise the text appears in a white block, which is not the desired intent.

HBRUSH CFloatingEdit::CtlColor(CDC * dc, UINT id)
    {
     CBrush * brush = Check();
     
     LOGBRUSH br;
     brush->GetLogBrush(&br);
     dc->SetBkColor(br.lbColor);
     return (HBRUSH)*brush;
    } // CFloatingEdit::CtlColor

Unlike the normal WM_CTLCOLOR handler, this does not need to indicate the window, nor does it need to indicate the subtype of WM_CTLCOLOR derived from the WM_CTLCOLORxxx message (required for backward compatibility with Win16 MFC). Because this is in the child class, You Know Where You Are. You Are Here. 

My Check() routine returns a brush of some color, depending on the results of the check. Rather than have some elaborate mechanism to return the color as well, since that is implicit in the brush, I just get the LOGBRUSH structure, extract the color, and use that to set the text background color. Why couldn't I just avoid this by setting the background mode TRANSPARENT? Because edit controls do not work correctly when the background mode is transparent! They do not implicitly erase what is underneath the text, so after a couple edits, you end up with an incomprehensible mishmash on the screen.

The key here is that all the intelligence about how to paint the background is contained entirely within the subclass, and the parent window does not need to know or care how the control paints itself. We are back to a proper, object-based, modular model.

However, this completely preempts the parent's notification. Suppose I wanted to handle the change notification without preempting the parent window's right to do so? There is a macro I can use, which unfortunately is not understood by ClassWizard: ON_CONTROL_REFLECT_EX. This allows the window class to insert itself into the event stream but do so in a transparent fashion. I needed to do this as well. To handle this, you must hand-edit the MESSAGE_MAP and insert the reflector handler yourself. 

For example, my message table for my validating control contains

BEGIN_MESSAGE_MAP(CFloatingEdit, CEdit)
	//{{AFX_MSG_MAP(CFloatingEdit)
	ON_WM_CHAR()
	ON_WM_CTLCOLOR_REFLECT()
	//}}AFX_MSG_MAP
	ON_CONTROL_REFLECT_EX(EN_CHANGE, OnChange)
END_MESSAGE_MAP()

This allows me to intercept the OnChange notification and still let it go back to the parent window. The way this works is that if the extended reflection handler returns TRUE, it means that it has done everything required, and no further processing should take place. But if it returns FALSE, it means that MFC should continue to handle the message. In my case, since I always want to be transparent, I just return FALSE.

BOOL CFloatingEdit::OnChange()
    {
     InvalidateRect(NULL);
     return FALSE;
    } // CFloatingEdit::OnChange

In this case, the action is pretty trivial but non-obvious: I simply force the window to be redrawn. The details of this don't matter here, but you can read about them in the essay on the validating edit control, which also contains an image showing why this is necessary.

Command Routing

MFC implements a concept called "Command Routing". In the normal course of events, a menu item or toolbar item routes its message to the main frame. The problem is that the main frame usually is clueless as to what to do with this. For example, what does "Cut" mean, or "Print"? Nothing whatsoever. Concepts like this are handled by the view classes, and what these commands mean depend upon what view is active! Similarly, a concept like "Save" is independent of which view you are looking at, but is very relevant for the document.

MFC extents the concept of messages by defining a class called a CCmdTarget. This is a class that is allowed to receive WM_COMMAND messages. Normally, only a window can handle messages, but since MFC concerns itself with C++ objects--of which windows are but one--any class derived from CCmdTarget is permitted to have a MESSAGE_MAP. One of the most important of these is CWinThread, which is why we can have message maps in UI threads (so PostThreadMessage can work). We can also have message maps in CWinApp-derived classes CDocTemplate-derived classes, and CDocument-derived classes, although neither of these actually has an associated window. You can send any message you want to these message maps. However, if it is a WM_COMMAND message, serious magic happens. The message is routed according to a set of rules. For example, when the mainframe receives a message, it routes it to the active view, which routes it to its document, which routes it to the document template, which routes it to the application, which routes it to the frame window. If, somewhere along the line, one of these classes has an entry in its MESSAGE_MAP, the message is handled, and no further processing is performed. (If you want further processing, you will have to call OnCmdMsg of the class you want to continue handling the message. This presumes that you know which class this is. Overriding OnCmdMsg is very risky; calling it is only somewhat less so. You could even induce routing loops!)

There are some additional features of message routing. For example, if you initially create a bunch of menu items but have not yet created handlers for them, you will notice that under normal conditions when you drop down a menu, or look at the corresponding toolbar icon, you will see the item is disabled. This is because when a menu is about to drop down, MFC searches through all the potential message maps looking to see if the event associated with that menu item has a handler anywhere along the routing path. If no handler is found, the menu item is disabled.

In addition, if there is an UPDATE_COMMAND_UI handler anywhere in the routing path, that method will be invoked, passing in a token, the CCmdUI object, that lets that handler enable, disable, check, uncheck, or change the text of the item in question. The WM_UPDATE_COMMAND_UI path follows the same routing as the WM_COMMAND request.

Does this "affect performance"? Sure, in the sense that it takes more computation. But why should it matter? If you think it matters, (a) you are wrong (b) to find out why, go read my essay on "Optimization--your worst enemy".

When a command is routed, it goes to the main frame. From the main frame, it is routed to the child frame of the active view; it is then routed to the view contained within that frame. If the view does not process it, it is routed to the document. If the document does not process it, it is routed to the document template. This would be used, for example, to handle something that was common to all documents, since given a document template you are able to locate all the documents that it has been used to create. If the document template does not handle the message, it is passed to the application. If the application does not handle it, it passes it to the main frame to actually be processed.

(main frame)Child frameViewDocumentDocument TemplateApplicationMainFrame
Object Receiving Command Routing
CMDIFrameWnd (main frame)
  1. Active CMDIChildWnd
  2. This frame window
  3. CWinApp

CMDIChildWnd
CFrameWnd
  1. Active View
  2. This frame window
  3. CWinApp
CView
  1. This view
  2. CDocument attached to this view
CDocument
  1. This document
  2. CDocumentTemplate
CDialog
  1. This dialog
  2. Parent of dialog
  3. CWinApp

However, when a menu is dropped down or when there is a need to update, first, the WM_UPDATE_COMMAND_UI request is passed around. If a handler is found, it is invoked. However, if no handler is found, a WM_COMMAND "No-op" query is routed. If no handler is found for this, the menu item is disabled (unless you set m_bAutoMenuEnable to FALSE in the main frame. Typically this is done the constructor). 

To demonstrate this routing, I use OnCmdMsg to intercept the routing and display what is happening. This is the only time I have ever used OnCmdMsg in MFC programming.

The execution of the program is shown to the left. I have a menu item for each possible CCmdTarget it the path. I have selected MainFrame here.

The output of this program for this selection is shown below. Each line except the one indicating the exit of the menu loop is generated by OnCmdMsg. What is interesting here is the fact that even after the menu item is selected, there is another set of routing of WM_UPDATE_COMMAND_UI messages, followed by another routing of WM_COMMAND, followed by yet another routing of WM_UPDATE_COMMAND_UI, followed by, finally, the routing that causes the command to be executed. My rather simple program does not determine what is different about these last sequences except the final WM_COMMAND routing.

Log file output Interpretation
CMainFrame::OnCmdMsg                    WM_UPDATE_COMMAND_UI IDM_TEMPLATE
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_TEMPLATE
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_TEMPLATE
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_TEMPLATE
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_TEMPLATE
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_TEMPLATE
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_TEMPLATE
Searches for an UPDATE_COMMAND_UI handler for the IDM_TEMPLATE item.
CMainFrame::OnCmdMsg              query WM_COMMAND           IDM_TEMPLATE
CChildFrame::OnCmdMsg             query WM_COMMAND           IDM_TEMPLATE
CMDITestView::OnCmdMsg            query WM_COMMAND           IDM_TEMPLATE
CMDITestDoc::OnCmdMsg             query WM_COMMAND           IDM_TEMPLATE
CMyMultiDocTemplate::OnCmdMsg     query WM_COMMAND           IDM_TEMPLATE
Searches for a WM_COMMAND handler for the IDM_TEMPLATE item
CMainFrame::OnCmdMsg                    WM_UPDATE_COMMAND_UI IDM_VIEW
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_VIEW
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_VIEW
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_VIEW
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_VIEW
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_VIEW
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_VIEW
Searches for an UPDATE_COMMAND_UI handler for the IDM_VIEW item
CMainFrame::OnCmdMsg              query WM_COMMAND           IDM_VIEW
CChildFrame::OnCmdMsg             query WM_COMMAND           IDM_VIEW
CMDITestView::OnCmdMsg            query WM_COMMAND           IDM_VIEW
Searches for a WM_COMMAND handler for the IDM_VIEW item
CMainFrame::OnCmdMsg                    WM_UPDATE_COMMAND_UI IDM_DOCUMENT
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_DOCUMENT
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_DOCUMENT
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_DOCUMENT
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_DOCUMENT
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_DOCUMENT
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_DOCUMENT
Searches for an UPDATE_COMMAND_UI handler for the IDM_DOCUMENT item
CMainFrame::OnCmdMsg              query WM_COMMAND           IDM_DOCUMENT
CChildFrame::OnCmdMsg             query WM_COMMAND           IDM_DOCUMENT
CMDITestView::OnCmdMsg            query WM_COMMAND           IDM_DOCUMENT
CMDITestDoc::OnCmdMsg             query WM_COMMAND           IDM_DOCUMENT
Searches for a WM_COMMAND handler for the IDM_DOCUMENT item
CMainFrame::OnCmdMsg                    WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
Searches for an UPDATE_COMMAND_UI handler for the IDM_MAINFRAME item
CMainFrame::OnCmdMsg              query WM_COMMAND           IDM_MAINFRAME
CChildFrame::OnCmdMsg             query WM_COMMAND           IDM_MAINFRAME
CMDITestView::OnCmdMsg            query WM_COMMAND           IDM_MAINFRAME
CMDITestDoc::OnCmdMsg             query WM_COMMAND           IDM_MAINFRAME
CMyMultiDocTemplate::OnCmdMsg     query WM_COMMAND           IDM_MAINFRAME
CMDITestApp::OnCmdMsg             query WM_COMMAND           IDM_MAINFRAME
Searches for a WM_COMMAND handler for the IDM_MAINFRAME item
CMainFrame::OnCmdMsg                    WM_UPDATE_COMMAND_UI IDM_CHILDRAME
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_CHILDRAME
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_CHILDRAME
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_CHILDRAME
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_CHILDRAME
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_CHILDRAME
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_CHILDRAME
Searches for an UPDATE_COMMAND_UI handler for the IDM_CHILDFRAME item
CMainFrame::OnCmdMsg              query WM_COMMAND           IDM_CHILDRAME
CChildFrame::OnCmdMsg             query WM_COMMAND           IDM_CHILDRAME
CMDITestView::OnCmdMsg            query WM_COMMAND           IDM_CHILDRAME
CMDITestDoc::OnCmdMsg             query WM_COMMAND           IDM_CHILDRAME
CMyMultiDocTemplate::OnCmdMsg     query WM_COMMAND           IDM_CHILDRAME
Seaches for a WM_COMMAND handler for the IDM_CHILDFRAME item
CMainFrame::OnCmdMsg                    WM_UPDATE_COMMAND_UI IDM_APP
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_APP
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_APP
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_APP
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_APP
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_APP
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_APP
Searches for an UPDATE_COMMAND_UI handler for the IDM_APP item
CMainFrame::OnCmdMsg              query WM_COMMAND           IDM_APP
CChildFrame::OnCmdMsg             query WM_COMMAND           IDM_APP
CMDITestView::OnCmdMsg            query WM_COMMAND           IDM_APP
CMDITestDoc::OnCmdMsg             query WM_COMMAND           IDM_APP
CMyMultiDocTemplate::OnCmdMsg     query WM_COMMAND           IDM_APP
CMDITestApp::OnCmdMsg             query WM_COMMAND           IDM_APP
Searches for a WM_COMMAND handler for the IDM_APP item
-----------Exit menu loop-----------
The menu item is clicked
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
This is interesting, and undocumented. It appears to route another UPDATE_COMMAND_UI request through the hierarchy!
CChildFrame::OnCmdMsg                   WM_COMMAND           IDM_MAINFRAME
CMDITestView::OnCmdMsg                  WM_COMMAND           IDM_MAINFRAME
CMDITestDoc::OnCmdMsg                   WM_COMMAND           IDM_MAINFRAME
CMyMultiDocTemplate::OnCmdMsg           WM_COMMAND           IDM_MAINFRAME
CMDITestApp::OnCmdMsg                   WM_COMMAND           IDM_MAINFRAME
Then there appears to be a routing of the WM_COMMAND message
CMainFrame::OnCmdMsg                    WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CChildFrame::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestView::OnCmdMsg                  WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestDoc::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMyMultiDocTemplate::OnCmdMsg           WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
CMDITestApp::OnCmdMsg                   WM_UPDATE_COMMAND_UI IDM_MAINFRAME
Then it routes the UPDATE_COMMAND_UI request again!
CMainFrame::OnCmdMsg                    WM_COMMAND           IDM_MAINFRAME
CChildFrame::OnCmdMsg                   WM_COMMAND           IDM_MAINFRAME
CMDITestView::OnCmdMsg                  WM_COMMAND           IDM_MAINFRAME
CMDITestDoc::OnCmdMsg                   WM_COMMAND           IDM_MAINFRAME
CMyMultiDocTemplate::OnCmdMsg           WM_COMMAND           IDM_MAINFRAME
CMDITestApp::OnCmdMsg                   WM_COMMAND           IDM_MAINFRAME
Finally, it routes the WM_COMMAND message for execution
CMainFrame::OnMainFrame
--------------------------------------------------------------------------------
It reaches the main frame, which writes the entry seen here.

 

download.gif (1234 bytes)The program is an interesting artifact, demonstrating not only the use of OnCmdMsg, but the also the use of PostMessage, the use of a resizable modeless dialog, a menu within a dialog, and a few other useful tricks. You can download it and play with it yourself. 

Summary

This essay covers both introductory material on messages and some advanced techniques for handling messages. These are practical message techniques which I use frequently, some of them daily.

Thanks to a reader, "Parish", for suggesting this essay.

[Dividing Line Image]

The views expressed in these essays are those of the author, and in no way represent, nor are they endorsed by, Microsoft.

Send mail to newcomer@flounder.com with questions or comments about this web site.
Copyright 2001 The Joseph M. Newcomer Co. All Rights Reserved
Last modified: May 14, 2011