//====== 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
