This example is the MDI version of the EX17A example from the previous chapter. It uses the same document and view class code and the same resources (except the program name). The application code and main frame class code are different, however. All the new code is listed here, including the code that AppWizard generates. A list of the files and classes in the EX18A example are shown in the table below.
| Header File | Source Code File | Class | Description |
| ex18a.h | ex18a.cpp | CEx18aApp | Application class (from AppWizard) |
| CAboutDlg | About dialog | ||
| MainFrm.h | MainFrm.cpp | CMainFrame | MDI main frame |
| ChildFrm.h | ChildFrm.cpp | CChildFrame | MDI child frame |
| StuDoc.h | StuDoc.cpp | CStudentDoc | Student document (from EX17A) |
| StuView.h | StuView.cpp | CStudentView | Student form view (from EX16B) |
| Student.h | Student.cpp | CStudent | Student record (from EX17A) |
| StdAfx.h | StdAfx.h | Precompiled headers (with afxtempl.h included) |
In the CEx18aApp source code listing, the OpenDocumentFile member function is overridden only for the purpose of inserting a TRACE statement. Also, a few lines have been added before the ProcessShellCommand call in InitInstance. They check the argument to ProcessShellCommand and change it if necessary to prevent the creation of any empty document window on startup. Figure 18-5 shows the source code.
|
EX18A.H // ex18a.h : main header file for the EX18A application
//
#if !defined(AFX_EX18A_H__7B5FE267_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_)
#define AFX_EX18A_H__7B5FE267_85E9_11D0_8FE3_00C04FC2A0C2__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
//////////////////////////////////////////////////////////////////////
// CEx18aApp:
// See ex18a.cpp for the implementation of this class
//
class CEx18aApp : public CWinApp
{
public:
CEx18aApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CEx18aApp)
public:
virtual BOOL InitInstance();
virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName);
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CEx18aApp)
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 Visual C++ will insert additional declarations
// immediately before the previous line.
#endif // !defined(AFX_EX18A_H__7B5FE267_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_)
EX18A.CPP // ex18a.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "ex18a.h"
#include "MainFrm.h"
#include "ChildFrm.h"
#include "StuDoc.h"
#include "StuView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////////
// CEx18aApp
BEGIN_MESSAGE_MAP(CEx18aApp, CWinApp)
//{{AFX_MSG_MAP(CEx18aApp)
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)
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////
// CEx18aApp construction
CEx18aApp::CEx18aApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
//////////////////////////////////////////////////////////////////////
// The one and only CEx18aApp object
CEx18aApp theApp;
//////////////////////////////////////////////////////////////////////
// CEx18aApp initialization
BOOL CEx18aApp::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(); // 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_EX18ATYPE,
RUNTIME_CLASS(CStudentDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CStudentView));
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
// Enable drag/drop open
m_pMainWnd->DragAcceptFiles();
// Enable DDE Execute open
EnableShellOpen();
RegisterShellFileTypes(TRUE);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// no empty document window on startup
if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew) {
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
}
// 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;
}
//////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV
// support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
// No message handlers
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// App command to run the dialog
void CEx18aApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
//////////////////////////////////////////////////////////////////////
// CEx18aApp message handlers
CDocument* CEx18aApp::OpenDocumentFile(LPCTSTR lpszFileName)
{
TRACE("CEx18aApp::OpenDocumentFile\n");
return CWinApp::OpenDocumentFile(lpszFileName);
}
|
Figure 18-5. The CEx18aApp source code listing.
CMainFrame
This main frame class, listed in Figure 18-6, is almost identical to the SDI version, except that it's derived from CMDIFrameWnd instead of CFrameWnd.
|
MAINFRM.H // MainFrm.h : interface of the CMainFrame class
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MAINFRM_H__7B5FE26B_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_)
#define AFX_MAINFRM_H__7B5FE26B_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMainFrame : public CMDIFrameWnd
{
DECLARE_DYNAMIC(CMainFrame)
public:
CMainFrame();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
// 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 Visual C++ will insert additional declarations
// immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__7B5FE26B_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_)
MAINFRM.CPP // MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "ex18a.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
//////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD
| WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS
| CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if ( !CMDIFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CMDIFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CMDIFrameWnd::Dump(dc);
}
#endif //_DEBUG
//////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
|
Figure 18-6. The CMainFrame class listing.
CChildFrame
This child frame class, listed in Figure 18-7, lets you conveniently control the child frame window's characteristics by adding code in the PreCreateWindow function. You can also map messages and override other virtual functions.
|
CHILDFRM.H // ChildFrm.h : interface of the CChildFrame class
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_CHILDFRM_H__7B5FE26D_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_)
#define AFX_CHILDFRM_H__7B5FE26D_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CChildFrame : public CMDIChildWnd
{
DECLARE_DYNCREATE(CChildFrame)
public:
CChildFrame();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CChildFrame)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void ActivateFrame(int nCmdShow = -1);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CChildFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// Generated message map functions
protected:
//{{AFX_MSG(CChildFrame)
// 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 Visual C++ will insert additional declarations
// immediately before the previous line.
#endif // !defined(AFX_CHILDFRM_H__7B5FE26D_85E9_11D0_8FE3_00C04FC2A0C2__INCLUDED_)
CHILDFRM.CPP // ChildFrm.cpp : implementation of the CChildFrame class
//
#include "stdafx.h"
#include "ex18a.h"
#include "ChildFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////////
// CChildFrame
IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd)
BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
//{{AFX_MSG_MAP(CChildFrame)
// 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
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////
// CChildFrame construction/destruction
CChildFrame::CChildFrame()
{
// TODO: add member initialization code here
}
CChildFrame::~CChildFrame()
{
}
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
if ( !CMDIChildWnd::PreCreateWindow(cs) )
return FALSE;
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CChildFrame diagnostics
#ifdef _DEBUG
void CChildFrame::AssertValid() const
{
CMDIChildWnd::AssertValid();
}
void CChildFrame::Dump(CDumpContext& dc) const
{
CMDIChildWnd::Dump(dc);
}
#endif //_DEBUG
//////////////////////////////////////////////////////////////////////
// CChildFrame message handlers
void CChildFrame::ActivateFrame(int nCmdShow)
{
TRACE("Entering CChildFrame::ActivateFrame\n");
CMDIChildWnd::ActivateFrame(nCmdShow);
}
|
Figure 18-7. The CChildFrame class listing.
Testing the EX18A Application
Do the build, run the program from Visual C++, and then make several documents. Try saving the documents on disk, closing them, and reloading them. Also, choose New Window from the Window menu. Notice that you now have two views (and child frames) attached to the same document. Now exit the program and start Windows Explorer. The files you created should show up with document icons. Double-click on a document icon and see whether the EX18A program starts up. Now, with both Windows Explorer and EX18A on the desktop, drag a document from Windows Explorer to EX18A. Was the file opened?