Lesson 3: MFC Application Framework

Now that you have an understanding of the Windows application architecture, you are ready to learn how MFC implements a basic Windows application.

In addition to the encapsulation of the Win32 API, MFC defines a small group of classes to represent common application objects, and establishes relationships within this group to implement fundamental Windows application behaviors. These application architecture classes, along with a number of global functions, comprise an application framework that you can use as a basis for constructing applications. You can use the MFC AppWizard to generate a set of classes that is derived from the framework classes. You can build upon these classes to construct an application to suit your individual requirements.

After this lesson, you will be able to:

  • Describe how the MFC application framework implements a Windows application.
  • Describe the role of the application class and the main window class in the application framework.
  • Describe how the AppWizard can be used to generate a basic framework application.
  • Describe how Windows messages are handled by the application framework.
Estimated lesson time: 40 minutes

MFC Application Architecture

The MFC application framework implements a basic Windows application architecture by providing:

  • A class to represent the application.
  • An implementation of the WinMain() function.
  • A class to represent the main application window.

Application Class

The MFC class CWinApp represents the application as a whole. CWinApp is derived from CWinThread, the class that represents a thread in an MFC application. CWinApp represents the primary thread of an application's process, and encapsulates the initialization, running, and termination of a Windows-based application. These behaviors are implemented by the member functions described in Table 3.3.

Table 3.3 CWin App Member Functions

CWinApp member function Purpose
InitInstance() Initializes each new instance of your application running under Windows. Displays the application's main window.
Run() Provides the implementation of the message loop.
OnIdle() Called by the framework when no Windows messages are being processed. You can override this function to perform background tasks.
ExitInstance() Called each time a copy of your application terminates.

An application built on the MFC framework must implement exactly one class derived from CWinApp. You must also provide your own overridden version of the InitInstance() member function. The InitInstance() function is called directly by the WinMain() function, and is the proper location for initialization specific to your application.

WinMain() Function

The framework provides a standard WinMain() function for your application. WinMain() calls a number of global functions to perform standard initialization services such as registering window classes. It then calls the InitInstance() member function of the application object to initialize the application. Next WinMain() calls the Run() member function of the application object to run the application message loop. The message loop will continue to acquire and dispatch messages until a WM_QUIT message is received, at which point it calls the application object's ExitInstance() function and returns. WinMain() will then call cleanup routines and terminate the application.

Main Window

An essential component of a Windows application is the main window, which represents the principal interface to your application. This might be a simple dialog box; or it might be a frame window, which is a resizable window that houses the application menu, the toolbars, and the window client area. In either case, a framework application should provide a class—derived from the CDialog class or from the CFrameWnd class—that the application can use to create the main window object. The main window is initially displayed by the application object's InitInstance() function.

As an exercise, return to the MyApp project you created in Chapter 2 to view the framework classes that have been created for you.

  • To view the MyApp framework classes
    1. Open the MyApp workspace by clicking Open Workspace on the File menu. If you saved your work in the default directory, the workspace name will appear in the list. If not, navigate to where you saved the workspace. Double-click CMyApp.dsw to open the workspace.
    2. In ClassView, expand the first item in the list, MyApp classes (if it is not already expanded), to view the classes created for this project by the AppWizard.
    3. Expand the CMyAppApp class to view the overloaded methods created by the AppWizard for this class. Your Workspace pane should now look like Figure 3.4.
    4. Figure 3.4 The MyApp project ClassView

    5. Double-click CMyAppApp to view the class declaration. Note how this class is derived from the MFC class CWinApp.
    6. Double-click InitInstance() to view its source code. Look through the code and the comments to gain an idea of the sort of initializations that are performed by this function. The implementation of InitInstance() that the AppWizard generates will perform initializations in accordance with the options you chose while stepping through the AppWizard.

    Application Framework Message Handling

    In Lesson 2, you learned that one of the key tasks of Windows application development is the mapping of system messages to routines that will handle them. In Win32 applications constructed without MFC, you supply a window procedure for each type of window class that is registered. These window procedures are often implemented as switch statements based on the value of the message ID. In an application based on the MFC framework, messages are handled by member functions of the application's classes. These can be classes that you create yourself or classes generated by the AppWizard for your application. The mapping of messages to their appropriate handler function is achieved by the use of message maps.

    Message Maps

    A message map is a table, declared within a class definition, that maps system messages to the member functions of the class. The message map contains entries that link the message IDs to the handler functions. The message map recognizes four types of messages, as described in Table 3.4.

    Table 3.4 MFC Message Types

    Message type Description
    Windows Windows messages are generated by the operating system. They inform the application about window creation, impending window destruction, mouse and keyboard events, changes to the system colors, and anything else that can affect the operation of the application. The identifiers for these mes- sages generally begin with the WM_ prefix. Windows messages are usually handled by the window to which Windows sends the message, such as an application's main frame window, or by a dialog box.
    Command Command messages are generated from user interaction with the user interface—for example when the user selects a menu item, clicks a tool- bar button, or presses a shortcut key. When one of these events occurs, a WM_COMMAND message with command-specific parameters is sent to the application. Command messages are routed by the framework to the application objects. This command routing is a feature that allows the application to handle the message in the class most closely associated with the message.
    User interface update command User interface update command messages are generated from within an application by the application framework—that is, they are MFC-specific. They signal the application to update the status of user interface elements such as menu items or toolbar buttons. For example, before a menu is dis- played, the application framework will send the application an appropriate update command message that gives the application the opportunity to modify the menu command state—whether it should be available, unavailable, or displayed with a check mark.
    Control notification Control notification messages are sent from controls and other child windows to their parent windows. These are generally sent as WM_COMMAND messages with control notification parameters. For example, an edit control sends its parent a WM_COMMAND message containing the EN_CHANGE control notification code when the user has taken an action that might have altered text in the edit control.

    Creating Message Maps

    MFC makes it easy to implement message maps. Any class that is derived from the CCmdTarget class is capable of supporting a message map. All the framework classes generated with the AppWizard will be created with a basic mes- sage map structure. You can use the ClassWizard tool to create new classes that implement message maps and to maintain the message maps of existing classes by adding and removing message map entries. Use ClassWizard to maintain your classes' message maps wherever possible to save time and to ensure that the message maps are correctly implemented.

    Adding Handler Functions Using ClassWizard

    In this section, you will learn how to use ClassWizard to add handlers for a Windows message and for a command message. In subsequent chapters, you will learn how to implement user interface update command messages and control notification messages. By looking at the code that is generated, you will learn how message maps are implemented in an MFC application.

    In the following exercise, you will add a handler to display a message box when the user clicks in the client area of your MyApp application window. The client area is the area enclosed by the frame window, where application data is usually displayed.

  • To add a handler for a Windows message
    1. Return to the MyApp project.
    2. Press CTRL+W to open ClassWizard. Click the Message Maps tab.
    3. In the Class Name list, click CMyAppView. This indicates that you want to handle a message sent to the application's view class. The view class encapsulates the main window's client area.
    4. In the Object IDs list, click CMyAppView.
    5. In the Messages list, click WM_LBUTTONDOWN. This message is sent to the application when a user clicks the left mouse button in the window client area.
    6. Click Add Function. ClassWizard creates a stub function to which you can add your own code. All Windows messages are handled by overloaded virtual functions on the CWnd base class. The name of the overloaded virtual function will start with "On" and is followed by the name of the message, with the initial "WM_" removed, and only the first letter of each word capitalized. In this case, the stub function created is named OnLButtonDown().
    7. Click Edit Code. The MyAppView.cpp file is opened and the insertion point is positioned at the top of the OnLButtonDown() function implementation.
    8. Replace the // TODO comment line with the following code:
    9. AfxMessageBox("You clicked?");

      so that your code reads as follows:

      void CMyAppView::OnLButtonDown(UINT nFlags, CPoint point)  {      AfxMessageBox("You clicked?");      CView::OnLButtonDown(nFlags, point); }

    10. Press F7 to build the MyApp project, and then press CTRL+F5 to run the application. Click with the left mouse button in the application client area to test that the WM_LBUTTONDOWN message is handled as expected. Close the MyApp application.

    In the following exercise, you will add a handler for a command message that is generated when the user clicks Paste on the Edit menu in the MyApp application.

  • To add a handler for a command message
    1. From within the MyApp project, press CTRL+W to open ClassWizard. Click the Message Maps tab.
    2. In the Class Name list, click CMyAppApp. Remember that command messages can be handled by any of the application classes. Because our handler function does very little, we will make it a member of the application class. The class most closely associated with the command should handle command messages. For example, the CMainFrame class would best handle a command that simply modifies attributes of the main frame window, such as hiding or showing a toolbar.
    3. In the Object IDs list, click ID_EDIT_PASTE. This is the command ID that is passed as a parameter of the WM_COMMAND message generated when Paste is clicked on the Edit menu.
    4. In the Messages list, click COMMAND. This indicates that we are to handle a command message and not a user interface update command message.
    5. Click Add Function. A dialog box appears, suggesting the name OnEditPaste() for your handler function. This is because you are defining a new function to handle the message rather than overloading an existing virtual function of the parent class. Click OK to accept the name.
    6. Click Edit Code. The MyAppView.cpp file is opened and the insertion point is positioned at the top of the function implementation.
    7. Replace the // TODO comment line with the following code:
    8. AfxMessageBox("MYAPP does not support the Paste command");

      so that your code reads as follows:

      void CMyAppApp::OnEditPaste()  {      AfxMessageBox("MYAPP does not support the Paste command"); }

    9. Build and run the CMyApp application. Click Paste on the Edit menu to test that your handler function behaves as expected. Note that the framework disables menu items for commands for which you haven't provided handlers.

    Understanding the Message Map Code

    When you use ClassWizard to add handler functions, it automatically performs the following tasks for you:

    • It declares the handler function in the class header file.
    • It creates a handler function stub in the class implementation file.
    • It adds an entry for the handler to the message map.

  • To see the declaration for the CMyAppApp::OnEditPaste() function
    1. In ClassView, double-click CMyAppApp to view the class definition in the file MyAppApp.h.
    2. Locate the code toward the bottom of the class definition that reads:
    3. //{{AFX_MSG(CMyAppApp) afx_msg void OnAppAbout(); afx_msg void OnEditPaste(); //}}AFX_MSG DECLARE_MESSAGE_MAP()

    Note the DECLARE_MESSAGE_MAP macro. This is an essential part of the message map implementation and is added to the class by the AppWizard or ClassWizard. You will learn how to create classes using ClassWizard in subsequent chapters.

    You have already seen, and added code to, the function stub that ClassWizard provides.

  • To view the message map entry for the CMyAppApp::OnEditPaste() function
    1. Return to the CMyApp.cpp file. If it has been closed, you can open it by double-clicking the OnEditPaste() function icon in ClassView (beneath the CMyAppApp class icon).
    2. Near the top of the CMyApp.cpp file is the message map that looks like this:
    3. BEGIN_MESSAGE_MAP(CMyAppApp, CWinApp)      //{{AFX_MSG_MAP(CMyAppApp)      ON_COMMAND(ID_APP_ABOUT, OnAppAbout)      ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)      //}}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()

    You can see that ClassWizard has added an ON_COMMAND entry macro to the message map. The structure of this macro is quite straightforward. The first parameter is the ID of the command. (You will learn more about assigning command IDs in the next chapter.) The second parameter is the name of the handler function.

    The OnLButtonDown () function handles the WM_LBUTTONDOWN message and is declared in MyAppView.h as:

    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

    The corresponding message map entry in MyAppView.cpp is:

    ON_WM_LBUTTONDOWN()

    Because Windows messages are handled by overloaded virtual functions on the CWnd base class, there is no need to supply the handler function name as a parameter. The MFC framework automatically maps the message to the appropriate virtual function. Windows messages often have additional information attached to them in the form of parameters. The framework will take care of extracting the information from these parameters and passing it to the handler functions. If you look at the CMyApp::OnLButtonDown function declaration, you will see that it takes the following: two parameters, derived from the WM_LBUTTONDOWN message parameters, which indicate the current screen position of the mouse pointer; and a flag value to indicate whether any of the "virtual keys" (for example, CTRL or SHIFT) are also being depressed.

    Message Map Entry Macros

    MFC defines four message map entry macros, listed in Table 3.5, to correspond to the four types of messages that can be handled by the message map.

    Table 3.5 Message Map Entry Macros

    Message type Macro form Parameters
    Standard Windows message ON_WM_XXX (where XXX is the name of the message) None
    Command message ON_COMMAND Command ID, Handler Name
    Update command ON_UPDATE_COMMAND_UI Command ID, Handler Name
    Control notification ON_XXX (where XXX is the name of the parameter indicating the control notification) Control ID, Handler Name

    You may have noticed that all ClassWizard-generated code is placed within comment blocks beginning with {{AFX_MSG and ending with }}AFX_MSG. These tags denote areas that are modified by ClassWizard. You are allowed to add message map entries or handler function declarations manually, but you should add them outside of these sections. Failure to do so might result in improper functioning of ClassWizard. The AFX_MSG modifier that precedes the handler declaration is also used by ClassWizard. As far as the compiler is concerned, it has no value.

    Deleting Message Map Entries

    If you use ClassWizard to delete message map entries, it will also delete the function declaration in the class header file. It will not delete the function implementation, which might contain code that you have written.

  • To remove the CCMyAppApp::OnEditPaste() function
    1. From within the CMyApp project, press CTRL+W to open ClassWizard. Click the Message Maps tab.
    2. In the Class Name list, click CCMyAppApp.
    3. In the Member functions list, click OnEditPaste.
    4. Click Delete Function. A message box appears, warning you that you must delete the function implementation yourself. Click Yes.
    5. Click OK to close ClassWizard.
    6. Locate the function implementation in MyApp.cpp and delete it.
    7. Build and execute the application to ensure you removed the function properly and to see the effect on the Edit menu.

    Command Routing

    You will recall that command messages are routed by the framework to the application objects. This command routing feature allows the application to handle the message in the class most closely associated with the message. The MFC application framework routes commands through a standard sequence of command-target objects (defined by the classes in your application that are derived from CCmdTarget and implement message maps) to see if any of them provide a handler for the command. Each command-target object checks its message map to see if it can handle the incoming message.

    This command routing sequence can sometimes be used to your advantage. For example, you can set up an application shortcut key to send a command message with ID_SAVE_WINDOW_STATE. This shortcut key indicates that the user wants to save the current window's settings. Some window objects in the system might provide their own implementations of the associated handler function OnSaveWindowState(). Other windows, such as temporary dialog boxes and help screens, might not. The command routing sequence will check the message map of the currently active window to see if it implements the function OnSaveWindowState(). If it does not, the message map of the parent window will be checked. If that does not provide a handler, the message map of the application object can be checked.

    The command routing sequence varies according to context. To find out more about command routing, search for "command routing" in the Visual C++ Help file.

    Lesson Summary

    The MFC application framework is a small group of interrelated classes that, together with a number of global functions, implement a basic Windows application. Using the AppWizard, you can easily generate a set of classes, derived from the framework classes, on which they can build an application to suit their own particular requirements.

    The framework classes include the CWinApp class, which encapsulates the application as a whole. It exposes several functions that are called by the frame-work's implementation of the WinMain() function to handle the initialization, running, and termination of a Windows-based application. The CFrameWnd class encapsulates a frame window, which is a main application window that is capable of hosting application menus, toolbars, and a window client area.

    In an application based on the MFC framework, messages are handled by member functions of the application's classes. The mapping of messages to their appropriate handler function is achieved by the use of message maps, a feature supported by classes derived from the MFC class CCmdTarget. Message maps are tables that are declared within a class definition to link message IDs to member functions of the class. You should use the ClassWizard tool to add and remove message map entries.

    In this lesson, you learned how to use ClassWizard to add handlers for Windows messages. Windows messages are generated by the operating system to inform the application of changes in the Windows environment. These changes include mouse and keyboard events and command messages. Command messages are generated by user interaction with user interface elements such as menus and toolbars.

    Command messages are routed by the framework to the application's command target objects in a specific sequence until an object is found that provides the appropriate handler. This command routing is a feature that allows the application to handle the message in the class most closely associated with the message.



    Microsoft Press - Desktop Applications with Microsoft Visual C++ 6. 0. MCSD Training Kit
    Desktop Applications with Microsoft Visual C++ 6.0 MCSD Training Kit
    ISBN: 0735607958
    EAN: 2147483647
    Year: 1999
    Pages: 95

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net