当把一个 文档名 作为 变量 来调用CWinApp::OpenDocumentFile()时,MFC是 如何选择 用来 打开一个给定文档的 文档模板对象的呢?
如果跟踪CWinApp::OpenDocumentFile()函数的整个调用过程,会发现该函数只是通过存储在 应用程序对象 中的m_pDocManager指针简单的调用CDocManager::OpenDocumentFile()函数,后面的这个函数完成选择与文档扩展名最匹配的文档模板对象的全部工作。
为了完成这一部分的处理,CDocManager::OpenDocumentFile()函数遍历它的文档模板对象表,并为表的每个成员(成员为文档模板对象)调用CDocTemplate::MatchDocType()函数,传递的参数是 要打开的 文档的 文件名。
而CDocTemplate::MatchDocType()执行下面的逻辑:
(1)遍历当前打开的文档对象的列表,查找它们中的哪一个的文件名与我们的变量相同。如果能找到,返回 指向这个文档对象的指针 和 yesAlreadyOpen确认值。
(2)如果文件名与所有打开的文档都不匹配,那么检查它的扩展名是否与 文档模板字符串 中的filterExt字串匹配。如果匹配的话,返回一个yesAttemptNative确认值。否则返回yesAttemptForeign确认值。
在遍历中,CDocManager::OpenDocumentFile()函数始终保留一个指向文档模板对象的指针,该对象提供了最后的确认,最后的确认值决定了CDocManager::OpenDocumentFile()函数将要发生的动作。
@如果文件名与一个已经打开的文档对象匹配(确认值==yesAlreadyOpen),那么激活这个文档的框架窗口和视图。
@如果文件的扩展名与某个文档模板对象的filterExt字串匹配(确认值==yesAlreadyNative),那么把这个文档模板对象作为最好的候选模板来使用,并调用它的OpenDocumentFile()函数。
@如果文件名的扩展名与任何文档模板对象的filterExt都不匹配(确认值==yesAlreadyForeign),那么随即的选择第一个注册过的文档模板对象作为最匹配的对象,并调用它的OpenDocumentFile()函数。注意:这种随即的选择通常都是错误的,在这种情况下,文档对象的Serialize()函数将可能触发一个错误异常,CDocument::OnOpenDocument()函数的默认句柄将捕获该异常并显示一条错误信息。
从上面的分析中可以看出,如果打算把自己的 某个文档模板对象 作为所有 扩展名与特殊filterExt字串 不匹配 的文档的默认模板,那么该 默认的文档模板对象 应该是AddDocTemplate()注册的第一个模板。
其中核心的CDocManager::OpenDocumentFile()函数的伪代码如下:
- CDocument* CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)
- {
- //1、遍历应用程序的文档模板列表
- POSITION pos=m_templateList.GetHeadposition();//文档模板列表中的第一个文档模板对象的位置
- CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt;
- CDocTemplate* pBestTemplate = NULL;//为与 文件 最匹配的 文档模板 准备的指针
- CDocument* pOpenDocument=NULL;//保存已经打开的文档指针,由MatchDocType()函数赋值
- TCHAR szPath[_MAX_PATH];
- while(pos != NULL)
- {
- CDocTemplate* pTemplate=(CDocTemplate*)m_templateList.GetNext(pos);//每个文档模板对象的指针
- //计算这个文档模板对象的确认值
- CDocTemplate::Confidence match;
- match=pTemplate->MatchDocType(szPath/*想要打开的文件名*/ , pOpenDocument/*已经打开的文档*/);
- //存储到目前位置最好的匹配
- if(match > bestMatch)
- {
- bestMatch=match;
- pBestTemplate=pTemplate;
- }
- //如果文件名与一个已经打开的文档对象匹配,则中断跳出
- if(match == CDocTemplate::yesAlreadyOpen)
- break;
- }
- if(pOpenDocument != NULL)
- {
- //如果我们已经找到了一个已经打开的文档对象,则激活的它的框架窗口和视图,并返回它的地址
- //......
- //激活框架和视图的代码省略......
- //......
- return pOpenDocument;
- }
- //没有“最好”的模板,返回Error!
- if(pBestTemplate == NULL)
- {
- AfxMessageBox(AFX_IDP_FAILED_TO_OPEN_DOC);
- return NULL;
- }
- //使用最匹配的文档模板对象打开给定的文件名
- return pBestTemplate->OpenDocumentFile(szPath);
- }