//====== Assertion/Debug output APIs ================================= #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. // // #ifndef DATASEG_READONLY #define DATASEG_READONLY ".text" // read only data, same as one generated by linker #endif #pragma data_seg(DATASEG_READONLY) TCHAR const FAR c_szCcshellIniFile[] = SZ_DEBUGINI; TCHAR const FAR c_szCcshellIniSecDebug[] = SZ_DEBUGSECTION; #ifdef UNICODE WCHAR const FAR c_wszTrace[] = TEXT("t ") TEXT(SZ_MODULE) TEXT(" "); #else WCHAR const FAR c_wszTrace[] = L""; #endif // UNICODE // (This is deliberately CHAR) CHAR const FAR c_szTrace[] = "t " SZ_MODULE " "; TCHAR const FAR c_szAssertFailed[] = TEXT(SZ_MODULE) TEXT(" Assert %s, line %d\r\n"); #pragma data_seg() #endif // DECLARE_DEBUG && DEBUG #ifdef __cplusplus extern "C" { #endif #if !defined(DECLARE_DEBUG) // // Debug macros and validation code // #undef Assert #undef AssertE #undef AssertMsg #undef DebugMsg #undef FullDebugMsg #undef ASSERT #undef EVAL extern DWORD g_dwDumpFlags; extern DWORD g_dwBreakFlags; extern DWORD g_dwTraceFlags; extern DWORD g_dwPrototype; extern DWORD g_dwFuncTraceFlags; // (There are no reserved bits for g_dwPrototype. It is for use // by the component.) // Break flags #define BF_ONVALIDATE 0x00000001 // Break on assertions or validation #define BF_ONOPEN 0x00000002 #define BF_ONCLOSE 0x00000004 #define BF_ONRUNONCE 0x00000008 #define BF_ONTHREADATT 0x00000010 #define BF_ONTHREADDET 0x00000020 #define BF_ONPROCESSATT 0x00000040 #define BF_ONPROCESSDET 0x00000080 #define BF_ONAPIENTER 0x00000100 // Break on entering an API // Trace flags #define TF_ALWAYS 0xFFFFFFFF #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 // (Upper 28 bits reserved for custom use per-module) // Function trace flags (FTF_) are per-component // Debug mask APIs // BUGBUG (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 // NOTE: Default debug mask is 0x00ff (show everything) // // Inside debugger, you can modify wDebugMask variable. // // Set debug mask; returning previous. // UINT WINAPI SetDebugMask(UINT mask); // Get debug mask. // UINT WINAPI GetDebugMask(); #ifndef WIN32 #if (defined(BUILDDLL) && !defined(ASSERTSEG)) #define ASSERTSEG _based(_segname("_ERRTEXT")) #endif #ifndef ASSERTSEG #define ASSERTSEG _based(_segname("_CODE")) #endif #else #define ASSERTSEG #endif // 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 ASSERTSEG sz[] = msg; #ifndef NOSHELLDEBUG // Others have own versions of these. #ifdef DEBUG // Assert(f) -- Generate "assertion failed in line x of file.c" // message if f is NOT true. // // AssertMsg(f, msg, args...) -- Generate wsprintf-formatted msg w/params // if f is NOT true. // // DebugMsg(mask, msg, args...) - // Generate wsprintf-formatted msg using // specified debug mask. System debug mask // governs whether message is output. // void CcshellAssertFailed(LPCTSTR szFile, int line); #define Assert(f) \ { \ DEBUGTEXT(szFile, TEXT(__FILE__)); \ if (!(f)) \ CcshellAssertFailed(szFile, __LINE__); \ } #define AssertE(f) Assert(f) #define ASSERT(f) Assert(f) void __cdecl _AssertMsg(BOOL f, LPCTSTR pszMsg, ...); #define AssertMsg _AssertMsg void __cdecl _DebugMsg(DWORD flag, LPCTSTR psz, ...); #define DebugMsg _DebugMsg #ifdef FULL_DEBUG #define FullDebugMsg _DebugMsg #else #define FullDebugMsg 1 ? (void)0 : (void) #endif /* * EVAL() may only be used as a logical expression. * * E.g., * * if (EVAL(exp)) * bResult = TRUE; */ #define EVAL(exp) ((exp) || (TraceMsg(TF_ERROR, "evaluation failed '%s'", (LPCTSTR)#exp), 0)) #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 void CcshellStackEnter(void); void CcshellStackLeave(void); void CDECL CcshellDebugMsgW( DWORD mask, LPCSTR pszMsg, ...); void CDECL CcshellDebugMsgA( DWORD mask, LPCSTR pszMsg, ...); #ifdef UNICODE #define CcshellDebugMsg CcshellDebugMsgW #else #define CcshellDebugMsg CcshellDebugMsgA #endif // UNICODE void CDECL CcshellFuncMsgW( DWORD mask, LPCSTR pszMsg, ...); void CDECL CcshellFuncMsgA( DWORD mask, LPCSTR pszMsg, ...); #ifdef UNICODE #define CcshellFuncMsg CcshellFuncMsgW #else #define CcshellFuncMsg CcshellFuncMsgA #endif // UNICODE void CDECL CcshellAssertMsgW( BOOL bAssert, LPCSTR pszMsg, ...); void CDECL CcshellAssertMsgA( BOOL bAssert, LPCSTR pszMsg, ...); #ifdef UNICODE #define CcshellAssertMsg CcshellAssertMsgW #else #define CcshellAssertMsg CcshellAssertMsgA #endif // UNICODE // ASSERT_MSG(bAssert, msg, args...) - Generate wsprintf-formatted msg // if the assertion is false. System trace mask // governs whether message is output, and // whether the function DebugBreaks. // #define ASSERT_MSGW CcshellAssertMsgW #define ASSERT_MSGA CcshellAssertMsgA #define ASSERT_MSG CcshellAssertMsg // TraceMsg(mask, msg, args...) - Generate wsprintf-formatted msg using // specified trace mask. System trace mask // governs whether message is output. // // (The difference b/t TraceMsg and DebugMsg is only one thing: // TraceMsg does not require you to wrap msg with TEXT() for // the unicode platform. It is always LPSTR, and properly // converts.) #define TRACE_MSGW CcshellDebugMsgW #define TRACE_MSGA CcshellDebugMsgA #define TRACE_MSG CcshellDebugMsg #define TraceMsgW TRACE_MSGW #define TraceMsgA TRACE_MSGA #define TraceMsg TRACE_MSG #define FUNC_MSG CcshellFuncMsg // 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 . // #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 . // #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. // #define DBG_EXIT_UL(flagFTF, fn, ul) \ (CcshellStackLeave(), \ FUNC_MSG(flagFTF, " < " #fn "() with %#08lx", (ULONG)(ul))) #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 Assert(f) #define AssertE(f) (f) #define ASSERT(f) #define AssertMsg 1 ? (void)0 : (void) #define DebugMsg 1 ? (void)0 : (void) #define FullDebugMsg 1 ? (void)0 : (void) #define EVAL(exp) ((exp) != 0) #define Dbg_SafeStr 1 ? (void)0 : (void) #define TRACE_MSGA 1 ? (void)0 : (void) #define TRACE_MSGW 1 ? (void)0 : (void) #ifdef UNICODE #define TRACE_MSG TRACE_MSGW #else #define TRACE_MSG TRACE_MSGA #endif #define TraceMsgW TRACE_MSGW #define TraceMsgA TRACE_MSGA #define TraceMsg TRACE_MSG #define FUNC_MSG 1 ? (void)0 : (void) #define ASSERT_MSGA TRACE_MSGA #define ASSERT_MSGW TRACE_MSGW #define ASSERT_MSG TRACE_MSG #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 /* parameter validation macros */ /* * call as: * * bOK = IS_VALID_READ_PTR(pfoo, CFOO); * * bOK = IS_VALID_HANDLE(hfoo, FOO); */ #ifdef DEBUG #define IS_VALID_READ_PTR(ptr, type) \ (IsBadReadPtr((ptr), sizeof(type)) ? \ (ASSERT_MSG(FALSE, "invalid %s read pointer - %#08lx", (LPCTSTR)"P"#type, (ptr)), FALSE) : \ TRUE) #define IS_VALID_WRITE_PTR(ptr, type) \ (IsBadWritePtr((PVOID)(ptr), sizeof(type)) ? \ (ASSERT_MSG(FALSE, "invalid %s write pointer - %#08lx", (LPCTSTR)"P"#type, (ptr)), FALSE) : \ TRUE) #define IS_VALID_STRING_PTRA(ptr, type) \ (IsBadStringPtrA((ptr), (UINT)-1) ? \ (ASSERT_MSG(FALSE, "invalid %s pointer - %#08lx", (LPCTSTR)"P"#type, (ptr)), FALSE) : \ TRUE) #define IS_VALID_STRING_PTRW(ptr, type) \ (IsBadStringPtrW((ptr), (UINT)-1) ? \ (ASSERT_MSG(FALSE, "invalid %s pointer - %#08lx", (LPCTSTR)"P"#type, (ptr)), FALSE) : \ TRUE) #define IS_VALID_CODE_PTR(ptr, type) \ (IsBadCodePtr((FARPROC)(ptr)) ? \ (ASSERT_MSG(FALSE, "invalid %s code pointer - %#08lx", (LPCTSTR)#type, (ptr)), FALSE) : \ TRUE) #define IS_VALID_READ_BUFFER_PTR(ptr, type, len) \ (IsBadReadPtr((ptr), len) ? \ (ASSERT_MSG(FALSE, "invalid %s read pointer - %#08lx", (LPCTSTR)"P"#type, (ptr)), FALSE) : \ TRUE) #define IS_VALID_WRITE_BUFFER_PTR(ptr, type, len) \ (IsBadWritePtr((ptr), len) ? \ (ASSERT_MSG(FALSE, "invalid %s write pointer - %#08lx", (LPCTSTR)"P"#type, (ptr)), FALSE) : \ TRUE) #define FLAGS_ARE_VALID(dwFlags, dwAllFlags) \ (((dwFlags) & (~(dwAllFlags))) ? \ (ASSERT_MSG(FALSE, "invalid flags set - %#08lx", ((dwFlags) & (~(dwAllFlags)))), FALSE) : \ TRUE) #else #define IS_VALID_READ_PTR(ptr, type) \ (! IsBadReadPtr((ptr), sizeof(type))) #define IS_VALID_WRITE_PTR(ptr, type) \ (! IsBadWritePtr((PVOID)(ptr), sizeof(type))) #define IS_VALID_STRING_PTRA(ptr, type) \ (! IsBadStringPtrA((ptr), (UINT)-1)) #define IS_VALID_STRING_PTRW(ptr, type) \ (! IsBadStringPtrW((ptr), (UINT)-1)) #define IS_VALID_CODE_PTR(ptr, type) \ (! IsBadCodePtr((FARPROC)(ptr))) #define IS_VALID_READ_BUFFER_PTR(ptr, type, len) \ (! IsBadReadPtr((ptr), len)) #define IS_VALID_WRITE_BUFFER_PTR(ptr, type, len) \ (! IsBadWritePtr((ptr), len)) #define FLAGS_ARE_VALID(dwFlags, dwAllFlags) \ (((dwFlags) & (~(dwAllFlags))) ? FALSE : TRUE) #endif #ifdef UNICODE #define IS_VALID_STRING_PTR IS_VALID_STRING_PTRW #else #define IS_VALID_STRING_PTR IS_VALID_STRING_PTRA #endif /* handle validation macros */ #ifdef DEBUG #define IS_VALID_HANDLE(hnd, type) \ (IsValidH##type(hnd) ? \ TRUE : \ (ASSERT_MSG(FALSE, "invalid H" #type " - %#08lx", (hnd)), FALSE)) #else #define IS_VALID_HANDLE(hnd, type) \ (IsValidH##type(hnd)) #endif /* structure validation macros */ // Define VSTF if you want to validate the fields in structures. This // requires a handler function (of the form IsValid*()) that knows how // to validate the specific structure type. #ifdef VSTF #ifdef DEBUG #define IS_VALID_STRUCT_PTR(ptr, type) \ (IsValidP##type(ptr) ? \ TRUE : \ (ASSERT_MSG(FALSE, "invalid %s pointer - %#08lx", (LPCTSTR)"P"#type, (ptr)), FALSE)) #else #define IS_VALID_STRUCT_PTR(ptr, type) \ (IsValidP##type(ptr)) #endif #else #define IS_VALID_STRUCT_PTR(ptr, type) \ (! IsBadReadPtr((ptr), sizeof(type))) #endif /* OLE interface validation macro */ #define IS_VALID_INTERFACE_PTR(ptr, iface) \ IS_VALID_STRUCT_PTR(ptr, ##iface) #endif // NOSHELLDEBUG #ifdef DEBUG BOOL CcshellGetDebugFlags(void); #if !defined(NO_SHELL_VALIDATION) BOOL IsValidPath( LPCTSTR pcszPath); BOOL IsValidPathResult( HRESULT hr, LPCTSTR pcszPath, UINT cchPathBufLen); BOOL IsValidExtension( LPCTSTR pcszExt); BOOL IsValidIconIndex( HRESULT hr, LPCTSTR pcszIconFile, UINT cchIconFileBufLen, int niIcon); BOOL IsValidHANDLE( HANDLE hnd); #define IsValidHEVENT IsValidHANDLE #define IsValidHGLOBAL IsValidHANDLE #define IsValidHFILE IsValidHANDLE #define IsValidHMENU IsValidHANDLE #define IsValidHINSTANCE IsValidHANDLE #define IsValidHICON IsValidHANDLE #define IsValidHKEY IsValidHANDLE #define IsValidHMODULE IsValidHANDLE #define IsValidHPROCESS IsValidHANDLE BOOL IsValidHWND( HWND hwnd); BOOL IsValidShowCmd( int nShow); BOOL IsFullPath( LPCTSTR pcszPath); #endif // NO_SHELL_VALIDATION #endif // DEBUG #endif // DECLARE_DEBUG #ifdef __cplusplus }; #endif