引文《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_pDocManager是CWinApp::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。其中,字符串资源描述了文档类型,由七个被“\n”分隔的子字符串组成,各 个 子 串 可 以 通 过 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()函数。