Monday, 4 March 2013

A Single Document Interface Application


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:
l CAboutDlg, a dialog class for the About dialog box
l CFirstSDIApp, a CWinApp class for the entire application
l CFirstSDIDoc, a document class
l CFirstSDIView, a view class
l CMainFrame, a frame class
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
is 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 commandline
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.

//{{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 is no need to handle OK or Cancel in any special way -
this is just an About box.





No comments:

Post a Comment