单文档/视图

引文《MFC深入浅出》李进久

如前一节所述,程序从 InitInstance 开始。在 SDI 应用程序的APP::InitInstance()里,至少有以下语句:

第一部分,创建文档模板对象并把它添加到应用程序的模板链表

CSingleDocTemplate* pDocTemplate; 
pDocTemplate = new CSingleDocTemplate( 
  IDR_MAINFRAME, 
  RUNTIME_CLASS(CTDoc), 
  RUNTIME_CLASS(CMainFrame), // main SDI frame window 
  RUNTIME_CLASS(CTView)); 
AddDocTemplate(pDocTemplate); 

CSingleDocTemplate调用构造函数,源码如下:

void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)
{
    if (m_pDocManager == NULL)
        m_pDocManager = new CDocManager;
    m_pDocManager->AddDocTemplate(pTemplate);
}

作用两个:

  • 生成一个CDocManager对象,其中m_pDocManagerCWinApp::m_pDocManager
  • 接着调用CDocManager的成员函数CDocManager::AddDocTemplate(),实际是转手了一次

接着跟踪CDocManager的成员函数AddDocTemplate,源码截选如下:

void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
{
...............
        ASSERT_VALID(pTemplate);
        ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);// must not be in list
        pTemplate->LoadTemplate();
        m_templateList.AddTail(pTemplate);//将文档模板指针加入到自己的CDocManager::CPtrList类型的链表中...
    }
}

第二部分,动态创建文档、视图、边框窗口等 MFC 对象和对应的 Windows 对象

//Parse command line for standard shell commands, DDE, file open 

CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo); 
// Dispatch commands specified on the command line 
if (!ProcessShellCommand(cmdInfo)) 
return FALSE; 

第三部分,返回 TRUE,WinMain 下一步调用 Run 开始消息循环
//否则,终止程序
return TRUE;
对于第二部分,又可以分解成许多步骤。
下面将解释每一步。

第一部分:文档模板的创建

第一步是创建文档模板。
文档模板的作用是动态创建其他 MFC 对象,它保存了要动态创建类的动态创建信息和该文档类型的资源 ID。这些信息保存在文档模板的成员变量里:

  • m_nIDResource(资源 ID)
  • m_pDocClass( 文 档 类 动 态 创 建 信 息 ) 
  • m_pFrameClass( 边 框 窗 口 类 动 态 创 建 信 息 ) 
  • m_pViewClass(视类动态创建信息)

资源 ID 包括菜单、像标、快捷键、字符串资源的 ID,它们都使用同一个 ID 值,如IDR_MAINFRAME。其中,字符串资源描述了文档类型,由七个被“ ”分隔的子字符串组成,各 个 子 串 可 以 通 过 CDocTemplate 的 成 员 函 数 GetDocString(CString& rString, enum DocStringIndex index)来获取。DocStringIndex 是 CDocTemplate 类定义的枚举变量以区分七个子串,描述如下(英文是枚举变量名称)。

  • WindowTitle 应用程序窗口的标题。仅仅对 SDI 程序指定。
  • DocName 用来构造缺省文档名的字符串。当用 File 菜单的菜单项 new 创建新文档时,缺省文档名由该字符串加一个数字构成。如果空,使用“unitled”。
  • FileNewName 文档类型的名称,在打开 File New 对话框时显示。
  • FilterName 匹配过滤字符串,在 File Open 对话框用来过滤要显示的文件。如果不指定,File Open 对话框的文件类型(file style)不可访问。
  • FilterExt 该类型文档的扩展名。如果不指定,则不可访问对话框的文件类型(File Style)。
  • RegFileTypeId 文档类型在 Windows 注册库中的存储标识。
  • RegFileTypeName 文档类型在 Windows 注册库中的类型名称。

文档模板被应用程序对象创建和管理。应用程序类 CWinApp 有一个 CDocManager 类型的成员变量m_pDocManager,通过该变量来管理应用程序的文档模板列表,把一些相关的操作委派给 CDocManager 对象处理。 CDocManager 使用 CPtrList 类型的m_templateList 变量来存储文档模板,并提供了操作文档模板列表的系列函数。 从语句 pDocTemplate = new CSingleDocTemplate(…)可以看出应用程序对象创建模板时传递一个资源 ID 和三个类的动态创建信息给它:
IDR_MAINFRAME,//资源 ID
RUNTIME_CLASS(CTDoc),//文档类动态创建信息
RUNTIME_CLASS(CMainFrame),//边框窗口类动态创建信息
RUNTIME_CLASS(CTView),//视类动态创建信息
文档模板对象接收这些信息并把它们保存到对应的成员变量里头。然后 AddDocTemplate 实
际调用 m_pDocManager->AddDocTemplate,把创建的模板对象加入到文档模板管理器的模
板列表中,也就是应用程序对象的文档模板列表中。

结果:

  • 生成文档模板对象
  • 初始化一些成员变量

第二部分:文件的创建或者打开

第二步是创建或者打开文件。对于SDI程序,MFC对象的动态创建过程是在创建或者打开文件中发生的。但是为什么没有看到文件操作相关的语句呢?
重点参考笔记《CCommandLineInfo类》

这一部分主要是命令行解析的操作,比如:命令类型是FILENEW时,调用的函数就是标准命令ID_FILE_NEW对应的处理函数OnFileNew;命令类型是FILEOPEN时调用的函数是OpenDocumentFile,标准命令ID_FILE_OPEN的处理函数OnFileOpen的工作实际上就是由OpenDocumentFile完成的。函数FileNew、OpenDocumentFile导致了窗口、文档的创建。

这一部分只解析命令,并根据结果来调用相关的函数。

继续跟踪,假如是OnFileNew,调用的是APP::OnFileNew,别忘了现在这些都是在APP对象内的操作。查看源码CWinApp::OnFileNew的调用

void CWinApp::OnFileNew()
{
    if (m_pDocManager != NULL)
        m_pDocManager->OnFileNew(); //调用m_pDocManager的..
}

可知,实际上调用的是m_pDocManager所指向的OnFileNew()函数。

原文地址:https://www.cnblogs.com/tinaluo/p/7835732.html