[Home]
[Contents]
[Prev]
[Next]
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.
The application types vary in the amount of functionality that
AppExpress generates as part of the skeleton program. For example,
SDI applications contain only one window, while MDI applications
contain a main window and a variable number of child windows.
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.)
Note:
The module name is recorded in the module
definition file generated by AppExpress. It can be
changed by using the Project Settings dialog box,
opened from within the IDDE by choosing Settings
from the Project menu.
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.")
This file, which AppExpress generated, contains the definition of the
class CMainFrame. It is reproduced in its entirety below.
// 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 class declaration, notice that the status bar and toolbar are
represented by class member variables, each of which is an instance
of yet another C++ class. When writing code to manipulate the
toolbar and status bar, reference these member variables.
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.
The next chapter covers ClassExpress, one of the
tools (along with the Resource Studio) used to enhance
an application generated by AppExpress.