//+---------------------------------------------------------------------------- // // 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 #ifdef DEBUG #include #include #include #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