这里的顶目名称是D-TriNet,文档扩展名是.dtn和.csv。
要让打开/保存对话框支持多个扩展名,最简单的方法是修改资源文件中的IDR_DTriNetTYPE字段:
STRINGTABLE BEGIN IDR_MAINFRAME "D-TriNet" IDR_DTriNetTYPE "\nDTriNet\nD-TriNet\nD-TriNet Files(*.dtn;*.csv)\n.dtn;.csv\nDTriNet.Document\nD-TriNet.Document" END这样做的不足是,文件虽然可以有多个扩展名,但仍然只分为两类:"D-TriNet Files"和"All Files"。
下面的文字有些凌乱,因为它的内容是按照我的探索过程组织的。
首先考虑打开对话框。第一步是要弄清,打开对话框是什么时候(在哪)弹出来的?
默认情况下,CDTriNetApp调用CWinApp::OnFileOpen方法处理FileOpen事件:
ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)CWinApp::OnFileOpen又调用CDocManager::OnFileOpen处理FileOpen事件:
void CWinApp::OnFileOpen() { ENSURE(m_pDocManager != NULL); m_pDocManager->OnFileOpen(); }CDocManager::OnFileOpen显示对话框与用户交互,然后调用CWinApp::OpenDocumentFile方法:
void CDocManager::OnFileOpen() { // prompt the user (with all document templates) CString newName; if (!DoPromptFileName(newName, AFX_IDS_OPENFILE, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL)) return; // open cancelled AfxGetApp()->OpenDocumentFile(newName); // if returns NULL, the user has already been alerted }显然,一种可能的解决办法是绕过CWinApp和CDocManager,在CDTriNetApp::OnFileOpen方法中显示自定义对话框,然后调用CWinApp::OpenDocumentFile方法。
ON_COMMAND(ID_FILE_OPEN, &CDTriNetApp::OnFileOpen) void CDTriNetApp::OnFileOpen() { LPCTSTR szFilter = L"DTriNet文件(*.dtn)|*.dtn|CSV文件(*.csv)|*.csv|所有文件(*.*)|*.*||"; CFileDialog oFileDlg(TRUE, L".dtn", NULL, 4|2, szFilter); if(oFileDlg.DoModal() == IDOK) OpenDocumentFile(oFileDlg.GetFileName()); // CDTriNetApp不需要重写CWinApp::OpenDocumentFile方法 }
现在考虑保存对话框。第一步仍然是弄清,保存对话框是什么时候(在哪)弹出来的?
分发消息时,调用了CDocument::DoFileSave虚方法:
BOOL CDocument::DoFileSave() { DWORD dwAttrib = GetFileAttributes(m_strPathName); if (dwAttrib & FILE_ATTRIBUTE_READONLY) { // we do not have read-write access or the file does not (now) exist if (!DoSave(NULL)) { TRACE(traceAppMsg, 0, "Warning: File save with new name failed.\n"); return FALSE; } } else { if (!DoSave(m_strPathName)) { TRACE(traceAppMsg, 0, "Warning: File save failed.\n"); return FALSE; } } return TRUE; }
CDocument::DoFileSave调用CDocument::DoSave,也是一个虚方法:
(注:没有DoSaveAs方法,lpszPathName参数决定了CDocument::DoSave是表现为“保存”还是“另存为”。)
BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace) // Save the document data to a file // lpszPathName = path name where to save document file // if lpszPathName is NULL then the user will be prompted (SaveAs) // note: lpszPathName can be different than 'm_strPathName' // if 'bReplace' is TRUE will change file name if successful (SaveAs) // if 'bReplace' is FALSE will not change path name (SaveCopyAs) { CString newName = lpszPathName; if (newName.IsEmpty()) { CDocTemplate* pTemplate = GetDocTemplate(); ASSERT(pTemplate != NULL); newName = m_strPathName; if (bReplace && newName.IsEmpty()) { newName = m_strTitle; // check for dubious filename int iBad = newName.FindOneOf(_T(":/\\")); if (iBad != -1) newName.ReleaseBuffer(iBad); // append the default suffix if there is one CString strExt; if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) && !strExt.IsEmpty()) { ASSERT(strExt[0] == '.'); int iStart = 0; newName += strExt.Tokenize(_T(";"), iStart); } } if (!AfxGetApp()->DoPromptFileName(newName, bReplace ? AFX_IDS_SAVEFILE : AFX_IDS_SAVEFILECOPY, OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, FALSE, pTemplate)) return FALSE; // don't even attempt to save } CWaitCursor wait; if (!OnSaveDocument(newName)) { if (lpszPathName == NULL) { // be sure to delete the file TRY { CFile::Remove(newName); } CATCH_ALL(e) { TRACE(traceAppMsg, 0, "Warning: failed to delete file after failed SaveAs.\n"); DELETE_EXCEPTION(e); } END_CATCH_ALL } return FALSE; } // reset the title and change the document name if (bReplace) SetPathName(newName); return TRUE; // success }
BOOL CDocManager::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate) { CFileDialog dlgFile(bOpenFileDialog, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, NULL, NULL, 0); CString title; VERIFY(title.LoadString(nIDSTitle)); dlgFile.m_ofn.Flags |= lFlags; CString strFilter; CString strDefault; if (pTemplate != NULL) { ASSERT_VALID(pTemplate); _AfxAppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault); } else {// do for all doc template POSITION pos = m_templateList.GetHeadPosition(); BOOL bFirst = TRUE; while (pos != NULL) { pTemplate = (CDocTemplate*)m_templateList.GetNext(pos); _AfxAppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate,bFirst ? &strDefault : NULL); bFirst = FALSE; } } // append the "*.*" all files filterCString allFilter; VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER)); strFilter += allFilter;strFilter += (TCHAR)'\0'; // next string please strFilter += _T("*.*"); strFilter += (TCHAR)'\0'; // last string dlgFile.m_ofn.nMaxCustFilter++; dlgFile.m_ofn.lpstrFilter = strFilter; dlgFile.m_ofn.lpstrTitle = title; dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH); INT_PTR nResult = dlgFile.DoModal(); fileName.ReleaseBuffer(); return nResult == IDOK; }
BOOL CDTriNetDocMgr::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate) { LPCTSTR strFilter = L"DTriNet文件(*.dtn)|*.dtn|CSV文件(*.csv)|*.csv|所有文件(*.*)|*.*||"; CFileDialog dlgFile(bOpenFileDialog, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, strFilter, NULL, 0); CString title; VERIFY(title.LoadString(nIDSTitle)); dlgFile.m_ofn.lpstrTitle = title; dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH); INT_PTR nResult = dlgFile.DoModal(); fileName.ReleaseBuffer(); return nResult == IDOK; }