11. Lesson 2: Generate an Application Framework
In this chapter you begin the process of building a Windows version of the TML Reader. This version is built around a Microsoft Foundation Class (MFC) version 2.5 Single Document Interface (SDI) framework. In this lesson you:- Use AppExpress to generate a new project containing the SDI framework
- Build and run the bare application framework, a standardized skeleton composed of C++ classes derived from MFC library base classes.
- Use precompiled headers to speed build time
- Add calls to the TRACE macro with Class Editor
- Follow TRACE output in the Trace Messages window
There are many ways to create an application framework. This lesson provides the most straightforward way.
Generating the Framework
In this lesson you use AppExpress to generate a new project containing an application framework. To start AppExpress:- Start the IDDE and close any open project by choosing Close from the Project menu.
- Start AppExpress by choosing AppExpress from the Tools menu.
[Figure 11-1 Setting up an SDI application with AppExpress]
AppExpress contains six pages of options that together define the project to be generated. You define these options in six steps, listed in the upper-left portion of the window. For this project, you need to change options on only four of the six pages. Set up the project options as follows:
- On the Application Type page (shown when AppExpress is started), select SDI.
- Deselect Include Help to suppress generation of Windows Help support.
- Click on Next to switch to the Select Directory page. Change to the samples\tutorial\lesson2 directory under the directory in which you installed Digital Mars C++, then click on Create New Directory.
- Type start in the textbox and click Create.
Note: To avoid filename conflicts, it is a good idea to keep each project you create in a separate directory.
- Click on Next to switch to the Miscellaneous page. Type your company name and suffix (or your own name) in the appropriate textboxes. This information is displayed in the automatically generated About dialog box, and in comments at the beginning of each source file.
- In the Project Name textbox, type TMLRead.
- Click on Next to switch to the Names page. You can customize the names of automatically generated classes here. From the Name drop-down list, select CTMLReadApp. In the Edit textbox, type CTMLReadApp.
- Click Finish.
- Source and header files for the MFC-derived classes
- Resource script and binary files
- Project options and other support files
Building and Running the New Project
Next you build the project and learn what the default application framework can do.- From the IDDE's Project menu, choose Rebuild All.
- From the Project menu, choose Execute Program.
[Figure 11-2 New application framework generated by AppExpress]
At present, default functionality for several menu commands is provided by the MFC base classes. For example, if you choose Open from the File menu, a standard Windows File Open dialog box opens. You can select a file in this dialog box, but the code needed to read data from the file is not yet installed.
To close TMLRead and return to the IDDE, choose Exit from the File menu.
The project can take a considerable amount of time to compile. Next you learn how to decrease compilation time by using precompiled headers.
Using Precompiled Headers
In the last section, over 70,000 lines of code were read during compilation. Many of these lines are in Windows and MFC header files that are changed infrequently (if ever), but still must be included by almost every source file. To speed compilation, you can precompile header files; thereafter, the symbols generated by the compiler can be loaded directly.To precompile the Windows and MFC header files:
- Choose Settings from the Project menu. The Project Settings dialog box opens.
- Click on the Build tab.
- In the left listbox, click on Header Files.
- In the Precompile section of the right pane, select Specific Header.
- In the textbox below the Specific Header selection, type
stdafx.h.
Note: You can specify multiple specific headers to precompile by entering in this textbox a list of their names separated by semicolons or spaces.
[Figure 11-3 Using precompiled headers]
- Click OK.
- An Editor/Browser message box is opens, noting that project settings have changed and asking if you want to reparse all files. Click No, because you are about to build in the next step, which will stop any parse in progress.
- From the IDDE Project menu, choose Rebuild All.
Now that you have created, compiled, and executed the application framework, the rest of the chapter helps you to understand the framework's structure. The following three sections are optional.
Adding TRACE Calls with Class Editor
In the remainder of this chapter, you investigate calls to member functions of the MFC-derived classes created by AppExpress to understand the structure of the application framework and the relationships between the classes. To do this, you use the Class Editor to insert calls to the MFC global TRACE macro into the member functions, then watch the output in the Trace Messages window.To add a TRACE call to the application class's constructor:
- Choose Class Editor from the Goto View submenu of the IDDE Window menu. The Class Editor window opens (see Figure 11-4).
- Under Classes, click on CTMLReadApp. The application class's members appear in the Members list.
- Under Members, double-click on CTMLReadApp. The application class constructor's source code is shown in the source pane.
- Add the following line to the constructor:
TRACE("CTMLReadApp::CTMLReadApp()\n");
The constructor should now appear as follows:////////////////////////////////////////////////////////////////// // CTMLReadApp construction CTMLReadApp:: CTMLReadApp() { TRACE("CTMLReadApp::CTMLReadApp()\n"); // TODO: add construction code here, // Place all significant initialization in InitInstance }
- Press Ctrl+S to save the modified constructor.
[Figure 11-4 Adding TRACE calls with Class Editor]
You can add similar TRACE calls to these other member functions:
- CTMLReadApp::InitInstance()
- CMainFrame::CMainFrame()
- CMainFrame::~CMainFrame()
- CMainFrame::OnCreate()
- CTMLReadDoc::CTMLReadDoc()
- CTMLReadDoc::~CTMLReadDoc()
- CTMLReadDoc::OnNewDocument()
- CTMLReadDoc::Serialize()
- CTMLReadView::CTMLReadView()
- CTMLReadView::~CTMLReadView()
- CTMLReadView::OnDraw()
In the next section you execute the application and watch the TRACE output in the Trace Messages window.
Watching TRACE Output in the Trace Messages Window
To watch TRACE output, first you must set up the Trace Messages window to receive and display TRACE messages.- Choose Trace Messages from the Goto View submenu of the IDDE's Window menu. The Trace Messages window opens.
- Choose Output to Window from the Options menu of the Trace Messages window.
- Choose MFC Debug Messages from the Options menu. The MFC Trace Debug Options dialog box opens.
- Check Enable Tracing and uncheck any other options that are checked. Click OK.
- Choose Execute Program from the IDDE's Project menu.
- The IDDE is minimized and the application window opens. Double-click on the IDDE icon to reopen the IDDE windows. Position the windows so you can watch the Trace Messages window while the program executes.
When you close TMLRead, the Trace Messages window receives messages from the application's class destructors.
[Figure 11-5 TRACE output in the Trace Messages window]
The next section gives an overview of the classes in the application framework and explains the messages you see in the Trace Messages window.
The Application Framework and MFC Classes
In this chapter, you have used AppExpress to build an application framework, a skeleton on which you can build a Windows application, consisting of C++ classes contained in and derived from classes in the Microsoft Foundation Class (MFC) library.The MFC library is a C++ class library that supports programming for Windows. It encapsulates most of the Windows Application Programming Interface (API), and provides additional C++ programming support such as container and string classes. The MFC library makes it easy to work with Windows elements in an object-oriented manner. For example, MFC library classes exist to represent objects such as windows, dialog boxes, controls, device contexts, Graphic Device Interface (GDI) objects, and so on. Windows API functions are implemented as member functions of the classes with which they are logically associated.
TMLRead is built on a Single Document Interface (SDI) framework. The SDI framework contains five fundamental objects:
- Document:
- The document contains data, reads the data from disk, and provides access to the data. In TMLRead, the document is an object of type CTMLReadDoc, derived from the MFC library class CDocument.
- View:
- The view displays the data contained by the document. In TMLRead, the view is an object of type CTMLReadView, derived from the MFC library class CView (which is, in turn, derived from CWnd, the base class for all types of windows).
- Document Template:
- The document template defines the association between document and view classes. In an SDI application, this is an object of type CSingleDocTemplate.
- Frame Window:
- The frame window object is the application's main window. In TMLRead it contains a toolbar, a status bar, and the view. The frame window is an object of type CMainFrame, derived from the MFC library class CFrameWnd.
- Application:
- The application object creates and controls the other objects, and takes care of general program initialization and cleanup. In TMLRead the application is an object of type CTMLReadApp, derived from the MFC library class CApplication.
The TRACE output from the previous section lets you see the creation, use, and destruction of objects in the application. For example, when you start the application, you see the following messages:
[00001] NOTIFY(StartTask) [00002] CTMLReadApp::CTMLReadApp() [00003] CTMLReadApp::InitInstance() [00004] CTMLReadDoc::CTMLReadDoc() [00005] CMainFrame::CMainFrame() [00006] CMainFrame::OnCreate() [00007] CTMLReadView::CTMLReadView() [00008] CTMLReadDoc::OnNewDocument() [00009] CTMLReadView::OnDraw()The application object is created first. Using a document template, the application object creates the document, frame window, and view objects. It then calls the document object to set up a new document. Finally, when the window is shown, the framework calls the view's OnDraw() function to repaint the window.
If you choose New from TMLRead's File menu, you see the following messages:
[00010] CTMLReadDoc::OnNewDocument() [00011] CTMLReadView::OnDraw()Or, if you choose Open from the File menu, then select a file, you see:
[00012] CTMLReadDoc::Serialize() [00013] CTMLReadView::OnDraw()The document object is called either to create a new document or to read a document from a file, depending on the menu item that was chosen. Note that neither the document object nor the view object is destroyed; in an SDI application, they are reused continually.
When you choose Exit from TMLRead's File menu, the application's objects are destroyed in reverse order in which they were created. You see these messages in the Trace Messages window:
[00014] CTMLReadView::~CTMLReadView() [00015] CMainFrame::~CMainFrame() [00016] CTMLReadDoc::~CTMLReadDoc() [00017] NOTIFY(ExitTask) [00018] NOTIFY(DelModule)There is no message from the application object's destructor, because it is not defined explicitly in the framework.
You may find it useful to continue to add TRACE calls to the application as it is built. It is often difficult to follow the workings of a message-driven system; the Trace Messages window, however, acts as a kind of passive debugger that keeps you informed of the internal workings of your application.
In the next chapter, you begin to shape the application framework to the specific needs of the application. The first step in this process is to customize the user interface with the Resource Editor.