本文主要介绍,在MFC中菜单保存命令的响应过程。
一、MFC保存命令的响应过程:
File->Save对应的ID为ID_FILE_SAVE,其响应过程如下:
首先调用响应函数 CDocument::OnFileSave(),其函数原型如下:
void CDocument::OnFileSave() { DoFileSave(); }
由此可见,CDocument::OnFileSave()调用了 DoFileSave()函数,其函数原型如下:
BOOL CDocument::DoFileSave() { DWORD dwAttrib = GetFileAttributes(m_strPathName); if (dwAttrib & FILE_ATTRIBUTE_READONLY) //如果文件是只读,或已经不存在了 { //使用DoSave(NULL) if (!DoSave(NULL)) { TRACE0("Warning: File save with new name failed.\n"); return FALSE; } } else { //使用DoSave(....) if (!DoSave(m_strPathName)) { TRACE0("Warning: File save failed.\n"); return FALSE; } } return TRUE; }此时如果操作的文件是只读或者已不存在,则不能实现对操作结果保存,否则调用DoSave()函数,其函数原型如下:
BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace) { 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] == '.'); newName += strExt; } } //bReplace为TRUE则显示保存文件对话框(AFX_IDS_ SAVEFILE), //否则显示拷贝保存对话框(AFX_IDS+SAVEFILECOPY) 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; //保存,由OnSaveDocument完成 if (!OnSaveDocument(newName)) { if (lpszPathName == NULL) { // be sure to delete the file TRY { CFile::Remove(newName); } CATCH_ALL(e) { TRACE0("Warning: failed to delete file \n"); DELETE_EXCEPTION(e); } END_CATCH_ALL } return FALSE; } // reset the title and change the document name if (bReplace) SetPathName(newName); return TRUE; // success }DoSave()函数先判段文件名参数是否为空,如果为空,则重新获取文件名,否则调用OnSaveDocument()函数,其函数原型如下:
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName) { CFileException fe; CFile* pFile = NULL; pFile = GetFile(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive, &fe); if (pFile == NULL) { ReportSaveLoadException(lpszPathName, &fe, TRUE, AFX_IDP_INVALID_FILENAME); return FALSE; } //建立保存用的CArchive CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete); saveArchive.m_pDocument = this; saveArchive.m_bForceFlat = FALSE; TRY { CWaitCursor wait; //使用文档类的序列化操作完成实际存档行为 Serialize(saveArchive); // save me saveArchive.Close(); ReleaseFile(pFile, FALSE); } CATCH_ALL(e) { ReleaseFile(pFile, TRUE); TRY { ReportSaveLoadException(lpszPathName, e, TRUE, AFX_IDP_FAILED_TO_SAVE_DOC); } END_TRY DELETE_EXCEPTION(e); return FALSE; } END_CATCH_ALL SetModifiedFlag(FALSE); // back to unmodified return TRUE; // success }
由此实现了对文件的保存过程,OnSaveDocument()函数也即是"工程名Doc.cpp"中的函数。
由此MFC中保存命令的响应过程已介绍完了,其响应过程为:
(1)首先调用 CDocument::OnFileSave(),OnFileSave调用CDocument::DoFileSave()
(2)CDocument::DoFileSave()判断文件是否只读,是则DoSave(NULL),否则调用DoSave(m_strPathName)
(3)CDocument::DoSave(LPCTSTR lpszPathName,BOOL bReplace=TRUE)的流程为:
第一步:判断lpszPathName不空 ,则跳第二步,为空则获取文档的路径名,加上扩展符。bReplace为TRUE,则显示保存文件对话框框,否则
显示拷贝保存对话框。
第二步:调用CDocument::OnSaveDocument()保存文档。
第三步:若bReplace==TRUE则SetPathName(newName)覆盖当前路径名。
(4)CDocument::OnSaveDocument()打开文件,创建CArchive对象saveArchive,Serialize(saveArchive)读写文件,SetModifiedFlag(FALSE)。