?? mfc
字號:
<P align=justify>使用ASSERT斷言判定程序是否可以繼續執行。</P>
<P align=justify>TRACE</P>
<P
align=justify>使用TRACE宏顯示或者打印調試信息。TRACE是通過函數AfxTrace實現的。由于AfxTrace函數使用了cdecl調用約定,故可以接受個數不定的參數,如同printf函數一樣。它的定義和實現如下:</P>
<P align=justify>void AFX_CDECL AfxTrace(LPCTSTR lpszFormat, ...)</P>
<P align=justify>{</P>
<P align=justify>#ifdef _DEBUG // all AfxTrace output is controlled by
afxTraceEnabled</P>
<P align=justify>if (!afxTraceEnabled)</P>
<P align=justify>return;</P>
<P align=justify>#endif</P>
<P align=justify></P>
<P align=justify>//處理個數不定的參數</P>
<P align=justify>va_list args;</P>
<P align=justify>va_start(args, lpszFormat);</P>
<P align=justify></P>
<P align=justify>int nBuf;</P>
<P align=justify>TCHAR szBuffer[512];</P>
<P align=justify></P>
<P align=justify>nBuf = _vstprintf(szBuffer, lpszFormat, args);</P>
<P align=justify>ASSERT(nBuf < _countof(szBuffer));</P>
<P align=justify></P>
<P align=justify>if ((afxTraceFlags & traceMultiApp) &&
(AfxGetApp() != NULL))</P>
<P align=justify>afxDump << AfxGetApp()->m_pszExeName << ":
";</P>
<P align=justify>afxDump << szBuffer;</P>
<P align=justify></P>
<P align=justify>va_end(args);</P>
<P align=justify>}</P>
<P align=justify>#endif //_DEBUG</P>
<P align=justify></P>
<P
align=justify>在程序源碼中,可以控制是否顯示跟蹤信息,顯示什么跟蹤信息。如果全局變量afxTraceEnabled為TRUE,則TRACE宏可以輸出;否則,沒有TRACE信息被輸出。如果通過afxTraceFlags指定了跟蹤什么消息,則輸出有關跟蹤信息,例如為了指定“Multilple
Application Debug”,令AfxTraceFlags|=traceMultiApp。可以跟蹤的信息有:</P>
<P align=justify>enum AfxTraceFlags</P>
<P align=justify>{</P>
<P align=justify>traceMultiApp = 1, // multi-app debugging</P>
<P align=justify>traceAppMsg = 2, // main message pump trace (includes
DDE)</P>
<P align=justify>traceWinMsg = 4, // Windows message tracing</P>
<P align=justify>traceCmdRouting = 8, // Windows command routing trace </P>
<P align=justify>//(set 4+8 for control notifications)</P>
<P align=justify>traceOle = 16, // special OLE callback trace</P>
<P align=justify>traceDatabase = 32, // special database trace</P>
<P align=justify>traceInternet = 64 // special Internet client trace</P>
<P align=justify>};</P>
<P
align=justify>這樣,應用程序可以在需要的地方指定afxTraceEnabled的值打開或者關閉TRACE開關,指定AfxTraceFlags的值過濾跟蹤信息。</P>
<P align=justify>Visual C++提供了一個TRACE工具,也可以用來完成上述功能。</P>
<P align=justify></P>
<P
align=justify>為了顯示消息信息,MFC內部定義了一個AFX_MAP_MESSAG類型的數組allMessages,儲存了Windows消息和消息名映射對。例如:</P>
<P align=justify>allMessages[1].nMsg = WM_CREATE,</P>
<P align=justify>allMessages[1].lpszMsg = “WM_CREATE”</P>
<P
align=justify>MFC內部還使用函數_AfxTraceMsg顯示跟蹤消息,它可以接收一個字符串和一個MSG指針,然后,把該字符串和MSG的各個域的信息組合成一個大的字符串并使用AfxTrace顯示出來。</P>
<P align=justify>allMessages和函數_AfxTraceMsg的詳細實現可以參見AfxTrace.cpp。</P>
<P align=justify></P>
<LI>MFC對象內容轉儲
<P></P>
<P
align=justify>對象內容轉儲是CObject類提供的功能,所有從它派生的類都可以通過覆蓋虛擬函數DUMP來支持該功能。在講述CObject類時曾提到過。</P>
<P align=justify>虛擬函數Dump的定義:</P>
<P align=justify>class ClassName : public CObject</P>
<P align=justify>{</P>
<P align=justify>public:</P>
<P align=justify>#ifdef _DEBUG</P>
<P align=justify>virtual void Dump( CDumpContext& dc ) const;</P>
<P align=justify>#endif</P>
<P align=justify>…</P>
<P align=justify>};</P>
<P
align=justify>在使用Dump時,必須給它提供一個CDumpContext類型的參數,該參數指定的對象將負責輸出調試信息。為此,MFC提供了一個預定義的全局CDumpContext對象afxDump,它把調試信息輸送給調試器的調試窗口。從前面AfxTrace的實現可以知道,MFC使用了afxDump輸出跟蹤信息到調試窗口。</P>
<P align=justify>CDumpContext類沒有基類,它提供了以文本形式輸出診斷信息的功能。</P>
<P align=justify>例如:</P>
<P align=justify>CPerson* pMyPerson = new CPerson;</P>
<P align=justify>// set some fields of the CPerson object...</P>
<P align=justify>//...</P>
<P align=justify>// now dump the contents</P>
<P align=justify>#ifdef _DEBUG</P>
<P align=justify>pMyPerson->Dump( afxDump );</P>
<P align=justify>#endif</P>
<P align=justify></P>
<LI>MFC對象有效性檢測
<P></P></LI></OL>
<P
align=justify>對象有效性檢測是CObject類提供的功能,所有從它派生的類都可以通過覆蓋虛擬函數AssertValid來支持該功能。在講述CObject類時曾提到過。</P>
<P align=justify>虛擬函數AssertValid的定義:</P>
<P align=justify>class ClassName : public CObject</P>
<P align=justify>{</P>
<P align=justify>public:</P>
<P align=justify>#ifdef _DEBUG</P>
<P align=justify>virtual void AssertValid( ) const;</P>
<P align=justify>#endif</P>
<P align=justify>… </P>
<P align=justify>};</P>
<P
align=justify>使用ASSERT_VALID宏判斷一個對象是否有效,該對象的類必須覆蓋了AssertValid函數。形式為:ASSERT_VALID(pObject)。</P>
<P align=justify>另外,MFC提供了一些函數來判斷地址是否有效,如:</P>
<P align=justify>AfxIsMemoryBlock,AfxIsString,AfxIsValidAddress。</P>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889128></A><A name=_Toc445782531></A><A
name=_Toc452640990></A><A name=_Toc457299099></A><B>內存診斷</B>
<P></P></LI></OL></OL></OL>
<P align=justify>MFC使用DEBUG_NEW來跟蹤內存分配時的執行的源碼文件和行數。</P>
<P align=justify>把#define new DEBUG_NEW插入到每一個源文件中,這樣,調試版本就使用_malloc_dbg來分配內存。MFC
Appwizard在創建框架文件時已經作了這樣的處理。</P>
<OL>
<P align=justify>
<LI>AfxDoForAllObjects
<P></P>
<P align=justify>MFC提供了函數AfxDoForAllObjects來追蹤動態分配的內存對象,函數原型如下:</P>
<P align=justify>void AfxDoForAllObjects( void (*pfn)(CObject* pObject, </P>
<P align=justify>void* pContext), void* pContext ); </P>
<P align=justify>其中:</P>
<P align=justify>參數1是一個函數指針,AfxDoForAllObjects對每個對象調用該指針表示的函數。</P>
<P align=justify>參數2將傳遞給參數1指定的函數。</P>
<P
align=justify>AfxDoForAllObjects可以檢測到所有使用new分配的CObject對象或者CObject類派生的對象,但全局對象、嵌入對象和棧中分配的對象除外。</P>
<P align=justify></P>
<LI>內存漏洞檢測
<P></P></LI></OL>
<P align=justify>僅僅用于new的DEBUG版本分配的內存。</P>
<P align=justify>完成內存漏洞檢測,需要如下系列步驟:</P>
<UL>
<P align=justify>
<LI>調用AfxEnableMemoryTracking(TRUE/FALSE)打開/關閉內存診斷。在調試版本下,缺省是打開的;關閉內存診斷可以加快程序執行速度,減少診斷輸出。
<P></P>
<P align=justify></P>
<LI>使用MFC全局變量afxMemDF更精確地指定診斷輸出的特征,缺省值是allocMemDF,可以取如下值或者這些值相或:
<P></P></LI></UL>
<P align=justify>afxMemDF,delayFreeMemDF,checkAlwaysMemDF</P>
<P
align=justify>其中:allocMemDF表示可以進行內存診斷輸出;delayFreeMemDF表示是否是在應用程序結束時才調用free或者delete,這樣導致程序最大可能的分配內存;checkAlwaysMemDF表示每一次分配或者釋放內存之后都調用函數AfxCheckMemory進行內存檢測(AfxCheckMemory檢查堆中所有通過new分配的內存(不含malloc))。</P>
<P align=justify>這一步是可選步驟,非必須。</P>
<UL>
<P align=justify>
<LI>創建一個CMemState類型的變量oldMemState,調用CMemState的成員函數CheckPoint獲得初次內存快照。
<P></P>
<P align=justify></P>
<LI>執行了系列內存分配或者釋放之后,創建另一個CMemState類型變量newMemState,調用CMemState的成員函數CheckPoint獲得新的內存快照。
<P></P>
<P align=justify></P>
<LI>創建第三個CMemState類型變量difMemState,調用CMemState的成員函數Difference比較oldMemState和newMemState,結果保存在變量difMemState中。如果沒有不同,則返回FALSE,否則返回TRUE。
<P></P>
<P align=justify></P>
<LI>如果不同,則調用成員函數DumpStatistics輸出比較結果。
<P></P></LI></UL>
<P align=justify>例如:</P>
<P align=justify>// Declare the variables needed</P>
<P align=justify>#ifdef _DEBUG</P>
<DIR>
<P align=justify>CMemoryState oldMemState, newMemState, diffMemState;</P>
<P align=justify>oldMemState.Checkpoint();</P></DIR>
<P align=justify>#endif</P>
<P align=justify></P>
<P align=justify>// do your memory allocations and deallocations...</P>
<P align=justify>CString s = "This is a frame variable";</P>
<P align=justify>// the next object is a heap object</P>
<P align=justify>CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );</P>
<P align=justify></P>
<P align=justify>#ifdef _DEBUG</P>
<DIR>
<P align=justify>newMemState.Checkpoint();</P>
<P align=justify>if( diffMemState.Difference( oldMemState, newMemState ) )</P>
<P align=justify>{</P>
<DIR>
<P align=justify>TRACE( "Memory leaked!\n" );</P>
<P align=justify>diffMemState.DumpStatistics();</P>
<P align=justify>//or diffMemState.DumpAllObjectsSince();</P></DIR>
<P align=justify>}</P></DIR>
<P align=justify>#endif</P>
<P align=justify>MFC在應用程序(調試版)結束時,自動進行內存漏洞檢測,如果存在漏洞,則輸出漏洞的有關信息。</P>
<HR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" align=center border=0>
<TBODY>
<TR>
<TD align=middle><A href="http://www.vczx.com/tutorial/mfc/mfc9.php"
target=_self>上一章</A> <A href="http://www.vczx.com/tutorial/mfc/mfc.php"
target=_self>回目錄</A> <A href="http://www.vczx.com/tutorial/mfc/mfc11.php"
target=_self>下一章</A></TD></TR></TBODY></TABLE>
<P> </P>
<P align=justify></P></BODY></HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -