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) |
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 : 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 : 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); }
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 : 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 : 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
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 : 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 : 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); }
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?