VC6 TRACE宏的学习

一,各宏定义如下:
#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(" %02X"), *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;
}

你可能感兴趣的:(GUI)