Special Edition Using Visual C++ 5 - Chapter 4

## Chapter 4

## Messages and Commands

If there is one thing that sets Windows programming apart from other kinds of programming, it is messages. Most DOS programs, for example, relied on watching (sometimes called polling) possible sources of input like the keyboard or the mouse to await input from them. A program that wasn't polling the mouse would not react to mouse input. In contrast, everything that happens in a Windows program is mediated by messages. A message is a way for the operating system to tell an application that something has happened—for example, the user has typed, clicked, or moved the mouse, or the printer has become available. A window (and every screen element is a window) can also send a message to another window, and typically most windows react to messages by passing a slightly different message along to another window. MFC has made it much easier to deal with messages, but you must understand what is going on beneath the surface.

- Message routing

  Windows messages direct your program to perform all the things that it does.

- Message loops

  In Windows C programming, developers write loops to deal with a steady stream of messages.

- Message maps

  MFC lightens your conceptual load by letting you catch messages without writing a message loop.

- How ClassWizard helps you catch messages

  Message map entries are easier to add with ClassWizard.

- What messages Windows can generate

  There are nearly 900 Windows messages.

- Messages versus commands

  A command can be routed to parts of your function that can't receive messages.

- The command update mechanism

  You can gray some menu items to reflect the current state of your application.

- How ClassWizard helps you catch and update commands

  Understanding command updates is tough, but arranging for them is simple with ClassWizard.

### Message Routing

Messages are all referred to by their names, though the operating system uses integers to refer to them. An enormous list of #define statements connects names to numbers and lets Windows programmers talk about WM_PAINT or WM_SIZE or whatever message they need to talk about. (The WM stands for Window Message.) As well as a name, a message knows what window it is for, and can have up to two parameters. (Often several different values are packed into these parameters, but that’s another story.)

Different messages are handled by different parts of the operating system or your application. For example, when the user moves the mouse over a window, the window gets a WM_MOUSEMOVE message, which it almost certainly passes to the operating system to deal with. The operating system redraws the mouse cursor at the new location. When the left button is clicked over a button, the button (which is a window) gets a WM_LBUTTONDOWN message, and handles it, often generating another message to the window that contains the button, saying, in effect, "I was clicked."

MFC has allowed many programmers to completely ignore low-level messages like WM_MOUSEMOVE and WM_LBUTTONDOWN. Instead, programmers deal only with higher-level messages that mean things like "The third item in this list box has been selected" or "The Submit button has been clicked." All these kinds of messages move around in your code and the operating system code in the same way as the lower-level messages. The only difference is what piece of code "chooses" to handle them. MFC makes it much simpler to announce, at the individual classes level, which messages each class can handle. The old C way, which you will see in the next section, made those announcements at a higher level and interfered with the object-oriented approach to Windows programming, which involves hiding implementation details as much as possible inside objects.

### Message Loops

The heart of any Windows program is the message loop, typically contained in a WinMain() routine. The WinMain() routine is, like the main() in DOS or UNIX, the function called by the operating system when you run the program. You won't write any WinMain() routines because it is now hidden away in the code that AppWizard generates for you. Still, there is a WinMain(), just as there is in Windows C programs. Listing 4.1 shows a typical WinMain().

Listing 4.1—Typical WinMain() Routine

    int APIENTRY WinMain(HINSTANCE hInstance,

                   HINSTANCE hPrevInstance,

                   LPSTR lpCmdLine,

                   int nCmdShow)

    {

         MSG msg;

         if (! InitApplication (hInstance))

          return (FALSE);

         if (! InitInstance (hInstance, nCmdShow))

          return (FALSE);

         while (GetMessage (&msg, NULL, 0, 0)){

          TranslateMessage (&msg);

          DispatchMessage (&msg);

         }

         return (msg.wParam);

    }

In a Windows C program like this, InitApplication() typically calls RegisterWindow(), and InitInstance() typically calls CreateWindow(). (More details on this are in Appendix A, "Windows Programming Review and a Look Inside Cwnd.") Then comes the message loop, the while loop that calls GetMessage(). The API function GetMessage() fills msg with a message destined for this application and almost always returns True, so this loop runs over and over until the program is finished. The only thing that makes GetMessage() return False is if the message it gets is WM_QUIT.

TranslateMessage() is an API function that streamlines dealing with keyboard messages. Most of the time, you don't need to know "the A key just went down" or"the A key just went up," and so on. It's enough to know "the user pressed A." TranslateMessage() deals with that. It catches the WM_KEYDOWN and WM_KEYUP messages, and usually sends a WM_CHAR message in their place. Of course, with MFC, most of the time you don't care that the user pressed A. The user types into an edit box or similar control, and you can get the entire string out of it later, when the user has clicked OK. So don't worry too much about TranslateMessage().

The API function DispatchMessage() calls the WndProc for the window that the message is headed for. The WndProc for a Windows C function is a huge switch statement with one case for each message the programmer planned to catch, like the one in Listing 4.2.

Listing 4.2—Typical WndProc() Routine

    LONG APIENTRY MainWndProc (HWND hWnd, // window handle

                        UINT message, // type of message

                         UINT wParam, // additional information

                         LONG lParam) // additional information

    {

         switch (message) {

          case WM_MOUSEMOVE:

              //handle mouse movement

          break;

          case WM_LBUTTONDOWN:

              //handle left click

          break;

          case WM_RBUTTONDOWN:

              //handle right click

          break;

          case WM_PAINT:

              //repaint the window

          break;

          case WM_DESTROY: // message: window being destroyed

          PostQuitMessage (0);

          break;

          default:

          return (DefWindowProc (hWnd, message, wParam, lParam));

         }

         return (0);

    }

As you can imagine, these WndProcs get very long in a hurry. Program maintenance can be a nightmare. MFC solves this problem by keeping information about message processing close to the functions that handle the messages, freeing you from maintaining a giant switch statement that is all in one place. Read on to see how it's done.

### Message Maps

Message maps are part of the MFC approach to Windows programming. Instead of writing a WinMain() function that sends messages to your WindProc and then writing a WindProc that checks which kind of message this is and then calls another of your functions, you just write the function that will handle the message, and add a message map to your class that says, in effect, “I will handle this sort of message.” The framework handles whatever routing is required to get that message to you.

> If you've worked in Microsoft Visual Basic, you should be familiar with event procedures, which handle specific events like a mouse click. The message-handling functions you will write in C++ are equivalent to event procedures. The message map is the way that events are connected to their handlers.

Message maps come in two parts: one in the .h file for a class and one in the corresponding .cpp. Typically, they are generated by wizards, although in some circumstances you will add entries yourself. Listing 4.3 shows the message map from the header file of one of the classes in a simple application called ShowString, presented in Chapter 9, "Building a Complete Application: ShowString."

Listing 4.3—Message Map from showstring.h

    //{{AFX_MSG(CShowStringApp)

         afx_msg void OnAppAbout();

              // NOTE - the ClassWizard will add and remove member functions here.

              //    DO NOT EDIT what you see in these blocks of generated code !

         //}}AFX_MSG

         DECLARE_MESSAGE_MAP()

This declares a function called OnAppAbout(). The specially formatted comments around the declarations help ClassWizard keep track of which messages are caught by each class. DECLARE_MESSAGE_MAP() is a macro, expanded by the C++ compiler’s preprocessor, that declares some variables and functions to set up some of this magic message catching.

The message map in the source file, as shown in Listing 4.4, is quite similar.

Listing 4.4—Message Map from Chapter 10’s showstring.cpp

    BEGIN_MESSAGE_MAP(CShowStringApp, CWinApp)

         //{{AFX_MSG_MAP(CShowStringApp)

         ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

              // NOTE - the ClassWizard will add and remove mapping macros here.

              //    DO NOT EDIT what you see in these blocks of generated code!

         //}}AFX_MSG_MAP

         // Standard file based document commands

         ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

         ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

         // Standard print setup command

         ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)

    END_MESSAGE_MAP()

Message Map Macros

BEGIN_MESSAGE_MAP and END_MESSAGE_MAP are macros that, like DECLARE_MESSAGE_MAP in the include file, declare some member variables and functions that the framework can use to navigate the maps of all the objects in the system. There are a number of macros used in message maps, including these:

- DECLARE_MESSAGE_MAP—Used in the include file to declare that there will be a message map in the source file.
- BEGIN MESSAGE MAP—Marks the beginning of a message map in the source file.
- END MESSAGE MAP—Marks the end of a message map in the source file.
- ON_COMMAND—Used to delegate the handling of a specific command to a member function of the class.
- ON_COMMAND_RANGE—Used to delegate the handling of a group of commands, expressed as a range of command IDs, to a single member function of the class.
- ON_CONTROL—Used to delegate the handling of a specific custom-control-notification message to a member function of the class.
- ON_CONTROL_RANGE—Used to delegate the handling of a group of custom-control-notification messages, expressed as a range of control IDs, to a single member function of the class.
- ON_MESSAGE—Used to delegate the handling of a user-defined message to a member function of the class.
- ON_REGISTERED_MESSAGE—Used to delegate the handling of a registered user-defined message to a member function of the class.
- ON_UPDATE_COMMAND_UI—Used to delegate the updating for a specific command to a member function of the class.
- ON_COMMAND_UPDATE_UI_RANGE—Used to delegate the updating for a group of commands, expressed as a range of command IDs, to a single member function of the class.
- ON_NOTIFY—Used to delegate the handling of a specific control-notification message with extra data to a member function of the class.
- ON_NOTIFY_RANGE—Used to delegate the handling of a group of control-notification messages with extra data, expressed as a range of child identifiers, to a single member function of the class. The controls that send these notifications are child windows of the window that catches them.
- ON_NOTIFY_EX—Used to delegate the handling of a specific control-notification message with extra data to a member function of the class that returns TRUE or FALSE to indicate if the notification should be passed on to another object for further reaction.
- ON_NOTIFY_EX_RANGE—Used to delegate the handling of a group of control-notification messages with extra data, expressed as a range of child identifiers, to a single member function of the class that returns TRUE or FALSE to indicate if the notification should be passed on to another object for further reaction. The controls that send these notifications are child windows of the window that catches them.

In addition to these, there are about 100 macros, one for each of the more common messages, that direct a single specific message to a member function. For example, ON_CREATE delegates the WM_CREATE message to a function called OnCreate(). You cannot change the function names in these macros. Typically, these macros are added to your message map by ClassWizard, as demonstrated in Chapter 9, "Building a Complete Application: ShowString."

How Message Maps Work

The message maps presented in Listings 4.3 and 4.4 are for the CShowStringApp class of the ShowString application. This class handles application-level tasks like opening a new file or displaying the About box. The entry added to the header file's message map can be read as "there is a function called OnAppAbout() that takes no parameters.” The entry in the source file's map means "when an ID_APP_ABOUT command message arrives, call OnAppAbout()." It shouldn't be a big surprise that the OnAppAbout() member function displays the About box for the application.

But how do message maps really work? Every application has an object that inherits from CWinApp, and has a member function called Run(). That function calls CWinThread::Run(), which is far longer than the simple WinMain() presented earlier, but has the same message loop at its heart: call GetMessage(), call TranslateMessage(), call DispatchMessage(). Almost every window object uses the same old-style windows class, and the same WindProc, called AfxWndProc(). The WindProc, as you've already seen, knows the handle, hWnd, of the window the message is for. MFC keeps something called a handle map, a table of window handles and pointers to objects, and the framework uses this to get a pointer to the C++ object, a CWnd*. Next, it calls WindowProc(), a virtual function of that object. Buttons or views might have different WindowProc() implementations, but through the magic of polymorphism, the right function gets called.

> Polymorphism

> Virtual functions and polymorphism are important C++ concepts for anyone working with MFC. They only arise when you are using pointers to objects, and when the class of objects to which the pointers are pointing is derived from another class. Consider as an example a class called CDerived that is derived from a base class called CBase, with a member function called Function() that is declared in the base class and overridden in the derived class. There are now two functions: one has the full name CBase::Function() and the other is CDerived::Function().

> If your code has a pointer to a base object, and sets that pointer equal to the address of the derived object, it can then call the function, like this:

>         CDerived derivedobject;

>         CBase* basepointer;

>         basepointer = &derivedobject;

>         basepointer->Function();

> In this case, CBase::Function() will be called. But there are times when that is not what you want, when you have to use a CBase pointer but you really want CDerived::Function() to be called. To indicate this, in CBase, Function() is declared to be virtual. Think of it as an instruction to the compiler to override this function if there is any way to do it.

> Once Function() is declared to be virtual in the base class, CBase, the code fragment above would actually call CDerived::Function() as desired. That's polymorphism, and that shows up again and again when using MFC classes. You use a pointer to a window, a CWnd*, that really points to a CButton or a CView or some other class derived from CWnd, and when a function like WindowProc() is called, it will be the derived function, CButton::WindowProc() for example, that is called.

WindowProc() calls OnWndMsg(), the C++ function that really handles messages. First, it checks to see if this is a message, a command, or a notification. Assuming it’s a message, it looks in the message map for the class, using the member variables and functions that were set up by DECLARE_MESSAGE_MAP, BEGIN_MESSAGE_MAP, and END_MESSAGE_MAP. Part of what those macros arrange is to allow access to the message map entries of the base class by the functions that search the message map of the derived class. That means if a class inherits from CView, and doesn't catch a message normally caught by CView, then that message will still be caught by the same CView function as inherited by the derived class. This message map inheritance parallels the C++ inheritance but is independent of it, and saves a lot of trouble carrying virtual functions around.

The bottom line: You add a message map entry and when a message arrives, the functions called by the hidden message loop look in these tables to decide which of your objects, and which member function of the object, should handle the message. That's what's really going on behind the scenes.

Messages Caught by MFC Code

The other great advantage of MFC is that the classes already catch most of the common messages and do the right thing, without any coding on your part at all. For example, you don't need to catch the message that tells you that the user has chosen File, Save As—MFC classes catch it, put up the dialog box to get the new file name, handle all the behind-the-scenes work, and finally call one of your functions, which must be named Serialize(), to actually write out the document. (App Wizard typically makes an empty Serialize() function for you to fill in). You only need to add message map entries for behavior that is not common to all applications.

### ClassWizard Helps You to Catch Messages

Message maps may not be simple to read, but they are simple to create if you use ClassWizard. There are two ways to add an entry to a message map in Visual C++ 5.0: with the main ClassWizard dialog box, or with one of the new dialog boxes that add message handlers or virtual functions.

The ClassWizard Tabbed Dialog Box

The main ClassWizard dialog box is displayed by choosing View, ClassWizard or by pressing Ctrl+W. ClassWizard is a tabbed dialog box, and Figure 4.1 shows the Message Map tab. At the top of the dialog box are two drop-down list boxes, one that reminds you which project you are working on (ShowString in this case) and the other that reminds you which class owns the message map you are editing. In this case, it is the CShowStringApp class, whose message map you have already seen.

Fig. 4.1

ClassWizard makes catching messages simple.

Below those single line boxes are a pair of multi-line boxes. The one on the left lists the class itself and all the commands that the user interface can generate. Commands are discussed in the "Commands" section later in this chapter. With the class name highlighted, the box on the right lists all the Windows messages this class might catch. It also lists a number of virtual functions that catch common messages.

To the right of those boxes are buttons where you can add a new class to the project, add a function to the class to catch the highlighted message, remove a function that was catching a message, or open the source code for the function that catches the highlighted message. Typically, you select a class, select a message, and click Add Function to catch the message. Here's what the Add Function button sets in motion:

- Adds a skeleton function to the bottom of the source file for the application.
- Adds an entry to the message map in the source file.
- Adds an entry to the message map in the include file.
- Updates the list of messages and member functions in the dialog box.

After you add a function, clicking Edit Code makes it simple to start filling in the behavior of that function. If you prefer, double-click the function name in the Member Functions list box.

Below the Object IDs and Messages boxes is a list of the member functions of this class that are related to messages. This class has two such functions:

- OnAppAbout()—Catches the ID_APP_ABOUT command, and is labeled with a W (for Windows message) in the list.
- InitInstance()—Overrides a virtual function in CWinApp, the base class for CShowStringApp, and is labeled with a V (for virtual function) in the list.

The InitInstance function is called whenever an application first starts. You do not need to understand this function to see that ClassWizard reminds you the function has been overridden.

Finally, under the Member Functions box is a reminder of the meaning of the highlighted message. Called to implement wait cursors is a description of the DoWaitCursor virtual function.

The Add Windows Message Handler Dialog Box

In release 5.0 of Visual C++, a new way of catching messages was added. Rather than bringing up ClassWizard and then remembering to set the right class name in a drop-down list box, you right-click on the class name in ClassView and then choose Add Windows Message Handler from the shortcut menu that appears. Figure 4.2 shows the dialog box that comes up when you make this choice.

Fig. 4.2

The New Windows Message and Event Handlers dialog box is another way to catch messages.

This dialog box does not show any of the virtual functions that were listed in the main ClassView dialog box. It is easy to see that this class catches the command ID_APP_ABOUT but does not catch the command update. (Commands and command updating are discussed in more detail later in this chapter.) To add a new virtual function, you right-click on the class in ClassView and choose Add New Virtual Function from the shortcut menu. Figure 4.3 shows this dialog box.

Fig. 4.3

The New Virtual Override dialog box simplifies implementing virtual functions.

You can see in Figure 4.3 that CShowStringApp already overrides the InitInstance() virtual function, and you can see what other functions are available to be overridden. As in the tabbed dialog box, a message area at the bottom of the dialog box reminds you of the purpose of each function: in fact the text—called to implement wait cursors—is identical to that in Figure 4.1.

Which Class should catch the message?

The only tricky part of message maps and message handling is deciding which class should catch the message. That's a decision you can't make until you understand all the different message and command targets that make up a typical application. The choice is usually among the following:

- The active view
- The document associated with the active view
- The frame window that holds the active view
- The application object

Views, documents, and frames are discussed in the next chapter, "Documents and Views."

### List of Messages

There are almost 900 Windows messages, so you won't find a list of them all in this chapter. Usually, you arrange to catch messages with ClassWizard, and are presented with a much shorter list that is appropriate for the class you are catching messages with. Not every kind of window can receive every kind of message. For example, only classes that inherit from CListBox receive list box messages like LB_SETSEL, which directs the list box to move the highlight to a specific list item. The first component of a message name indicates the kind of window this message is destined for, or coming from. These window types are listed in Table 4.1.

Table 4.1—Windows Message Prefixes and Window Types

Prefix | Window Type

    ABM, ABN

Appbar

    ACM, ACN

Animation control

    BM, BN

Button

    CB, CBN

Combo box

    CDM, CDN

Common dialog box

    CPL

Control Panel application

    DBT

Any application (device change message)

    DL

Drag list box

    DM

Dialog box

    EM, EN

Edit box

    FM, FMEVENT

File Manager

    HDM, HDN

Header control

    HKM

HotKey control

    IMC, IMN

IME window

    LB, LBN

List box

    LVM, LVN

List view

    NM

Any parent window (notification message)

    PBM

Progress bar

    PBT

Any application (battery power broadcast)

    PSM, PSN

Property sheet

    SB

Status bar

    SBM

Scroll bar

    STM, STN

Static control

    TB, TBN

Tool bar

    TBM

Track bar

    TCM, TCN

Tab control

    TTM, TTN

ToolTip

    TVM, TVN

Tree view

    UDM

Up Down control

    WM

Generic window

What’s the difference between, say, a BM message and a BN message? A BM message is a message to a button, such as "act as though you were just clicked." A BN message is a notification from a button to the window that owns it, such as "I was clicked." The same pattern holds for all the prefixes that end with M or N in the preceding table.

Sometimes the "message" prefix does not end with M; for example CB is the prefix for a message to a combo box while CBN is the prefix for a notification from a combo box to the window that owns it. For example, CB_SETCURSEL is a message to a combo box directing it to select one of its strings, while CBN_SELCHANGE is a message sent from a combo box notifying its parent that the user has changed which string is selected.

### Commands

What is a command? It is a special type of message. Windows generates a command whenever a user chooses a menu item, clicks a button, or otherwise tells the system to do something. In older versions of Windows, both menu choices and button clicks generated a WM_COMMAND message; these days you get a WM_COMMAND for a menu choice and a WM_NOTIFY for a control notification like button clicking or list box selecting. Commands and notifications get passed around by the operating system just like any other message, until they get into the top of OnWndMsg(). At that point, Windows message passing stops and MFC command routing starts.

Command messages all have, as their first parameter, the resource ID of the menu item that was chosen or the button that was clicked. These resource IDs are assigned according to a standard pattern—for example, the menu item File, Save has the resource ID ID_FILE_SAVE.

Command routing is the mechanism OnWndMsg() uses to send the command (or notification) to objects that can't receive messages. Only objects that inherit from CWnd can receive messages, but all objects that inherit from CCmdTarget, including CWnd and CDocument, can receive commands and notifications. That means a class that inherits from CDocument can have a message map. There won’t be any entries in it for messages, only for commands and notifications, but it’s still called a message map.

How do the commands and notifications get to the class, though? By command routing. (This gets messy, so if you don't want the inner details, skip this paragraph and the next.) OnWndMsg() calls CWnd::OnCommand() or CWnd::OnNotify(). OnCommand() checks all sorts of petty stuff (like whether this menu item was grayed after the user selected it but before this piece of code started to execute) and then calls OnCmdMsg(). OnNotify() checks different conditions and then it, too, calls OnCmdMsg(). OnCmdMsg() is virtual, which means that different command targets have different implementations. The implementation for a frame window sends the command to the views and documents it contains.

This is how something that started out as a message can end up being handled by a member function of an object that is not a window, and therefore can't really catch messages.

Should you care about this? Even if you don't care how it all happens, you should care that you can arrange for the right class to handle whatever happens within your application. If the user resizes the window, a WM_SIZE message is sent, and you may have to rescale an image or do some other work inside your view. If the user chooses a menu item, a command is generated, and that means your document can handle it if that’s more appropriate. You see examples of these decisions at work in the next chapter, "Documents and Views."

## Command Updates

This under-the-hood tour of just how MFC connects user actions like window resizing or menu choices to your code is almost complete. All that's left is to handle the graying of menus and buttons, a process called command updating.

Imagine you are designing an operating system, and you know it's a good idea to have some menu items grayed to show they can't be used right now. There are two ways you can go about implementing this.

One is to have a huge table with one entry for every menu item, and a flag to indicate whether it's available or not. Whenever you have to display the menu, you can quickly check the table. Whenever the program does anything that makes the item available or unavailable, it updates the table. This is called the continuous-update approach.

The other way is not to have a table, but to check all the conditions just before your program displays the menu. This is called the update-on-demand approach and is the approach taken in Windows. In the old C way of doing things—to check whether each menu option should be grayed or not—the system sent a WM_INITMENUPOPUP message, which means "I'm about to display a menu." The giant switch in the WindProc caught that message and quickly enabled or disabled each menu item. This wasn't very object-oriented though. In an object-oriented program, different pieces of information are stored in different objects and are not generally made available to the entire program.

When it comes to updating menus, different objects "know" whether or not each item should be grayed. For example, the document knows whether it has been modified since it was last saved, so it can decide whether File, Save should be grayed or not; but, only the view knows whether or not some text is currently highlighted; therefore, it can decide if Edit, Cut and Edit, Copy should be grayed. This means that the job of updating these menus should be parcelled out to various objects within the application rather than handled within the WindProc.

The MFC approach is to use a little object called a CCmdUI, a command user interface, and give this object to whomever catches a CN_UPDATE_COMMAND_UI message. You catch those messages by adding (or getting ClassWizard to add) an ON_UPDATE_COMMAND_UI macro in your message map. If you want to know what's going on behind the scenes, it's this: The operating system still sends WM_INITMENUPOPUP, then the MFC base classes like CFrameWnd take over. They make a CCmdUI, set its member variables to correspond to the first menu item, and call one of that object's own member functions, DoUpdate(). Then, DoUpdate() sends out the CN_COMMAND_UPDATE_UI message with a pointer to itself as the CCmdUI object the handlers use. Then the same CCmdUI object is reset to correspond to the second menu item, and so on until the entire menu is ready to be displayed. The CCmdUI object is also used to gray and ungray buttons and other controls in a slightly different context.

CCmdUI has the following member functions:

- Enable()—Takes a True or False (defaults to True). Grays the user interface item if False; makes it available if True.
- SetCheck()—Checks or unchecks the item.
- SetRadio()—Checks or unchecks the item as part of a group of radio buttons, only one of which can be set at any time.
- SetText()—Sets the menu text or button text, if this is a button.
- DoUpdate()—Generates the message.

It's usually pretty straightforward to determine which member function you want to use. Here is a shortened version of the message map from an object called CWhoisView, a class derived from CFormView that is showing information to a user. This form view contains several edit boxes and the user may wish to paste text into one of them. The message map contains an entry to catch the update for the ID_EDIT_PASTE command, like this:

    BEGIN_MESSAGE_MAP(CWhoisView, CFormView)

         ...

         ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)

         ...

    END_MESSAGE_MAP()

The function that catches the update, OnUpdateEditPaste(), looks like this:

    void CWhoisView::OnUpdateEditPaste(CCmdUI* pCmdUI)

    {

     pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));

    }

This calls the API function ::IsClipboardFormatAvailable() to see if there is text in the Clipboard. Other applications may be able to paste in images or other non-text Clipboard contents, but this application cannot, and grays the menu item if there is no text available to paste. Most command update functions look just like this: They call Enable() with a parameter that is a call to a function that returns True or False, or perhaps a simple logical expression. Command update handlers must be fast, because five to ten of them must run from the moment the user clicks to display the menu to before the menu is actually displayed.

### ClassWizard Helps You Catch Commands and Command Updates

The ClassWizard dialog box shown in Figure 4.1 has the class name highlighted in the box labeled Object IDs. Below that are resource IDs of every resource (menu, toolbar, dialog box controls and so on) that can generate a command or message when this object (view, dialog, and so on) is on the screen. If you highlight one of those, the list of messages associated with it is much smaller, as you see in Figure 4.4.

Fig. 4.4

ClassWizard allows you to catch or update commands.

There are only two messages associated with each resource ID: COMMAND and UPDATE_COMMAND_UI. The first allows you to add a function to handle the user selecting the menu option or clicking the button—that is, to catch the command. The second enables you to add a function to set the state of the menu item, button, or other control just as the operating system is about to display it—that is, to update the command. (The COMMAND choice is boldface in Figure 4.4 because this class already catches that command.)

Clicking Add Function to add a function that catches or updates a command involves an extra step. ClassWizard gives you a chance to change the default function name, as shown in Figure 4.5. This is almost never appropriate. There is a regular pattern to the suggested names, and experienced MFC programmers come to count on function names that follow that pattern. Command handler functions, like message handlers, have names that start with On. Typically, the remainder of the function name is formed by removing the ID and the underscores from the resource ID, and capitalizing each word. Command update handlers have names that start with OnUpdate and use the same conventions for the remainder of the function name. For example, the function that catches ID_APP_EXIT should be called OnAppExit(), and the function that updates ID_APP_EXIT should be called OnUpdateAppExit().

Fig. 4.5

It is possible, but not wise, to change the name for your command handler or command update handler from the name suggested by ClassWizard.

Not every command needs an update handler. The framework does some very nice work graying and ungraying for you automatically. Say you have a menu item, Network, Send, whose command is caught by the document. When there is no open document, this menu item is grayed by the framework, without any coding on your part. For many commands, it's enough that an object that can handle them exists, and no special updating is necessary. For others, you may want to check that something is selected or highlighted, or that no errors are present before making certain commands available. That's when you use command updating. If you'd like to see an example of command updating at work, there's one in Chapter 9, "Building a Complete Application: ShowString," in the "Command Updating" section.

### From Here...

This chapter has provided the theory of message handling and command routing, and a behind-the-scenes look at the ways MFC implements these for you. To see this theory in action, check out the following chapters:

- Chapter 5, "Documents and Views," discusses views, documents, and frames, and the way in which they interact. Issues like which class should catch certain messages are explored in more detail here.
- Chapter 6, "Drawing on the Screen," discusses what code, if any, you should write to handle messages like WM_PAINT and WM_SIZE that indicate your window needs to be redrawn.
- Chapter 8, "Persistence and File I/O," discusses the way that documents get saved and loaded in more detail, explains why you need a Serialize() function, and illustrates the sort of code it typically contains.
- Chapter 9, "Building A Complete Application: ShowString," shows how to build your own menus and dialog boxes and assign resource IDs to interface items. You see examples of ClassWizard in action, hooking interface items to code.
- Chapter 10, "Status Bars and Toolbars," draws on what you have learned about menus to explain toolbars.

© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.