|
|
//+----------------------------------------------------------------------------
//
// File: cmdebug.cpp
//
// Module: CMDEBUG.LIB
//
// Synopsis: This source file contains the debugging routines common to all
// of the CM components.
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// Author: nickball Created 02/04/98
//
//+----------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" { #endif
#include <windows.h>
#ifdef DEBUG
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include "cmdebug.h"
//
// Ansi Versions
//
void MyDbgPrintfA(const char *pszFmt, ...) { va_list valArgs; char szTmp[512]; CHAR szOutput[512];
va_start(valArgs, pszFmt); wvsprintfA(szTmp, pszFmt, valArgs); va_end(valArgs);
wsprintfA(szOutput, "0x%x: 0x%x: %s\r\n", GetCurrentProcessId(), GetCurrentThreadId(), szTmp);
OutputDebugStringA(szOutput);
//
// Attempt to log output
//
CHAR szFileName[MAX_PATH + 1]; DWORD dwBytes; GetSystemDirectoryA(szFileName, MAX_PATH); lstrcatA(szFileName, "\\CMTRACE.TXT"); HANDLE hFile = CreateFileA(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) { if (INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, 0, FILE_END)) { WriteFile(hFile, szOutput, sizeof(CHAR)*lstrlenA(szOutput), &dwBytes, NULL); } CloseHandle(hFile); } }
void MyDbgAssertA(const char *pszFile, unsigned nLine, const char *pszMsg) { char szOutput[1024];
wsprintfA(szOutput, "%s(%u) - %s", pszFile, nLine, pszMsg);
MyDbgPrintfA(szOutput);
//
// Prompt user
//
wsprintfA(szOutput, "%s(%u) - %s\n( Press Retry to debug )", pszFile, nLine, pszMsg); int nCode = IDIGNORE;
static long dwAssertCount = -1; // Avoid another assert while the messagebox is up
//
// If there is no Assertion meesagebox, popup one
//
if (InterlockedIncrement(&dwAssertCount) == 0) { nCode = MessageBoxExA(NULL, szOutput, "Assertion Failed", MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE, LANG_USER_DEFAULT); }
InterlockedDecrement(&dwAssertCount);
if (nCode == IDIGNORE) { return; // ignore
} else if (nCode == IDRETRY) { // break into the debugger (or Dr Watson log)
#ifdef _X86_
_asm { int 3 }; #else
DebugBreak(); #endif
return; // ignore and continue in debugger to diagnose problem
} else if (0 == nCode) { //
// MessageBoxEx Failed. Lets call GLE
//
DWORD dwError = GetLastError();
//
// Fall through and exit process anyway
//
} // else fall through and call Abort
ExitProcess((DWORD)-1);
}
//
// Unicode Versions
//
void MyDbgPrintfW(const WCHAR *pszFmt, ...) { va_list valArgs; CHAR szOutput[512]; CHAR szTmp[512];
va_start(valArgs, pszFmt); int iRet = wvsprintfWtoAWrapper(szTmp, pszFmt, valArgs); va_end(valArgs);
if (0 == iRet) { //
// We weren't able to write the Unicode string as expected. Lets
// try just putting a failure string in the szTmp buffer instead.
//
lstrcpyA(szTmp, "MyDbgPrintfW -- wvsprintfWtoAWrapper failed. Unsure of original message, please investigate."); }
#if defined(DEBUG_TRACETIME)
static const CHAR c_szaFmtTime[] = "[%02dh%02d:%02d.%03d]"; CHAR szTime[15] = ""; // NOTE: the size of this must be in sync with the string above
SYSTEMTIME stLocal; GetLocalTime(&stLocal); wsprintfA (szTime, c_szaFmtTime, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, stLocal.wMilliseconds);
wsprintfA(szOutput, "%s 0x%x: 0x%x: %s\r\n", szTime, GetCurrentProcessId(), GetCurrentThreadId(), szTmp);
#else
wsprintfA(szOutput, "0x%x: 0x%x: %s\r\n", GetCurrentProcessId(), GetCurrentThreadId(), szTmp); #endif
OutputDebugStringA(szOutput);
//
// Attempt to log output
//
CHAR szFileName[MAX_PATH + 1]; DWORD dwBytes; GetSystemDirectoryA(szFileName, MAX_PATH); lstrcatA(szFileName, "\\CMTRACE.TXT");
HANDLE hFile = CreateFileA(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) { if (INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, 0, FILE_END)) { WriteFile(hFile, szOutput, sizeof(CHAR)*lstrlen(szOutput), &dwBytes, NULL); } CloseHandle(hFile); } }
void MyDbgAssertW(const char *pszFile, unsigned nLine, WCHAR *pszMsg) { CHAR szOutput[1024];
wsprintfA(szOutput, "%s(%u) - %S", pszFile, nLine, pszMsg);
MyDbgPrintfA(szOutput);
//
// Prompt user
//
wsprintfA(szOutput, "%s(%u) - %S\n( Press Retry to debug )", pszFile, nLine, pszMsg); int nCode = IDIGNORE;
static long dwAssertCount = -1; // Avoid another assert while the messagebox is up
//
// If there is no Assertion meesagebox, popup one
//
if (InterlockedIncrement(&dwAssertCount) == 0) { nCode = MessageBoxExA(NULL, szOutput, "Assertion Failed", MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE, LANG_USER_DEFAULT); }
InterlockedDecrement(&dwAssertCount);
if (nCode == IDIGNORE) { return; // ignore
} else if (nCode == IDRETRY) { // break into the debugger (or Dr Watson log)
#ifdef _X86_
_asm { int 3 }; #else
DebugBreak(); #endif
return; // ignore and continue in debugger to diagnose problem
} // else fall through and call Abort
ExitProcess((DWORD)-1);
}
#endif //DEBUG
//
// Included to make MyDbgPrintfW work on win9x. Please note that it steps through the string
// byte by byte (doesn't deal with MBCS chars) but since this is really called on Format strings
// this shouldn't be a problem.
//
void InvertPercentSAndPercentC(LPSTR pszFormat) { if (pszFormat) { LPSTR pszTmp = pszFormat; BOOL bPrevCharPercent = FALSE;
while(*pszTmp) { switch (*pszTmp) { case '%': //
// if we have %% then we must ignore the percent, otherwise save it.
//
bPrevCharPercent = !bPrevCharPercent; break;
case 'S': if (bPrevCharPercent) { *pszTmp = 's'; } break;
case 's': if (bPrevCharPercent) { *pszTmp = 'S'; } break;
case 'C': if (bPrevCharPercent) { *pszTmp = 'c'; } break;
case 'c': if (bPrevCharPercent) { *pszTmp = 'C'; } break;
default: //
// don't fool ourselves by always keeping this set.
//
bPrevCharPercent = FALSE; break; } pszTmp++; } } }
//
// This function takes Unicode input strings (potentially in the va_list as well)
// and uses the fact that wvsprintfA will print Unicode strings into an Ansi
// output string if the special char %S is used instead of %s. Thus we will convert
// the input parameter string and then replace all the %s chars with %S chars (and vice versa).
// This will allow us to call wvsprintfA since wvsprintfW isn't available on win9x.
//
int WINAPI wvsprintfWtoAWrapper(OUT LPSTR pszAnsiOut, IN LPCWSTR pszwFmt, IN va_list arglist) { int iRet = 0; LPSTR pszAnsiFormat = NULL;
if ((NULL != pszAnsiOut) && (NULL != pszwFmt) && (L'\0' != pszwFmt[0])) { //
// Convert pszwFmt to Ansi
//
DWORD dwSize = WideCharToMultiByte(CP_ACP, 0, pszwFmt, -1, pszAnsiFormat, 0, NULL, NULL);
if (0 != dwSize) { pszAnsiFormat = (LPSTR)LocalAlloc(LPTR, dwSize*sizeof(CHAR));
if (pszAnsiFormat) { if (WideCharToMultiByte(CP_ACP, 0, pszwFmt, -1, pszAnsiFormat, dwSize, NULL, NULL)) { //
// Now change the little s's and c's to their capital equivalent and vice versa
//
InvertPercentSAndPercentC(pszAnsiFormat); //
// Finally construct the string
//
iRet = wvsprintfA(pszAnsiOut, pszAnsiFormat, arglist); } } } }
LocalFree(pszAnsiFormat); return iRet; }
#ifdef __cplusplus
} #endif
|