Leaked source code of windows server 2003
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.

882 lines
30 KiB

  1. //====== Assertion/Debug output APIs =================================
  2. #include <platform.h> // for __endexcept
  3. #if defined(DECLARE_DEBUG) && defined(DEBUG)
  4. //
  5. // Declare module-specific debug strings
  6. //
  7. // When including this header in your private header file, do not
  8. // define DECLARE_DEBUG. But do define DECLARE_DEBUG in one of the
  9. // source files in your project, and then include this header file.
  10. //
  11. // You may also define the following:
  12. //
  13. // SZ_DEBUGINI - the .ini file used to set debug flags
  14. // SZ_DEBUGSECTION - the section in the .ini file specific to
  15. // the module component.
  16. // SZ_MODULE - ansi version of the name of your module.
  17. //
  18. //
  19. // (These are deliberately CHAR)
  20. EXTERN_C const CHAR FAR c_szCcshellIniFile[] = SZ_DEBUGINI;
  21. EXTERN_C const CHAR FAR c_szCcshellIniSecDebug[] = SZ_DEBUGSECTION;
  22. #if 0
  23. EXTERN_C const WCHAR FAR c_wszTrace[] = L"trc " TEXTW(SZ_MODULE) L" ";
  24. EXTERN_C const WCHAR FAR c_wszErrorDbg[] = L"err " TEXTW(SZ_MODULE) L" ";
  25. EXTERN_C const WCHAR FAR c_wszWarningDbg[] = L"wrn " TEXTW(SZ_MODULE) L" ";
  26. EXTERN_C const WCHAR FAR c_wszGeneralDbg[] = L"gen " TEXTW(SZ_MODULE) L" ";
  27. EXTERN_C const WCHAR FAR c_wszFuncDbg[] = L"fnc " TEXTW(SZ_MODULE) L" ";
  28. EXTERN_C const WCHAR FAR c_wszMemLeakDbg[] = L"mem " TEXTW(SZ_MODULE) L" ";
  29. #else
  30. EXTERN_C const WCHAR FAR c_wszTrace[] = TEXTW(SZ_MODULE) L"-[Trc] ";
  31. EXTERN_C const WCHAR FAR c_wszErrorDbg[] = TEXTW(SZ_MODULE) L"-[Err] ";
  32. EXTERN_C const WCHAR FAR c_wszWarningDbg[] = TEXTW(SZ_MODULE) L"-[Wrn] ";
  33. EXTERN_C const WCHAR FAR c_wszGeneralDbg[] = TEXTW(SZ_MODULE) L"-[Gen] ";
  34. EXTERN_C const WCHAR FAR c_wszFuncDbg[] = TEXTW(SZ_MODULE) L"-[Fnc] ";
  35. EXTERN_C const WCHAR FAR c_wszMemLeakDbg[] = TEXTW(SZ_MODULE) L"-[Mem] ";
  36. #endif
  37. EXTERN_C const WCHAR FAR c_wszAssertMsg[] = TEXTW(SZ_MODULE) L" Assert: ";
  38. EXTERN_C const WCHAR FAR c_wszAssertFailed[] = TEXTW(SZ_MODULE) L" Assert %ls, line %d: (%ls)\r\n";
  39. EXTERN_C const WCHAR FAR c_wszRip[] = TEXTW(SZ_MODULE) L" RIP in %s at %s, line %d: (%s)\r\n";
  40. EXTERN_C const WCHAR FAR c_wszRipNoFn[] = TEXTW(SZ_MODULE) L" RIP at %s, line %d: (%s)\r\n";
  41. // (These are deliberately CHAR)
  42. #if 0
  43. EXTERN_C const CHAR FAR c_szTrace[] = "trc " SZ_MODULE " ";
  44. EXTERN_C const CHAR FAR c_szErrorDbg[] = "err " SZ_MODULE " ";
  45. EXTERN_C const CHAR FAR c_szWarningDbg[] = "wrn " SZ_MODULE " ";
  46. EXTERN_C const CHAR FAR c_szGeneralDbg[] = "gen " SZ_MODULE " ";
  47. EXTERN_C const CHAR FAR c_szFuncDbg[] = "fnc " SZ_MODULE " ";
  48. EXTERN_C const CHAR FAR c_szMemLeakDbg[] = "mem " SZ_MODULE " ";
  49. #else
  50. EXTERN_C const CHAR FAR c_szTrace[] = SZ_MODULE "-[Trc] ";
  51. EXTERN_C const CHAR FAR c_szErrorDbg[] = SZ_MODULE "-[Err] ";
  52. EXTERN_C const CHAR FAR c_szWarningDbg[] = SZ_MODULE "-[Wrn] ";
  53. EXTERN_C const CHAR FAR c_szGeneralDbg[] = SZ_MODULE "-[Gen] ";
  54. EXTERN_C const CHAR FAR c_szFuncDbg[] = SZ_MODULE "-[Fnc] ";
  55. EXTERN_C const CHAR FAR c_szMemLeakDbg[] = SZ_MODULE "-[Mem] ";
  56. #endif
  57. EXTERN_C const CHAR FAR c_szAssertMsg[] = SZ_MODULE " Assert: ";
  58. EXTERN_C const CHAR FAR c_szAssertFailed[] = SZ_MODULE " Assert %s, line %d: (%s)\r\n";
  59. EXTERN_C const CHAR FAR c_szRip[] = SZ_MODULE " RIP in %s at %s, line %d: (%s)\r\n";
  60. EXTERN_C const CHAR FAR c_szRipNoFn[] = SZ_MODULE " RIP at %s, line %d: (%s)\r\n";
  61. #endif // DECLARE_DEBUG && DEBUG
  62. #if defined(DECLARE_DEBUG) && defined(PRODUCT_PROF)
  63. EXTERN_C const CHAR FAR c_szCcshellIniFile[] = SZ_DEBUGINI;
  64. EXTERN_C const CHAR FAR c_szCcshellIniSecDebug[] = SZ_DEBUGSECTION;
  65. #endif
  66. #ifdef __cplusplus
  67. extern "C" {
  68. #endif
  69. #if !defined(DECLARE_DEBUG)
  70. //
  71. // Debug macros and validation code
  72. //
  73. // Undefine the macros that we define in case some other header
  74. // might have tried defining these commonly-named macros.
  75. #undef Assert
  76. #undef AssertE
  77. #undef AssertMsg
  78. #undef AssertStrLen
  79. #undef DebugMsg
  80. #undef FullDebugMsg
  81. #undef ASSERT
  82. #undef EVAL
  83. #undef ASSERTMSG // catch people's typos
  84. #undef DBEXEC
  85. #ifdef _ATL_NO_DEBUG_CRT
  86. #undef _ASSERTE // we substitute this ATL macro
  87. #endif
  88. // Access these globals to determine which debug flags are set.
  89. // These globals are modified by CcshellGetDebugFlags(), which
  90. // reads an .ini file and sets the appropriate flags.
  91. //
  92. // g_dwDumpFlags - bits are application specific. Typically
  93. // used for dumping structures.
  94. // g_dwBreakFlags - uses BF_* flags. The remaining bits are
  95. // application specific. Used to determine
  96. // when to break into the debugger.
  97. // g_dwTraceFlags - uses TF_* flags. The remaining bits are
  98. // application specific. Used to display
  99. // debug trace messages.
  100. // g_dwFuncTraceFlags - bits are application specific. When
  101. // TF_FUNC is set, CcshellFuncMsg uses this
  102. // value to determine which function traces
  103. // to display.
  104. // g_dwProtoype - bits are application specific. Use it for
  105. // anything.
  106. // g_dwProfileCAP - bits are application specific. Used to
  107. // control ICECAP profiling.
  108. //
  109. extern DWORD g_dwDumpFlags;
  110. extern DWORD g_dwBreakFlags;
  111. extern DWORD g_dwTraceFlags;
  112. #ifdef DEBUG
  113. extern DWORD g_dwPrototype;
  114. #else
  115. #define g_dwPrototype 0
  116. #endif
  117. extern DWORD g_dwFuncTraceFlags;
  118. #if defined(DEBUG) || defined(PRODUCT_PROF)
  119. BOOL CcshellGetDebugFlags(void);
  120. #else
  121. #define CcshellGetDebugFlags() 0
  122. #endif
  123. // Break flags for g_dwBreakFlags
  124. #define BF_ASSERT 0x00000001 // Break on assertions
  125. #define BF_ONAPIENTER 0x00000002 // Break on entering an API
  126. #define BF_ONERRORMSG 0x00000004 // Break on TF_ERROR
  127. #define BF_ONWARNMSG 0x00000008 // Break on TF_WARNING
  128. #define BF_THR 0x00000100 // Break when THR() receives a failure
  129. #define BF_RIP 0x00000200 // Break on RIPs
  130. #define BF_ASSERTPOPUP 0x00000400 // Break on RIPs
  131. // Trace flags for g_dwTraceFlags
  132. #define TF_ALWAYS 0xFFFFFFFF
  133. #define TF_NEVER 0x00000000
  134. #define TF_WARNING 0x00000001
  135. #define TF_ERROR 0x00000002
  136. #define TF_GENERAL 0x00000004 // Standard messages
  137. #define TF_FUNC 0x00000008 // Trace function calls
  138. #define TF_ATL 0x00000008 // Since TF_FUNC is so-little used, I'm overloading this bit
  139. #define TF_EVENT 0x00000010
  140. #define TF_MEMORY_LEAK 0x00000020
  141. // (Upper 28 bits reserved for custom use per-module)
  142. // Old, archaic debug flags.
  143. // Issue (scotth): the following flags will be phased out over time.
  144. #ifdef DM_TRACE
  145. #undef DM_TRACE
  146. #undef DM_WARNING
  147. #undef DM_ERROR
  148. #endif
  149. #define DM_TRACE TF_GENERAL // OBSOLETE Trace messages
  150. #define DM_WARNING TF_WARNING // OBSOLETE Warning
  151. #define DM_ERROR TF_ERROR // OBSOLETE Error
  152. // Use this macro to declare message text that will be placed
  153. // in the CODE segment (useful if DS is getting full)
  154. //
  155. // Ex: DEBUGTEXT(szMsg, "Invalid whatever: %d");
  156. //
  157. #define DEBUGTEXT(sz, msg) /* ;Internal */ \
  158. static const TCHAR sz[] = msg
  159. #ifndef NOSHELLDEBUG // Others have own versions of these.
  160. #ifdef DEBUG
  161. #ifdef _X86_
  162. // Use int 3 so we stop immediately in the source
  163. #define DEBUG_BREAK do { _try { _asm int 3 } _except (EXCEPTION_EXECUTE_HANDLER) {;} } while (0)
  164. #else
  165. #define DEBUG_BREAK do { _try { DebugBreak(); } _except (EXCEPTION_EXECUTE_HANDLER) {;} __endexcept } while (0)
  166. #endif
  167. BOOL AttachDebugger(DWORD pid);
  168. // Prototypes for debug functions
  169. void CcshellStackEnter(void);
  170. void CcshellStackLeave(void);
  171. void CDECL CcshellFuncMsgW(DWORD mask, LPCSTR pszMsg, ...);
  172. void CDECL CcshellFuncMsgA(DWORD mask, LPCSTR pszMsg, ...);
  173. void CDECL _AssertMsgA(BOOL f, LPCSTR pszMsg, ...);
  174. void CDECL _AssertMsgW(BOOL f, LPCWSTR pszMsg, ...);
  175. void _AssertStrLenA(LPCSTR pszStr, int iLen);
  176. void _AssertStrLenW(LPCWSTR pwzStr, int iLen);
  177. #ifdef UNICODE
  178. #define CcshellFuncMsg CcshellFuncMsgW
  179. #define CcshellAssertMsg CcshellAssertMsgW
  180. #define _AssertMsg _AssertMsgW
  181. #define _AssertStrLen _AssertStrLenW
  182. #else
  183. #define CcshellFuncMsg CcshellFuncMsgA
  184. #define CcshellAssertMsg CcshellAssertMsgA
  185. #define _AssertMsg _AssertMsgA
  186. #define _AssertStrLen _AssertStrLenA
  187. #endif
  188. #endif // DEBUG
  189. // ASSERT(f)
  190. //
  191. // Generates a "Assert file.c, line x (eval)" message if f is NOT true.
  192. //
  193. // Use ASSERT() to check for logic invariance. These are typically considered
  194. // fatal problems, and falls into the 'this should never ever happen'
  195. // category.
  196. //
  197. // Do *not* use ASSERT() to verify successful API calls if the APIs can
  198. // legitimately fail due to low resources. For example, LocalAlloc can
  199. // legally fail, so you shouldn't assert that it will never fail.
  200. //
  201. // The BF_ASSERT bit in g_dwBreakFlags governs whether the function
  202. // performs a DebugBreak().
  203. //
  204. // Default Behavior-
  205. // Retail builds: nothing
  206. // Debug builds: spew and break
  207. // Full debug builds: spew and break
  208. //
  209. #ifdef DEBUG
  210. BOOL CcshellAssertFailedA(LPCSTR szFile, int line, LPCSTR pszEval, BOOL bBreakInside, BOOL bAssertPopup);
  211. BOOL CcshellAssertFailedW(LPCWSTR szFile, int line, LPCWSTR pwszEval, BOOL bBreakInside, BOOL bAssertPopup);
  212. #ifdef UNICODE
  213. #define CcshellAssertFailed CcshellAssertFailedW
  214. #else
  215. #define CcshellAssertFailed CcshellAssertFailedA
  216. #endif
  217. #define ASSERT(f) \
  218. { \
  219. DEBUGTEXT(szFile, TEXT(__FILE__)); \
  220. if (!(f) && CcshellAssertFailed(szFile, __LINE__, TEXT(#f), FALSE, TRUE)) \
  221. DEBUG_BREAK; \
  222. }
  223. #define ASSERTPRIVATE(f) \
  224. { \
  225. DEBUGTEXT(szFile, TEXT(__FILE__)); \
  226. if (!(f) && CcshellAssertFailed(szFile, __LINE__, TEXT(#f), FALSE, FALSE)) \
  227. DEBUG_BREAK; \
  228. }
  229. // The old Win95 code used to use "Assert()". We discourage the use
  230. // of this macro now because it is not msdev-friendly.
  231. #ifdef DISALLOW_Assert
  232. #define Assert(f) Dont_use_Assert___Use_ASSERT
  233. #define AssertPrivate(f) Dont_use_AssertPrivate___Use_ASSERT
  234. #else
  235. #define Assert(f) ASSERT(f)
  236. #define AssertPrivate(f) ASSERTPRIVATE(f)
  237. #endif
  238. #else // DEBUG
  239. #define ASSERT(f)
  240. #define ASSERTPRIVATE(f)
  241. #define Assert(f)
  242. #define AssertPrivate(f)
  243. #endif // DEBUG
  244. // ASSERTMSG(f, szFmt, args...)
  245. //
  246. // Behaves like ASSERT, except it prints the wsprintf-formatted message
  247. // instead of the file and line number.
  248. //
  249. // The sz parameter is always ANSI; AssertMsg correctly converts it
  250. // to unicode if necessary. This is so you don't have to wrap your
  251. // debug strings with TEXT().
  252. //
  253. // The BF_ASSERT bit in g_dwBreakFlags governs whether the function
  254. // performs a DebugBreak().
  255. //
  256. // Default Behavior-
  257. // Retail builds: nothing
  258. // Debug builds: spew and break
  259. // Full debug builds: spew and break
  260. //
  261. #ifdef DEBUG
  262. void CDECL CcshellAssertMsgW(BOOL bAssert, LPCSTR pszMsg, ...);
  263. void CDECL CcshellAssertMsgA(BOOL bAssert, LPCSTR pszMsg, ...);
  264. #ifdef UNICODE
  265. #define CcshellAssertMsg CcshellAssertMsgW
  266. #else
  267. #define CcshellAssertMsg CcshellAssertMsgA
  268. #endif
  269. #define ASSERTMSG CcshellAssertMsg
  270. #else // DEBUG
  271. #define ASSERTMSG 1 ? (void)0 : (void)
  272. #endif // DEBUG
  273. // EVAL(f)
  274. //
  275. // Behaves like ASSERT(). Evaluates the expression (f). The expression
  276. // is always evaluated, even in retail builds. But the macro only asserts
  277. // in the debug build. This macro may be used on logical expressions, eg:
  278. //
  279. // if (EVAL(exp))
  280. // // do something
  281. //
  282. // Do *not* use EVAL() to verify successful API calls if the APIs can
  283. // legitimately fail due to low resources. For example, LocalAlloc can
  284. // legally fail, so you shouldn't assert that it will never fail.
  285. //
  286. // The BF_ASSERT bit in g_dwBreakFlags governs whether the function
  287. // performs a DebugBreak().
  288. //
  289. // Default Behavior-
  290. // Retail builds: nothing
  291. // Debug builds: spew and break
  292. // Full debug builds: spew and break
  293. //
  294. #ifdef DEBUG
  295. #define EVAL(exp) \
  296. ((exp) || (CcshellAssertFailed(TEXT(__FILE__), __LINE__, TEXT(#exp), TRUE, FALSE), 0))
  297. #else // DEBUG
  298. #define EVAL(exp) ((exp) != 0)
  299. #endif // DEBUG
  300. // RIP(f)
  301. //
  302. // Generates a "RIP at file.c, line x (eval)" message if f is NOT true.
  303. //
  304. // Use RIP() to perform parameter validation, especially when you
  305. // know the function or method may be called by a 3rd party app.
  306. // Typically, RIPs are used to indicate the caller passed in an invalid
  307. // parameter, so the problem is really not in the code itself.
  308. //
  309. // Do *not* use RIP() to verify successful API calls if the APIs can
  310. // legitimately fail due to low resources. For example, LocalAlloc can
  311. // legally fail, so you shouldn't assert that it will never fail.
  312. //
  313. // RIP performs a debugbreak only in the following processes:
  314. //
  315. // explore.exe
  316. // iexplore.exe
  317. // rundll32.exe
  318. // welcome.exe
  319. //
  320. // In any other process, this just spews the debug message, but doesn't stop.
  321. //
  322. // Setting the BF_RIP bit in g_dwBreakFlags will cause the macro to perform
  323. // a DebugBreak() even in non-shell processes.
  324. //
  325. // Default Behavior-
  326. // Retail builds: nothing
  327. // Debug builds: spew (other processes), spew and break (shell processes)
  328. // Full debug builds: spew (other processes), spew and break (shell processes)
  329. //
  330. #ifdef DEBUG
  331. BOOL CcshellRipA(LPCSTR pszFile, int line, LPCSTR pszEval, BOOL bBreakInside);
  332. BOOL CcshellRipW(LPCWSTR pszFile, int line, LPCWSTR pwszEval, BOOL bBreakInside);
  333. #ifdef UNICODE
  334. #define CcshellRip CcshellRipW
  335. #else
  336. #define CcshellRip CcshellRipA
  337. #endif
  338. #define RIP(f) \
  339. { \
  340. DEBUGTEXT(szFile, TEXT(__FILE__)); \
  341. if (!(f) && CcshellRip(szFile, __LINE__, TEXT(#f), FALSE)) \
  342. { \
  343. DEBUG_BREAK; \
  344. } \
  345. } \
  346. #define RIPMSG(f, msg) \
  347. { \
  348. DEBUGTEXT(szFile, TEXT(__FILE__)); \
  349. if (!(f) && CcshellRip(szFile, __LINE__, TEXT(#msg), FALSE)) \
  350. { \
  351. DEBUG_BREAK; \
  352. } \
  353. } \
  354. #else // DEBUG
  355. #define RIP(f)
  356. #define RIPMSG(f, msg)
  357. #endif // DEBUG
  358. // TraceMsg(dwMask, sz, args...)
  359. //
  360. // Generate wsprintf-formatted message using the specified trace dwMask.
  361. // dwMask may be one of the predefined bits:
  362. //
  363. // TF_ERROR - display "err <MODULE> <string>"
  364. // TF_WARNING - display "wn <MODULE> <string>"
  365. // TF_GENERAL - display "t <MODULE> <string>"
  366. // TF_ALWAYS - display "t <MODULE> <string>" regardless of g_dwTraceFlags.
  367. //
  368. // or it may be a custom bit (any of the upper 28 bits).
  369. //
  370. // The g_dwTraceFlags global governs whether the message is displayed (based
  371. // upon the dwMask parameter).
  372. //
  373. // The sz parameter is always ANSI; TraceMsg correctly converts it
  374. // to unicode if necessary. This is so you don't have to wrap your
  375. // debug strings with TEXT().
  376. //
  377. // In addition to squirting the trace message, you may optionally cause
  378. // the trace message to stop if you need to trace down the source of
  379. // an error. The BF_ONERRORMSG and BF_ONWARNMSG bits may be set in
  380. // g_dwBreakFlags to make TraceMsg stop when a TF_ERROR or TF_WARNING
  381. // message is displayed. But typically these bits are disabled.
  382. //
  383. // Default Behavior-
  384. // Retail builds: nothing
  385. // Debug builds: only TF_ALWAYS and TF_ERROR messages spew
  386. // Full debug builds: spew
  387. //
  388. #ifdef DEBUG
  389. void CDECL CcshellDebugMsgW(DWORD mask, LPCSTR pszMsg, ...);
  390. void CDECL CcshellDebugMsgA(DWORD mask, LPCSTR pszMsg, ...);
  391. void CDECL _DebugMsgA(DWORD flag, LPCSTR psz, ...);
  392. void CDECL _DebugMsgW(DWORD flag, LPCWSTR psz, ...);
  393. #ifdef UNICODE
  394. #define CcshellDebugMsg CcshellDebugMsgW
  395. #define _DebugMsg _DebugMsgW
  396. #else
  397. #define CcshellDebugMsg CcshellDebugMsgA
  398. #define _DebugMsg _DebugMsgA
  399. #endif
  400. #define TraceMsgW CcshellDebugMsgW
  401. #define TraceMsgA CcshellDebugMsgA
  402. #define TraceMsg CcshellDebugMsg
  403. // Use TraceMsg instead of DebugMsg. DebugMsg is obsolete.
  404. #ifdef DISALLOW_DebugMsg
  405. #define DebugMsg Dont_use_DebugMsg___Use_TraceMsg
  406. #else
  407. #define DebugMsg _DebugMsg
  408. #endif
  409. #else // DEBUG
  410. #define TraceMsgA 1 ? (void)0 : (void)
  411. #define TraceMsgW 1 ? (void)0 : (void)
  412. #define TraceMsg 1 ? (void)0 : (void)
  413. #define DebugMsg 1 ? (void)0 : (void)
  414. #endif // DEBUG
  415. // THR(pfn)
  416. // TBOOL(pfn)
  417. // TINT(pfn)
  418. // TPTR(pfn)
  419. // TW32(pfn)
  420. //
  421. // These macros are useful to trace failed calls to functions that return
  422. // HRESULTs, BOOLs, ints, or pointers. An example use of this is:
  423. //
  424. // {
  425. // ...
  426. // hres = THR(CoCreateInstance(CLSID_Bar, NULL, CLSCTX_INPROC_SERVER,
  427. // IID_IBar, (LPVOID*)&pbar));
  428. // if (SUCCEEDED(hres))
  429. // ...
  430. // }
  431. //
  432. // If CoCreateInstance failed, you would see spew similar to:
  433. //
  434. // err MODULE THR: Failure of "CoCreateInstance(CLSID_Bar, NULL, CLSCTX_INPROC_SERVER, IID_IBar, (LPVOID*)&pbar)" at foo.cpp, line 100 (0x80004005)
  435. //
  436. // THR keys off of the failure code of the hresult.
  437. // TBOOL considers FALSE to be a failure case.
  438. // TINT considers -1 to be a failure case.
  439. // TPTR considers NULL to be a failure case.
  440. // TW32 keys off the failure code of the Win32 error code.
  441. //
  442. // Set the BF_THR bit in g_dwBreakFlags to stop when these macros see a failure.
  443. //
  444. // Default Behavior-
  445. // Retail builds: nothing
  446. // Debug builds: nothing
  447. // Full debug builds: spew on error
  448. //
  449. #ifdef DEBUG
  450. EXTERN_C HRESULT TraceHR(HRESULT hrTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
  451. EXTERN_C BOOL TraceBool(BOOL bTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
  452. EXTERN_C int TraceInt(int iTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
  453. EXTERN_C LPVOID TracePtr(LPVOID pvTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
  454. EXTERN_C DWORD TraceWin32(DWORD dwTest, LPCSTR pszExpr, LPCSTR pszFile, int iLine);
  455. #define THR(x) (TraceHR((x), #x, __FILE__, __LINE__))
  456. #define TBOOL(x) (TraceBool((x), #x, __FILE__, __LINE__))
  457. #define TINT(x) (TraceInt((x), #x, __FILE__, __LINE__))
  458. #define TPTR(x) (TracePtr((x), #x, __FILE__, __LINE__))
  459. #define TW32(x) (TraceWin32((x), #x, __FILE__, __LINE__))
  460. #else // DEBUG
  461. #define THR(x) (x)
  462. #define TBOOL(x) (x)
  463. #define TINT(x) (x)
  464. #define TPTR(x) (x)
  465. #define TW32(x) (x)
  466. #endif // DEBUG
  467. // DBEXEC(flg, expr)
  468. //
  469. // under DEBUG, does "if (flg) expr;" (w/ the usual safe syntax)
  470. // under !DEBUG, does nothing (and does not evaluate either of its args)
  471. //
  472. #ifdef DEBUG
  473. #define DBEXEC(flg, expr) ((flg) ? (expr) : 0)
  474. #else // DEBUG
  475. #define DBEXEC(flg, expr) /*NOTHING*/
  476. #endif // DEBUG
  477. // string and buffer whacking functions
  478. //
  479. #ifdef DEBUG
  480. EXTERN_C void DEBUGWhackPathBufferA(LPSTR psz, UINT cch);
  481. EXTERN_C void DEBUGWhackPathBufferW(LPWSTR psz, UINT cch);
  482. EXTERN_C void DEBUGWhackPathStringA(LPSTR psz, UINT cch);
  483. EXTERN_C void DEBUGWhackPathStringW(LPWSTR psz, UINT cch);
  484. #ifdef UNICODE
  485. #define DEBUGWhackPathBuffer DEBUGWhackPathBufferW
  486. #define DEBUGWhackPathString DEBUGWhackPathStringW
  487. #else
  488. #define DEBUGWhackPathBuffer DEBUGWhackPathBufferA
  489. #define DEBUGWhackPathString DEBUGWhackPathStringA
  490. #endif
  491. #else // DEBUG
  492. #define DEBUGWhackPathBuffer(psz, cch)
  493. #define DEBUGWhackPathString(psz, cch)
  494. #endif // DEBUG
  495. // Some trickery to map ATL debug macros to ours, so ATL code that stops
  496. // or spews in our code will look like the rest of our squirties.
  497. #ifdef DEBUG
  498. #ifdef _ATL_NO_DEBUG_CRT
  499. // ATL uses _ASSERTE. Map it to ours.
  500. #define _ASSERTE(f) ASSERT(f)
  501. // We map ATLTRACE macros to our functions
  502. void _cdecl ShellAtlTraceA(LPCSTR lpszFormat, ...);
  503. void _cdecl ShellAtlTraceW(LPCWSTR lpszFormat, ...);
  504. #ifdef UNICODE
  505. #define ShellAtlTrace ShellAtlTraceW
  506. #else
  507. #define ShellAtlTrace ShellAtlTraceA
  508. #endif
  509. #define ATLTRACE ShellAtlTrace
  510. #endif
  511. #else // DEBUG
  512. #ifdef _ATL_NO_DEBUG_CRT
  513. // ATL uses _ASSERTE. Map it to ours.
  514. #define _ASSERTE(f)
  515. // We map ATLTRACE macros to our functions
  516. #define ATLTRACE 1 ? (void)0 : (void)
  517. #endif
  518. #endif // DEBUG
  519. // ------ Stay away from these macros below ----------
  520. // Issue (scotth): remove these by 8/15/98. They should not be used anymore.
  521. #ifdef DEBUG
  522. #define AssertE(f) ASSERT(f)
  523. #define AssertMsg _AssertMsg
  524. #define AssertStrLen _AssertStrLen
  525. #define AssertStrLenA _AssertStrLenA
  526. #define AssertStrLenW _AssertStrLenW
  527. #ifdef FULL_DEBUG
  528. #define FullDebugMsg _DebugMsg
  529. #else
  530. #define FullDebugMsg 1 ? (void)0 : (void)
  531. #endif
  532. #define ASSERT_MSGW CcshellAssertMsgW
  533. #define ASSERT_MSGA CcshellAssertMsgA
  534. #define ASSERT_MSG CcshellAssertMsg
  535. #else // DEBUG
  536. #define AssertE(f) (f)
  537. #define AssertMsg 1 ? (void)0 : (void)
  538. #define AssertStrLen(lpStr, iLen)
  539. #define FullDebugMsg 1 ? (void)0 : (void)
  540. #define ASSERT_MSGA 1 ? (void)0 : (void)
  541. #define ASSERT_MSGW 1 ? (void)0 : (void)
  542. #define ASSERT_MSG 1 ? (void)0 : (void)
  543. #endif // DEBUG
  544. // ------ Stay away from these macros above ----------
  545. // It's necessary to find when classes that were designed to be single threaded are used
  546. // across threads so they can be fixed to be multithreaded. These asserts will point
  547. // out such cases.
  548. #ifdef DEBUG
  549. #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."))
  550. #define INIT_SINGLE_THREADED_ASSERT _dwThreadIDForSingleThreadedAssert = GetCurrentThreadId();
  551. #define SINGLE_THREADED_MEMBER_VARIABLE DWORD _dwThreadIDForSingleThreadedAssert;
  552. #else // DEBUG
  553. #define ASSERT_SINGLE_THREADED NULL;
  554. #define INIT_SINGLE_THREADED_ASSERT NULL;
  555. #define SINGLE_THREADED_MEMBER_VARIABLE
  556. #endif // DEBUG
  557. #ifdef DEBUG
  558. #define Dbg_SafeStrA(psz) (SAFECAST(psz, LPCSTR), (psz) ? (psz) : "NULL string")
  559. #define Dbg_SafeStrW(psz) (SAFECAST(psz, LPCWSTR), (psz) ? (psz) : L"NULL string")
  560. #ifdef UNICODE
  561. #define Dbg_SafeStr Dbg_SafeStrW
  562. #else
  563. #define Dbg_SafeStr Dbg_SafeStrA
  564. #endif
  565. #define FUNC_MSG CcshellFuncMsg
  566. // Helpful macro for mapping manifest constants to strings. Assumes
  567. // return string is pcsz. You can use this macro in this fashion:
  568. //
  569. // LPCSTR Dbg_GetFoo(FOO foo)
  570. // {
  571. // LPCTSTR pcsz = TEXT("Unknown <foo>");
  572. // switch (foo)
  573. // {
  574. // STRING_CASE(FOOVALUE1);
  575. // STRING_CASE(FOOVALUE2);
  576. // ...
  577. // }
  578. // return pcsz;
  579. // }
  580. //
  581. #define STRING_CASE(val) case val: pcsz = TEXT(#val); break
  582. // Debug function enter
  583. // DBG_ENTER(flag, fn) -- Generates a function entry debug spew for
  584. // a function
  585. //
  586. #define DBG_ENTER(flagFTF, fn) \
  587. (FUNC_MSG(flagFTF, " > " #fn "()"), \
  588. CcshellStackEnter())
  589. // DBG_ENTER_TYPE(flag, fn, dw, pfnStrFromType) -- Generates a function entry debug
  590. // spew for functions that accept <type>.
  591. //
  592. #define DBG_ENTER_TYPE(flagFTF, fn, dw, pfnStrFromType) \
  593. (FUNC_MSG(flagFTF, " < " #fn "(..., %s, ...)", (LPCTSTR)pfnStrFromType(dw)), \
  594. CcshellStackEnter())
  595. // DBG_ENTER_SZ(flag, fn, sz) -- Generates a function entry debug spew for
  596. // a function that accepts a string as one of its
  597. // parameters.
  598. //
  599. #define DBG_ENTER_SZ(flagFTF, fn, sz) \
  600. (FUNC_MSG(flagFTF, " > " #fn "(..., \"%s\",...)", Dbg_SafeStr(sz)), \
  601. CcshellStackEnter())
  602. // Debug function exit
  603. // DBG_EXIT(flag, fn) -- Generates a function exit debug spew
  604. //
  605. #define DBG_EXIT(flagFTF, fn) \
  606. (CcshellStackLeave(), \
  607. FUNC_MSG(flagFTF, " < " #fn "()"))
  608. // DBG_EXIT_TYPE(flag, fn, dw, pfnStrFromType) -- Generates a function exit debug
  609. // spew for functions that return <type>.
  610. //
  611. #define DBG_EXIT_TYPE(flagFTF, fn, dw, pfnStrFromType) \
  612. (CcshellStackLeave(), \
  613. FUNC_MSG(flagFTF, " < " #fn "() with %s", (LPCTSTR)pfnStrFromType(dw)))
  614. // DBG_EXIT_INT(flag, fn, us) -- Generates a function exit debug spew for
  615. // functions that return an INT.
  616. //
  617. #define DBG_EXIT_INT(flagFTF, fn, n) \
  618. (CcshellStackLeave(), \
  619. FUNC_MSG(flagFTF, " < " #fn "() with %d", (int)(n)))
  620. // DBG_EXIT_BOOL(flag, fn, b) -- Generates a function exit debug spew for
  621. // functions that return a boolean.
  622. //
  623. #define DBG_EXIT_BOOL(flagFTF, fn, b) \
  624. (CcshellStackLeave(), \
  625. FUNC_MSG(flagFTF, " < " #fn "() with %s", (b) ? (LPTSTR)TEXT("TRUE") : (LPTSTR)TEXT("FALSE")))
  626. // DBG_EXIT_UL(flag, fn, ul) -- Generates a function exit debug spew for
  627. // functions that return a ULONG.
  628. //
  629. #ifdef _WIN64
  630. #define DBG_EXIT_UL(flagFTF, fn, ul) \
  631. (CcshellStackLeave(), \
  632. FUNC_MSG(flagFTF, " < " #fn "() with %#016I64x", (ULONG_PTR)(ul)))
  633. #else
  634. #define DBG_EXIT_UL(flagFTF, fn, ul) \
  635. (CcshellStackLeave(), \
  636. FUNC_MSG(flagFTF, " < " #fn "() with %#08lx", (ULONG)(ul)))
  637. #endif // _WIN64
  638. #define DBG_EXIT_DWORD DBG_EXIT_UL
  639. // DBG_EXIT_HRES(flag, fn, hres) -- Generates a function exit debug spew for
  640. // functions that return an HRESULT.
  641. //
  642. #define DBG_EXIT_HRES(flagFTF, fn, hres) DBG_EXIT_TYPE(flagFTF, fn, hres, Dbg_GetHRESULTName)
  643. #else // DEBUG
  644. #define Dbg_SafeStr 1 ? (void)0 : (void)
  645. #define FUNC_MSG 1 ? (void)0 : (void)
  646. #define DBG_ENTER(flagFTF, fn)
  647. #define DBG_ENTER_TYPE(flagFTF, fn, dw, pfn)
  648. #define DBG_ENTER_SZ(flagFTF, fn, sz)
  649. #define DBG_EXIT(flagFTF, fn)
  650. #define DBG_EXIT_INT(flagFTF, fn, n)
  651. #define DBG_EXIT_BOOL(flagFTF, fn, b)
  652. #define DBG_EXIT_UL(flagFTF, fn, ul)
  653. #define DBG_EXIT_DWORD DBG_EXIT_UL
  654. #define DBG_EXIT_TYPE(flagFTF, fn, dw, pfn)
  655. #define DBG_EXIT_HRES(flagFTF, fn, hres)
  656. #endif // DEBUG
  657. // COMPILETIME_ASSERT(f)
  658. //
  659. // Generates a build break at compile time if the constant expression
  660. // is not true. Unlike the "#if" compile-time directive, the expression
  661. // in COMPILETIME_ASSERT() is allowed to use "sizeof".
  662. //
  663. // Compiler magic! If the expression "f" is FALSE, then you get the
  664. // compiler error "Duplicate case expression in switch statement".
  665. //
  666. #define COMPILETIME_ASSERT(f) switch (0) case 0: case f:
  667. #endif // NOSHELLDEBUG
  668. //
  669. // Debug dump helper functions
  670. //
  671. #ifdef DEBUG
  672. LPCTSTR Dbg_GetCFName(UINT ucf);
  673. LPCTSTR Dbg_GetHRESULTName(HRESULT hr);
  674. LPCTSTR Dbg_GetREFIIDName(REFIID riid);
  675. LPCTSTR Dbg_GetVTName(VARTYPE vt);
  676. #else
  677. #define Dbg_GetCFName(ucf) (void)0
  678. #define Dbg_GetHRESULTName(hr) (void)0
  679. #define Dbg_GetREFIIDName(riid) (void)0
  680. #define Dbg_GetVTName(vt) (void)0
  681. #endif // DEBUG
  682. // I'm a lazy typist...
  683. #define Dbg_GetHRESULT Dbg_GetHRESULTName
  684. // Parameter validation macros
  685. #include "validate.h"
  686. #endif // DECLARE_DEBUG
  687. #ifdef PRODUCT_PROF
  688. int __stdcall StartCAP(void); // start profiling
  689. int __stdcall StopCAP(void); // stop profiling until StartCAP
  690. int __stdcall SuspendCAP(void); // suspend profiling until ResumeCAP
  691. int __stdcall ResumeCAP(void); // resume profiling
  692. int __stdcall StartCAPAll(void); // process-wide start profiling
  693. int __stdcall StopCAPAll(void); // process-wide stop profiling
  694. int __stdcall SuspendCAPAll(void); // process-wide suspend profiling
  695. int __stdcall ResumeCAPAll(void); // process-wide resume profiling
  696. void __stdcall MarkCAP(long lMark); // write mark to MEA
  697. extern DWORD g_dwProfileCAP;
  698. #else
  699. #define StartCAP() 0
  700. #define StopCAP() 0
  701. #define SuspendCAP() 0
  702. #define ResumeCAP() 0
  703. #define StartCAPAll() 0
  704. #define StopCAPAll() 0
  705. #define SuspendCAPAll() 0
  706. #define ResumeCAPAll() 0
  707. #define MarkCAP(n) 0
  708. #define g_dwProfileCAP 0
  709. #endif
  710. #ifdef __cplusplus
  711. };
  712. #endif