用视图体系结构具有最多个文件扩展名与每个文档类型关联的 Microsoft 基础类 (MFC) 文档生成的应用程序。
此默认文件扩展名,如果指定,则存储在字符串表中存储的文档模板字符串。
它通常非常有用,将两种文件扩展名与给定的文档类型相关联。本文介绍了一种技术,您可以使用来允许两种文件扩展名的文档模板字符串中存储。通过派生类和函数重写,就可以将这两个文件扩展名与文档模板相关联。
分步过程
使用以下步骤可以将两种文件扩展名与 SDI 或 MDI 应用程序中的单个文档类型相关联。- 修改字符串表项,以使其包含两种文件扩展名。两个扩展都将输入到 filterExt 字段之间用分号 (例如,.aaa ;。bbb)。文档模板字符串可能与此类似:
\nExts\nExts\nFiles (*.aaa; *.bbb)\n.aaa;.bbb\nExts.Doc\nExts Doc.
- 派生类从 CMultiDocTemplate 的 MDI 应用程序或 CSingleDocTemplate 的 SDI 应用程序。将此类添加到项目中,并在 InitInstance 函数中创建的文档模板时使用它。您将需要创建的构造函数只调用基类构造函数。
CMyMultiDocTemplate::CMyMultiDocTemplate( UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass ) : CMultiDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass) { };
- 重写从 CMultiDocTemplate 或 CSingleDocTemplate 在步骤 2 中的派生类中的 GetDocString 函数。
BOOL CMyMultiDocTemplate::GetDocString(CString& rString, enum DocStringIndex i) const { CString strTemp,strLeft,strRight; int nFindPos; AfxExtractSubString(strTemp, m_strDocStrings, (int)i); if(i == CDocTemplate::filterExt) { nFindPos=strTemp.Find(';'); if(-1 != nFindPos) { //string contains two extensions strLeft=strTemp.Left(nFindPos+1); strRight=strTemp.Right(lstrlen((const char*)strTemp)-nFindPos-1); strTemp=strLeft+strRight; } } rString = strTemp; return TRUE; }
- 以便识别这两种文件扩展名打开文件时,重写 CMyMultiDocTemplate::MatchDocType。
CDocTemplate::Confidence CMyMultiDocTemplate::MatchDocType(const char* pszPathName, CDocument*& rpDocMatch) { ASSERT(pszPathName != NULL); rpDocMatch = NULL; // go through all documents POSITION pos = GetFirstDocPosition(); while (pos != NULL) { CDocument* pDoc = GetNextDoc(pos); if (pDoc->GetPathName() == pszPathName) { // already open rpDocMatch = pDoc; return yesAlreadyOpen; } } // end while // see if it matches either suffix CString strFilterExt; if (GetDocString(strFilterExt, CDocTemplate::filterExt) && !strFilterExt.IsEmpty()) { // see if extension matches ASSERT(strFilterExt[0] == '.'); CString ext1,ext2; int nDot = CString(pszPathName).ReverseFind('.'); const char* pszDot = nDot < 0 ? NULL : pszPathName + nDot; int nSemi = strFilterExt.Find(';'); if(-1 != nSemi) { // string contains two extensions ext1=strFilterExt.Left(nSemi); ext2=strFilterExt.Mid(nSemi+2); // check for a match against either extension if (nDot >= 0 && (lstrcmpi(pszPathName+nDot, ext1) == 0 || lstrcmpi(pszPathName+nDot,ext2) ==0)) return yesAttemptNative; // extension matches } else { // string contains a single extension if (nDot >= 0 && (lstrcmpi(pszPathName+nDot, strFilterExt)==0)) return yesAttemptNative; // extension matches } } return yesAttemptForeign; //unknown document type }
- 要保存和正确保存为函数,DoSave 函数 CDocument 派生类中的重写。只需剪切并粘贴到您的派生类的从 Mfc\Src\Doccore.cpp CDocument::DoSave() 的 MFC 实现。
替换这些行:// append the default suffix if there is one CString strExt; if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) && !strExt.IsEmpty()) { ASSERT(strExt[0] == '.'); newName += strExt; }
// append the default suffix if there is one CString strExt; if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) && !strExt.IsEmpty()) { ASSERT(strExt[0] == '.'); int nSemi; //added if(nSemi = strExt.Find(';')); //added strExt = strExt.Left(nSemi); //added newName += strExt; }
您需要将下面的代码行:CATCH_ALL(e) { TRACE0("Warning: failed to delete file after failed SaveAs.\n"); DELETE_EXCEPTION(e); }
CATCH_ALL(e) { TRACE0("Warning: failed to delete file after failed SaveAs.\n"); e->Delete(); //modified }
- (仅适用于 16 位版本)使用类向导来提供文档派生的类中的 OnFileSave 和 OnFileSaveAs 命令处理程序。这是有必要的因为在 Visual C++ 16 位版本中,DoSave 函数不是虚拟。只是剪切和粘贴命令处理程序从 Mfc\Src\Doccore.cpp 这两个函数的基类版本的内容。生成函数调用 DoSave,而不是基类版本的本地副本。它可能需要添加 #include"io.h",向项目提供的 _access 函数的定义。