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.
 
 
 
 
 
 

904 lines
29 KiB

//====== Assertion/Debug output APIs =================================
#include <platform.h> // for __endexcept
#pragma warning (disable:4096) // '__cdecl' must be used with '...'
#pragma warning (disable:4201) // nonstandard extension used : nameless struct/union
#pragma warning (disable:4115) // named type definition in parentheses
#if defined(DECLARE_DEBUG) && defined(DEBUG)
//
// Declare module-specific debug strings
//
// When including this header in your private header file, do not
// define DECLARE_DEBUG. But do define DECLARE_DEBUG in one of the
// source files in your project, and then include this header file.
//
// You may also define the following:
//
// SZ_DEBUGINI - the .ini file used to set debug flags
// SZ_DEBUGSECTION - the section in the .ini file specific to
// the module component.
// SZ_MODULE - ansi version of the name of your module.
//
//
// (These are deliberately CHAR)
EXTERN_C const CHAR c_szCcshellIniFile[] = SZ_DEBUGINI;
EXTERN_C const CHAR c_szCcshellIniSecDebug[] = SZ_DEBUGSECTION;
EXTERN_C const WCHAR c_wszTrace[] = L"t " TEXTW(SZ_MODULE) L" ";
EXTERN_C const WCHAR c_wszErrorDbg[] = L"err " TEXTW(SZ_MODULE) L" ";
EXTERN_C const WCHAR c_wszWarningDbg[] = L"wn " TEXTW(SZ_MODULE) L" ";
EXTERN_C const WCHAR c_wszAssertMsg[] = TEXTW(SZ_MODULE) L" Assert: ";
EXTERN_C const WCHAR c_wszAssertFailed[] = TEXTW(SZ_MODULE) L" Assert %ls, line %d: (%ls)\r\n";
EXTERN_C const WCHAR c_wszRip[] = TEXTW(SZ_MODULE) L" RIP in %s at %s, line %d: (%s)\r\n";
EXTERN_C const WCHAR c_wszRipNoFn[] = TEXTW(SZ_MODULE) L" RIP at %s, line %d: (%s)\r\n";
// (These are deliberately CHAR)
EXTERN_C const CHAR c_szTrace[] = "t " SZ_MODULE " ";
EXTERN_C const CHAR c_szErrorDbg[] = "err " SZ_MODULE " ";
EXTERN_C const CHAR c_szWarningDbg[] = "wn " SZ_MODULE " ";
EXTERN_C const CHAR c_szAssertMsg[] = SZ_MODULE " Assert: ";
EXTERN_C const CHAR c_szAssertFailed[] = SZ_MODULE " Assert %s, line %d: (%s)\r\n";
EXTERN_C const CHAR c_szRip[] = SZ_MODULE " RIP in %s at %s, line %d: (%s)\r\n";
EXTERN_C const CHAR c_szRipNoFn[] = SZ_MODULE " RIP at %s, line %d: (%s)\r\n";
EXTERN_C const CHAR c_szRipMsg[] = SZ_MODULE " RIP: ";
#endif // DECLARE_DEBUG && DEBUG
#if defined(DECLARE_DEBUG) && defined(PRODUCT_PROF)
EXTERN_C const CHAR c_szCcshellIniFile[] = SZ_DEBUGINI;
EXTERN_C const CHAR c_szCcshellIniSecDebug[] = SZ_DEBUGSECTION;
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(DECLARE_DEBUG)
//
// Debug macros and validation code
//
#if !defined(UNIX) || (defined(UNIX) && !defined(NOSHELLDEBUG))
// Undefine the macros that we define in case some other header
// might have tried defining these commonly-named macros.
#undef Assert
#undef AssertE
#undef AssertMsg
#undef AssertStrLen
#undef DebugMsg
#undef FullDebugMsg
#undef ASSERT
#undef EVAL
#undef ASSERTMSG // catch people's typos
#undef DBEXEC
#ifdef _ATL_NO_DEBUG_CRT
#undef _ASSERTE // we substitute this ATL macro
#endif
#endif // !UNIX
// Access these globals to determine which debug flags are set.
// These globals are modified by CcshellGetDebugFlags(), which
// reads an .ini file and sets the appropriate flags.
//
// g_dwDumpFlags - bits are application specific. Typically
// used for dumping structures.
// g_dwBreakFlags - uses BF_* flags. The remaining bits are
// application specific. Used to determine
// when to break into the debugger.
// g_qwTraceFlags - uses TF_* flags. The remaining bits are
// application specific. Used to display
// debug trace messages.
// g_dwFuncTraceFlags - bits are application specific. When
// TF_FUNC is set, CcshellFuncMsg uses this
// value to determine which function traces
// to display.
// g_dwProtoype - bits are application specific. Use it for
// anything.
// g_dwProfileCAP - bits are application specific. Used to
// control ICECAP profiling.
//
extern DWORD g_dwDumpFlags;
extern DWORD g_dwBreakFlags;
extern ULONGLONG g_qwTraceFlags;
#ifdef DEBUG
extern DWORD g_dwPrototype;
#else
#define g_dwPrototype 0
#endif
extern DWORD g_dwFuncTraceFlags;
#if defined(DEBUG) || defined(PRODUCT_PROF)
BOOL CcshellGetDebugFlags(void);
#else
#define CcshellGetDebugFlags() 0
#endif
// Break flags for g_dwBreakFlags
#define BF_ASSERT 0x00000001 // Break on assertions
#define BF_ONAPIENTER 0x00000002 // Break on entering an API
#define BF_ONERRORMSG 0x00000004 // Break on TF_ERROR
#define BF_ONWARNMSG 0x00000008 // Break on TF_WARNING
#define BF_THR 0x00000100 // Break when THR() receives a failure
#define BF_RIP 0x00000200 // Break on RIPs
#define BF_LEAKS 0x80000000 // Break on detecting a leak
// Trace flags for g_qwTraceFlags
#define TF_ALWAYS 0xFFFFFFFFFFFFFFFF
#define TF_NEVER 0x00000000
#define TF_WARNING 0x00000001
#define TF_ERROR 0x00000002
#define TF_GENERAL 0x00000004 // Standard messages
#define TF_FUNC 0x00000008 // Trace function calls
#define TF_ATL 0x00000008 // Since TF_FUNC is so-little used, I'm overloading this bit
#define TF_MEMUSAGE 0x0000000100000000
#define TF_KEEP_ALLOCATION_STACKS 0x0000000200000000
// (Upper 28 bits reserved for custom use per-module)
#define TF_CUSTOM1 0x40000000 // Custom messages #1
#define TF_CUSTOM2 0x80000000 // Custom messages #2
// Old, archaic debug flags.
// APPCOMPAT (scotth): the following flags will be phased out over time.
#ifdef DM_TRACE
#undef DM_TRACE
#undef DM_WARNING
#undef DM_ERROR
#endif
#define DM_TRACE TF_GENERAL // OBSOLETE Trace messages
#define DM_WARNING TF_WARNING // OBSOLETE Warning
#define DM_ERROR TF_ERROR // OBSOLETE Error
// Use this macro to declare message text that will be placed
// in the CODE segment (useful if DS is getting full)
//
// Ex: DEBUGTEXT(szMsg, "Invalid whatever: %d");
//
#define DEBUGTEXT(sz, msg) /* ;Internal */ \
static const TCHAR sz[] = msg
#ifndef NOSHELLDEBUG // Others have own versions of these.
#ifdef DEBUG
void AttachUserModeDebugger (void);
#ifdef _X86_
// Use int 3 so we stop immediately in the source
#define DEBUG_BREAK \
{ \
static BOOL gAlwaysAssert = FALSE; \
AttachUserModeDebugger(); \
do \
{ \
_try \
{ \
_asm int 3 \
} \
_except (EXCEPTION_EXECUTE_HANDLER) \
{ \
} \
} while (gAlwaysAssert); \
}
#else
#define DEBUG_BREAK \
{ \
static BOOL gAlwaysAssert = FALSE; \
AttachUserModeDebugger(); \
do \
{ \
_try \
{ \
DebugBreak(); \
} \
_except (EXCEPTION_EXECUTE_HANDLER) \
{ \
} \
__endexcept \
} while (gAlwaysAssert); \
}
#endif
// Prototypes for debug functions
void CcshellStackEnter(void);
void CcshellStackLeave(void);
void CDECL CcshellFuncMsgW(ULONGLONG mask, LPCSTR pszMsg, ...);
void CDECL CcshellFuncMsgA(ULONGLONG mask, LPCSTR pszMsg, ...);
void CDECL _AssertMsgA(BOOL f, LPCSTR pszMsg, ...);
void CDECL _AssertMsgW(BOOL f, LPCWSTR pszMsg, ...);
void _AssertStrLenA(LPCSTR pszStr, int iLen);
void _AssertStrLenW(LPCWSTR pwzStr, int iLen);
#ifdef UNICODE
#define CcshellFuncMsg CcshellFuncMsgW
#define CcshellAssertMsg CcshellAssertMsgW
#define _AssertMsg _AssertMsgW
#define _AssertStrLen _AssertStrLenW
#else
#define CcshellFuncMsg CcshellFuncMsgA
#define CcshellAssertMsg CcshellAssertMsgA
#define _AssertMsg _AssertMsgA
#define _AssertStrLen _AssertStrLenA
#endif
#endif // DEBUG
// ASSERT(f)
//
// Generates a "Assert file.c, line x (eval)" message if f is NOT true.
//
// Use ASSERT() to check for logic invariance. These are typically considered
// fatal problems, and falls into the 'this should never ever happen'
// category.
//
// Do *not* use ASSERT() to verify successful API calls if the APIs can
// legitimately fail due to low resources. For example, LocalAlloc can
// legally fail, so you shouldn't assert that it will never fail.
//
// The BF_ASSERT bit in g_dwBreakFlags governs whether the function
// performs a DebugBreak().
//
// Default Behavior-
// Retail builds: nothing
// Debug builds: spew and break
// Full debug builds: spew and break
//
#ifdef DEBUG
BOOL CcshellAssertFailedA(LPCSTR szFile, int line, LPCSTR pszEval, BOOL bBreakInside);
BOOL CcshellAssertFailedW(LPCWSTR szFile, int line, LPCWSTR pwszEval, BOOL bBreakInside);
#ifdef UNICODE
#define CcshellAssertFailed CcshellAssertFailedW
#else
#define CcshellAssertFailed CcshellAssertFailedA
#endif
#define ASSERT(f) \
{ \
DEBUGTEXT(szFile, TEXT(__FILE__)); \
if (!(f) && CcshellAssertFailed(szFile, __LINE__, TEXT(#f), FALSE)) \
DEBUG_BREAK; \
}
// The old Win95 code used to use "Assert()". We discourage the use
// of this macro now because it is not msdev-friendly.
#ifdef DISALLOW_Assert
#define Assert(f) Dont_use_Assert___Use_ASSERT
#else
#define Assert(f) ASSERT(f)
#endif
#else // DEBUG
#define ASSERT(f)
#define Assert(f)
#endif // DEBUG
// ASSERTMSG(f, szFmt, args...)
//
// Behaves like ASSERT, except it prints the wsprintf-formatted message
// instead of the file and line number.
//
// The sz parameter is always ANSI; AssertMsg correctly converts it
// to unicode if necessary. This is so you don't have to wrap your
// debug strings with TEXT().
//
// The BF_ASSERT bit in g_dwBreakFlags governs whether the function
// performs a DebugBreak().
//
// Default Behavior-
// Retail builds: nothing
// Debug builds: spew and break
// Full debug builds: spew and break
//
#ifdef DEBUG
void CDECL CcshellAssertMsgW(BOOL bAssert, LPCSTR pszMsg, ...);
void CDECL CcshellAssertMsgA(BOOL bAssert, LPCSTR pszMsg, ...);
#ifdef UNICODE
#define CcshellAssertMsg CcshellAssertMsgW
#else
#define CcshellAssertMsg CcshellAssertMsgA
#endif
#define ASSERTMSG CcshellAssertMsg
#else // DEBUG
#define ASSERTMSG 1 ? (void)0 : (void)
#endif // DEBUG
// EVAL(f)
//
// Behaves like ASSERT(). Evaluates the expression (f). The expression
// is always evaluated, even in retail builds. But the macro only asserts
// in the debug build. This macro may be used on logical expressions, eg:
//
// if (EVAL(exp))
// // do something
//
// Do *not* use EVAL() to verify successful API calls if the APIs can
// legitimately fail due to low resources. For example, LocalAlloc can
// legally fail, so you shouldn't assert that it will never fail.
//
// The BF_ASSERT bit in g_dwBreakFlags governs whether the function
// performs a DebugBreak().
//
// Default Behavior-
// Retail builds: nothing
// Debug builds: spew and break
// Full debug builds: spew and break
//
#ifdef DEBUG
#define EVAL(exp) \
((exp) || (CcshellAssertFailed(TEXT(__FILE__), __LINE__, TEXT(#exp), TRUE), 0))
#else // DEBUG
#define EVAL(exp) ((exp) != 0)
#endif // DEBUG
// RIP(f)
//
// Generates a "RIP at file.c, line x (eval)" message if f is NOT true.
//
// Use RIP() to perform parameter validation, especially when you
// know the function or method may be called by a 3rd party app.
// Typically, RIPs are used to indicate the caller passed in an invalid
// parameter, so the problem is really not in the code itself.
//
// Do *not* use RIP() to verify successful API calls if the APIs can
// legitimately fail due to low resources. For example, LocalAlloc can
// legally fail, so you shouldn't assert that it will never fail.
//
// RIP performs a debugbreak only in the following processes:
//
// explore.exe
// iexplore.exe
// rundll32.exe
//
// In any other process, this just spews the debug message, but doesn't stop.
//
// Setting the BF_RIP bit in g_dwBreakFlags will cause the macro to perform
// a DebugBreak() even in non-shell processes.
//
// Default Behavior-
// Retail builds: nothing
// Debug builds: spew (other processes), spew and break (shell processes)
// Full debug builds: spew (other processes), spew and break (shell processes)
//
#ifdef DEBUG
BOOL CcshellRipA(LPCSTR pszFile, int line, LPCSTR pszEval, BOOL bBreakInside);
BOOL CcshellRipW(LPCWSTR pszFile, int line, LPCWSTR pwszEval, BOOL bBreakInside);
BOOL CDECL CcshellRipMsgA(BOOL bRip, LPCSTR pszMsg, ...);
BOOL CDECL CcshellRipMsgW(BOOL bRip, LPCSTR pszMsg, ...);
#ifdef UNICODE
#define CcshellRip CcshellRipW
#define CcshellRipMsg CcshellRipMsgW
#else
#define CcshellRip CcshellRipA
#define CcshellRipMsg CcshellRipMsgA
#endif
#define RIP(f) \
{ \
DEBUGTEXT(szFile, TEXT(__FILE__)); \
if (!(f) && CcshellRip(szFile, __LINE__, TEXT(#f), FALSE)) \
{ \
DEBUG_BREAK; \
} \
} \
#define RIPMSG CcshellRipMsg
#else // DEBUG
#define RIP(f)
#define RIPMSG 1 ? (void)0 : (void)
#endif // DEBUG
// TraceMsg(dwMask, sz, args...)
//
// Generate wsprintf-formatted message using the specified trace dwMask.
// dwMask may be one of the predefined bits:
//
// TF_ERROR - display "err <MODULE> <string>"
// TF_WARNING - display "wn <MODULE> <string>"
// TF_GENERAL - display "t <MODULE> <string>"
// TF_ALWAYS - display "t <MODULE> <string>" regardless of g_qwTraceFlags.
//
// or it may be a custom bit (any of the upper 28 bits).
//
// The g_qwTraceFlags global governs whether the message is displayed (based
// upon the dwMask parameter).
//
// The sz parameter is always ANSI; TraceMsg correctly converts it
// to unicode if necessary. This is so you don't have to wrap your
// debug strings with TEXT().
//
// In addition to squirting the trace message, you may optionally cause
// the trace message to stop if you need to trace down the source of
// an error. The BF_ONERRORMSG and BF_ONWARNMSG bits may be set in
// g_dwBreakFlags to make TraceMsg stop when a TF_ERROR or TF_WARNING
// message is displayed. But typically these bits are disabled.
//
// Default Behavior-
// Retail builds: nothing
// Debug builds: only TF_ALWAYS and TF_ERROR messages spew
// Full debug builds: spew
//
#ifdef DEBUG
UINT GetStack(UINT nDepth, CHAR *szBuffer, UINT nBufferLength);
void CDECL CcshellDebugMsgW(ULONGLONG mask, LPCSTR pszMsg, ...);
void CDECL CcshellDebugMsgA(ULONGLONG mask, LPCSTR pszMsg, ...);
void CDECL _DebugMsgA(ULONGLONG flag, LPCSTR psz, ...);
void CDECL _DebugMsgW(ULONGLONG flag, LPCWSTR psz, ...);
#ifdef UNICODE
#define CcshellDebugMsg CcshellDebugMsgW
#define _DebugMsg _DebugMsgW
#else
#define CcshellDebugMsg CcshellDebugMsgA
#define _DebugMsg _DebugMsgA
#endif
#define TraceMsgW CcshellDebugMsgW
#define TraceMsgA CcshellDebugMsgA
#define TraceMsg CcshellDebugMsg
// Use TraceMsg instead of DebugMsg. DebugMsg is obsolete.
#ifdef DISALLOW_DebugMsg
#define DebugMsg Dont_use_DebugMsg___Use_TraceMsg
#else
#define DebugMsg _DebugMsg
#endif
#else // DEBUG
#define TraceMsgA 1 ? (void)0 : (void)
#define TraceMsgW 1 ? (void)0 : (void)
#define TraceMsg 1 ? (void)0 : (void)
#define DebugMsg 1 ? (void)0 : (void)
#endif // DEBUG
// THR(pfn)
// TBOOL(pfn)
// TINT(pfn)
// TPTR(pfn)
// TW32(pfn)
//
// These macros are useful to trace failed calls to functions that return
// HRESULTs, BOOLs, ints, or pointers. An example use of this is:
//
// {
// ...
// hres = THR(CoCreateInstance(CLSID_Bar, NULL, CLSCTX_INPROC_SERVER,
// IID_IBar, (LPVOID*)&pbar));
// if (SUCCEEDED(hres))
// ...
// }
//
// If CoCreateInstance failed, you would see spew similar to:
//
// err MODULE THR: Failure of "CoCreateInstance(CLSID_Bar, NULL, CLSCTX_INPROC_SERVER, IID_IBar, (LPVOID*)&pbar)" at foo.cpp, line 100 (0x80004005)
//
// THR keys off of the failure code of the hresult.
// TBOOL considers FALSE to be a failure case.
// TINT considers -1 to be a failure case.
// TPTR considers NULL to be a failure case.
// TW32 keys off the failure code of the Win32 error code.
//
// Set the BF_THR bit in g_dwBreakFlags to stop when these macros see a failure.
//
// Default Behavior-
// Retail builds: nothing
// Debug builds: nothing
// Full debug builds: spew on error
//
#ifdef DEBUG
EXTERN_C HRESULT TraceHR(HRESULT hrTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
EXTERN_C BOOL TraceBool(BOOL bTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
EXTERN_C int TraceInt(int iTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
EXTERN_C LPVOID TracePtr(LPVOID pvTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
EXTERN_C DWORD TraceWin32(DWORD dwTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
#define THR(x) (TraceHR((x), #x, __FILE__, __LINE__))
#define TBOOL(x) (TraceBool((x), #x, __FILE__, __LINE__))
#define TINT(x) (TraceInt((x), #x, __FILE__, __LINE__))
#define TPTR(x) (TracePtr((x), #x, __FILE__, __LINE__))
#define TW32(x) (TraceWin32((x), #x, __FILE__, __LINE__))
#else // DEBUG
#define THR(x) (x)
#define TBOOL(x) (x)
#define TINT(x) (x)
#define TPTR(x) (x)
#define TW32(x) (x)
#endif // DEBUG
// DBEXEC(flg, expr)
//
// under DEBUG, does "if (flg) expr;" (w/ the usual safe syntax)
// under !DEBUG, does nothing (and does not evaluate either of its args)
//
#ifdef DEBUG
#define DBEXEC(flg, expr) ((flg) ? (expr) : 0)
#else // DEBUG
#define DBEXEC(flg, expr) /*NOTHING*/
#endif // DEBUG
// string and buffer whacking functions
//
#ifdef DEBUG
EXTERN_C void DEBUGWhackPathBufferA(LPSTR psz, UINT cch);
EXTERN_C void DEBUGWhackPathBufferW(LPWSTR psz, UINT cch);
EXTERN_C void DEBUGWhackPathStringA(LPSTR psz, UINT cch);
EXTERN_C void DEBUGWhackPathStringW(LPWSTR psz, UINT cch);
#else // DEBUG
#define DEBUGWhackPathBufferA(psz, cch)
#define DEBUGWhackPathBufferW(psz, cch)
#define DEBUGWhackPathStringA(psz, cch)
#define DEBUGWhackPathStringW(psz, cch)
#endif // DEBUG
#ifdef UNICODE
#define DEBUGWhackPathBuffer DEBUGWhackPathBufferW
#define DEBUGWhackPathString DEBUGWhackPathStringW
#else
#define DEBUGWhackPathBuffer DEBUGWhackPathBufferA
#define DEBUGWhackPathString DEBUGWhackPathStringA
#endif
// Some trickery to map ATL debug macros to ours, so ATL code that stops
// or spews in our code will look like the rest of our squirties.
#ifdef DEBUG
#ifdef _ATL_NO_DEBUG_CRT
// ATL uses _ASSERTE. Map it to ours.
#define _ASSERTE(f) ASSERT(f)
// We map ATLTRACE macros to our functions
void _cdecl ShellAtlTraceA(LPCSTR lpszFormat, ...);
void _cdecl ShellAtlTraceW(LPCWSTR lpszFormat, ...);
#ifdef UNICODE
#define ShellAtlTrace ShellAtlTraceW
#else
#define ShellAtlTrace ShellAtlTraceA
#endif
// These are turned off because they normally don't give
// feedback of error cases and so many fire that they
// swamp out other useful debug spew.
//#define ATLTRACE ShellAtlTrace
#endif
#else // DEBUG
#ifdef _ATL_NO_DEBUG_CRT
// ATL uses _ASSERTE. Map it to ours.
#define _ASSERTE(f)
// We map ATLTRACE macros to our functions
#define ATLTRACE 1 ? (void)0 : (void)
#define ATLTRACE2 1 ? (void)0 : (void)
#endif
#endif // DEBUG
// ------ Stay away from these macros below ----------
// APPCOMPAT (scotth): remove these by 8/15/98. They should not be used anymore.
#ifdef DEBUG
#define AssertE(f) ASSERT(f)
#define AssertMsg _AssertMsg
#define AssertStrLen _AssertStrLen
#define AssertStrLenA _AssertStrLenA
#define AssertStrLenW _AssertStrLenW
#ifdef FULL_DEBUG
#define FullDebugMsg _DebugMsg
#else
#define FullDebugMsg 1 ? (void)0 : (void)
#endif
#define ASSERT_MSGW CcshellAssertMsgW
#define ASSERT_MSGA CcshellAssertMsgA
#define ASSERT_MSG CcshellAssertMsg
#else // DEBUG
#define AssertE(f) (f)
#define AssertMsg 1 ? (void)0 : (void)
#define AssertStrLen(lpStr, iLen)
#define FullDebugMsg 1 ? (void)0 : (void)
#define ASSERT_MSGA 1 ? (void)0 : (void)
#define ASSERT_MSGW 1 ? (void)0 : (void)
#define ASSERT_MSG 1 ? (void)0 : (void)
#endif // DEBUG
// ------ Stay away from these macros above ----------
// It's necessary to find when classes that were designed to be single threaded are used
// across threads so they can be fixed to be multithreaded. These asserts will point
// out such cases.
#ifdef DEBUG
#define ASSERT_SINGLE_THREADED AssertMsg(_dwThreadIDForSingleThreadedAssert == GetCurrentThreadId(), TEXT("MULTI-THREADED BUG: This class is being used by more than one thread, but it's not thread safe."))
#define INIT_SINGLE_THREADED_ASSERT _dwThreadIDForSingleThreadedAssert = GetCurrentThreadId();
#define SINGLE_THREADED_MEMBER_VARIABLE DWORD _dwThreadIDForSingleThreadedAssert;
#else // DEBUG
#define ASSERT_SINGLE_THREADED NULL;
#define INIT_SINGLE_THREADED_ASSERT NULL;
#define SINGLE_THREADED_MEMBER_VARIABLE
#endif // DEBUG
#ifdef DEBUG
#define Dbg_SafeStrA(psz) (SAFECAST(psz, LPCSTR), (psz) ? (psz) : "NULL string")
#define Dbg_SafeStrW(psz) (SAFECAST(psz, LPCWSTR), (psz) ? (psz) : L"NULL string")
#ifdef UNICODE
#define Dbg_SafeStr Dbg_SafeStrW
#else
#define Dbg_SafeStr Dbg_SafeStrA
#endif
#define FUNC_MSG CcshellFuncMsg
// Helpful macro for mapping manifest constants to strings. Assumes
// return string is pcsz. You can use this macro in this fashion:
//
// LPCSTR Dbg_GetFoo(FOO foo)
// {
// LPCTSTR pcsz = TEXT("Unknown <foo>");
// switch (foo)
// {
// STRING_CASE(FOOVALUE1);
// STRING_CASE(FOOVALUE2);
// ...
// }
// return pcsz;
// }
//
#define STRING_CASE(val) case val: pcsz = TEXT(#val); break
// Debug function enter
// DBG_ENTER(flag, fn) -- Generates a function entry debug spew for
// a function
//
#define DBG_ENTER(flagFTF, fn) \
(FUNC_MSG(flagFTF, " > " #fn "()"), \
CcshellStackEnter())
// DBG_ENTER_TYPE(flag, fn, dw, pfnStrFromType) -- Generates a function entry debug
// spew for functions that accept <type>.
//
#define DBG_ENTER_TYPE(flagFTF, fn, dw, pfnStrFromType) \
(FUNC_MSG(flagFTF, " < " #fn "(..., %s, ...)", (LPCTSTR)pfnStrFromType(dw)), \
CcshellStackEnter())
// DBG_ENTER_SZ(flag, fn, sz) -- Generates a function entry debug spew for
// a function that accepts a string as one of its
// parameters.
//
#define DBG_ENTER_SZ(flagFTF, fn, sz) \
(FUNC_MSG(flagFTF, " > " #fn "(..., \"%s\",...)", Dbg_SafeStr(sz)), \
CcshellStackEnter())
// Debug function exit
// DBG_EXIT(flag, fn) -- Generates a function exit debug spew
//
#define DBG_EXIT(flagFTF, fn) \
(CcshellStackLeave(), \
FUNC_MSG(flagFTF, " < " #fn "()"))
// DBG_EXIT_TYPE(flag, fn, dw, pfnStrFromType) -- Generates a function exit debug
// spew for functions that return <type>.
//
#define DBG_EXIT_TYPE(flagFTF, fn, dw, pfnStrFromType) \
(CcshellStackLeave(), \
FUNC_MSG(flagFTF, " < " #fn "() with %s", (LPCTSTR)pfnStrFromType(dw)))
// DBG_EXIT_INT(flag, fn, us) -- Generates a function exit debug spew for
// functions that return an INT.
//
#define DBG_EXIT_INT(flagFTF, fn, n) \
(CcshellStackLeave(), \
FUNC_MSG(flagFTF, " < " #fn "() with %d", (int)(n)))
// DBG_EXIT_BOOL(flag, fn, b) -- Generates a function exit debug spew for
// functions that return a boolean.
//
#define DBG_EXIT_BOOL(flagFTF, fn, b) \
(CcshellStackLeave(), \
FUNC_MSG(flagFTF, " < " #fn "() with %s", (b) ? (LPTSTR)TEXT("TRUE") : (LPTSTR)TEXT("FALSE")))
// DBG_EXIT_UL(flag, fn, ul) -- Generates a function exit debug spew for
// functions that return a ULONG.
//
#ifdef _WIN64
#define DBG_EXIT_UL(flagFTF, fn, ul) \
(CcshellStackLeave(), \
FUNC_MSG(flagFTF, " < " #fn "() with %#016I64x", (ULONG_PTR)(ul)))
#else
#define DBG_EXIT_UL(flagFTF, fn, ul) \
(CcshellStackLeave(), \
FUNC_MSG(flagFTF, " < " #fn "() with %#08lx", (ULONG)(ul)))
#endif // _WIN64
#define DBG_EXIT_DWORD DBG_EXIT_UL
// DBG_EXIT_HRES(flag, fn, hres) -- Generates a function exit debug spew for
// functions that return an HRESULT.
//
#define DBG_EXIT_HRES(flagFTF, fn, hres) DBG_EXIT_TYPE(flagFTF, fn, hres, Dbg_GetHRESULTName)
#else // DEBUG
#define Dbg_SafeStr 1 ? (void)0 : (void)
#define FUNC_MSG 1 ? (void)0 : (void)
#define DBG_ENTER(flagFTF, fn)
#define DBG_ENTER_TYPE(flagFTF, fn, dw, pfn)
#define DBG_ENTER_SZ(flagFTF, fn, sz)
#define DBG_EXIT(flagFTF, fn)
#define DBG_EXIT_INT(flagFTF, fn, n)
#define DBG_EXIT_BOOL(flagFTF, fn, b)
#define DBG_EXIT_UL(flagFTF, fn, ul)
#define DBG_EXIT_DWORD DBG_EXIT_UL
#define DBG_EXIT_TYPE(flagFTF, fn, dw, pfn)
#define DBG_EXIT_HRES(flagFTF, fn, hres)
#endif // DEBUG
// COMPILETIME_ASSERT(f)
//
// Generates a build break at compile time if the constant expression
// is not true. Unlike the "#if" compile-time directive, the expression
// in COMPILETIME_ASSERT() is allowed to use "sizeof".
//
// Compiler magic! If the expression "f" is FALSE, then you get the
// compiler error "Duplicate case expression in switch statement".
//
#define COMPILETIME_ASSERT(f) switch (0) case 0: case f:
#else // NOSHELLDEBUG
#ifdef UNIX
#include <crtdbg.h>
#define ASSERT(f) _ASSERT(f)
#include <mainwin.h>
#define TraceMsg(type, sformat) DebugMessage(0, sformat)
#define TraceMSG(type, sformat, args) DebugMessage(0, sformat, args)
#endif
#endif // NOSHELLDEBUG
//
// Debug dump helper functions
//
#ifdef DEBUG
LPCTSTR Dbg_GetCFName(UINT ucf);
LPCTSTR Dbg_GetHRESULTName(HRESULT hr);
LPCTSTR Dbg_GetREFIIDName(REFIID riid);
LPCTSTR Dbg_GetVTName(VARTYPE vt);
#else
#define Dbg_GetCFName(ucf) (void)0
#define Dbg_GetHRESULTName(hr) (void)0
#define Dbg_GetREFIIDName(riid) (void)0
#define Dbg_GetVTName(vt) (void)0
#endif // DEBUG
// I'm a lazy typist...
#define Dbg_GetHRESULT Dbg_GetHRESULTName
// Parameter validation macros
#include "validate.h"
#endif // DECLARE_DEBUG
#ifdef PRODUCT_PROF
int __stdcall StartCAP(void); // start profiling
int __stdcall StopCAP(void); // stop profiling until StartCAP
int __stdcall SuspendCAP(void); // suspend profiling until ResumeCAP
int __stdcall ResumeCAP(void); // resume profiling
int __stdcall StartCAPAll(void); // process-wide start profiling
int __stdcall StopCAPAll(void); // process-wide stop profiling
int __stdcall SuspendCAPAll(void); // process-wide suspend profiling
int __stdcall ResumeCAPAll(void); // process-wide resume profiling
void __stdcall MarkCAP(long lMark); // write mark to MEA
extern DWORD g_dwProfileCAP;
#else
#define StartCAP() 0
#define StopCAP() 0
#define SuspendCAP() 0
#define ResumeCAP() 0
#define StartCAPAll() 0
#define StopCAPAll() 0
#define SuspendCAPAll() 0
#define ResumeCAPAll() 0
#define MarkCAP(n) 0
#define g_dwProfileCAP 0
#endif
#ifdef __cplusplus
};
#endif