#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)
#define TRACE0(sz)
#define TRACE1(sz, p1)
#define TRACE2(sz, p1, p2)
#define TRACE3(sz, p1, p2, p3)
#endif
#pragma code_seg(AFX_AUX_SEG)
#endif
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Helper routines that can be called from debugger
{
afxDump << pOb;
}
// Diagnostic Trace
{
#ifdef _DEBUG // all AfxTrace output is controlled by afxTraceEnabled
if (!afxTraceEnabled)
return;
#endif
va_start(args, lpszFormat);
TCHAR szBuffer[512];
ASSERT(nBuf >= 0);
afxDump << AfxGetApp()->m_pszExeName << ": ";
afxDump << szBuffer;
}
#endif //_DEBUG
{
public:
CDumpContext(CFile* pFile = NULL);
int GetDepth() const; // 0 => this object, 1 => children objects
void SetDepth(int nNewDepth);
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();
protected:
// dump context objects cannot be copied or assigned
CDumpContext(const CDumpContext& dcSrc);
void operator=(const CDumpContext& dcSrc);
void OutputString(LPCTSTR lpsz);
CFile* m_pFile;
};
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));
if (!afxTraceEnabled)
return;
#endif //_DEBUG
TCHAR szBuffer[32];
{
if (nRow == 0)
{
wsprintf(szBuffer, lpszLine, pby);
*this << szBuffer;
}
*this << szBuffer;
{
*this << _T("/n");
nRow = 0;
}
}
if (nRow != 0)
*this << _T("/n");
}
// special version for ANSI characters
CDumpContext& CDumpContext::operator<<(LPCSTR lpsz)
{
if (lpsz == NULL)
{
OutputString(L"(NULL)");
return *this;
}
if (!afxTraceEnabled)
return *this;
#endif //_DEBUG
TCHAR szBuffer[512];
_mbstowcsz(szBuffer, lpsz, _countof(szBuffer));
return *this << szBuffer;
}
{
if (lpsz == NULL)
{
OutputString(_T("(NULL)"));
return *this;
}
if (!afxTraceEnabled)
return *this;
#endif //_DEBUG
{
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;
}
return *this;
}
{
if (m_pFile)
m_pFile->Flush();
}
{
#ifdef _DEBUG
// all CDumpContext output is controlled by afxTraceEnabled
if (!afxTraceEnabled)
return;
#endif
if (m_pFile == NULL)
{
AfxOutputDebugString(lpsz);
return;
}
m_pFile->Write(lpsz, lstrlen(lpsz)*sizeof(TCHAR));
}
#define AfxOutputDebugString(lpsz) /
do /
{ /
USES_CONVERSION; /
_RPT0(_CRT_WARN, W2CA(lpsz)); /
} while (0)
#else
#define AfxOutputDebugString(lpsz) _RPT0(_CRT_WARN, lpsz)
#endif
do { if ((1 == _CrtDbgReport(rptno, NULL, 0, NULL, "%s", msg))) /
_CrtDbgBreak(); } while (0)
#endif
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!"
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;
{
HANDLE hlib = LoadLibrary("user32.dll");
(int (APIENTRY *)(LPSTR, LPCSTR, ...))
GetProcAddress(hlib, "wsprintfA")))
return -1;
}
"Second Chance Assertion Failed: File %s, Line %d/n",
szFile, nLine);
#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 */
return -1;
}
MAX_MSG-max(sizeof(ASSERTINTRO1),sizeof(ASSERTINTRO2)),
szFormat,
arglist) < 0)
strcpy(szUserMessage, TOOLONGMSG);
strcpy(szLineMessage, szFormat ? ASSERTINTRO1 : ASSERTINTRO2);
{
if (_CrtDbgMode[nRptType] & _CRTDBG_MODE_FILE)
strcat(szLineMessage, "/r");
strcat(szLineMessage, "/n");
}
{
if (_snprintf(szOutMessage, MAX_MSG, "%s(%d) : %s",
szFile, nLine, szLineMessage) < 0)
strcpy(szOutMessage, TOOLONGMSG);
}
else
strcpy(szOutMessage, szLineMessage);
if (_pfnReportHook && (*_pfnReportHook)(nRptType, szOutMessage, &retval))
{
if (_CRT_ASSERT == nRptType)
_CrtInterlockedDecrement(&_crtAssertBusy);
return retval;
}
{
if (_CrtDbgFile[nRptType] != _CRTDBG_INVALID_HFILE)
{
#ifdef _WIN32
DWORD written;
WriteFile(_CrtDbgFile[nRptType], szOutMessage, strlen(szOutMessage), &written, NULL);
#else /* _WIN32 */
long written = strlen(szOutMessage);
#endif /* _WIN32 */
}
}
{
#ifdef _WIN32
OutputDebugString(szOutMessage);
#else /* _WIN32 */
_CrtOutputDebugString(szOutMessage);
#endif /* _WIN32 */
}
{
char szLine[20];
if (_CRT_ASSERT == nRptType)
_CrtInterlockedDecrement(&_crtAssertBusy);
return retval;
}
_CrtInterlockedDecrement(&_crtAssertBusy);
/* ignore */
return FALSE;
}
WINAPI
OutputDebugStringA(LPCSTR _OutputString)
{
_SEH2_TRY
{
ULONG_PTR a_nArgs[2];
a_nArgs[1] = (ULONG_PTR)_OutputString;
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 */
static HANDLE s_hDBMonMutex = NULL;
/* true if we already attempted to open/create the mutex */
static BOOL s_bDBMonMutexTriedOpen = FALSE;
volatile HANDLE hDBMonMutex = s_hDBMonMutex;
/* handle to the Section of the shared buffer */
volatile HANDLE hDBMonBuffer = NULL;
process id followed by the message string */
struct { DWORD ProcessId; CHAR Buffer[1]; } * pDBMonBuffer = NULL;
to the shared buffer */
volatile HANDLE hDBMonBufferReady = NULL;
shared buffer */
volatile HANDLE hDBMonDataReady = NULL;
if(hDBMonMutex == NULL && !s_bDBMonMutexTriedOpen)
{
/* open/create the mutex */
hDBMonMutex = K32CreateDBMonMutex();
/* store the handle */
s_hDBMonMutex = hDBMonMutex;
}
{
volatile PCHAR a_cBuffer = NULL;
if(hDBMonMutex == NULL)
{
/* remember next time */
s_bDBMonMutexTriedOpen = TRUE;
}
/* opening the mutex succeeded */
else
{
do
{
/* synchronize with other invocations of OutputDebugString */
WaitForSingleObject(hDBMonMutex, INFINITE);
hDBMonBuffer = OpenFileMappingW(SECTION_MAP_WRITE, FALSE, L"DBWIN_BUFFER");
if(hDBMonBuffer == NULL) break;
pDBMonBuffer = MapViewOfFile(hDBMonBuffer,
SECTION_MAP_READ | SECTION_MAP_WRITE,
0,
0,
0);
if(pDBMonBuffer == NULL) break;
hDBMonBufferReady = OpenEventW(SYNCHRONIZE, FALSE, L"DBWIN_BUFFER_READY");
if(hDBMonBufferReady == NULL) break;
hDBMonDataReady = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"DBWIN_DATA_READY");
}
while(0);
string to the kernel debugger */
if(hDBMonDataReady == NULL) ReleaseMutex(hDBMonMutex);
}
{
/* size of the current output block */
volatile SIZE_T nRoundLen;
volatile SIZE_T nOutputStringLen;
nOutputStringLen = strlen(_OutputString);
{
/* 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;
}
pDBMonBuffer->ProcessId = GetCurrentProcessId();
if(nOutputStringLen > (PAGE_SIZE - sizeof(DWORD) - 1))
nRoundLen = PAGE_SIZE - sizeof(DWORD) - 1;
else
nRoundLen = nOutputStringLen;
memcpy(pDBMonBuffer->Buffer, _OutputString, nRoundLen);
pDBMonBuffer->Buffer[nRoundLen] = 0;
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);
{
DbgPrint("OutputDebugStringA: Failed/n");
break;
}
if(nOutputStringLen > 510)
nRoundLen = 510;
else
nRoundLen = nOutputStringLen;
memcpy(a_cBuffer, _OutputString, nRoundLen);
a_cBuffer[nRoundLen] = 0;
DbgPrint("%s", a_cBuffer);
{
HeapFree(GetProcessHeap(), 0, a_cBuffer);
a_cBuffer = NULL;
}
}
_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);
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);
if(hDBMonDataReady != NULL)
ReleaseMutex(hDBMonMutex);
}
_SEH2_END;
}
_SEH2_END;
}