VC6 TRACE宏的学习

    技术2022-05-11  22

    一,各宏定义如下: #ifdef _DEBUG #define TRACE              ::AfxTrace #define TRACE0(sz)              ::AfxTrace(_T("%s"), _T(sz)) #define TRACE1(sz, p1)          ::AfxTrace(_T(sz), p1) #define TRACE2(sz, p1, p2)      ::AfxTrace(_T(sz), p1, p2) #define TRACE3(sz, p1, p2, p3)  ::AfxTrace(_T(sz), p1, p2, p3) #else inline void AFX_CDECL AfxTrace(LPCTSTR, ...) { } #define TRACE              1 ? (void)0 : ::AfxTrace #define TRACE0(sz) #define TRACE1(sz, p1) #define TRACE2(sz, p1, p2) #define TRACE3(sz, p1, p2, p3) #endif   二. 调试输出的核心函数 MFC调试输出的核心函数是AfxTrace,其代码如下: #ifdef _DEBUG   // entire file #ifdef AFX_AUX_SEG #pragma code_seg(AFX_AUX_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif / // Helper routines that can be called from debugger void AFXAPI AfxDump(const CObject* pOb) {  afxDump << pOb; } / // Diagnostic Trace void AFX_CDECL AfxTrace(LPCTSTR lpszFormat, ...) { #ifdef _DEBUG // all AfxTrace output is controlled by afxTraceEnabled  if (!afxTraceEnabled)   return; #endif  va_list args;  va_start(args, lpszFormat);  int nBuf;  TCHAR szBuffer[512];  nBuf = _vsntprintf(szBuffer, _countof(szBuffer), lpszFormat, args);  // was there an error? was the expanded string too long?  ASSERT(nBuf >= 0);  if ((afxTraceFlags & traceMultiApp) && (AfxGetApp() != NULL))   afxDump << AfxGetApp()->m_pszExeName << ": ";   afxDump << szBuffer;  va_end(args); } #endif //_DEBUG   三 全局DumpDC AFX_DATADEF CDumpContext afxDump;   四. CDumpContext类接口   class CDumpContext { public:  CDumpContext(CFile* pFile = NULL); // Attributes  int GetDepth() const;      // 0 => this object, 1 => children objects  void SetDepth(int nNewDepth); // Operations  CDumpContext& operator<<(LPCTSTR lpsz); #ifdef _UNICODE  CDumpContext& operator<<(LPCSTR lpsz);  // automatically widened #else  CDumpContext& operator<<(LPCWSTR lpsz); // automatically thinned #endif  CDumpContext& operator<<(const void* lp);  CDumpContext& operator<<(const CObject* pOb);  CDumpContext& operator<<(const CObject& ob);  CDumpContext& operator<<(BYTE by);  CDumpContext& operator<<(WORD w);  CDumpContext& operator<<(UINT u);  CDumpContext& operator<<(LONG l);  CDumpContext& operator<<(DWORD dw);  CDumpContext& operator<<(float f);  CDumpContext& operator<<(double d);  CDumpContext& operator<<(int n);  void HexDump(LPCTSTR lpszLine, BYTE* pby, int nBytes, int nWidth);  void Flush(); // Implementation protected:  // dump context objects cannot be copied or assigned  CDumpContext(const CDumpContext& dcSrc);  void operator=(const CDumpContext& dcSrc);  void OutputString(LPCTSTR lpsz);  int m_nDepth; public:  CFile* m_pFile; };   void CDumpContext::HexDump(LPCTSTR lpszLine, BYTE* pby,  int nBytes, int nWidth) // do a simple hex-dump (8 per line) to a CDumpContext //  the "lpszLine" is a string to print at the start of each line //    (%lx should be used to expand the current address) {  ASSERT(nBytes > 0);  ASSERT(nWidth > 0);  ASSERT(AfxIsValidString(lpszLine));  ASSERT(AfxIsValidAddress(pby, nBytes, FALSE)); #ifdef _DEBUG // all CDumpContext output is controlled by afxTraceEnabled  if (!afxTraceEnabled)   return; #endif //_DEBUG  int nRow = 0;  TCHAR szBuffer[32];  while (nBytes--)  {   if (nRow == 0)   {    wsprintf(szBuffer, lpszLine, pby);    *this << szBuffer;   }   wsprintf(szBuffer, _T(" X"), *pby++);   *this << szBuffer;   if (++nRow >= nWidth)   {    *this << _T("/n");    nRow = 0;   }  }  if (nRow != 0)   *this << _T("/n"); } / #ifdef _UNICODE // special version for ANSI characters CDumpContext& CDumpContext::operator<<(LPCSTR lpsz) {  if (lpsz == NULL)  {   OutputString(L"(NULL)");   return *this;  } #ifdef _DEBUG // all CDumpContext output is controlled by afxTraceEnabled  if (!afxTraceEnabled)   return *this; #endif //_DEBUG  // limited length  TCHAR szBuffer[512];  _mbstowcsz(szBuffer, lpsz, _countof(szBuffer));  return *this << szBuffer; }   CDumpContext& CDumpContext::operator<<(LPCTSTR lpsz) {  if (lpsz == NULL)  {   OutputString(_T("(NULL)"));   return *this;  } #ifdef _DEBUG // all CDumpContext output is controlled by afxTraceEnabled  if (!afxTraceEnabled)   return *this; #endif //_DEBUG  if (m_pFile == NULL)  {   TCHAR szBuffer[512];   LPTSTR lpBuf = szBuffer;   while (*lpsz != '/0')   {    if (lpBuf > szBuffer + _countof(szBuffer) - 3)    {     *lpBuf = '/0';     OutputString(szBuffer);     lpBuf = szBuffer;    }    if (*lpsz == '/n')     *lpBuf++ = '/r';    *lpBuf++ = *lpsz++;   }   *lpBuf = '/0';   OutputString(szBuffer);   return *this;  }  m_pFile->Write(lpsz, lstrlen(lpsz)*sizeof(TCHAR));  return *this; }   void CDumpContext::Flush() {  if (m_pFile)   m_pFile->Flush(); } void CDumpContext::OutputString(LPCTSTR lpsz) { #ifdef _DEBUG  // all CDumpContext output is controlled by afxTraceEnabled  if (!afxTraceEnabled)   return; #endif  // use C-runtime/OutputDebugString when m_pFile is NULL  if (m_pFile == NULL)  {   AfxOutputDebugString(lpsz);   return;  }  // otherwise, write the string to the file  m_pFile->Write(lpsz, lstrlen(lpsz)*sizeof(TCHAR)); }   五 AfxOutputDebugString宏 #ifdef _UNICODE #define AfxOutputDebugString(lpsz) /  do /  { /   USES_CONVERSION; /   _RPT0(_CRT_WARN, W2CA(lpsz)); /  } while (0) #else #define AfxOutputDebugString(lpsz) _RPT0(_CRT_WARN, lpsz) #endif   #ifdef _DEBUG #define _RPT0(rptno, msg) /         do { if ((1 == _CrtDbgReport(rptno, NULL, 0, NULL, "%s", msg))) /                 _CrtDbgBreak(); } while (0) #endif   六 进入CRT   _CRTIMP int __cdecl _CrtDbgReport(         int nRptType,         const char * szFile,         int nLine,         const char * szModule,         const char * szFormat,         ...         ) {         int retval;         va_list arglist;         char szLineMessage[MAX_MSG] = {0};         char szOutMessage[MAX_MSG] = {0};         char szUserMessage[MAX_MSG] = {0};         #define ASSERTINTRO1 "Assertion failed: "         #define ASSERTINTRO2 "Assertion failed!"         va_start(arglist, szFormat);         if (nRptType < 0 || nRptType >= _CRT_ERRCNT)             return -1;         /*          * handle the (hopefully rare) case of          *          * 1) ASSERT while already dealing with an ASSERT          *      or          * 2) two threads asserting at the same time          */         if (_CRT_ASSERT == nRptType && _CrtInterlockedIncrement(&_crtAssertBusy) > 0)         {             /* use only 'safe' functions -- must not assert in here! */ #ifdef _WIN32             static int (APIENTRY *pfnwsprintfA)(LPSTR, LPCSTR, ...) = NULL;             if (NULL == pfnwsprintfA)             {                 HANDLE hlib = LoadLibrary("user32.dll");                 if (NULL == hlib || NULL == (pfnwsprintfA =                             (int (APIENTRY *)(LPSTR, LPCSTR, ...))                             GetProcAddress(hlib, "wsprintfA")))                     return -1;             }             (*pfnwsprintfA)( szOutMessage,                 "Second Chance Assertion Failed: File %s, Line %d/n",                 szFile, nLine);             OutputDebugString(szOutMessage); #else  /* _WIN32 */             strcpy(szOutMessage, "Second Chance Assertion Failed: File ");             strcat(szOutMessage, szFile);             strcat(szOutMessage, ", Line ");             numtostring(nLine, &szOutMessage[strlen(szOutMessage)]);             strcat(szOutMessage, "/n");             _CrtOutputDebugString(szOutMessage); #endif  /* _WIN32 */             _CrtInterlockedDecrement(&_crtAssertBusy);             _CrtDbgBreak();             return -1;         }         if (szFormat && _vsnprintf(szUserMessage,                        MAX_MSG-max(sizeof(ASSERTINTRO1),sizeof(ASSERTINTRO2)),                        szFormat,                        arglist) < 0)             strcpy(szUserMessage, TOOLONGMSG);         if (_CRT_ASSERT == nRptType)             strcpy(szLineMessage, szFormat ? ASSERTINTRO1 : ASSERTINTRO2);         strcat(szLineMessage, szUserMessage);         if (_CRT_ASSERT == nRptType)         {             if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_FILE)                 strcat(szLineMessage, "/r");             strcat(szLineMessage, "/n");         }         if (szFile)         {             if (_snprintf(szOutMessage, MAX_MSG, "%s(%d) : %s",                 szFile, nLine, szLineMessage) < 0)             strcpy(szOutMessage, TOOLONGMSG);         }         else             strcpy(szOutMessage, szLineMessage);         /* user hook may handle report */         if (_pfnReportHook && (*_pfnReportHook)(nRptType, szOutMessage, &retval))         {             if (_CRT_ASSERT == nRptType)                 _CrtInterlockedDecrement(&_crtAssertBusy);             return retval;         }         if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_FILE)         {             if (_CrtDbgFile[nRptType] != _CRTDBG_INVALID_HFILE)             { #ifdef _WIN32                 DWORD written;                 WriteFile(_CrtDbgFile[nRptType], szOutMessage, strlen(szOutMessage), &written, NULL); #else  /* _WIN32 */                 long written = strlen(szOutMessage);                 FSWrite((short)_CrtDbgFile[nRptType], &written, szOutMessage); #endif  /* _WIN32 */             }         }         if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_DEBUG)         { #ifdef _WIN32             OutputDebugString(szOutMessage); #else  /* _WIN32 */             _CrtOutputDebugString(szOutMessage); #endif  /* _WIN32 */         }         if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_WNDW)         {             char szLine[20];             retval = CrtMessageWindow(nRptType, szFile, nLine ? _itoa(nLine, szLine, 10) : NULL, szModule, szUserMessage);             if (_CRT_ASSERT == nRptType)                 _CrtInterlockedDecrement(&_crtAssertBusy);             return retval;         }         if (_CRT_ASSERT == nRptType)             _CrtInterlockedDecrement(&_crtAssertBusy);         /* ignore */         return FALSE; } 七 REACTOS中的OutputDebugStringA VOID WINAPI OutputDebugStringA(LPCSTR _OutputString) {  _SEH2_TRY  {   ULONG_PTR a_nArgs[2];   a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);   a_nArgs[1] = (ULONG_PTR)_OutputString;   /* send the string to the user-mode debugger */   RaiseException(DBG_PRINTEXCEPTION_C, 0, 2, a_nArgs);  }  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)  {   /* no user-mode debugger: try the systemwide debug message monitor, or the      kernel debugger as a last resort */   /* mutex used to synchronize invocations of OutputDebugString */   static HANDLE s_hDBMonMutex = NULL;   /* true if we already attempted to open/create the mutex */   static BOOL s_bDBMonMutexTriedOpen = FALSE;   /* local copy of the mutex handle */   volatile HANDLE hDBMonMutex = s_hDBMonMutex;   /* handle to the Section of the shared buffer */   volatile HANDLE hDBMonBuffer = NULL;   /* pointer to the mapped view of the shared buffer. It consist of the current      process id followed by the message string */   struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;   /* event: signaled by the debug message monitor when OutputDebugString can write      to the shared buffer */   volatile HANDLE hDBMonBufferReady = NULL;   /* event: to be signaled by OutputDebugString when it's done writing to the      shared buffer */   volatile HANDLE hDBMonDataReady = NULL;   /* mutex not opened, and no previous attempts to open/create it */   if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)   {    /* open/create the mutex */    hDBMonMutex = K32CreateDBMonMutex();    /* store the handle */    s_hDBMonMutex = hDBMonMutex;   }   _SEH2_TRY   {    volatile PCHAR a_cBuffer = NULL;    /* opening the mutex failed */    if(hDBMonMutex == NULL)    {     /* remember next time */     s_bDBMonMutexTriedOpen = TRUE;    }    /* opening the mutex succeeded */    else    {     do     {      /* synchronize with other invocations of OutputDebugString */      WaitForSingleObject(hDBMonMutex, INFINITE);      /* buffer of the system-wide debug message monitor */      hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");      /* couldn't open the buffer: send the string to the kernel debugger */      if(hDBMonBuffer == NULL) break;      /* map the buffer */      pDBMonBuffer = MapViewOfFile(hDBMonBuffer,              SECTION_MAP_READ | SECTION_MAP_WRITE,              0,              0,              0);      /* couldn't map the buffer: send the string to the kernel debugger */      if(pDBMonBuffer == NULL) break;      /* open the event signaling that the buffer can be accessed */      hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");      /* couldn't open the event: send the string to the kernel debugger */      if(hDBMonBufferReady == NULL) break;      /* open the event to be signaled when the buffer has been filled */      hDBMonDataReady = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");     }     while(0);     /* we couldn't connect to the system-wide debug message monitor: send the        string to the kernel debugger */     if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);    }    _SEH2_TRY    {     /* size of the current output block */     volatile SIZE_T nRoundLen;     /* size of the remainder of the string */     volatile SIZE_T nOutputStringLen;     /* output the whole string */     nOutputStringLen = strlen(_OutputString);     do     {      /* we're connected to the debug monitor:         write the current block to the shared buffer */      if(hDBMonDataReady)      {       /* wait a maximum of 10 seconds for the debug monitor          to finish processing the shared buffer */       if(WaitForSingleObject(hDBMonBufferReady, 10000) != WAIT_OBJECT_0)       {        /* timeout or failure: give up */        break;       }       /* write the process id into the buffer */       pDBMonBuffer->ProcessId = GetCurrentProcessId();       /* write only as many bytes as they fit in the buffer */       if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1))        nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1;       else        nRoundLen = nOutputStringLen;       /* copy the current block into the buffer */       memcpy(pDBMonBuffer->Buffer, _OutputString, nRoundLen);       /* null-terminate the current block */       pDBMonBuffer->Buffer[nRoundLen] = 0;       /* signal that the data contains meaningful data and can be read */       SetEvent(hDBMonDataReady);      }      /* else, send the current block to the kernel debugger */      else      {       /* output in blocks of 512 characters */       a_cBuffer = (CHAR*)HeapAlloc(GetProcessHeap(), 0, 512);       if (!a_cBuffer)       {        DbgPrint("OutputDebugStringA: Failed/n");        break;       }       /* write a maximum of 511 bytes */       if(nOutputStringLen > 510)        nRoundLen = 510;       else        nRoundLen = nOutputStringLen;       /* copy the current block */       memcpy(a_cBuffer, _OutputString, nRoundLen);       /* null-terminate the current block */       a_cBuffer[nRoundLen] = 0;       /* send the current block to the kernel debugger */        DbgPrint("%s", a_cBuffer);       if (a_cBuffer)       {        HeapFree(GetProcessHeap(), 0, a_cBuffer);        a_cBuffer = NULL;       }      }      /* move to the next block */      _OutputString += nRoundLen;      nOutputStringLen -= nRoundLen;     }     /* repeat until the string has been fully output */     while (nOutputStringLen > 0);    }    /* ignore access violations and let other exceptions fall through */    _SEH2_EXCEPT((_SEH2_GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)    {     if (a_cBuffer)      HeapFree(GetProcessHeap(), 0, a_cBuffer);     /* string copied verbatim from Microsoft's kernel32.dll */     DbgPrint("/nOutputDebugString faulted during output/n");    }    _SEH2_END;   }   _SEH2_FINALLY   {    /* close all the still open resources */    if(hDBMonBufferReady) CloseHandle(hDBMonBufferReady);    if(pDBMonBuffer) UnmapViewOfFile(pDBMonBuffer);    if(hDBMonBuffer) CloseHandle(hDBMonBuffer);    if(hDBMonDataReady) CloseHandle(hDBMonDataReady);    /* leave the critical section */    if(hDBMonDataReady != NULL)     ReleaseMutex(hDBMonMutex);   }   _SEH2_END;  }  _SEH2_END; }

    最新回复(0)