Special Edition Using Visual C++ 6

Previous chapterNext chapterContents


- 1 -

Building Your First Windows Application


Creating a Windows Application

Visual C++ doesn't just compile code; it generates code. You can create a Windows application in minutes with a tool called AppWizard. In this chapter you'll learn how to tell AppWizard to make you a starter app with all the Windows boilerplate code you want. AppWizard is a very effective tool. It copies into your application the code that almost all Windows applications require. After all, you aren't the first programmer to need an application with resizable edges, minimize and maximize buttons, a File menu with Open, Close, Print Setup, Print, and Exit options, are you?

AppWizard can make many kinds of applications, but what most people want, at least at first, is an executable (.exe) program. Most people also want AppWizard to produce boilerplate code--the classes, objects, and functions that have to be in every program. To create a program like this, Choose File, New and click the Projects tab in the New dialog box, as shown in Figure 1.1.

FIG. 1.1 The Projects tab of the New dialog box is where you choose the kind of application you want to build.

Choose MFC AppWizard (EXE) from the list box on the left, fill in a project name, and click OK. AppWizard will work through a number of steps. At each step, you make a decision about what kind of application you want and then click Next. At any time, you can click Back to return to a previous decision, Cancel to abandon the whole process, Help for more details, or Finish to skip to the end and create the application without answering any more questions (not recommended before the last step). The following sections explain each step.


NOTE: An MFC application uses MFC, the Microsoft Foundation Classes. You will learn more about MFC throughout this book.

Deciding How Many Documents the Application Supports

The first decision to communicate to AppWizard, as shown in Figure 1.2, is whether your application should be MDI, SDI, or dialog based. AppWizard generates different code and classes for each of these application types.

FIG. 1.2 The first step in building a typical application with AppWizard is choosing the interface.

The three application types to choose from are as follows:

FIG. 1.3 Character Map is a dialog-based application.


As you change the radio button selection, the picture on the left of the screen changes to demonstrate how the application appears if you choose this type of application.


NOTE:: Dialog-based applications are quite different from MDI or SDI applications. The AppWizard dialogs are different when you're creating a dialog-based application. They are presented later in the section "Creating a Dialog-Based Application." 

Beneath these choices is a checkbox for you to indicate whether you want support for the Document/View architecture. This framework for your applications is explained in Chapter 4, "Documents and Views." Experienced Visual C++ developers, especially those who are porting an application from another development system, might choose to turn off this support. You should leave the option selected.

Lower on the screen is a drop-down box to select the language for your resources. If you have set your system language to anything other than the default, English[United States], make sure you set your resources to that language, too. If you don't, you will encounter unexpected behavior from ClassWizard later. (Of course, if your application is for users who will have their language set to U.S. English, you might not have a choice. In that case, change your system language under Control Panel.) Click Next after you make your choices.

Databases

The second step in creating an executable Windows program with AppWizard is to choose the level of database support, as shown in Figure 1.4.

FIG. 1.4 The second step to building a typical application with AppWizard is to set the database options you will use.

There are four choices for database support:

Chapter 22 clarifies these choices and demonstrates database programming with MFC. If you choose to have a database view, you must specify a data source now. Click the Data Source button to set this up.

As you select different radio buttons, the picture on the left changes to show you the results of your choice. Click Next to move to the next step.

Compound Document Support

The third step in running AppWizard to create an executable Windows program is to decide on the amount of compound document support you want to include, as shown in Figure 1.5. OLE (object linking and embedding) has been officially renamed ActiveX to clarify the recent technology shifts, most of which are hidden from you by MFC. ActiveX and OLE technology are jointly referred to as compound document technology. Chapter 13, "ActiveX Concepts," covers this technology in detail.

FIG. 1.5 The third step of building a typical application with AppWizard is to set the compound document support you will need.

There are five choices for compound document support:

If you choose to support compound documents, you can also support compound files. Compound files contain one or more ActiveX objects and are saved in a special way so that one of the objects can be changed without rewriting the whole file. This spares you a great deal of time. Use the radio buttons in the middle of this Step 3 dialog box to say Yes, Please, or No, Thank You to compound files.

If you want your application to surrender control to other applications through automation, check the Automation check box. (Automation is the subject of Chapter 16, "Building an Automation Server.") If you want your application to use ActiveX controls, select the ActiveX Controls check box. Click Next to move to the next step.


NOTE: If you want your application to be an ActiveX control, you don't create a typical .exe application as described in this section. Creating ActiveX controls with the ActiveX ControlWizard is covered in Chapter 17, "Building an ActiveX Control." 

Appearance and Other Options

The fourth step in running AppWizard to create an executable Windows program (see Figure 1.6) is to determine some of the interface appearance options for your application. This Step 4 dialog box contains a number of independent check boxes. Check them if you want a feature; leave them unchecked if you don't.

FIG. 1.6 The fourth step of building a typical application with AppWizard is to set some interface options.

The following are the options that affect your interface's appearance:

You can ask AppWizard to build applications with "traditional" toolbars, like those in Word or Visual C++ itself, or with toolbars like those in Internet Explorer. You can read more about this in Chapter 9.

You can also set how many files you want to appear on the recent file list for this application. Four is the standard number; change it only if you have good reason to do so.

Clicking the Advanced button at the bottom of this Step 4 dialog box brings up the Advanced Options dialog box, which has two tabs. The Document Template Strings tab is shown in Figure 1.7. AppWizard builds many names and prompts from the name of your application, and sometimes it needs to abbreviate your application name. Until you are familiar with the names AppWizard builds, you should check them on this Document Template Strings dialog box and adjust them, if necessary. You can also change the mainframe caption, which appears in the title bar of your application. The file extension, if you choose one, will be incorporated into filenames saved by your application and will restrict the files initially displayed when the user chooses File, Open.

The Window Styles tab is shown in Figure 1.8. Here you can change the appearance of your application quite dramatically. The first check box, Use Split Window, adds all the code needed to implement splitter windows like those in the code editor of Developer Studio. The remainder of the Window Styles dialog box sets the appearance of your main frame and, for an MDI application, of your MDI child frames. Frames hold windows; the system menu, title bar, minimize and maximize boxes, and window edges are all frame properties. The main frame holds your entire application. An MDI application has a number of MDI child frames--one for each document window, inside the main frame.

FIG. 1.7 The Document Template Strings tab of the Advanced Options dialog box lets you adjust the way names are abbreviated.

FIG. 1.8 The Window Styles tab of the Advanced Options dialog box lets you adjust the appearance of your windows.

Here are the properties you can set for frames:

When you have made your selections, click Close to return to step 4 and click Next to move on to the next step.

Other Options

The fifth step in running AppWizard to create an executable Windows program (see Figure 1.9) asks the leftover questions that are unrelated to menus, OLE, database access, or appearance. Do you want comments inserted in your code? You certainly do. That one is easy.

FIG. 1.9 The fifth step of building an application with AppWizard is to decide on comments and the MFC library.

The next question isn't as straightforward. Do you want the MFC library as a shared DLL or statically linked? A DLL (dynamic link library) is a collection of functions used by many different applications. Using a DLL makes your programs smaller but makes the installation a little more complex. Have you ever moved an executable to another directory, or another computer, only to find it won't run anymore because it's missing DLLs? If you statically link the MFC library into your application, it is larger, but it is easier to move and copy around.

If your users are likely to be developers themselves and own at least one other application that uses the MFC DLL or aren't intimidated by the need to install DLLs as well as the program itself, choose the shared DLL option. The smaller executable is convenient for all. If your users are not developers, choose the statically linked option. It reduces the technical support issues you have to face with inexperienced users. If you write a good install program, you can feel more confident about using shared DLLs.

After you've made your Step 5 choices, click Next to move to Step 6.

Filenames and Classnames

The final step in running AppWizard to create an executable Windows program is to confirm the classnames and the filenames that AppWizard creates for you, as shown in Figure 1.10. AppWizard uses the name of the project (FirstSDI in this example) to build the classnames and filenames. You should not need to change these names. If your application includes a view class, you can change the class from which it inherits; the default is CView, but many developers prefer to use another view, such as CScrollView or CEditView. The view classes are discussed in Chapter 4. Click Finish when this Step 6 dialog box is complete.


TIP: Objects, classes, and inheritance are reviewed in Appendix A, "C++ Review and Object-Oriented Concepts."

FIG. 1.10 The final step of building a typical application with AppWizard is to confirm filenames and classnames.

Creating the Application

After you click Finish, AppWizard shows you what is going to be created in a dialog box, similar to Figure 1.11. If anything here is wrong, click Cancel and work your way back through AppWizard with the Back buttons until you reach the dialog box you need to change. Move forward with Next, Finish; review this dialog box again; and click OK to actually create the application. This takes a few minutes, which is hardly surprising because hundreds of code lines, menus, dialog boxes, help text, and bitmaps are being generated for you in as many as 20 files. Let it work.

FIG. 1.11 When AppWizard is ready to build your application, you get one more chance to confirm everything.

Try It Yourself

If you haven't started Developer Studio already, do so now. If you've never used it before, you may find the interface intimidating. There's a full explanation of all the areas, toolbars, menus, and shortcuts in Appendix C, "The Visual Studio User Interface, Menus, and Toolbars."

Bring up AppWizard by choosing File, New and clicking the Projects tab. On the Projects tab, fill in a folder name where you would like to keep your applications; AppWizard will make a new folder for each project. Fill in FirstSDI for the project name; then move through the six AppWizard steps. Choose an SDI application at Step 1, and on all the other steps simply leave the selections as they are and click Next. When AppWizard has created the project, choose Build, Build from the Developer Studio menu to compile and link the code.

When the build is complete, choose Build, Execute. You have a real, working Windows application, shown in Figure 1.12. Play around with it a little: Resize it, minimize it, maximize it.

FIG. 1.12 Your first application looks like any full-fledged Windows application.

Try out the File menu by choosing File, Open; bring up the familiar Windows File Open dialog (though no matter what file you choose, nothing seems to happen); and then choose File, Exit to close the application. Execute the program again to continue exploring the capabilities that have been automatically generated for you. Move the mouse cursor over one of the toolbar buttons and pause; a ToolTip will appear, reminding you of the toolbar button's purpose. Click the Open button to confirm that it is connected to the File Open command you chose earlier. Open the View menu and click Toolbar to hide the toolbar; then choose View Toolbar again to restore it. Do the same thing with the status bar. Choose Help, About, and you'll see it even has an About box with its own name and the current year in the copyright date (see Figure 1.13).

Repeat these steps to create an MDI application called FirstMDI. The creation process will differ only on Step 0, where you specify the project name, and Step 1, where you choose an MDI application. Accept the defaults on all the other steps, create the application, build it, and execute it. You'll see something similar to Figure 1.14, an MDI application with a single document open. Try out the same operations you tried with FirstSDI.

FIG. 1.13 You even get an About box in this start application.

FIG. 1.14 An MDI application can display a number of documents at once.

Choose File, New, and a second window, FirstM2, appears. Try minimizing, maximizing, and restoring these windows. Switch among them using the Window menu. All this functionality is yours from AppWizard, and you don't have to write a single line of code to get it.

Creating a Dialog-Based Application

A dialog-based application has no menus other than the system menu, and it cannot save or open a file. This makes it good for simple utilities like the Windows Character Map. The AppWizard process is a little different for a dialog-based application, primarily because such applications can't have a document and therefore can't support database access or compound documents. To create a dialog-based application, start AppWizard as you did for the SDI or MDI application, but in Step 1 choose a dialog-based application, as shown in Figure 1.15. Call this application FirstDialog.

FIG. 1.15 To create a dialog-based application, specify your preference in Step 1 of the AppWizard process.

Choose Dialog Based and click Next to move to Step 2, shown in Figure 1.16.

FIG. 1.16 Step 2 of the AppWizard process for a dialog-based application involves choosing Help, Automation, ActiveX, and Sockets settings.

If you would like an About item on the system menu, select the About Box item. To have AppWizard lay the framework for Help, select the Context-Sensitive Help option. The third check box, 3D Controls, should be selected for most Windows 95 and Windows NT applications. If you want your application to surrender control to other applications through automation, as discussed in Chapter 16, select the Automation check box. If you want your application to contain ActiveX controls, select the ActiveX Controls check box. If you are planning to have this application work over the Internet with sockets, check the Windows Sockets box. (Dialog-based apps can't use MAPI because they have no document.) Click Next to move to the third step, shown in Figure 1.17.

As with the SDI and MDI applications created earlier, you want comments in your code. The decision between static linking and a shared DLL is also the same as for the SDI and MDI applications. If your users are likely to already have the MFC DLLs (because they are developers or because they have another product that uses the DLL) or if they won't mind installing the DLLs as well as your executable, go with the shared DLL to make a smaller executable file and a faster link. Otherwise, choose As A Statically Linked Library. Click Next to move to the final step, shown in Figure 1.18.

FIG. 1.17 Step 3 of the AppWizard process for a dialog-based application deals with comments and the MFC library.

FIG. 1.18 Step 4 of the AppWizard process for a dialog-based application gives you a chance to adjust filenames and classnames.

In this step you can change the names AppWizard chooses for files and classes. This is rarely a good idea because it will confuse people who maintain your code if the filenames can't be easily distinguished from the classnames, and vice versa. If you realize after looking at this dialog that you made a poor choice of project name, use Back to move all the way back to the New Project Workspace dialog, change the name, click Create, and then use Next to return to this dialog. Click Finish to see the summary of the files and classes to be created, similar to that in Figure 1.19.

If any information on this dialog isn't what you wanted, click Cancel and then use Back to move to the appropriate step and change your choices. When the information is right, click OK and watch as the application is created.

To try it yourself, create an empty dialog-based application yourself, call it FirstDialog, and accept the defaults for each step of AppWizard. When it's complete, choose Build, Build to compile and link the application. Choose Build, Execute to see it in action. Figure 1.20 shows the empty dialog-based application running.

FIG. 1.19 AppWizard confirms the files and classes before creating them.

FIG. 1.20 A starter dialog application includes a reminder of the work ahead of you.

Clicking the OK or Cancel button, or the X in the top-right corner, makes the dialog disappear. Clicking the system menu in the top-left corner gives you a choice of Move, Close, or About. Figure 1.21 shows the About box that was generated for you.

FIG. 1.21 The same About box is generated for SDI, MDI, and dialog-based applications.

Creating DLLs, Console Applications, and More

Although most people use AppWizard to create an executable program, it can make many other kinds of projects. You choose File, New and then the Projects tab, as discussed at the start of this chapter, but choose a different wizard from the list on the left of the New dialog box, shown in Figure 1.1. The following are some of the other projects AppWizard can create:

These projects are explained in the following sections.

ATL COM AppWizard

ATL is the Active Template Library, and it's used to write small ActiveX controls. It's generally used by developers who have already mastered writing MFC ActiveX controls, though an MFC background is not required to learn ATL. Chapter 17 introduces important control concepts while demonstrating how to build an MFC control; Chapter 21, "The Active Template Library," teaches you ATL.

Custom AppWizard

Perhaps you work in a large programming shop that builds many applications. Although AppWizard saves a lot of time, your programmers may spend a day or two at the start of each project pasting in your own boilerplate, which is material that is the same in every one of your projects. You may find it well worth your time to build a Custom AppWizard, a wizard of your very own that puts in your boilerplate as well as the standard MFC material. After you have done this, your application type is added to the list box on the left of the Projects tab of the New dialog box shown in Figure 1.1. Creating and using Custom AppWizards is discussed in Chapter 25, "Achieving Reuse with the Gallery and Your Own AppWizards."

Database Project

If you have installed the Enterprise Edition of Visual C++, you can create a database project. This is discussed in Chapter 23, "SQL and the Enterprise Edition."

DevStudio Add-In Wizard

Add-ins are like macros that automate Developer Studio, but they are written in C++ or another programming language; macros are written in VBScript. They use automation to manipulate Developer Studio.

ISAPI Extension Wizard

ISAPI stands for Internet Server API and refers to functions you can call to interact with a running copy of Microsoft Internet Information Server, a World Wide Web server program that serves out Web pages in response to client requests. You can use this API to write DLLs used by programs that go far beyond browsing the Web to sophisticated automatic information retrieval. This process is discussed in Chapter 18.

Makefile

If you want to create a project that is used with a different make utility than Developer Studio, choose this wizard from the left list in the New Project Workspace dialog box. No code is generated. If you don't know what a make utility is, don't worry--this wizard is for those who prefer to use a standalone tool to replace one portion of Developer Studio.

MFC ActiveX ControlWizard

ActiveX controls are controls you write that can be used on a Visual C++ dialog, a Visual Basic form, or even a Web page. These controls are the 32-bit replacement for the VBX controls many developers were using to achieve intuitive interfaces or to avoid reinventing the wheel on every project. Chapter 17 guides you through building a control with this wizard.

MFC AppWizard (DLL)

If you want to collect a number of functions into a DLL, and these functions use MFC classes, choose this wizard. (If the functions don't use MFC, choose Win32 Dynamic Link Library, discussed a little later in this section.) Building a DLL is covered in Chapter 28, "Future Explorations." AppWizard generates code for you so you can get started.

Win32 Application

There are times when you want to create a Windows application in Visual C++ that doesn't use MFC and doesn't start with the boilerplate code that AppWizard produces for you. To create such an application, choose the Win32 Application wizard from the left list in the Projects tab, fill in the name and folder for your project, and click OK. You are not asked any questions; AppWizard simply creates a project file for you and opens it. You have to create all your code from scratch and insert the files into the project.

Win32 Console Application

A console application looks very much like a DOS application, though it runs in a resizable window. (Console applications are 32-bit applications that won't run under DOS, however.) It has a strictly character-based interface with cursor keys instead of mouse movement. You use the Console API and character-based I/O functions such as printf() and scanf() to interact with the user. Some very rudimentary boilerplate code can be generated for you, or you can have just an empty project. Chapter 28 discusses building and using console applications.

Win32 Dynamic Link Library

If you plan to build a DLL that does not use MFC and does not need any boilerplate, choose the Win32 Dynamic Link Library option instead of MFC AppWizard (dll). You get an empty project created right away with no questions.

Win32 Static Library

Although most code you reuse is gathered into a DLL, you may prefer to use a static library because that means you don't have to distribute the DLL with your application. Choose this wizard from the left list in the New Project Workspace dialog box to create a project file into which you can add object files to be linked into a static library, which is then linked into your applications.

Changing Your AppWizard Decisions

Running AppWizard is a one-time task. Assuming you are making a typical application, you choose File, New; click the Projects tab; enter a name and folder; choose MFC Application (exe); go through the six steps; create the application starter files; and then never touch AppWizard again. However, what if you choose not to have online Help and later realize you should have included it?

AppWizard, despite the name, isn't really magic. It pastes in bits and pieces of code you need, and you can paste in those very same bits yourself. Here's how to find out what you need to paste in.

First, create a project with the same options you used in creating the project whose settings you want to change, and don't add any code to it. Second, in a different folder create a project with the same name and all the same settings, except the one thing you want to change (Context-Sensitive Help in this example). Compare the files, using WinDiff, which comes with Visual C++. Now you know what bits and pieces you need to add to your full-of-code project to implement the feature you forgot to ask AppWizard for.

Some developers, if they discover their mistake soon enough, find it quicker to create a new project with the desired features and then paste their own functions and resources from the partially built project into the new empty one. It's only a matter of taste, but after you go through either process for changing your mind, you probably will move a little more slowly through those AppWizard dialog boxes.

Understanding AppWizard's Code

The code generated by AppWizard may not make sense to you right away, especially if you haven't written a C++ program before. You don't need to understand this code in order to write your own simple applications. Your programs will be better ones, though, if you know what they are doing, so a quick tour of AppWizard's boilerplate code is a good idea. You'll see the core of an SDI application, an MDI application, and a dialog-based application.

You'll need the starter applications FirstSDI, FirstMDI, and FirstDialog, so if you didn't create them earlier, do so now. If you're unfamiliar with the Developer Studio interface, glance through Appendix C to learn how to edit code and look at classes.

A Single Document Interface Application

An SDI application has menus that the user uses to open one document at a time and work with that document. This section presents the code that is generated when you create an SDI application with no database or compound document support, with a toolbar, a status bar, Help, 3D controls, source file comments, and with the MFC library as a shared DLL--in other words, when you accept all the AppWizard defaults after Step 1.

Five classes have been created for you. For the application FirstSDI, they are as follows:

Dialog classes are discussed in Chapter 2, "Dialogs and Controls." Document, view, and frame classes are discussed in Chapter 4. The header file for CFirstSDIApp is shown in Listing 1.1. The easiest way for you to see this code is to double-click on the classname, CFirstDSIApp, in the ClassView pane. This will edit the header file for the class.

Listing 1.1  FirstSDI.h--Main Header File for the FirstSDI Application

// FirstSDI.h : main header file for the FIRSTSDI application
//
#if !defined(AFX_FIRSTSDI_H__CDF38D8A_8718_11D0_B02C_0080C81A3AA2__INCLUDED_)
#define AFX_FIRSTSDI_H__CDF38D8A_8718_11D0_B02C_0080C81A3AA2__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#ifndef __AFXWIN_H__
     #error include `stdafx.h' before including this file for PCH
#endif
#include "resource.h"       // main symbols
/////////////////////////////////////////////////////////////////////////////
// CFirstSDIApp:
// See FirstSDI.cpp for the implementation of this class
//
class CFirstSDIApp : public CWinApp
{
public:
     CFirstSDIApp();
// Overrides
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CFirstSDIApp)
     public:
     virtual BOOL InitInstance();
     //}}AFX_VIRTUAL
// Implementation
     //{{AFX_MSG(CFirstSDIApp)
     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()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations
// immediately before the previous line.
#endif //!defined(AFX_FIRSTSDI_H__CDF38D8A_8718_11D0_B02C_0080C81A3AA2__INCLUDED_)

This code is confusing at the beginning. The #if(!defined) followed by the very long string (yours will be different) is a clever form of include guarding. You may have seen a code snippet like this before:

#ifndef test_h
#include "test.h"
#define test_h
#endif

This guarantees that the file test.h will never be included more than once. Including the same file more than once is quite likely in C++. Imagine that you define a class called Employee, and it uses a class called Manager. If the header files for both Employee and Manager include, for example, BigCorp.h, you will get error messages from the compiler about "redefining" the symbols in BigCorp.h the second time it is included.

There is a problem with this approach: If someone includes test.h but forgets to set test_h, your code will include test.h the second time. The solution is to put the test and the definition in the header file instead, so that test.h looks like this:

#ifndef test_h
... the entire header file
#define test_h
#endif

All AppWizard did was generate a more complicated variable name than test_h (this wild name prevents problems when you have several files, in different folders and projects, with the same name) and use a slightly different syntax to check the variable. The #pragma once code is also designed to prevent multiple definitions if this file is ever included twice.

The actual meat of the file is the definition of the class CFirstSDIApp. This class inherits from CWinApp, an MFC class that provides most of the functionality you need. AppWizard has generated some functions for this class that override the ones inherited from the base class. The section of code that begins //Overrides is for virtual function overrides. AppWizard generated the odd-looking comments that surround the declaration of InitInstance(): ClassWizard will use these to simplify the job of adding other overrides later, if they are necessary. The next section of code is a message map and declares there is a function called OnAppAbout. You can learn all about message maps in Chapter 3, "Messages and Commands."

AppWizard generated the code for the CFirstSDIApp constructor, InitInstance(), and OnAppAbout() in the file firstsdi.cpp. Here's the constructor, which initializes a CFirstSDIApp object as it is created:

CFirstSDIApp::CFirstSDIApp()
{
    // TODO: add construction code here,
    // Place all significant initialization in InitInstance
}

This is a typical Microsoft constructor. Because constructors don't return values, there's no easy way to indicate that there has been a problem with the initialization. There are several ways to deal with this. Microsoft's approach is a two-stage initialization, with a separate initializing function so that construction does no initialization. For an application, that function is called InitInstance(), shown in Listing 1.2.

Listing 1.2  CFirstSDIApp::InitInstance()

BOOL CFirstSDIApp::InitInstance()
{
     AfxEnableControlContainer();
     // Standard initialization
     // If you are not using these features and want to reduce the size
     //  of your final executable, you should remove from the following
     //  the specific initialization routines you don't need.
#ifdef _AFXDLL
     Enable3dControls();        // Call this when using MFC in a shared DLL
#else
     Enable3dControlsStatic();  // Call this when linking to MFC statically
#endif
     // Change the registry key under which our settings are stored.
     // You should modify this string to be something appropriate,
     // such as the name of your company or organization.
     SetRegistryKey(_T("Local AppWizard-Generated Applications"));
     LoadStdProfileSettings();  // Load standard INI file options (including  				 // MRU)
     // Register the application's document templates. Document templates
     //  serve as the connection between documents, frame windows, and views.
     CSingleDocTemplate* pDocTemplate;
     pDocTemplate = new CSingleDocTemplate(
          IDR_MAINFRAME,
          RUNTIME_CLASS(CFirstSDIDoc),
          RUNTIME_CLASS(CMainFrame),       // main SDI frame window
          RUNTIME_CLASS(CFirstSDIView));
     AddDocTemplate(pDocTemplate);
     // Parse command line for standard shell commands, DDE, file open
     CCommandLineInfo cmdInfo;
     ParseCommandLine(cmdInfo);
     // Dispatch commands specified on the command line
     if (!ProcessShellCommand(cmdInfo))
          return FALSE;
     // The one and only window has been initialized, so show and update it.
     m_pMainWnd->ShowWindow(SW_SHOW);
     m_pMainWnd->UpdateWindow();
     return TRUE;
}

InitInstance gets applications ready to go. This one starts by enabling the application to contain ActiveX controls with a call to AfxEnableControlContainer() and then turns on 3D controls. It then sets up the Registry key under which this application will be registered. (The Registry is introduced in Chapter 7, "Persistence and File I/O." If you've never heard of it, you can ignore it for now.)

InitInstance() goes on to register single document templates, which is what makes this an SDI application. Documents, views, frames, and document templates are all discussed in Chapter 4.

Following the comment about parsing the command line, InitInstance() sets up an empty CCommandLineInfo object to hold any parameters that may have been passed to the application when it was run, and it calls ParseCommandLine() to fill that. Finally, it calls ProcessShellCommand() to do whatever those parameters requested. This means your application can support command-line parameters to let users save time and effort, without effort on your part. For example, if the user types at the command line FirstSDI fooble, the application starts and opens the file called fooble. The command-line parameters that ProcessShellCommand() supports are the following:

Parameter Action
None Start app and open new file.
Filename Start app and open file.
/p filename Start app and print file to default printer.
/pt filename printer driver port Start app and print file to the specified printer.
/dde Start app and await DDE command.
/Automation Start app as an OLE automation server.
/Embedding Start app to edit an embedded OLE item.

If you would like to implement other behavior, make a class that inherits from CCommandLineInfo to hold the parsed command line; then override CWinApp:: ParseCommandLine() and CWinApp::ProcessShellCommand() in your own App class.


TIP:: You may already know that you can invoke many Windows programs from the command line; for example, typing Notepad blah.txt at a DOS prompt will open blah.txt in Notepad. Other command line options work, too, so typing Notepad /p blah.txt will open blah.txt in Notepad, print it, and then close Notepad.

That's the end of InitInstance(). It returns TRUE to indicate that the rest of the application should now run.

The message map in the header file indicated that the function OnAppAbout() handles a message. Which one? Here's the message map from the source file:

BEGIN_MESSAGE_MAP(CFirstSDIApp, CWinApp)
     //{{AFX_MSG_MAP(CFirstSDIApp)
     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()

This message map catches commands from menus, as discussed in Chapter 3. When the user chooses Help About, CFirstSDIApp::OnAppAbout() will be called. When the user chooses File New, File Open, or File Print Setup, functions from CWinApp will handle that work for you. (You would override those functions if you wanted to do something special for those menu choices.) OnAppAbout() looks like this:

void CFirstSDIApp::OnAppAbout()
{
     CAboutDlg aboutDlg;
     aboutDlg.DoModal();
}

This code declares an object that is an instance of CAboutDlg, and calls its DoModal() function to display the dialog onscreen. (Dialog classes and the DoModal() function are both covered in Chapter 2.) There's no need to handle OK or Cancel in any special way--this is just an About box.

Other Files

If you selected Context-Sensitive Help, AppWizard generates an .HPJ file and a number of .RTF files to give some context-sensitive help. These files are discussed in Chapter 11 in the "Components of the Help System" section.

AppWizard also generates a README.TXT file that explains what all the other files are and what classes have been created. Read this file if all the similar filenames become confusing.

There are also a number of project files used to hold your settings and options, to speed build time by saving partial results, and to keep information about all your variables and functions. These files have extensions like .ncb, .aps, .dsw, and so on. You can safely ignore these files because you will not be using them directly.

Understanding a Multiple Document Interface Application

A multiple document interface application also has menus, and it enables the user to have more than one document open at once. This section presents the code that is generated when you choose an MDI application with no database or compound document support, but instead with a toolbar, a status bar, Help, 3D controls, source file comments, and the MFC library as a shared DLL. As with the SDI application, these are the defaults after Step 1. The focus here is on what differs from the SDI application in the previous section.

Five classes have been created for you. For the application FirstMDI, they are

The App class header is shown in Listing 1.3.

Listing 1.3  FirstMDI.h--Main Header File for the FirstMDI Application

// FirstMDI.h : main header file for the FIRSTMDI application
//
#if !defined(AFX_FIRSTMDI_H__CDF38D9E_8718_11D0_B02C_0080C81A3AA2__INCLUDED_)
#define AFX_FIRSTMDI_H__CDF38D9E_8718_11D0_B02C_0080C81A3AA2__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#ifndef __AFXWIN_H__
     #error include `stdafx.h' before including this file for PCH
#endif
#include "resource.h"       // main symbols
/////////////////////////////////////////////////////////////////////////////
// CFirstMDIApp:
// See FirstMDI.cpp for the implementation of this class
//
class CFirstMDIApp : public CWinApp
{
public:
     CFirstMDIApp();
// Overrides
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CFirstMDIApp)
     public:
     virtual BOOL InitInstance();
     //}}AFX_VIRTUAL
// Implementation
     //{{AFX_MSG(CFirstMDIApp)
     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()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately
// before the previous line.
#endif //!defined(AFX_FIRSTMDI_H__CDF38D9E_8718_11D0_B02C_0080C81A3AA2__INCLUDED_)

How does this differ from FirstSDI.h? Only in the classnames. The constructor is also the same as before. OnAppAbout() is just like the SDI version. How about InitInstance()? It is in Listing 1.4.

Listing 1.4  CFirstMDIApp::InitInstance()

BOOL CFirstMDIApp::InitInstance()
{
     AfxEnableControlContainer();
     // Standard initialization
     // If you are not using these features and want to reduce the size
     //  of your final executable, you should remove from the following
     //  the specific initialization routines you don't need.
#ifdef _AFXDLL
     Enable3dControls();        // Call this when using MFC in a shared DLL
#else
     Enable3dControlsStatic();  // Call this when linking to MFC statically
#endif
     // Change the registry key under which your settings are stored.
     // You should modify this string to be something appropriate,
     // such as the name of your company or organization.
     SetRegistryKey(_T("Local AppWizard-Generated Applications"));
     LoadStdProfileSettings();  // Load standard INI file options (including  				 // MRU)
     // Register the application's document templates. Document templates
     //  serve as the connection between documents, frame windows, and views.
     CMultiDocTemplate* pDocTemplate;
     pDocTemplate = new CMultiDocTemplate(
          IDR_FIRSTMTYPE,
          RUNTIME_CLASS(CFirstMDIDoc),
          RUNTIME_CLASS(CChildFrame), // custom MDI child frame
          RUNTIME_CLASS(CFirstMDIView));
     AddDocTemplate(pDocTemplate);
     // create main MDI Frame window
     CMainFrame* pMainFrame = new CMainFrame;
     if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
          return FALSE;
     m_pMainWnd = pMainFrame;
     // Parse command line for standard shell commands, DDE, file open
     CCommandLineInfo cmdInfo;
     ParseCommandLine(cmdInfo);
     // Dispatch commands specified on the command line
     if (!ProcessShellCommand(cmdInfo))
          return FALSE;
     // The main window has been initialized, so show and update it.
     pMainFrame->ShowWindow(m_nCmdShow);
     pMainFrame->UpdateWindow();
     return TRUE;
}

What's different here? Using WinDiff can help. WinDiff is a tool that comes with Visual C++ and is reached from the Tools menu. (If WinDiff isn't on your Tools menu, see the "Tools" section of Appendix C.) Using WinDiff to compare the FirstSDI and FirstMDI versions of InitInstance() confirms that, other than the classnames, the differences are

This shows a major advantage of the Document/View paradigm: It enables an enormous design decision to affect only a small amount of the code in your project and hides that decision as much as possible.

Understanding the Components of a Dialog-Based Application

Dialog applications are much simpler than SDI and MDI applications. Create one called FirstDialog, with an About box, no Help, 3D controls, no automation, ActiveX control support, no sockets, source file comments, and MFC as a shared DLL. In other words, accept all the default options.

Three classes have been created for you for the application called FirstMDI:

The dialog classes are the subject of Chapter 2. Listing 1.5 shows the header file for CFirstDialogApp.

Listing 1.5  dialog16.h--Main Header File

// FirstDialog.h : main header file for the FIRSTDIALOG application
//
#if !defined(AFX_FIRSTDIALOG_H__CDF38DB4_8718_11D0_B02C_0080C81A3AA2__INCLUDED_)
#define AFX_FIRSTDIALOG_H__CDF38DB4_8718_11D0_B02C_0080C81A3AA2__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#ifndef __AFXWIN_H__
     #error include `stdafx.h' before including this file for PCH
#endif
#include "resource.h"          // main symbols
/////////////////////////////////////////////////////////////////////////////
// CFirstDialogApp:
// See FirstDialog.cpp for the implementation of this class
//
class CFirstDialogApp : public CWinApp
{
public:
     CFirstDialogApp();
// Overrides
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CFirstDialogApp)
     public:
     virtual BOOL InitInstance();
     //}}AFX_VIRTUAL
// Implementation
     //{{AFX_MSG(CFirstDialogApp)
          // 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()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately
// before the previous line.
#endif // !defined(AFX_FIRSTDIALOG_H__CDF38DB4_8718_11D0_B02C_0080C81A3AA2
¬__INCLUDED_)

CFirstDialogApp inherits from CWinApp, which provides most of the functionality. CWinApp has a constructor, which does nothing, as did the SDI and MDI constructors earlier in this chapter, and it overrides the virtual function InitInstance(), as shown in Listing 1.6.

Listing 1.6  FirstDialog.cpp--CDialog16App::InitInstance()

BOOL CFirstDialogApp::InitInstance()
{
     AfxEnableControlContainer();
     // Standard initialization
     // If you are not using these features and want to reduce the size
     //  of your final executable, you should remove from the following
     //  the specific initialization routines you don't need.
#ifdef _AFXDLL
     Enable3dControls();         // Call this when using MFC in a shared DLL
#else
     Enable3dControlsStatic();   // Call this when linking to MFC statically
#endif
     CFirstDialogDlg dlg;
     m_pMainWnd = &dlg;
     int nResponse = dlg.DoModal();
     if (nResponse == IDOK)
     {
          // TODO: Place code here to handle when the dialog is
          //  dismissed with OK
     }
     else if (nResponse == IDCANCEL)
     {
          // TODO: Place code here to handle when the dialog is
          // dismissed with Cancel
     }
     // Because the dialog has been closed, return FALSE so that you exit the
     //  application, rather than start the application's message pump.
     return FALSE;
}

This enables 3D controls, because you asked for them, and then puts up the dialog box that is the entire application. To do that, the function declares an instance of CDialog16Dlg, dlg, and then calls the DoModal() function of the dialog, which displays the dialog box onscreen and returns IDOK if the user clicks OK, or IDCANCEL if the user clicks Cancel. (This process is discussed further in Chapter 2.) It's up to you to make that dialog box actually do something. Finally, InitInstance() returns FALSE because this is a dialog-based application and when the dialog box is closed, the application is ended. As you saw earlier for the SDI and MDI applications, InitInstance() usually returns TRUE to mean "everything is fine--run the rest of the application" or FALSE to mean "something went wrong while initializing." Because there is no "rest of the application," dialog-based apps always return FALSE from their InitInstance().

Reviewing AppWizard Decisions and This Chapter

AppWizard asks a lot of questions and starts you down a lot of roads at once. This chapter explains InitInstance and shows some of the code affected by the very first AppWizard decision: whether to have AppWizard generate a dialog-based, SDI, or MDI application. Most of the other AppWizard decisions are about topics that take an entire chapter. The following table summarizes those choices and where you can learn more:

Step Decision Chapter Dialog
0 MFC DLL or 28, Future Explorations
non-MFC DLL
0 OCX Control 17, Building an ActiveX
Control
0 Console 28, Future Explorations
Application
0 Custom 25, Achieving Reuse with the
AppWizards Gallery and Your Own AppWizard
0 ISAPI Extension 18, Sockets, MAPI, and the
Internet Wizard
1 Language Support 28, Future Explorations Yes
2 Database Support 22, Database Access
3 Compound 14, Building an ActiveX
Document Container Container Application
3 Compound Document 15, Building an ActiveX
Mini-Server Server Application
3 Compound Document 15, Building an ActiveX
Full Server Server Application
3 Compound Files 14, Building an ActiveX
Container Application
3 Automation 16, Building an Automation Yes
Server
3 Using ActiveX 17, Building an ActiveX Yes
Controls Control
4 Docking Toolbar 9, Status Bars and Toolbars
4 Status Bar 9, Status Bars and Toolbars
4 Printing and 6, Printing and Print
Print Preview Preview
4 Context-Sensitive 11, Help Yes
Help
4 3D Controls -- Yes
4 MAPI 18, Sockets, MAPI,
and the Internet
4 Windows Sockets 18, Sockets, MAPI, Yes
and the Internet
4 Files in MRU list --
5 Comments in code -- Yes
5 MFC library -- Yes
6 Base class for View 4, Documents and Views

Because some of these questions are not applicable for dialog-based applications, this table has a Dialog column Yes that indicates this decision applies to dialog-based applications, too. An entry of -- in the Chapter column means that this decision doesn't really warrant discussion. These topics get a sentence or two in passing in this chapter or elsewhere.

By now you know how to create applications that don't do much of anything. To make them do something, you need menus or dialog controls that give commands, and you need other dialog controls that gather more information. These are the subject of the next chapter, Chapter 2, "Dialogs and Controls."


Previous chapterNext chapterContents

© Copyright, Macmillan Computer Publishing. All rights reserved.