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?