• 温故而知新,学习MFC框架如何创建的过程

    2005-03-26

    Tag:Visual_C++

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://dezhao.blogbus.com/logs/1081859.html

    文章标题:温故而知新,学习MFC框架如何创建的过程
    原 作 者:liukaven
    原 出 处:CSDN
    发 布 者:liukaven
    发布类型:原创
    发布日期:2004-12-23
    今日浏览:7
    总 浏 览:2749

     

    很久没有使用MFC了,以至于都忘记MFC框架复杂的窗口、文档、视的创建过程了。

    下面我们跟踪一个MFC MDI的应用程序,来温习或学习一下。

     

    使用AppWizard创建一个MDI应用程序,我创建的应用程序叫MDITest,这样MFC生成了如下的类:

    类名

    作用

    CMDITestApp

    派生于CWinApp的应用程序类。

    CMainFrame

    派生于CMDIFrameWnd的MDI框架窗口类。

    CMDITestDoc

    派生于CDocument的文档类。

    CChildFrame

    派生于CMDIChildWnd的MDI子窗口类。

    CMDITestView

    派生于CView的文档显示类。

    在运行时刻,CMainFrame, CChildFrame, CMDITestView的窗口关系如下面的表格示出:

    CMainFrame

    Menu, Toolbar

    MDIClient

     

    CChildFrame

    CMDITestView

       pDocument = *CMDITestDoc   (带有文档的指针)

     

     

     

     

     

    [StatusBar]

    其中,最外层的是顶层窗口CMainFrame,里面包含一个MDIClient窗口。CChildFrame做为子窗口包含于MDIClient中(可以包含多个),CChildFrame里面则是真实的文档表示窗口CMDITestView了。

     

    我们从这里开始:

    // CMDITestApp 初始化

    BOOL CMDITestApp::InitInstance()

     

    做为CWinApp的派生类,通常需要重载InitInstance(), ExitInstance()两个函数,以完成应用的初始化和退出。我们现在关心InitInstance中关于文档模板、窗口处理的部分,而忽略掉一些CommonControl, OLE初始化部分。

     

    整个InitInstance代码如下:

    BOOL CMDITestApp::InitInstance()

    {

         InitCommonControls();       // 这里删减了大量注释和错误处理

         CWinApp::InitInstance();

         AfxOleInit();

         AfxEnableControlContainer();

         SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

         LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)

     

         TRACE("Before CMultiDocTemplate\n");

         // 注册应用程序的文档模板。文档模板

         // 将用作文档、框架窗口和视图之间的连接

         CMultiDocTemplate* pDocTemplate;

         pDocTemplate = new CMultiDocTemplate(IDR_MDITestTYPE,

             RUNTIME_CLASS(CMDITestDoc),

             RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架

             RUNTIME_CLASS(CMDITestView));

         if (!pDocTemplate)

             return FALSE;

         TRACE("Before AddDocTemplate\n");

         AddDocTemplate(pDocTemplate);

     

         // 创建主 MDI 框架窗口

         TRACE("Before new CMainFrame\n");

         CMainFrame* pMainFrame = new CMainFrame;

         TRACE("Before pMainFrame->LoadFrame\n");

         if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))

             return FALSE;

         m_pMainWnd = pMainFrame;

     

         TRACE("Before ParseCommandLine\n");

         CCommandLineInfo cmdInfo;

         ParseCommandLine(cmdInfo);

     

         // 调度在命令行中指定的命令。如果

         // 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。

         TRACE("Before ProcessShellCommand\n");

         if (!ProcessShellCommand(cmdInfo))

             return FALSE;

     

         TRACE("Before pMainFrame->ShowWindow\n");

         // 主窗口已初始化,因此显示它并对其进行更新

         pMainFrame->ShowWindow(m_nCmdShow);

         TRACE("Before pMainFrame->UpdateWindow\n");

         pMainFrame->UpdateWindow();

         return TRUE;

    }

     

    为了研究整个创建过程,我在其中添加了一些TRACE来跟踪创建顺序。

     

    忽略掉开始的乱七八糟的初始化,从CMultiDocTemplate开始:

         CMultiDocTemplate* pDocTemplate = new CMultiDocTemplate(IDR_MDITestTYPE,

             RUNTIME_CLASS(CMDITestDoc),

             RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架

             RUNTIME_CLASS(CMDITestView));

         AddDocTemplate(pDocTemplate);

    (作了一点点简化)

    这里首先创建了一个CMultiDocTemplate —— 文档模板,文档模板包括的三个运行时刻类信息:Document – CMDITestDoc, FrameWnd – CChildFrame, View – CMDITestView

    然后通过AddDocTemplate函数将新创建的文档模板添加到模板管理器之中(我们以后再研究模板管理器)。

     

    然后创建主框架窗口CMainFrame

         CMainFrame* pMainFrame = new CMainFrame;

         if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))

             return FALSE;

     

    其中,需要研究的是LoadFrame的实现,以及里面都做了些什么。我们稍后研究。

     

    处理命令行,在这里第一个空文档被建立出来:

         CCommandLineInfo cmdInfo;

         ParseCommandLine(cmdInfo);

     

         // 调度在命令行中指定的命令。如果用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。

         if (!ProcessShellCommand(cmdInfo))               // ß 这里创建出初始空文档

             return FALSE;

     

    我们一会会重点研究ProcessShellCommand

     

    最后,显示主窗口:

         pMainFrame->ShowWindow(m_nCmdShow);

         pMainFrame->UpdateWindow();

     

    至此,WinApp::InitInstance()完成了自己的工作。

     

    上面遗留了三个待研究的分支,让我们现在去研究它们:

    1、  CDocTemplate

    2、  CFrameWnd::LoadFrame

    3、  CWnd::ProcessShellCommand

     

     

     

    研究CDocTemplate

     

    我们的例子中是构造了一个CMultiDocTemplate,它是从CDocTemplate派生而来,所以我们主要研究CDocTemplate

    CDocTemplate的几个关键属性列表如下:

         CRuntimeClass* m_pDocClass;         // class for creating new documents

         CRuntimeClass* m_pFrameClass;       // class for creating new frames

         CRuntimeClass* m_pViewClass;        // class for creating new views

     

    其中:

    m_pDocClass

    表示文档类类型,在此例子中就是CMDITestDoc

    m_pFrameClass

    表示容纳View窗口的框架窗口类类型,此例中为CChildFrame

    m_pViewClass

    表示显示文档的View视类类型,此例中为CMDITestView

     

    我们可以这样认为,CDocTemplate

    历史上的今天:

    (RTP)RFC 3550 2005-03-26

    收藏到:Del.icio.us