- Table of Contents
- Copyright
- About the Authors
- About the Contributors
- Acknowledgments
- Tell Us What You Think!
- Introduction
- How to Use This Book
- What You Need to Use This Book
- What's New in Visual C++ 6.0
- Contacting the Main Author
- Part I: Introduction
- Chapter 1. The Visual C++ 6.0 Environment
- Part II: MFC Programming
- Chapter 2. MFC Class Library Overview
- Chapter 3. MFC Message Handling Mechanism
- Chapter 4. The Document View Architecture
- Chapter 5. Creating and Using Dialog Boxes
- Chapter 6. Working with Device Contexts and GDI Objects
- Chapter 7. Creating and Using Property Sheets
- Chapter 8. Working with the File System
- Chapter 9. Using Serialization with File and Archive Objects
- Part III: Internet Programming with MFC
- Chapter 10. MFC and the Internet Server API (ISAPI)
- Chapter 11. The WinInet API
- Chapter 12. MFC HTML Support
- Part IV: Advanced Programming Topics
- Chapter 13. Using the Standard C++ Library
- Chapter 14. Error Detection and Exception Handling Techniques
- Chapter 15. Debugging and Profiling Strategies
- Chapter 16. Multithreading
- Chapter 17. Using Scripting and Other Tools to Automate the Visual C++ IDE
- Part V: Database Programming
- Chapter 18. Creating Custom AppWizards
- Chapter 19. Database Overview
- Chapter 20. ODBC Programming
- Chapter 21. MFC Database Classes
- Chapter 22. Using OLE DB
- Chapter 23. Programming with ADO
- Part VI: MFC Support for COM and ActiveX
- Chapter 24. Overview of COM and Active Technologies
- Chapter 25. Active Documents
- Chapter 26. Active Containers
- Chapter 27. Active Servers
- Chapter 28. ActiveX Controls
- Part VII: Using the Active Template Library
- Chapter 29. ATL Architecture
- Chapter 30. Creating COM Objects Using ATL
- Chapter 31. Creating ActiveX Controls Using ATL
- Chapter 32. Using ATL to Create MTS and COM+ Components
- Part VIII: Finishing Touches
- Chapter 33. Adding Windows Help
- Part IX: Appendix
Putting It All Together
In this chapter, you have taken a look at the classes in the application architecture hierarchy and have seen many of the features these classes have to offer. Now let's take a look at how MFC brings this all together to get your application off and running.
The first thing that your application will do when it begins executing is initialize all the static and global objects in your application. Perhaps the most important global object that will be created is an instance of your CWinApp class. If you have created your app with MFC AppWizard, this is done for you by code like this from HiMom.cpp in the HiMom sample:
// The one and only CHiMomApp object CHiMomApp theApp;
The code created by Visual C++ will call the constructor of your CWinApp class just after creating global variables by loading an initialized data segment and constructing a few other objects that MFC uses internally.
You should be aware that the initialization of your application has not been completed when the constructor for your CWinApp (or any other static object) is called. You should avoid doing any serious operations in these constructors, particularly with Windows classes. Simple initialization of your variables (including CString objects) is fine, but you will soon run into trouble if you try to perform operations on other more complicated classes, particularly classes such as CWnd, because the actual window underlying CWnd objects has not been created yet.
WinMain()
Once all the constructors for static objects have run, the runtime library will call MFC's implementation of WinMain(). This function will take care of initializing MFC for you and will then call the InitApplication() and InitInstance() members of your CWinApp class. When these have finished, WinMain() will call the Run() function of your CWinApp class. Normally, this defaults to CWinThread::Run(), which will get the message pump for your application going. At this point, your application will begin to process messages like any good Windows application.
When your application terminates (typically, when a WM_QUIT message is received) MFC will call the ExitInstance() function of your CWinApp class, then the destructors of any static objects, including your CWinApp object. The application then returns control to the operating system and is done.
InitApplication() and InitInstance()
The InitApplication() function is really not necessary for Win32 programming, but is a relic from the good (or bad) days of Win16. In 16-bit windows, two instances of an application could run at the same time, with the InitApplication() code running only when the first instance was started. In Win32, an application that is run twice, it will exist in two totally separate, independent processes. You can place code in InitApplication(), but it is no different than InitInstance() in Win32, except InitApplication() will be called first. If you choose to override the default InitApplication(), you should return TRUE if all is well. If your function returns FALSE, initialization will halt, ending your program.
Your InitInstance() function is where all the serious initialization for your app should occur. If you look at the InitInstance() function created by MFC AppWizard for the HiMom example shown next, you will notice that it does several very important things. Depending on the options you selected in MFC AppWizard, you may see how the wizard initializes things such as OLE, Windows sockets, and 3D controls:
BOOL CHiMomApp::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.
// TODO: 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();
// Register the application's document templates. Document templates
//serve as the connection between documents, frame windows and views.
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_HIMOMTYPE,
RUNTIME_CLASS(CHiMomDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CHiMomView));
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;
}
LoadStdProfileSettings()
You should also notice a call to LoadStdProfileSettings(). This will load some standard data items, including the files on the Most Recently Used list, from either the application's .ini file or from the registry. For now, suffice it to say that the registry allows a hierarchical, secure place to store and retrieve data that was formerly relegated to various .ini files in Win16.
Working with the Command Line
In MFC applications, you can handle command-line information in several ways. Traditional C-style argc and argv processing is available by using the __argc and __argv global variables provided. You may also look at the entire command line provided by m_lpCmdLine. Windows applications, however, can support some special command-line options that are best handled with the methods shown next.
As you can see from the previous example, InitInstance() creates a CCommandLineInfo object and passes it to ParseCommandLine(). This function will then call CCommandLineInfo::ParseParam() for each parameter. ParseParam() will modify the CCommandLineInfo structure based on these parameters. In InitInstance(), the resulting CCommandLineInfo object is then passed to ProcessShellCommand(), which is responsible for carrying out any default actions specified in the command line.
The default implementation of ParseParam() will handle the parameters and the actions detailed in Table 2.2.
Table 2.2. Default parameter actions
| Parameter | Action |
| (No parameter) | Create new document. |
| < filename > | Open specified file. |
| /p < filename > | Print specified file. |
| /pt < filename > < printer > < driver > < port > | Print file to specified printer. |
| /dde | Serve a DDE session. |
| /automation | Start as an Automation server. |
| /embedding | Prepare to serve an embedded |
| OLE object. |
You may use argc, argv processing along with ParseCommandLine() if you want, or you may change the way ParseCommandLine() works by creating your own class derived from CCommandLineInfo and overriding the ParseParam() function.
You may also change your application's behavior by modifying the CCommandLineInfo object before you call ProcessShellCommand(). For example, if you do not want your application to create a new document by default, you can make sure that the m_nShellCommand member of the CCommandLineInfo object is not FileNew before you pass it to ProcessShellCommand(). For more on this, refer to CCommandLineInfo in the Visual C++ online documentation.
Creating the Main Window
The last thing that the MFC AppWizard-generated version of InitInstance does is call ShowWindow() and UpdateWindow() to present the main window of your application, which was created earlier in InitInstance. Like InitApplication(), your InitInstance() call should return FALSE only if something has gone wrong and you want to bail out of your program right there.
The Message Pump | Next Section

Account Sign In
View your cart