Visual C++ doesn't just compile code, it generates code. You can create a Windows application in minutes by telling AppWizard to make you a "starter app" with all the Windows boilerplate code you want. AppWizard is a very effective tool. It copies code that almost all Windows applications need into your application. After all, you aren't the first programmer who has needed an application with resizable edges, minimize and maximize buttons, a File menu with Open, Close, Print Setup, Print, and Exit options, are you?
When most people think "application," they expect an EXE file. AppWizard makes skeleton, executable Windows programs in less than a minute.
Other application generating wizards can make DLLs, ActiveX controls, console applications, libraries, makefile, Internet Server extensions and filters, and more.
AppWizard can add a lot of functionality to an application that you are building for the first time. What if you want to add some of the functionality to an application that is already built? This section shows you how.
See the code generated for you by AppWizard and understand the different application types.
This section directs you to the places in this book where the consequences of AppWizard decisions such as database support, ActiveX technology, and application type are explained in detail.
AppWizard can make many different 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 then works through a number of steps. At each step, you make a decision about what kind of application you want, and 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). Each step is covered in the following sections.
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. App Wizard generates different code and classes for each of these application types.
Fig. 1.2 The first step in building a typical application with App Wizard 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 remind you what the application looks like if you choose this type of application.
Dialog-based applications are quite different from MDI or SDI applications. The AppWizard dialogs are different when creating a dialog-based application, and are presented in the next section entitled ìCreating a Dialog-Based Application.î
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 US English, 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 US 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, as follows:
Chapter 22, "Database Access," 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 consequences 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, as follows:
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 can save a great deal of time. Use the radio buttons in the middle of this Step 3 dialog box to say Yes, Please or No, or thank you to compound files.
If you want your application to surrender control to other applications through Automation, check the Automation checkbox. (Automation is the subject of Chapter 16, "Building an Automation Server.") If you want your application to use ActiveX controls, select the ActiveX Controls checkbox. Click Next to move to the next step.
If you want your application to be an ActiveX control, you do not 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 checkboxes; check them if you want a feature, leave them unchecked if you do not.
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 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 main frame caption, which appears in the title bar of your application. The file extension, if you choose one, will be incorporated into file names saved by your application and will restrict the files initially displayed when the user chooses File, Open.
Fig. 1.7 The Document Template Strings tab of the Advanced Options dialog box lets you adjust the way names are abbreviated.
The Window Styles tab is shown in Figure 1.8. Here you can change the appearance of your application quite dramatically. The first checkbox, 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.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 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 not related 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 is not so 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 only to find it won't run any more 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 needing to install DLLs as well as the program itself, choose the shared DLL option. The smaller executable is convenient for all of you. 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.
File and Class Names
The final step in running AppWizard to create an executable Windows program is to confirm the class names and the file names 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 class names and file names. 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 eight view classes are discussed in Chapter 5, "Documents and Views." Click Finish when this Step 6 dialog box is complete.
Fig. 1.10 The final step of building a typical application with AppWizard is to confirm file names and class names.
Creating the Application
After you click Finish, AppWizard shows you what is going to be created in a dialog box, like that shown in Figure 1.11. If anything here is wrong, click Cancel and then 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 then click OK to actually create the application. This takes a few minutes, which is hardly surprising because hundreds of lines of code, 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 a little intimidating. There's a full explanation of all the areas, toolbars, menus, and shortcuts in Appendix B, "The Developer Studio Interface."
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 fully-fledged Windows application.
Try out the File menu by choosing File, Open and 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. Move the mouse cursor over one of the toolbar buttons and pause; a tool tip will appear reminding you of the purpose of the toolbar button. Click the Open button to confirm that it is connected to the File Open command you chose earlier. Bring up 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).
Fig. 1.13 You even get an About box in this start application.
Repeat these steps to create an MDI application called FirstMDI. The creation process will only differ 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 like Figure 1.14, an MDI application with a single document open. Try out the same operations you tried with FirstSDI.
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.
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 they cannot have a document, and so cannot support database access or compound documents. To create a dialog-based application, start AppWizard as you did for the SDI or MDI application, but on Step 1 choose a dialog-based application, as shown in Figure 1.15.
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 checkbox, 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, "Building an Automation Server," select the Automation checkbox. If you want your application to contain ActiveX controls, select the ActiveX Controls checkbox. 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.
Fig. 1.17 Step 3 of the AppWizard process for a dialog-based application deals with comments and the MFC library.
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 have the MFC DLLs already (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.18 Step 4 of the AppWizard process for a dialog-based application gives you a chance to adjust file and class names.
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 file names can't be easily determined from the class names, 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, like that in Figure 1.19.
Fig. 1.19 AppWizard confirms the files and classes before creating them.
If any of the information on this dialog is not 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.
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.20 A starter dialog application includes a reminder of the work you have ahead of you.
Clicking the OK or Cancel buttons, 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.
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. Chapter 17, "Building an ActiveX Control," 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 a lot of 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 that can be used by programs that go far beyond browsing the Web to automating information retrieval. This process is discussed in Chapter 18, "Sockets, MAPI, and the Internet."
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-hand 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 stand-alone tool to replace one portion of Developer Studio.
MFC ActiveX Control Wizard
ActiveX controls are controls you write that can be used on a Visual C++ dialog, a Visual Basic form, 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 save reinventing the wheel on every project. Chapter 17, "Building an ActiveX Control," 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." App Wizard generates code for you so you can get started.
New Database Wizard
This wizard is for those with Visual InterDev installed. It simplifies connecting a Web page to an SQL database.
Win32 Application
There are times when you want to create an application in Visual C++ that does not use MFC and does not start with the boilerplate code that AppWizard produces for you. To create such an application, choose the Win32 Application wizard from the left-hand 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. It has a strictly character-based interface with cursor keys rather than mouse movement. You use the Console API and character based I/O functions like printf() and scanf() to interact with the user. No boilerplate code is generated for you, just an empty project. Chapter 28, "Future Explorations," 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 rather than MFC AppWizard (dll). You get an empty project created right away with no questions.
Win32 Static Library
While most code you reuse is gathered into a DLL, you may prefer to use a static library, because that means you do not have to distribute the DLL with your application. Choose this wizard from the left-hand 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.
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. But what if you choose, for example, not to have online Help, and then later realize you should have included it?
AppWizard, despite the name, is not 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 wish 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). Now, 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've gone through either process for changing your mind, you probably will move a little more slowly through those AppWizard dialog boxes.
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. But your programs will be better ones if you know what they are doing, and so a quick tour of AppWizard's boilerplate code is a good idea. You'll see the guts of an SDI application, an MDI application, and a dialog-based application.
If you didn't create the starter applications FirstSDI, FirstMDI, and FirstDialog, you can open them from the CD-ROM as you read this chapter. If you did create them, open them from your own hard drive. If you're unfamiliar with the Developer Studio interface, glance through Reference Appendix B, "The Developer Studio Interface," 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, 3-D 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 called FirstSDI, they are as follows:
Dialog classes are discussed in Chapter 2, "Dialogs and Controls." Document, view, and frame classes are discussed in Chapter 5, "Documents and Views." The header file for CFirstSDIApp is shown in Listing 1.1.
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 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 the approach above: 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(): they will be used by ClassWizard 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 4, "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 different 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 wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not 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(), then turns on 3-D controls. It then sets up the Registry key under which this application will be registered. (The Registry is introduced in Chapter 8, "Persistence and File I/O." If you've never heard of it before, 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 5, "Documents and Views."
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 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 then 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 |
Start app and print file to the |
driver port |
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.
You may have already known that you could 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 and print it.
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 4, "Messages and Commands." 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 on the screen. (Dialog classes and the DoModal() function are both covered in Chapter 2, "Dialogs and Controls." 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 a .HPJ file and a number of .RTF files to give some context-sensitive help. These files are discussed in Chapter 11, "Help," 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 file names start to get confusing.
A Multiple Document Interface application also has menus, and 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, 3-D 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 is different from the SDI application in the previous section.
Five classes have been created for you: for the application called 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 class names. The constructor is also the same as before. And 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 wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not 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.
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 is not on your Tools menu, see the "Tools" section of Reference B, "The Developer Studio Interface." Using WinDiff to compare the FirstSDI and FirstMDI versions of InitInstance() confirms that other than the class names, 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.
Dialog applications are much simpler than SDI and MDI applications. Create one called FirstDialog, with an About box, no Help, 3-D 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 and they are the following :
The dialog classes are the subject of Chapter 2, "Dialogs and Controls." 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ñCDialog16App::InitInstance()
BOOL CFirstDialogApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not 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
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
This enables 3-D 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 on the screen and returns IDOK if the user clicks OK, or IDCANCEL if the user clicks Cancel. (This process is discussed further in Chapter 2, "Dialogs and Controls.") 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 over. 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 meaning, "something went wrong while initializing." Because there is no "rest of the application," dialog-based apps always return FALSE from their InitInstance().
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 non MFC DLL | 28, Future Explorations | |
0 | OCX Control | 17, Building an ActiveX Control | |
0 | Console Application | 28, Future Explorations | |
0 | Custom AppWizard | 25, Achieving Reuse with the Gallery and Your Own AppWizards | |
0 | ISAPI Extension Wizard | 18, Sockets, MAPI, and the Internet | |
1 | Language support | 28, Future Explorations | yes |
2 | Database support | 22, Database Access | |
3 | Compound document container | 14, Building an ActiveX Container Application | |
3 | Compound document mini-server | 15, Building an ActiveX Server Application | |
3 | Compound document full server | 15, Building an ActiveX Server Application | |
3 | Compound files | 14, Building an ActiveX Container Application | |
3 | Automation | 16, Building an Automation Server | yes |
3 | Using ActiveX Controls | 17, Building an ActiveX Control | yes |
4 | Docking toolbar | 10, Status Bars and Toolbars | |
4 | Status bar | 10, Status Bars and Toolbars | |
4 | Printing and print | 7, Printing and Print Preview preview | |
4 | Context sensitive help | 11, Help | yes |
4 | 3D Controls | -- | yes |
4 | MAPI | 18, Sockets, MAPI, and the Internet | |
4 | Windows Sockets | 18, Sockets, MAPI, and the Internet | yes |
4 | Files in MRU list | -- | |
5 | Comments in code | -- | yes |
5 | MFC library | -- | yes |
6 | Base class for View | 5, Documents and Views |
Because some of these questions are not applicable for dialog-based applications, this table has the 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 other dialog controls that gather more information. These are the subject of the next chapter, "Dialogs and Controls."
Once you have seen how to get an application to do something, you can move through the rest of the book adding features like these:
© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.