The Ex16b Example: An MDI Application
This example is the MDI version of the Ex16a example. 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 the MFC Application Wizard generates. A list of the files and classes in the Ex16b example are shown in Table 16-3.
Header File | Source Code File | Class | Description |
---|---|---|---|
![]() | ![]() | CEx16bApp | Application class (from the MFC Application Wizard) |
CAboutDlg | About dialog box | ||
![]() | ![]() | CMainFrame | MDI main frame |
![]() | ![]() | CChildFrame | MDI child frame |
C ![]() | C ![]() | CEx16bDoc | Student document (borrowed from Ex16a) |
C ![]() | ![]() | CEx16bView | Student form view (borrowed from Ex16a) |
![]() | ![]() | CStudent | Student record (from Ex16a) |
![]() | ![]() | Precompiled headers (with afxtempl.h included) |
CEx16bApp
In the CEx16bApp 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. The following shows the source code:Ex16b.h
// Ex16b.h : main header file for the Ex16b application
//
#pragma once
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
// CEx16bApp:
// See Ex16b.cpp for the implementation of this class
//
class CEx16bApp : public CWinApp
{
public:
CEx16bApp();
// Overrides
public:
virtual BOOL InitInstance();
// Implementation
afx_msg void OnAppAbout();
DECLARE_MESSAGE_MAP()
virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName);
};
extern CEx16bApp theApp;
Ex16b.cpp
// Ex16b.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "Ex16b.h"
#include "MainFrm.h"
#include "ChildFrm.h"
#include "Ex16bDoc.h"
#include "Ex16bView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CEx16bApp
BEGIN_MESSAGE_MAP(CEx16bApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
END_MESSAGE_MAP()
// CEx16bApp construction
CEx16bApp::CEx16bApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CEx16bApp object
CEx16bApp theApp;
// CEx16bApp initialization
BOOL CEx16bApp::InitInstance()
{
// InitCommonControls() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to enable
// visual styles. Otherwise, any window creation will fail.
InitCommonControls();
CWinApp::InitInstance();
// Initialize OLE libraries
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
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
// 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"));
// Load standard INI file options (including MRU)
LoadStdProfileSettings(4);
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_Ex16bTYPE,
RUNTIME_CLASS(CEx16bDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CEx16bView));
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
// call DragAcceptFiles only if there's a suffix
// In an MDI app, this should occur immediately after setting m_pMainWnd
// 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. Will return FALSE
// if app was launched with /RegServer, /Register, /Unregserver
// or /Unregister.
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
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// App command to run the dialog
void CEx16bApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
// CEx16bApp message handlers
CDocument* CEx16bApp::OpenDocumentFile(LPCTSTR lpszFileName)
{
TRACE("CEx16bApp::OpenDocumentFile\n");
return CWinApp::OpenDocumentFile(lpszFileName);
}
CMainFrame
This main frame class, as shown in the following code listings, 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
//
#pragma once
class CMainFrame : public CMDIFrameWnd
{
DECLARE_DYNAMIC(CMainFrame)
public:
CMainFrame();
// Attributes
public:
// Operations
public:
// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 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 int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
};
MainFrm.cpp
// MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "Ex16b.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_WM_CREATE()
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
CChildFrame
This child frame class, shown in the following code listings, 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
//
#pragma once
class CChildFrame : public CMDIChildWnd
{
DECLARE_DYNCREATE(CChildFrame)
public:
CChildFrame();
// Attributes
public:
// Operations
public:
// Overrides
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// Implementation
public:
virtual ~CChildFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
public:
virtual void ActivateFrame(int nCmdShow = -1);
};
ChildFrm.cpp
// ChildFrm.cpp : implementation of the CChildFrame class
//
#include "stdafx.h"
#include "Ex16b.h"
#include "ChildFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildFrame
IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd)
BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
END_MESSAGE_MAP()
// CChildFrame construction/destruction
CChildFrame::CChildFrame()
{
// TODO: add member initialization code here
}
CChildFrame::~CChildFrame()
{
}
BOOL CChildFrame::PreCreateWindow(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);
}
Testing the Ex16b Application
Do the build, run the program from Visual C++ .NET, 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 Ex16b program starts up. Now, with both Windows Explorer and Ex16b on the desktop, drag a document from Windows Explorer to Ex16b. Was the file opened?