|
|
//
// Debug squirty functions
//
#include "stock.h"
#pragma hdrstop
#include "shellp.h"
#include <platform.h> // LINE_SEPARATOR_STR and friends
#include <winbase.h> // for GetModuleFileNameA
#include <strsafe.h>
#define DM_DEBUG 0
#ifdef DEBUG
// --------------------------------------------------------------------------
// AttachUserModeDebugger
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Attaches a user-mode debugger to the current process if one
// is not already attached. This allows the ASSERT/RIP/TRACE to
// be debugged in a user-mode debugger rather than ending up in
// the kernel debugger which is sometimes limiting.
//
// History: 2000-08-21 vtan created
// --------------------------------------------------------------------------
void AttachUserModeDebugger (void)
{ // Win95 does not support IsDebuggerPresent so we must
// GetProcAddress for it below or we would fail to load.
// In fact, we punt completely on Win9x
if (GetVersion() & 0x80000000) return;
__try { typedef BOOL (WINAPI *ISDEBUGGERPRESENT)(); ISDEBUGGERPRESENT _IsDebuggerPresent = (ISDEBUGGERPRESENT)GetProcAddress(GetModuleHandleA("KERNEL32"), "IsDebuggerPresent"); if (_IsDebuggerPresent && !_IsDebuggerPresent()) { HKEY hKeyAEDebug; TCHAR szDebugger[MAX_PATH];
szDebugger[0] = TEXT('\0');
// Read HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AEDebug\Debugger
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AEDebug"), 0, KEY_QUERY_VALUE, &hKeyAEDebug)) { DWORD dwDebuggerSize;
dwDebuggerSize = sizeof(szDebugger); (LONG)RegQueryValueEx(hKeyAEDebug, TEXT("Debugger"), NULL, NULL, (LPBYTE)&szDebugger, &dwDebuggerSize); (LONG)RegCloseKey(hKeyAEDebug); }
if (szDebugger[0] != TEXT('\0')) { static const TCHAR s_szDrWatsonImageName[] = TEXT("drwtsn32"); HRESULT hr; BOOL fWatson = FALSE;
TCHAR szCommandLine[MAX_PATH + 64];
// Duplicate the string to szCommandLine and NULL terminate
// to compare directly for "drwtsn32" which we do NOT want
// attached to the process.
hr = StringCchCopy(szCommandLine, ARRAYSIZE(szCommandLine), szDebugger); if (SUCCEEDED(hr)) { szCommandLine[ARRAYSIZE(s_szDrWatsonImageName)-1] = TEXT('\0');
if (lstrcmpi(szCommandLine, s_szDrWatsonImageName) == 0) { fWatson = TRUE; } }
if (!fWatson) { HANDLE hEvent; SECURITY_ATTRIBUTES securityAttributes;
// Create an unnamed event which is passed to the debugger as an
// inherited handle. It will signal this handle to release this
// thread when the debugger is completely attached to the process.
securityAttributes.nLength = sizeof(securityAttributes); securityAttributes.lpSecurityDescriptor = NULL; securityAttributes.bInheritHandle = TRUE; hEvent = CreateEvent(&securityAttributes, TRUE, FALSE, NULL); if (hEvent != NULL) { STARTUPINFO startupInfo; PROCESS_INFORMATION processInformation;
ZeroMemory(&startupInfo, sizeof(startupInfo)); ZeroMemory(&processInformation, sizeof(processInformation)); startupInfo.cb = sizeof(startupInfo);
// Now formulate the command line to pass to the debugger.
// It's in the form "cdb -p %ld -e %ld -gGx".
hr = StringCchPrintf(szCommandLine, ARRAYSIZE(szCommandLine), szDebugger, GetCurrentProcessId(), hEvent); // ok to truncate - devs can figure it out
if (SUCCEEDED(hr)) { if (CreateProcess(NULL, szCommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInformation) != FALSE) {
// Now wait for the event. Give a generous 10 seconds
// for the debugger to signal this event. If the debugger
// doesn't then continue execution. Close all handles.
(DWORD)WaitForSingleObject(hEvent, INFINITE); (BOOL)CloseHandle(processInformation.hProcess); (BOOL)CloseHandle(processInformation.hThread); } } (BOOL)CloseHandle(hEvent); } } else { OutputDebugStringA("drwtsn32 detected in AEDebug. Dropping to KD\r\n"); } } } } __except (EXCEPTION_CONTINUE_EXECUTION) { } }
#endif /* DEBUG */
// UnicodeFromAnsi is used by shlwapi so it should not be inside the ifdef debug
//
/*----------------------------------------------------------
Purpose: This function converts a multi-byte string to a wide-char string.
If pszBuf is non-NULL and the converted string can fit in pszBuf, then *ppszWide will point to the given buffer. Otherwise, this function will allocate a buffer that can hold the converted string.
If pszAnsi is NULL, then *ppszWide will be freed. Note that pszBuf must be the same pointer between the call that converted the string and the call that frees the string.
Returns: TRUE FALSE (if out of memory)
*/ BOOL UnicodeFromAnsi( LPWSTR * ppwszWide, LPCSTR pszAnsi, // NULL to clean up
LPWSTR pwszBuf, int cchBuf) { BOOL bRet;
// Convert the string?
if (pszAnsi) { // Yes; determine the converted string length
int cch; LPWSTR pwsz; int cchAnsi = lstrlenA(pszAnsi)+1;
cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, NULL, 0);
// String too big, or is there no buffer?
if (cch > cchBuf || NULL == pwszBuf) { // Yes; allocate space
cchBuf = cch + 1; pwsz = (LPWSTR)LocalAlloc(LPTR, CbFromCchW(cchBuf)); } else { // No; use the provided buffer
pwsz = pwszBuf; }
if (pwsz) { // Convert the string
cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, pwsz, cchBuf); bRet = (0 < cch); } else { bRet = FALSE; }
*ppwszWide = pwsz; } else { // No; was this buffer allocated?
if (*ppwszWide && pwszBuf != *ppwszWide) { // Yes; clean up
LocalFree((HLOCAL)*ppwszWide); *ppwszWide = NULL; } bRet = TRUE; }
return bRet; }
#if 0 // nobody seems to use this one any more
/*----------------------------------------------------------
Purpose: This function converts a wide-char string to a multi-byte string.
If pszBuf is non-NULL and the converted string can fit in pszBuf, then *ppszAnsi will point to the given buffer. Otherwise, this function will allocate a buffer that can hold the converted string.
If pszWide is NULL, then *ppszAnsi will be freed. Note that pszBuf must be the same pointer between the call that converted the string and the call that frees the string.
Returns: TRUE FALSE (if out of memory)
Cond: -- */ BOOL AnsiFromUnicode( LPSTR * ppszAnsi, LPCWSTR pwszWide, // NULL to clean up
LPSTR pszBuf, int cchBuf) { BOOL bRet;
// Convert the string?
if (pwszWide) { // Yes; determine the converted string length
int cch; LPSTR psz;
cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, NULL, 0, NULL, NULL);
// String too big, or is there no buffer?
if (cch > cchBuf || NULL == pszBuf) { // Yes; allocate space
cchBuf = cch + 1; psz = (LPSTR)LocalAlloc(LPTR, CbFromCchA(cchBuf)); } else { // No; use the provided buffer
ASSERT(pszBuf); psz = pszBuf; }
if (psz) { // Convert the string
cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, psz, cchBuf, NULL, NULL); bRet = (0 < cch); } else { bRet = FALSE; }
*ppszAnsi = psz; } else { // No; was this buffer allocated?
if (*ppszAnsi && pszBuf != *ppszAnsi) { // Yes; clean up
LocalFree((HLOCAL)*ppszAnsi); *ppszAnsi = NULL; } bRet = TRUE; }
return bRet; } #endif // 0
#if defined(DEBUG) || defined(PRODUCT_PROF)
// (c_szCcshellIniFile and c_szCcshellIniSecDebug are declared in debug.h)
extern CHAR const FAR c_szCcshellIniFile[]; extern CHAR const FAR c_szCcshellIniSecDebug[]; HANDLE g_hDebugOutputFile = INVALID_HANDLE_VALUE;
void ShellDebugAppendToDebugFileA(LPCSTR pszOutputString) { if (g_hDebugOutputFile != INVALID_HANDLE_VALUE) { DWORD cbWrite = lstrlenA(pszOutputString); WriteFile(g_hDebugOutputFile, pszOutputString, cbWrite, &cbWrite, NULL); } }
void ShellDebugAppendToDebugFileW(LPCWSTR pszOutputString) { if (g_hDebugOutputFile != INVALID_HANDLE_VALUE) { char szBuf[500];
DWORD cbWrite = WideCharToMultiByte(CP_ACP, 0, pszOutputString, -1, szBuf, ARRAYSIZE(szBuf), NULL, NULL);
WriteFile(g_hDebugOutputFile, szBuf, cbWrite, &cbWrite, NULL); } }
//
// We cannot link to shlwapi, because comctl32 cannot link to shlwapi.
// Duplicate some functions here so unicode stuff can run on Win95 platforms.
//
VOID MyOutputDebugStringWrapW(LPCWSTR lpOutputString) { if (staticIsOS(OS_NT)) { OutputDebugStringW(lpOutputString); ShellDebugAppendToDebugFileW(lpOutputString); } else { char szBuf[1024+40];
WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1, szBuf, ARRAYSIZE(szBuf), NULL, NULL);
OutputDebugStringA(szBuf); ShellDebugAppendToDebugFileA(szBuf); } } #define OutputDebugStringW MyOutputDebugStringWrapW
VOID MyOutputDebugStringWrapA(LPCSTR lpOutputString) { OutputDebugStringA(lpOutputString); ShellDebugAppendToDebugFileA(lpOutputString); }
#define OutputDebugStringA MyOutputDebugStringWrapA
/*----------------------------------------------------------
Purpose: Special verion of atoi. Supports hexadecimal too.
If this function returns FALSE, *piRet is set to 0.
Returns: TRUE if the string is a number, or contains a partial number FALSE if the string is not a number
Cond: -- */ static BOOL MyStrToIntExA( LPCSTR pszString, DWORD dwFlags, // STIF_ bitfield
LONGLONG FAR * piRet) { #define IS_DIGIT(ch) InRange(ch, '0', '9')
BOOL bRet; LONGLONG n; BOOL bNeg = FALSE; LPCSTR psz; LPCSTR pszAdj;
// Skip leading whitespace
//
for (psz = pszString; *psz == ' ' || *psz == '\n' || *psz == '\t'; psz = CharNextA(psz)) ;
// Determine possible explicit signage
//
if (*psz == '+' || *psz == '-') { bNeg = (*psz == '+') ? FALSE : TRUE; psz++; }
// Or is this hexadecimal?
//
pszAdj = CharNextA(psz); if ((STIF_SUPPORT_HEX & dwFlags) && *psz == '0' && (*pszAdj == 'x' || *pszAdj == 'X')) { // Yes
// (Never allow negative sign with hexadecimal numbers)
bNeg = FALSE; psz = CharNextA(pszAdj);
pszAdj = psz;
// Do the conversion
//
for (n = 0; ; psz = CharNextA(psz)) { if (IS_DIGIT(*psz)) n = 0x10 * n + *psz - '0'; else { CHAR ch = *psz; int n2;
if (ch >= 'a') ch -= 'a' - 'A';
n2 = ch - 'A' + 0xA; if (n2 >= 0xA && n2 <= 0xF) n = 0x10 * n + n2; else break; } }
// Return TRUE if there was at least one digit
bRet = (psz != pszAdj); } else { // No
pszAdj = psz;
// Do the conversion
for (n = 0; IS_DIGIT(*psz); psz = CharNextA(psz)) n = 10 * n + *psz - '0';
// Return TRUE if there was at least one digit
bRet = (psz != pszAdj); }
*piRet = bNeg ? -n : n;
return bRet; }
#endif
#ifdef DEBUG
EXTERN_C g_bUseNewLeakDetection = FALSE;
DWORD g_dwDumpFlags = 0; // DF_*
#ifdef FULL_DEBUG
ULONGLONG g_qwTraceFlags = TF_ERROR | TF_WARNING; // TF_*
DWORD g_dwBreakFlags = BF_ASSERT | BF_ONERRORMSG; // BF_*
#else
ULONGLONG g_qwTraceFlags = TF_ERROR; // TF_*
DWORD g_dwBreakFlags = BF_ASSERT; // BF_*
#endif
DWORD g_dwPrototype = 0; DWORD g_dwFuncTraceFlags = 0; // FTF_*
// TLS slot used to store depth for CcshellFuncMsg indentation
static DWORD g_tlsStackDepth = TLS_OUT_OF_INDEXES;
// Hack stack depth counter used when g_tlsStackDepth is not available
static DWORD g_dwHackStackDepth = 0;
static char g_szIndentLeader[] = " ";
static WCHAR g_wszIndentLeader[] = L" ";
static CHAR const FAR c_szNewline[] = LINE_SEPARATOR_STR; // (Deliberately CHAR)
static WCHAR const FAR c_wszNewline[] = TEXTW(LINE_SEPARATOR_STR);
extern CHAR const FAR c_szTrace[]; // (Deliberately CHAR)
extern CHAR const FAR c_szErrorDbg[]; // (Deliberately CHAR)
extern CHAR const FAR c_szWarningDbg[]; // (Deliberately CHAR)
extern WCHAR const FAR c_wszTrace[]; extern WCHAR const FAR c_wszErrorDbg[]; extern WCHAR const FAR c_wszWarningDbg[];
extern const CHAR FAR c_szAssertMsg[]; extern CHAR const FAR c_szAssertFailed[]; extern const WCHAR FAR c_wszAssertMsg[]; extern WCHAR const FAR c_wszAssertFailed[];
extern CHAR const FAR c_szRip[]; extern CHAR const FAR c_szRipNoFn[]; extern CHAR const FAR c_szRipMsg[]; extern WCHAR const FAR c_wszRip[]; extern WCHAR const FAR c_wszRipNoFn[];
/*-------------------------------------------------------------------------
Purpose: Adds one of the following prefix strings to pszBuf: "t MODULE " "err MODULE " "wrn MODULE "
Returns the count of characters written. */ int SetPrefixStringA( OUT LPSTR pszBuf, IN UINT cchBuf, IN ULONGLONG qwFlags) { if (TF_ALWAYS == qwFlags) StringCchCopyA(pszBuf, cchBuf, c_szTrace); // ok to truncate - debug message
else if (IsFlagSet(qwFlags, TF_WARNING)) StringCchCopyA(pszBuf, cchBuf, c_szWarningDbg); // ok to truncate - debug message
else if (IsFlagSet(qwFlags, TF_ERROR)) StringCchCopyA(pszBuf, cchBuf, c_szErrorDbg); // ok to truncate - debug message
else StringCchCopyA(pszBuf, cchBuf, c_szTrace); // ok to truncate - debug message
return lstrlenA(pszBuf); }
int SetPrefixStringW( OUT LPWSTR pszBuf, IN UINT cchBuf, IN ULONGLONG qwFlags) { if (TF_ALWAYS == qwFlags) StringCchCopyW(pszBuf, cchBuf, c_wszTrace); // ok to truncate - debug message
else if (IsFlagSet(qwFlags, TF_WARNING)) StringCchCopyW(pszBuf, cchBuf, c_wszWarningDbg);// ok to truncate - debug message
else if (IsFlagSet(qwFlags, TF_ERROR)) StringCchCopyW(pszBuf, cchBuf, c_wszErrorDbg); // ok to truncate - debug message
else StringCchCopyW(pszBuf, cchBuf, c_wszTrace); // ok to truncate - debug message
return lstrlenW(pszBuf); }
static LPCSTR _PathFindFileNameA( LPCSTR pPath) { LPCSTR pT;
for (pT = pPath; *pPath; pPath = CharNextA(pPath)) { if ((pPath[0] == '\\' || pPath[0] == ':' || pPath[0] == '/') && pPath[1] && pPath[1] != '\\' && pPath[1] != '/') pT = pPath + 1; }
return pT; }
static LPCWSTR _PathFindFileNameW( LPCWSTR pPath) { LPCWSTR pT;
for (pT = pPath; *pPath; pPath++) { if ((pPath[0] == TEXTW('\\') || pPath[0] == TEXTW(':') || pPath[0] == TEXTW('/')) && pPath[1] && pPath[1] != TEXTW('\\') && pPath[1] != TEXTW('/')) pT = pPath + 1; }
return pT; }
/*-------------------------------------------------------------------------
Purpose: Returns TRUE if this process is a shell-related process. */ BOOL _IsShellProcess() { CHAR szModuleName[MAX_PATH]; if (GetModuleFileNameA(NULL, szModuleName, sizeof(CHAR) * MAX_PATH) > 0 ) { if (StrStrIA(szModuleName, "explorer.exe") || StrStrIA(szModuleName, "iexplore.exe") || StrStrIA(szModuleName, "rundll32.exe") || StrStrIA(szModuleName, "mshtmpad.exe")) { // yes, the exe is a shell one
return TRUE; } }
// not a normal shell executable
return FALSE; }
// FEATURE (scotth): Use the Ccshell functions. _AssertMsg and
// _DebugMsg are obsolete. They will be removed once all the
// components don't have TEXT() wrapping their debug strings anymore.
void WINCAPI _AssertMsgA( BOOL f, LPCSTR pszMsg, ...) { CHAR ach[1024+40]; va_list vArgs;
if (!f) { int cch;
StringCchCopyA(ach, ARRAYSIZE(ach), c_szAssertMsg); // ok to truncate - debug message
cch = lstrlenA(ach); va_start(vArgs, pszMsg);
StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringA(ach);
OutputDebugStringA(c_szNewline);
if (IsFlagSet(g_dwBreakFlags, BF_ASSERT)) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } }
void WINCAPI _AssertMsgW( BOOL f, LPCWSTR pszMsg, ...) { WCHAR ach[1024+40]; va_list vArgs;
if (!f) { int cch;
StringCchCopyW(ach, ARRAYSIZE(ach), c_wszAssertMsg); // ok to truncate - debug message
cch = lstrlenW(ach); va_start(vArgs, pszMsg);
StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringW(ach);
OutputDebugStringW(c_wszNewline);
if (IsFlagSet(g_dwBreakFlags, BF_ASSERT)) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } }
void _AssertStrLenW( LPCWSTR pszStr, int iLen) { if (pszStr && iLen < lstrlenW(pszStr)) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} }
void _AssertStrLenA( LPCSTR pszStr, int iLen) { if (pszStr && iLen < lstrlenA(pszStr)) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} }
void WINCAPI _DebugMsgA( ULONGLONG flag, LPCSTR pszMsg, ...) { CHAR ach[5*MAX_PATH+40]; // Handles 5*largest path + slop for message
va_list vArgs;
if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag)) { int cch;
cch = SetPrefixStringA(ach, ARRAYSIZE(ach), flag); va_start(vArgs, pszMsg);
try { StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
} except(EXCEPTION_EXECUTE_HANDLER) { OutputDebugString(TEXT("CCSHELL: DebugMsg exception: ")); OutputDebugStringA(pszMsg); } __endexcept
va_end(vArgs); OutputDebugStringA(ach); OutputDebugStringA(c_szNewline);
if (TF_ALWAYS != flag && ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) || (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG))) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } }
void WINCAPI _DebugMsgW( ULONGLONG flag, LPCWSTR pszMsg, ...) { WCHAR ach[5*MAX_PATH+40]; // Handles 5*largest path + slop for message
va_list vArgs;
if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag)) { int cch;
SetPrefixStringW(ach, ARRAYSIZE(ach), flag); cch = lstrlenW(ach); va_start(vArgs, pszMsg);
try { StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
} except(EXCEPTION_EXECUTE_HANDLER) { OutputDebugString(TEXT("CCSHELL: DebugMsg exception: ")); OutputDebugStringW(pszMsg); } __endexcept
va_end(vArgs); OutputDebugStringW(ach); OutputDebugStringW(c_wszNewline);
if (TF_ALWAYS != flag && ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) || (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG))) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } }
//
// Smart debug functions
//
/*----------------------------------------------------------
Purpose: Displays assertion string.
Returns: TRUE to debugbreak */ BOOL CcshellAssertFailedA( LPCSTR pszFile, int line, LPCSTR pszEval, BOOL bBreakInside) { BOOL bRet = FALSE; LPCSTR psz; CHAR ach[256];
psz = _PathFindFileNameA(pszFile); StringCchPrintfA(ach, ARRAYSIZE(ach), c_szAssertFailed, psz, line, pszEval); // ok to truncate - debug message
OutputDebugStringA(ach);
if (IsFlagSet(g_dwBreakFlags, BF_ASSERT)) { if (bBreakInside) { // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
} else bRet = TRUE; }
return bRet; }
/*----------------------------------------------------------
Purpose: Displays assertion string.
*/ BOOL CcshellAssertFailedW( LPCWSTR pszFile, int line, LPCWSTR pszEval, BOOL bBreakInside) { BOOL bRet = FALSE; LPCWSTR psz; WCHAR ach[1024]; // Some callers use more than 256
psz = _PathFindFileNameW(pszFile);
// If psz == NULL, CharPrevW failed which implies we are running on Win95. We can get this
// if we get an assert in some of the W functions in shlwapi... Call the A version of assert...
if (!psz) { char szFile[MAX_PATH]; char szEval[256]; // since the total output is thhis size should be enough...
WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL); WideCharToMultiByte(CP_ACP, 0, pszEval, -1, szEval, ARRAYSIZE(szEval), NULL, NULL); return CcshellAssertFailedA(szFile, line, szEval, bBreakInside); }
StringCchPrintfW(ach, ARRAYSIZE(ach), c_wszAssertFailed, psz, line, pszEval); // ok to truncate - debug message
OutputDebugStringW(ach);
if (IsFlagSet(g_dwBreakFlags, BF_ASSERT)) { if (bBreakInside) { // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
} else bRet = TRUE; }
return bRet; }
/*----------------------------------------------------------
Purpose: Displays a RIP string.
Returns: TRUE to debugbreak */ BOOL CcshellRipA( LPCSTR pszFile, int line, LPCSTR pszEval, BOOL bBreakInside) { BOOL bRet = FALSE; LPCSTR psz; CHAR ach[256];
psz = _PathFindFileNameA(pszFile); StringCchPrintfA(ach, ARRAYSIZE(ach), c_szRipNoFn, psz, line, pszEval); // ok to truncate - debug message
OutputDebugStringA(ach);
if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP)) { if (bBreakInside) { // !!! RIP !!!! RIP !!!! RIP !!!
// MSDEV USERS: This is not the real RIP. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! RIP !!!! RIP !!!! RIP !!!
} else bRet = TRUE; }
return bRet; }
/*----------------------------------------------------------
Purpose: Displays a RIP string.
*/ BOOL CcshellRipW( LPCWSTR pszFile, int line, LPCWSTR pszEval, BOOL bBreakInside) { BOOL bRet = FALSE; LPCWSTR psz; WCHAR ach[256];
psz = _PathFindFileNameW(pszFile);
// If psz == NULL, CharPrevW failed which implies we are running on Win95.
// We can get this if we get an assert in some of the W functions in
// shlwapi... Call the A version of assert...
if (!psz) { char szFile[MAX_PATH]; char szEval[256]; // since the total output is thhis size should be enough...
WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL); WideCharToMultiByte(CP_ACP, 0, pszEval, -1, szEval, ARRAYSIZE(szEval), NULL, NULL); return CcshellRipA(szFile, line, szEval, bBreakInside); }
StringCchPrintfW(ach, ARRAYSIZE(ach), c_wszRipNoFn, psz, line, pszEval); // ok to truncate - debug message
OutputDebugStringW(ach);
if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP)) { if (bBreakInside) { // !!! RIP !!!! RIP !!!! RIP !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! RIP !!!! RIP !!!! RIP !!!
} else bRet = TRUE; }
return bRet; }
BOOL WINCAPI CcshellRipMsgA( BOOL f, LPCSTR pszMsg, ...) { CHAR ach[1024+40]; va_list vArgs;
if (!f) { OutputDebugStringA(c_szRipMsg);
va_start(vArgs, pszMsg); StringCchVPrintfA(ach, ARRAYSIZE(ach), pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringA(ach);
OutputDebugStringA(c_szNewline);
if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP)) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } return FALSE; }
BOOL WINCAPI CcshellRipMsgW( BOOL f, LPCSTR pszMsg, ...) // (this is deliberately CHAR)
{ WCHAR ach[1024+40]; va_list vArgs;
if (!f) { LPWSTR pwsz; WCHAR wszBuf[128]; OutputDebugStringA(c_szRipMsg);
// (We convert the string, rather than simply input an
// LPCWSTR parameter, so the caller doesn't have to wrap
// all the string constants with the TEXT() macro.)
ach[0] = L'\0'; // In case this fails
if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf))) { va_start(vArgs, pszMsg); StringCchVPrintfW(ach, ARRAYSIZE(ach), pwsz, vArgs); // ok to truncate - debug message
va_end(vArgs); UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0); }
OutputDebugStringW(ach); OutputDebugStringA(c_szNewline);
if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP)) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } return FALSE; }
/*----------------------------------------------------------
Purpose: Keep track of the stack depth for function call trace messages.
*/ void CcshellStackEnter(void) { if (TLS_OUT_OF_INDEXES != g_tlsStackDepth) { DWORD dwDepth;
dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
TlsSetValue(g_tlsStackDepth, (LPVOID)(ULONG_PTR)(dwDepth + 1)); } else { g_dwHackStackDepth++; } }
/*----------------------------------------------------------
Purpose: Keep track of the stack depth for functionc all trace messages.
*/ void CcshellStackLeave(void) { if (TLS_OUT_OF_INDEXES != g_tlsStackDepth) { DWORD dwDepth;
dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
if (EVAL(0 < dwDepth)) { EVAL(TlsSetValue(g_tlsStackDepth, (LPVOID)(ULONG_PTR)(dwDepth - 1))); } } else { if (EVAL(0 < g_dwHackStackDepth)) { g_dwHackStackDepth--; } } }
/*----------------------------------------------------------
Purpose: Return the stack depth.
*/ static DWORD CcshellGetStackDepth(void) { DWORD dwDepth;
if (TLS_OUT_OF_INDEXES != g_tlsStackDepth) { dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth)); } else { dwDepth = g_dwHackStackDepth; }
return dwDepth; }
/*----------------------------------------------------------
Purpose: Wide-char version of CcshellAssertMsgA */ void CDECL CcshellAssertMsgW( BOOL f, LPCSTR pszMsg, ...) { WCHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (!f) { WCHAR wszBuf[1024]; LPWSTR pszEnd; LPWSTR pwsz;
HRESULT hr = StringCchCopyExW(ach, ARRAYSIZE(ach), c_wszAssertMsg, &pszEnd, NULL, 0); if (SUCCEEDED(hr)) { va_start(vArgs, pszMsg);
// (We convert the string, rather than simply input an
// LPCWSTR parameter, so the caller doesn't have to wrap
// all the string constants with the TEXT() macro.)
if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf))) { StringCchVPrintfW(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pwsz, vArgs); // ok to truncate - debug message
UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0); }
va_end(vArgs); OutputDebugStringW(ach); OutputDebugStringW(c_wszNewline); }
if (IsFlagSet(g_dwBreakFlags, BF_ASSERT)) { // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
} } }
/*----------------------------------------------------------
Purpose: Wide-char version of CcshellDebugMsgA. Note this function deliberately takes an ANSI format string so our trace messages don't all need to be wrapped in TEXT().
*/ void CDECL CcshellDebugMsgW( ULONGLONG flag, LPCSTR pszMsg, ...) // (this is deliberately CHAR)
{ WCHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag)) { int cch; WCHAR wszBuf[1024]; LPWSTR pwsz;
SetPrefixStringW(ach, ARRAYSIZE(ach), flag); cch = lstrlenW(ach); va_start(vArgs, pszMsg);
// (We convert the string, rather than simply input an
// LPCWSTR parameter, so the caller doesn't have to wrap
// all the string constants with the TEXT() macro.)
if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf))) { StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pwsz, vArgs); // ok to truncate - debug message
UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0); }
va_end(vArgs); OutputDebugStringW(ach); OutputDebugStringW(c_wszNewline);
if (TF_ALWAYS != flag && ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) || (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG))) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } }
/*-------------------------------------------------------------------------
Purpose: Since the ATL code does not pass in a flag parameter, we'll hardcode and check for TF_ATL. */ void CDECL ShellAtlTraceW(LPCWSTR pszMsg, ...) { WCHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (g_qwTraceFlags & TF_ATL) { LPWSTR pszEnd; HRESULT hr;
SetPrefixStringW(ach, ARRAYSIZE(ach), TF_ATL); hr = StringCchCatExW(ach, ARRAYSIZE(ach), L"(ATL) ", &pszEnd, NULL, 0); if (SUCCEEDED(hr)) { va_start(vArgs, pszMsg); StringCchVPrintfW(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringW(ach); } } }
/*----------------------------------------------------------
Purpose: Wide-char version of CcshellFuncMsgA. Note this function deliberately takes an ANSI format string so our trace messages don't all need to be wrapped in TEXT().
*/ void CDECL CcshellFuncMsgW( ULONGLONG flag, LPCSTR pszMsg, ...) // (this is deliberately CHAR)
{ WCHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (IsFlagSet(g_qwTraceFlags, TF_FUNC) && IsFlagSet(g_dwFuncTraceFlags, flag)) { int cch; WCHAR wszBuf[1024]; LPWSTR pwsz; DWORD dwStackDepth; LPWSTR pszLeaderEnd; WCHAR chSave;
// Determine the indentation for trace message based on
// stack depth.
dwStackDepth = CcshellGetStackDepth();
if (dwStackDepth < SIZECHARS(g_szIndentLeader)) { pszLeaderEnd = &g_wszIndentLeader[dwStackDepth]; } else { pszLeaderEnd = &g_wszIndentLeader[SIZECHARS(g_wszIndentLeader)-1]; }
chSave = *pszLeaderEnd; *pszLeaderEnd = '\0';
StringCchPrintfW(ach, ARRAYSIZE(ach), L"%s %s", c_wszTrace, g_wszIndentLeader); // ok to truncate - debug message
*pszLeaderEnd = chSave;
// Compose remaining string
cch = lstrlenW(ach); va_start(vArgs, pszMsg);
// (We convert the string, rather than simply input an
// LPCWSTR parameter, so the caller doesn't have to wrap
// all the string constants with the TEXT() macro.)
if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf))) { StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pwsz, vArgs); // ok to truncate - debug message
UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0); }
va_end(vArgs); OutputDebugStringW(ach); OutputDebugStringW(c_wszNewline); } }
/*----------------------------------------------------------
Purpose: Assert failed message only */ void CDECL CcshellAssertMsgA( BOOL f, LPCSTR pszMsg, ...) { CHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (!f) { LPSTR pszEnd;
HRESULT hr = StringCchCopyExA(ach, ARRAYSIZE(ach), c_szAssertMsg, &pszEnd, NULL, 0); if (SUCCEEDED(hr)) { va_start(vArgs, pszMsg); StringCchVPrintfA(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringA(ach); OutputDebugStringA(c_szNewline); }
if (IsFlagSet(g_dwBreakFlags, BF_ASSERT)) { // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
} } }
/*----------------------------------------------------------
Purpose: Debug spew */ void CDECL CcshellDebugMsgA( ULONGLONG flag, LPCSTR pszMsg, ...) { CHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag)) { int cch;
cch = SetPrefixStringA(ach, ARRAYSIZE(ach), flag); va_start(vArgs, pszMsg); StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringA(ach); OutputDebugStringA(c_szNewline);
if (TF_ALWAYS != flag && ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) || (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG))) { // MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
} } }
/*-------------------------------------------------------------------------
Purpose: Since the ATL code does not pass in a flag parameter, we'll hardcode and check for TF_ATL. */ void CDECL ShellAtlTraceA(LPCSTR pszMsg, ...) { CHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (g_qwTraceFlags & TF_ATL) { LPSTR pszEnd; HRESULT hr;
SetPrefixStringA(ach, ARRAYSIZE(ach), TF_ATL); hr = StringCchCatExA(ach, ARRAYSIZE(ach), "(ATL) ", &pszEnd, NULL, 0); if (SUCCEEDED(hr)) { va_start(vArgs, pszMsg); StringCchVPrintfA(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringA(ach); } } }
/*----------------------------------------------------------
Purpose: Debug spew for function trace calls */ void CDECL CcshellFuncMsgA( ULONGLONG flag, LPCSTR pszMsg, ...) { CHAR ach[1024+40]; // Largest path plus extra
va_list vArgs;
if (IsFlagSet(g_qwTraceFlags, TF_FUNC) && IsFlagSet(g_dwFuncTraceFlags, flag)) { int cch; DWORD dwStackDepth; LPSTR pszLeaderEnd; CHAR chSave;
// Determine the indentation for trace message based on
// stack depth.
dwStackDepth = CcshellGetStackDepth();
if (dwStackDepth < sizeof(g_szIndentLeader)) { pszLeaderEnd = &g_szIndentLeader[dwStackDepth]; } else { pszLeaderEnd = &g_szIndentLeader[sizeof(g_szIndentLeader)-1]; }
chSave = *pszLeaderEnd; *pszLeaderEnd = '\0';
StringCchPrintfA(ach, ARRAYSIZE(ach), "%s %s", c_szTrace, g_szIndentLeader); // ok to truncate - debug message
*pszLeaderEnd = chSave;
// Compose remaining string
cch = lstrlenA(ach); va_start(vArgs, pszMsg); StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
va_end(vArgs); OutputDebugStringA(ach); OutputDebugStringA(c_szNewline); } }
/*-------------------------------------------------------------------------
Purpose: Spews a trace message if hrTest is a failure code. */ HRESULT TraceHR( HRESULT hrTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine) { CHAR ach[1024+40]; // Largest path plus extra
if (g_qwTraceFlags & TF_WARNING && FAILED(hrTest)) { int cch;
cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING); StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, "THR: Failure of \"%s\" at %s, line %d (%#08lx)", pszExpr, _PathFindFileNameA(pszFile), iLine, hrTest); // ok to truncate - debug message
OutputDebugStringA(ach); OutputDebugStringA(c_szNewline);
if (IsFlagSet(g_dwBreakFlags, BF_THR)) { // !!! THR !!!! THR !!!! THR !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! THR !!!! THR !!!! THR !!!
} } return hrTest; }
/*-------------------------------------------------------------------------
Purpose: Spews a trace message if bTest is false. */ BOOL TraceBool( BOOL bTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine) { CHAR ach[1024+40]; // Largest path plus extra
if (g_qwTraceFlags & TF_WARNING && !bTest) { int cch;
cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING); StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, "TBOOL: Failure of \"%s\" at %s, line %d", pszExpr, _PathFindFileNameA(pszFile), iLine); // ok to truncate - debug message
OutputDebugStringA(ach); OutputDebugStringA(c_szNewline);
if (IsFlagSet(g_dwBreakFlags, BF_THR)) { // !!! TBOOL !!!! TBOOL !!!! TBOOL !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! TBOOL !!!! TBOOL !!!! TBOOL !!!
} } return bTest; }
/*-------------------------------------------------------------------------
Purpose: Spews a trace message if iTest is -1. */ int TraceInt( int iTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine) { CHAR ach[1024+40]; // Largest path plus extra
if (g_qwTraceFlags & TF_WARNING && -1 == iTest) { int cch;
cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING); StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, "TINT: Failure of \"%s\" at %s, line %d", pszExpr, _PathFindFileNameA(pszFile), iLine); // ok to truncate - debug message
OutputDebugStringA(ach); OutputDebugStringA(c_szNewline);
if (IsFlagSet(g_dwBreakFlags, BF_THR)) { // !!! TINT !!!! TINT !!!! TINT !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! TINT !!!! TINT !!!! TINT !!!
} } return iTest; }
/*-------------------------------------------------------------------------
Purpose: Spews a trace message if pvTest is NULL. */ LPVOID TracePtr( LPVOID pvTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine) { CHAR ach[1024+40]; // Largest path plus extra
if (g_qwTraceFlags & TF_WARNING && NULL == pvTest) { int cch;
cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING); StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, "TPTR: Failure of \"%s\" at %s, line %d", pszExpr, _PathFindFileNameA(pszFile), iLine); // ok to truncate - debug message
OutputDebugStringA(ach); OutputDebugStringA(c_szNewline);
if (IsFlagSet(g_dwBreakFlags, BF_THR)) { // !!! TPTR !!!! TPTR !!!! TPTR !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! TPTR !!!! TPTR !!!! TPTR !!!
} } return pvTest; }
/*-------------------------------------------------------------------------
Purpose: Spews a trace message if dwTest is a Win32 failure code. */ DWORD TraceWin32( DWORD dwTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine) { CHAR ach[1024+40]; // Largest path plus extra
if (g_qwTraceFlags & TF_WARNING && ERROR_SUCCESS != dwTest) { int cch;
cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING); StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, "TW32: Failure of \"%s\" at %s, line %d (%#08lx)", pszExpr, _PathFindFileNameA(pszFile), iLine, dwTest); // ok to truncate - debug message
OutputDebugStringA(ach); OutputDebugStringA(c_szNewline);
if (IsFlagSet(g_dwBreakFlags, BF_THR)) { // !!! THR !!!! THR !!!! THR !!!
// MSDEV USERS: This is not the real assert. Hit
// Shift-F11 to jump back to the caller.
DEBUG_BREAK; // ASSERT
// !!! THR !!!! THR !!!! THR !!!
} } return dwTest; }
//
// Debug .ini functions
//
#pragma data_seg(DATASEG_READONLY)
// (These are deliberately CHAR)
CHAR const FAR c_szNull[] = ""; CHAR const FAR c_szZero[] = "0"; CHAR const FAR c_szIniKeyBreakFlags[] = "BreakFlags"; CHAR const FAR c_szIniKeyTraceFlags[] = "TraceFlags"; CHAR const FAR c_szIniKeyFuncTraceFlags[] = "FuncTraceFlags"; CHAR const FAR c_szIniKeyDumpFlags[] = "DumpFlags"; CHAR const FAR c_szIniKeyProtoFlags[] = "Prototype";
#pragma data_seg()
// Some of the .ini processing code was pimped from the sync engine.
//
typedef struct _INIKEYHEADER { LPCTSTR pszSectionName; LPCTSTR pszKeyName; LPCTSTR pszDefaultRHS; } INIKEYHEADER;
typedef struct _BOOLINIKEY { INIKEYHEADER ikh; LPDWORD puStorage; DWORD dwFlag; } BOOLINIKEY;
typedef struct _INTINIKEY { INIKEYHEADER ikh; LPDWORD puStorage; } INTINIKEY;
#define PutIniIntCmp(idsSection, idsKey, nNewValue, nSave) \
if ((nNewValue) != (nSave)) PutIniInt(idsSection, idsKey, nNewValue)
#define WritePrivateProfileInt(szApp, szKey, i, lpFileName) \
{CHAR sz[7]; \ WritePrivateProfileString(szApp, szKey, SzFromInt(sz, i), lpFileName);}
#ifdef BOOL_INI_VALUES
/* Boolean TRUE strings used by IsIniYes() (comparison is case-insensitive) */
static LPCTSTR s_rgpszTrue[] = { TEXT("1"), TEXT("On"), TEXT("True"), TEXT("Y"), TEXT("Yes") };
/* Boolean FALSE strings used by IsIniYes() (comparison is case-insensitive) */
static LPCTSTR s_rgpszFalse[] = { TEXT("0"), TEXT("Off"), TEXT("False"), TEXT("N"), TEXT("No") }; #endif
#ifdef BOOL_INI_VALUES
/*----------------------------------------------------------
Purpose: Determines whether a string corresponds to a boolean TRUE value. Returns: The boolean value (TRUE or FALSE) */ BOOL PRIVATE IsIniYes( LPCTSTR psz) { int i; BOOL bNotFound = TRUE; BOOL bResult;
ASSERT(psz);
/* Is the value TRUE? */
for (i = 0; i < ARRAYSIZE(s_rgpszTrue); i++) { if (IsSzEqual(psz, s_rgpszTrue[i])) { bResult = TRUE; bNotFound = FALSE; break; } }
/* Is the value FALSE? */
if (bNotFound) { for (i = 0; i < ARRAYSIZE(s_rgpszFalse); i++) { if (IsSzEqual(psz, s_rgpszFalse[i])) { bResult = FALSE; bNotFound = FALSE; break; } }
/* Is the value a known string? */
if (bNotFound) { /* No. Whine about it. */
TraceMsg(TF_WARNING, "IsIniYes() called on unknown Boolean RHS '%s'.", psz); bResult = FALSE; } }
return bResult; }
/*----------------------------------------------------------
Purpose: Process keys with boolean RHSs. */ void PRIVATE ProcessBooleans(void) { int i;
for (i = 0; i < ARRAYSIZE(s_rgbik); i++) { DWORD dwcbKeyLen; TCHAR szRHS[MAX_BUF]; BOOLINIKEY * pbik = &(s_rgbik[i]); LPCTSTR lpcszRHS;
/* Look for key. */
dwcbKeyLen = GetPrivateProfileString(pbik->ikh.pszSectionName, pbik->ikh.pszKeyName, TEXT(""), szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (dwcbKeyLen) lpcszRHS = szRHS; else lpcszRHS = pbik->ikh.pszDefaultRHS;
if (IsIniYes(lpcszRHS)) { if (IsFlagClear(*(pbik->puStorage), pbik->dwFlag)) TraceMsg(TF_GENERAL, "ProcessIniFile(): %s set in %s![%s].", pbik->ikh.pszKeyName, c_szCcshellIniFile, pbik->ikh.pszSectionName);
SetFlag(*(pbik->puStorage), pbik->dwFlag); } else { if (IsFlagSet(*(pbik->puStorage), pbik->dwFlag)) TraceMsg(TF_GENERAL, "ProcessIniFile(): %s cleared in %s![%s].", pbik->ikh.pszKeyName, c_szCcshellIniFile, pbik->ikh.pszSectionName);
ClearFlag(*(pbik->puStorage), pbik->dwFlag); } } } #endif
/*----------------------------------------------------------
Purpose: This function reads a .ini file to determine the debug flags to set. The .ini file and section are specified by the following manifest constants:
SZ_DEBUGINI SZ_DEBUGSECTION
The debug variables that are set by this function are g_dwDumpFlags, g_qwTraceFlags, g_dwBreakFlags, and g_dwFuncTraceFlags, g_dwPrototype.
Returns: TRUE if initialization is successful */ BOOL PUBLIC CcshellGetDebugFlags(void) { CHAR szRHS[MAX_PATH]; ULONGLONG val;
// (scotth): Yes, COMCTL32 exports StrToIntEx, but I
// don't want to cause a dependency delta and force everyone
// to get a new comctl32 just because they built debug.
// So use a local version of StrToIntEx.
// Trace Flags
GetPrivateProfileStringA(c_szCcshellIniSecDebug, c_szIniKeyTraceFlags, c_szNull, szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val)) g_qwTraceFlags = val; #ifdef FULL_DEBUG
else g_qwTraceFlags = 3; // default to TF_ERROR and TF_WARNING trace messages
#endif
TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#16I64x.", c_szIniKeyTraceFlags, g_qwTraceFlags);
// Function trace Flags
GetPrivateProfileStringA(c_szCcshellIniSecDebug, c_szIniKeyFuncTraceFlags, c_szNull, szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val)) g_dwFuncTraceFlags = (DWORD)val;
TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.", c_szIniKeyFuncTraceFlags, g_dwFuncTraceFlags);
// Dump Flags
GetPrivateProfileStringA(c_szCcshellIniSecDebug, c_szIniKeyDumpFlags, c_szNull, szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val)) g_dwDumpFlags = (DWORD)val;
TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.", c_szIniKeyDumpFlags, g_dwDumpFlags);
// Break Flags
GetPrivateProfileStringA(c_szCcshellIniSecDebug, c_szIniKeyBreakFlags, c_szNull, szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val)) g_dwBreakFlags = (DWORD)val; #ifdef FULL_DEBUG
else g_dwBreakFlags = 5; // default to break on ASSERT and TF_ERROR
#endif
TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.", c_szIniKeyBreakFlags, g_dwBreakFlags);
// Prototype Flags
GetPrivateProfileStringA(c_szCcshellIniSecDebug, c_szIniKeyProtoFlags, c_szNull, szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val)) g_dwPrototype = (DWORD)val;
// Are we using the new leak detection from shelldbg.dll?
GetPrivateProfileStringA("ShellDbg", "NewLeakDetection", c_szNull, szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val)) g_bUseNewLeakDetection = BOOLIFY(val);
TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.", c_szIniKeyProtoFlags, g_dwPrototype);
GetPrivateProfileStringA(c_szCcshellIniSecDebug, "DebugOutputFile", c_szNull, szRHS, SIZECHARS(szRHS), c_szCcshellIniFile); if (szRHS[0] != TEXT('\0')) { g_hDebugOutputFile = CreateFileA(szRHS, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); }
return TRUE; }
// Function to call in allocspy.dll (GetShellMallocSpy)
typedef BOOL (__stdcall *pfnGSMS) (IShellMallocSpy **ppout);
STDAPI_(void) IMSAddToList(BOOL bAdd, void*pv, SIZE_T cb) { static BOOL bDontTry=FALSE; static IShellMallocSpy *pms=NULL;
if (!bDontTry && pms == NULL) { pfnGSMS pfnGetShellMallocSpy; HMODULE hmod;
bDontTry = TRUE; // assume failure
if (hmod = LoadLibraryA("ALLOCSPY.DLL")) { pfnGetShellMallocSpy = (pfnGSMS) GetProcAddress(hmod, "GetShellMallocSpy");
pfnGetShellMallocSpy(&pms); } } if (bDontTry) return;
if (bAdd) pms->lpVtbl->AddToList(pms, pv, cb); else pms->lpVtbl->RemoveFromList(pms, pv); }
#endif // DEBUG
#ifdef PRODUCT_PROF
DWORD g_dwProfileCAP = 0;
BOOL PUBLIC CcshellGetDebugFlags(void) { CHAR szRHS[MAX_PATH]; LONGLONG val;
GetPrivateProfileStringA(c_szCcshellIniSecDebug, "Profile", "", szRHS, SIZECHARS(szRHS), c_szCcshellIniFile);
if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val)) g_dwProfileCAP = (DWORD)val;
return TRUE; } #endif // PRODUCT_PROF
#ifdef DEBUG
// turn on path whacking for full-debug builds
#ifdef FULL_DEBUG
static BOOL g_fWhackPathBuffers = TRUE; #else
static BOOL g_fWhackPathBuffers = FALSE; #endif
void DEBUGWhackPathBufferA(LPSTR psz, UINT cch) { if (g_fWhackPathBuffers) { if (psz && IS_VALID_WRITE_BUFFER(psz, char, cch)) { FillMemory(psz, cch * sizeof(char), 0xFE); } } }
void DEBUGWhackPathBufferW(LPWSTR psz, UINT cch) { if (g_fWhackPathBuffers) { if (psz && IS_VALID_WRITE_BUFFER(psz, WCHAR, cch)) { FillMemory(psz, cch * sizeof(WCHAR), 0xFE); } } }
void DEBUGWhackPathStringA(LPSTR psz, UINT cch) { if (g_fWhackPathBuffers) { if (psz && IS_VALID_WRITE_BUFFER(psz, char, cch) && IS_VALID_STRING_PTRA(psz, -1)) { UINT len = lstrlenA(psz);
if (len >= cch) { TraceMsg(TF_WARNING, "DEBUGWhackPathStringA: caller of caller passed strange Path string (strlen > buffer size)"); } else { FillMemory(psz+len+1, (cch-len-1) * sizeof(char), 0xFE); } } } }
void DEBUGWhackPathStringW(LPWSTR psz, UINT cch) { if (g_fWhackPathBuffers) { if (psz && IS_VALID_WRITE_BUFFER(psz, WCHAR, cch) && IS_VALID_STRING_PTRW(psz, -1)) { UINT len = lstrlenW(psz);
if (len >= cch) { TraceMsg(TF_WARNING, "DEBUGWhackPathStringW: caller of caller passed strange Path string (strlen > buffer size)"); } else { FillMemory(psz+len+1, (cch-len-1) * sizeof(WCHAR), 0xFE); } } } } #endif // DEBUG
|