17. More about AppExpress
Chapter 4, "Generating an Application Framework," defines an application framework and outlines the steps for generating a skeleton application using AppExpress. This companion reference chapter provides further detail concerning application types, program detail, program architecture, message maps, as well as generating and examining source files.Selecting an Application Type
Select Application Type from the list of steps at the upper left of the AppExpress window. The options pane at the right contains three groups of controls, labeled Applications, OLE Options, and Project Options.
[Figure 17-1 AppExpress application type options
Applications
The group of Applications radio buttons contains six categories of applications. Of these, only Quick Console does not use the MFC library. These categories are:- Quick Console: The kind of application generated is determined by whether the 32-Bit Project box in the Project Options group is checked. See the information on the Project Option group later in this section.
- Dialog Box: This standard Windows dialog box can be either modal or modeless and can include dialog box controls such as push buttons, textboxes, and listboxes.
- Form or Database: This is a window with the functionality of a dialog box enhanced with scroll bars. It is appropriate for dialog boxes that have more than one screen of controls.
- Single Document Interface (SDI): This application uses a single window in which the application data is displayed. The OLE Options group of controls is enabled if this application type is selected.
- Multiple Document Interface (MDI): This application lets you display more than one window of data within a parent frame window. The OLE Options group of controls is enabled if this application type is selected.
- OCX Control in MFC: This template is for a custom control that is an OLE2 object.
OLE Options group
The OLE Options group is enabled only if you select the SDI or MDI application type. The group contains four radio buttons:- No Support: The application is not OLE-aware: it is neither a server nor a container. This option is the default.
- Server: The generated application acts as an OLE2 server. An OLE2 server can create or edit data, which OLE2 containers can link to or embed.
- Container: A host application. The generated application can contain OLE2 server data elements (OLE2 objects) within this host application's data.
- Server & Container: The generated application acts as both an OLE2 server and as an OLE2 container.
Project options group
The Project Options group contains two check boxes, Include Help and 32-Bit Project.Checking Include Help tells AppExpress to generate the files necessary to build a Windows Help file for the specified application type. AppExpress creates a Help subdirectory named hlp beneath the project directory, which contains those files. It also creates the file makehelp.bat, which you run to compile a Windows Help file from the files AppExpress provides.
For all application types other than Quick Console, checking the 32- Bit Project box causes the MFC 3.0 to be used instead of the 16-bit MFC 2.5.
For Quick Console, leaving the box unchecked results in a skeleton WINIO program being generated. WINIO is a library that allows you to write simple Windows programs that perform input/output using standard C library functions (in other words, those functions prototyped in stdio.h.). If the 32-Bit Project box is checked, a Win32 console application is generated. Win32 console applications can only be run under Windows NT and Windows 95 (and not under Win32s).
If you check the 32-Bit Project box, your application can call the Win32 API.
Providing Miscellaneous Information
Selecting Miscellaneous in the steps list opens the Miscellaneous options page. This page lets you provide copyright information as well as a name for the project.- In the first three fields, provide a company name, suffix, and copyright year.
- In the Project Name field, type a name for the project. (This name is also referred to as the Windows module name.)
The Document/View Architecture
The MFC library provides a number of C++ classes that, when used together, create the object-oriented structure for your application. These are the document, view, frame window, and document template classes. The Form or Database, SDI, and MDI application types all use document/view architecture. This section introduces the MFC classes that implement this program structure.Frame window
The frame window contains views on the data used by the application. In an SDI application, there is only one frame window, which is derived from the MFC class CFrameWnd. In an MDI application, there is a main frame window derived from CMDIFrameWnd, as well as document frame windows derived from CMDIChildWnd.In addition to containing child view windows, the frame window handles all window management- for example, minimizing, maximizing, and closing the window. A standard toolbar and status bar also are displayed in this window.
View
Each frame window can contain a view on the data used by the application. A view is a C++ class derived from the class CView. Your application interacts with the user through this view class.In the SDI frame window, AppExpress generates a child view window that takes up the client area of the frame window. (The client area refers to the part of the window in which the program's data is displayed. It excludes the window border, caption, and menu.) In an SDI application, this view window is given the default class name CSDIAPPView. All display and printing of the application's data is done using this view window and its class. The user's manipulation of the data is also done through the view.
Document
A document is a C++ class, derived from CDocument, that represents the data in your application. For example, a standard Windows application has a File menu that is a variant of the one shown in Figure 17-2.
[Figure 17-2 Standard Windows file menu] When you choose Open from this menu, you are telling the program to open a document.
Note: The word document refers to whatever type of data is used by the application. It does not necessarily mean a text-based word processing document.
As the developer of the application, you write code in a CDocument-derived class to handle the operations on the File menu. An example of a skeleton CDocument-derived class follows.
class CSDIAPPDoc : public CDocument { protected: // create from serialization only CSDIAPPDoc(); DECLARE_DYNCREATE(CSDIAPPDoc) // Attributes public: // Operations public: // Implementation public: virtual ~CSDIAPPDoc(); virtual void Serialize(CArchive& ar); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump( CDumpContext& dc) const; #endif };Notice that no member variables are included with this class. It is up to you as the developer to add whatever data you need for your application.
In the example above, a Serialize method is included in the Implementation section of the class definition. This method, inherited from the base class, CDocument, performs object storage and retrieval to and from a disk file. In fact, the framework generated by AppExpress already handles the File Open, File Save, and File Save As operations by automatically calling the Serialize method in your CDocument-derived class. You can use the Serialize method to implement object persistence- the ability to preserve the complete state of objects across multiple executions of the program.
When you add your own member variables to this class, you should also override the Serialize method to read and write the added variables.
Pulling it all together: the document template
Creating and managing an application's frame window, views, and documents is the job of another C++ class, derived from the CDocTemplate class. In an SDI application, the CSingleDocTemplate class is used; in an MDI application, the CMultiDocTemplate class is used.For more information, refer to the Microsoft Foundation Class Library Reference.
More about Message Maps
This section outlines the purpose of message maps and identifies the different parts of a message.The rationale for maps
Using message maps saves you development time. The reason for this productivity improvement lies in the event-driven nature of Windows applications.As a user of a Windows application clicks on buttons, selects menus, drags the mouse to highlight text, or performs any other mouse or keyboard action, the application is notified of this action through a Windows message. This message contains pertinent contextual information such as the screen coordinates at which the mouse was clicked, or an identifier indicating the button that was clicked.
The application developer decides which messages the application should respond to and how. If the developer decides not to write code to handle a particular message, the message can still be passed back to Windows to perform default processing.
If you write a Windows application using the Windows SDK, these decisions are most likely implemented as a switch statement in the main window procedure (usually referred to as a WndProc). For example, your window procedure might look like this:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_PAINT: PAINTSTRUCT ps; BeginPaint(hwnd, &ps); MyPaintProc(hwnd, ps. hdc); EndPaint(hwnd, &ps); return(0); case WM_CREATE: hmenu = GetSystemMenu(hwnd, FALSE); AppendMenu(hmenu, MF_SEPARATOR, 0, (LPSTR) NULL); AppendMenu(hmenu, MF_STRING, IDM_ABOUT, "About..."); break; case WM_DESTROY: PostQuitMessage(0); return(0); } return DefWindowProc(hwnd, message, wParam, lParam); }If your application must respond to many types of messages, the window procedure can get quite large and become difficult to maintain. One of the advantages of the MFC library is the use of message maps, which drastically reduce the amount of code required to process messages.
Components of the message map
A message map is composed of the three components described in this section.BEGIN_MESSAGE_MAP, END_MESSAGE_MAP macros
All message maps must begin and end with these macros. At run-time, the expanded macro sets up the message mapping between events and the code to handle the events.ClassExpress-specific comment sections
AppExpress and ClassExpress add special-purpose comments to the message map so that ClassExpress knows where to add or remove mapping macros. Because ClassExpress provides an easy-to-use interface to your C++ class mappings, you should not manually edit the comments or code in a message map.Message-mapping macros
If a C++ class has a method (that is, a class member function) to respond to a message, ClassExpress writes a message-mapping macro for that message in the class's message map. This macro begins with the prefix ON_, usually followed by the macro name for the Windows message. The mapping macro takes two parameters:- The message identifier.
- The method that is called when the message event
occurs at run-time.
For example:
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
This macro sets up a linkage between the Windows message WM_COMMAND and the method OnFilePrint. This method is only called, however, if the WM_COMMAND parameter (in this case, the wParam) is equal to ID_FILE_PRINT. This mapping macro is equivalent to the following case statement in a window procedure:case WM_COMMAND: if (wParam == ID_FILE_FORMAT) CView::OnFilePrint();
Having the Express tools generate message maps lets you concentrate on the specific function of the application without having to worry about syntactical issues.
Generating and Examining the Source Files
Generating the source files of the application framework is as easy as clicking on a button. After the files are generated, you may want to examine the header and implementation files. AppExpress typically generates one header and one implementation file for each class. (An exception is the CAboutDlg class, which shares files with the application class.) Examining a few generated files in the IDDE, setting breakpoints on methods, and tracing through their code will help you understand the internal workings of the frameworks that AppExpress generates. At that point you will then be ready to edit the code in order to enhance it as needed.To generate and examine sample source files:
- Launch AppExpress from the IDDE Tools menu, and make all the selections necessary to create an SDI application. When you click on Finish, AppExpress generates all the source files for this skeleton program. When it is done, AppExpress gives control to the IDDE (with the new project open), and then closes.
- Open the Project window in the IDDE by clicking the Project View icon and dragging it onto the desktop, or by pressing Ctrl+ Shift+ P.
- Double-click on the filename mainfrm.h. A Source window opens containing the header file mainfrm.h. (For more information on Source windows, see Chapter 2, "Introducing the IDDE.")
// mainfrm.h : interface of the CMainFrame class // // Copyright (c) XYZ Corporation, 1994. All Rights Reserved. // // class CMainFrame : public CFrameWnd { protected: // create from serialization only CMainFrame(); DECLARE_DYNCREATE(CMainFrame) // Attributes public: // Operations public: // Implementation public: virtual ~CMainFrame(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // control bar embedded members CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; // Generated message map functions protected: //{{ AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); // ClassExpress will add and remove member functions here. // DO NOT EDIT these blocks of generated code ! //}} AFX_MSG DECLARE_MESSAGE_MAP() };The file contains:
- A file header that uses the company name, suffix, and copyright year that you specified in AppExpress
- The CMainFrame class declaration
In the protected section of the class declaration is a prototype for a function that is called as part of the class's message map. As indicated, do not edit the code in this section because it is reserved for ClassExpress.
AppExpress also generates a .cpp, or implementation, file for the CMainFrame class. This file has the same base name, mainfrm, as the class header file, but has the .cpp extension. To examine mainfrm.cpp, open this file in an IDDE Source window. This implementation file contains the following components:
- A file header.
- Preprocessor include statements for the required header files.
- A declaration of the CMainFrame message map containing a single entry (for the Windows WM_CREATE message).
- Static array data for initialization of the toolbar and status bar.
- The definitions of the CMainFrame constructor and destructor functions. Notice the comment in the constructor indicating where to add member initialization code. Edit these functions to insert initialization and shutdown code for object instantiation.
- The definition of the class's method, OnCreate, for handling WM_CREATE messages.
- The definitions of two functions- AssertValid and Dump- that may be used during debugging.
- A final comment indicating where ClassExpress will add stub methods for new entries in the CMainFrame message map.