Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

352 lines
8.7 KiB

//+----------------------------------------------------------------------------
//
// 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.");
}
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)*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