歡迎您光臨本站 註冊首頁

第一次深入MFC 調試一個小小的錯誤

←手機掃碼閱讀     火星人 @ 2014-03-26 , reply:0

以前常認為自己mfc學得不錯,因為有CSDN+MSDN+GOOGLE,可是今天收到一個網友(女的哦!)的消息,說他有個程序有點問題,她把程序發到我的郵箱里去了,我down了下來.研究了一嚇,這個程序給我補了一些基礎知識,並認識到其實自己還很菜.然後就寫了這篇文章了.

  那個程序(網友給我發的那個程序)是一個SDI程序,錯誤是在點擊文件(自動生成的那個)->保存(打開\另存為)時會出錯,是一個斷言的錯誤提示形式,這時我就去看了看她的CXXXDoc里,OnSaveDocument()是怎樣寫的,去看了看,發現並沒有重載這個函數,這時就鬱悶啦?那到底錯在哪裡呢?我馬上想到不如debug一嚇吧,在debug下,我再點文件->保存,可是並沒有斷下來?它直接就彈出個錯誤框.不知道是為什麼,苦思了一會,在沒辦法的情況下,又試了一嚇,,看能不能斷下來,可是還是斷不下來,又在沒辦法+失望的情況下,我點了重試(ASSERT的提示框不是有三個按鈕的嗎,分別是終止\重試\忽略),這下就可以斷下來了?哈,我看看是斷到哪裡,噢,斷到了CDocument::DoSave(...)里去了,我看了看,這個函數被CDocument::DoFileSave()所調用,看看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))
{
TRACE0("Warning: File save with new name failed.\n");
return FALSE;
}
}
else
{
if (!DoSave(m_strPathName))
{
TRACE0("Warning: File save failed.\n");
return FALSE;
}
}
return TRUE;
}

  明顯,第一個if是另存為時調用的,下面的則為保存時的.

  然後我又看了看CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace)

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] == '.');
newName += strExt;
}
}
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)
{
TRACE0("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
}

看到OnSaveDocument(newName)沒?我們平時寫程序重載的OnSaveDocument就是運行到這裡被調用的.

  回到正題來,看看上面代碼的粗體字那句話,程序就斷到該句話上,這時我通過Watch1框(在上面輸入變數

  名,能看到該變數的值)上看到strExt的值為Progra.Document.則strExt[0]是'p',不是'.',我再往上面看一嚇,

  看到這句if (pTemplate->GetDocString(strExt, CDocTemplate::filterExt) ....,知道strExt的值是CDocTemplate::filterExt的值,我想,有GetDocString(...)就應該有 SetDocString(...)吧?我去試了一嚇,並沒有這個函數.我在想,文件的後綴名應該是可以定製的,突然想到字元串資源,以前在看深入淺出 MFC時,講到過後綴是可以

  定製的,我翻一嚇深入淺出MFC,找到了,在321頁,我複習了一嚇,也說一嚇(呵呵),是這樣的,其實在創建工程的時候,你就可以定製7個字元串,分別是CDocTemplate::windowTitle

CDocTemplate::docName
CDocTemplate::fileNewName
CDocTemplate::filterName
CDocTemplate::filterExt
CDocTemplate::regFileTypeld
CDocTemplate::regFileTypeName

  我解釋一嚇每個字元串的意義,

  CDocTemplate::windowTitle很簡單,就是窗口標題欄上的字元串,如你指定為BM,那運行時在標題欄上顯示的就是"你的文檔名 - BM".

  CDocTemplate::docName這個是在MDI程序上才有用,如你指定為DL(眾人:怎樣又是劍聖,又是恐懼,是打魔獸還是談VC 啊!!!),那在MDI程序時,這個DL將做為默認的名字,如第一個文件將叫做DL1,再新建一個文件的話,則叫DL2,如此類推.

  CDocTemplate::filterName這個是在文件->打開后,彈出打開對話框后,這個字元串將顯示在文件類型里,並不是作為打開對話框的過濾字元串

  CDocTemplate::filterExt這個作為打開對話框的過濾字元串,如設為".dl",則剛打開"打開"對話框后,將顯示*.dl類型的文件,其他的都不顯示.

  CDocTemplate::regFileTypeld和CDocTemplate::regFileTypeName是在自定義文件類型時有用,詳細的就不說了,說下去將是一篇教程.:)`

  回到正題來,我們剛才發現在的問題是strExt為Progra.Document,我們要把他改成*.某個後綴名,我們去到工程文件夾下,找到 xxx.rc,xxx是你的工程名,用記事本打開他,然後往下拉,找到String Table,其實可以搜索String Table,就可以直接到那裡,找到后往下看一嚇(也就是String Table后的第一段),就能看到

  BEGIN
  IDR_MAINFRAME "通訊錄\n\nProgra\n通訊錄(*.adr)\nProgra.Document\nProgra   Document"
END(我這裡是這樣,你那裡應該不一樣,反正是這個格式),每個字元串之間用\n分隔

  我們要修改的是Progra.Document這個,把他改成你喜歡的一個格式,如".mk",".xy"等等,

  修改完后,保存,關閉,回到VC6.0里,會彈出一個對話框,問你是否重新載入資源文件, 點"是"就好了.這時再點文件->保存就不會出錯了

  呼,寫完了,感覺不錯,又進步了,呵呵!

[火星人 ] 第一次深入MFC 調試一個小小的錯誤已經有717次圍觀

http://coctec.com/docs/linux/show-post-190234.html