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.

4972 lines
138 KiB

  1. //
  2. // Copyright 2001 - Microsoft Corporation
  3. //
  4. // Created By:
  5. // Geoff Pease (GPease) 23-JAN-2001
  6. //
  7. // Maintained By:
  8. // Geoff Pease (GPease) 23-JAN-2001
  9. //
  10. #include "pch.h"
  11. #if defined( DEBUG )
  12. //
  13. // Include the WINERROR, HRESULT and NTSTATUS codes
  14. //
  15. #include <winerror.dbg>
  16. //
  17. // Constants
  18. //
  19. static const int cchDEBUG_OUTPUT_BUFFER_SIZE = 512;
  20. static const int cchFILEPATHLINESIZE = 70;
  21. static const int TRACE_OUTPUT_BUFFER_SIZE = 512;
  22. //
  23. // Globals
  24. //
  25. DWORD g_TraceMemoryIndex = -1;
  26. DWORD g_TraceFlagsIndex = -1;
  27. DWORD g_ThreadCounter = 0;
  28. DWORD g_dwCounter = 0;
  29. TRACEFLAG g_tfModule = mtfNEVER;
  30. LONG g_lDebugSpinLock = FALSE;
  31. static CRITICAL_SECTION * g_pcsTraceLog = NULL;
  32. static HANDLE g_hTraceLogFile = INVALID_HANDLE_VALUE;
  33. //
  34. // Strings
  35. //
  36. static const TCHAR g_szNULL[] = TEXT("");
  37. static const TCHAR g_szTrue[] = TEXT("True");
  38. static const TCHAR g_szFalse[] = TEXT("False");
  39. static const TCHAR g_szFileLine[] = TEXT("%s(%u):");
  40. static const TCHAR g_szFormat[] = TEXT("%-60s %-10.10s ");
  41. static const TCHAR g_szUnknown[] = TEXT("<unknown>");
  42. //
  43. // ImageHlp Stuff - not ready for prime time yet.
  44. //
  45. #if defined(IMAGEHLP_ENABLED)
  46. //
  47. // ImageHelp
  48. //
  49. typedef VOID (*PFNRTLGETCALLERSADDRESS)(PVOID*,PVOID*);
  50. HINSTANCE g_hImageHlp = NULL;
  51. PFNSYMGETSYMFROMADDR g_pfnSymGetSymFromAddr = NULL;
  52. PFNSYMGETLINEFROMADDR g_pfnSymGetLineFromAddr = NULL;
  53. PFNSYMGETMODULEINFO g_pfnSymGetModuleInfo = NULL;
  54. PFNRTLGETCALLERSADDRESS g_pfnRtlGetCallersAddress = NULL;
  55. #endif // IMAGEHLP_ENABLED
  56. //
  57. // Per thread structure.
  58. //
  59. typedef struct _SPERTHREADDEBUG {
  60. DWORD dwFlags;
  61. DWORD dwStackCounter;
  62. LPCTSTR pcszName;
  63. } SPerThreadDebug;
  64. //****************************************************************************
  65. //
  66. // Debugging and Tracing Routines
  67. //
  68. //****************************************************************************
  69. //////////////////////////////////////////////////////////////////////////////
  70. //
  71. // void
  72. // DebugIncrementStackDepthCounter( void )
  73. //
  74. // Description:
  75. // Increases the stack scope depth counter. If "per thread" tracking is
  76. // on it will increment the "per thread" counter. Otherwise, it will
  77. // increment the "global" counter.
  78. //
  79. // Arguments:
  80. // None.
  81. //
  82. // Return Values:
  83. // None.
  84. //
  85. //////////////////////////////////////////////////////////////////////////////
  86. void
  87. DebugIncrementStackDepthCounter( void )
  88. {
  89. if ( g_tfModule & mtfPERTHREADTRACE )
  90. {
  91. SPerThreadDebug * ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  92. if ( ptd != NULL )
  93. {
  94. ptd->dwStackCounter++;
  95. } // if: ptd
  96. } // if: per thread
  97. else
  98. {
  99. InterlockedIncrement( (LONG*) &g_dwCounter );
  100. } // else: global
  101. } // DebugIncrementStackDepthCounter()
  102. //////////////////////////////////////////////////////////////////////////////
  103. //++
  104. //
  105. // void
  106. // DebugDecrementStackDepthCounter( void )
  107. //
  108. // Description:
  109. // Decreases the stack scope depth counter. If "per thread" tracking is
  110. // on it will decrement the "per thread" counter. Otherwise, it will
  111. // decrement the "global" counter.
  112. //
  113. // Arguments:
  114. // None.
  115. //
  116. // Return Values:
  117. // None.
  118. //
  119. //--
  120. //////////////////////////////////////////////////////////////////////////////
  121. void
  122. DebugDecrementStackDepthCounter( void )
  123. {
  124. if ( g_tfModule & mtfPERTHREADTRACE )
  125. {
  126. SPerThreadDebug * ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  127. if ( ptd != NULL )
  128. {
  129. ptd->dwStackCounter--;
  130. } // if: ptd
  131. } // if: per thread
  132. else
  133. {
  134. Assert( 0 != g_dwCounter );
  135. InterlockedDecrement( (LONG*) &g_dwCounter );
  136. } // else: global
  137. } // DebugDecrementStackDepthCounter()
  138. //////////////////////////////////////////////////////////////////////////////
  139. //++
  140. //
  141. // void
  142. // DebugAcquireSpinLock(
  143. // LONG * pLock
  144. // )
  145. //
  146. // Description:
  147. // Acquires the spin lock pointed to by pLock.
  148. //
  149. // Arguments:
  150. // pLock - Pointer to the spin lock.
  151. //
  152. // Return Values:
  153. // None.
  154. //
  155. //--
  156. //////////////////////////////////////////////////////////////////////////////
  157. void
  158. DebugAcquireSpinLock(
  159. LONG * pLock
  160. )
  161. {
  162. for(;;)
  163. {
  164. LONG lInitialValue;
  165. lInitialValue = InterlockedCompareExchange( pLock, TRUE, FALSE );
  166. if ( lInitialValue == FALSE )
  167. {
  168. //
  169. // Lock acquired.
  170. //
  171. break;
  172. } // if: got lock
  173. else
  174. {
  175. //
  176. // Sleep to give other thread a chance to give up the lock.
  177. //
  178. Sleep( 1 );
  179. } // if: lock not acquired
  180. } // for: forever
  181. } // DebugAcquireSpinLock()
  182. //////////////////////////////////////////////////////////////////////////////
  183. //++
  184. //
  185. // void
  186. // DebugReleaseSpinLock(
  187. // LONG * pLock
  188. // )
  189. //
  190. // Description:
  191. // Releases the spin lock pointer to by pLock.
  192. //
  193. // Arguments:
  194. // pLock - Pointer to the spin lock.
  195. //
  196. // Return Values:
  197. // None.
  198. //
  199. //--
  200. //////////////////////////////////////////////////////////////////////////////
  201. void
  202. DebugReleaseSpinLock(
  203. LONG * pLock
  204. )
  205. {
  206. *pLock = FALSE;
  207. } // DebugReleaseSpinLock()
  208. //////////////////////////////////////////////////////////////////////////////
  209. //++
  210. //
  211. // BOOL
  212. // IsDebugFlagSet(
  213. // TRACEFLAG tfIn
  214. // )
  215. //
  216. // Description:
  217. // Checks the global g_tfModule and the "per thread" Trace Flags to
  218. // determine if the flag (any of the flags) are turned on.
  219. //
  220. // Arguments:
  221. // tfIn - Trace flags to compare.
  222. //
  223. // Return Values:
  224. // TRUE At least of one of the flags are present.
  225. // FALSE None of the flags match.
  226. //
  227. //--
  228. //////////////////////////////////////////////////////////////////////////////
  229. BOOL
  230. IsDebugFlagSet(
  231. TRACEFLAG tfIn
  232. )
  233. {
  234. if ( g_tfModule & tfIn )
  235. {
  236. return TRUE;
  237. } // if: global flag set
  238. if ( g_tfModule & mtfPERTHREADTRACE )
  239. {
  240. SPerThreadDebug * ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  241. if ( ptd != NULL
  242. && ptd->dwFlags & tfIn
  243. )
  244. {
  245. return TRUE;
  246. } // if: per thread flag set
  247. } // if: per thread settings
  248. return FALSE;
  249. } //*** IsDebugFlagSet()
  250. //////////////////////////////////////////////////////////////////////////////
  251. //++
  252. //
  253. // void
  254. // DebugOutputString(
  255. // LPCTSTR pszIn
  256. // )
  257. //
  258. // Description:
  259. // Dumps the spew to the appropriate orafice.
  260. //
  261. // Arguments:
  262. // pszIn Message to dump.
  263. //
  264. // Return Values:
  265. // None.
  266. //
  267. //--
  268. //////////////////////////////////////////////////////////////////////////////
  269. void
  270. DebugOutputString(
  271. LPCTSTR pszIn
  272. )
  273. {
  274. if ( IsTraceFlagSet( mtfOUTPUTTODISK ) )
  275. {
  276. TraceLogMsgNoNewline( pszIn );
  277. } // if: trace to file
  278. else
  279. {
  280. DebugAcquireSpinLock( &g_lDebugSpinLock );
  281. OutputDebugString( pszIn );
  282. DebugReleaseSpinLock( &g_lDebugSpinLock );
  283. } // else: debugger
  284. } //*** DebugOutputString()
  285. #if 0
  286. /*
  287. //////////////////////////////////////////////////////////////////////////////
  288. //++
  289. // void
  290. // DebugFindNTStatusSymbolicName(
  291. // DWORD dwStatusIn,
  292. // LPTSTR pszNameOut,
  293. // LPDWORD pcchNameInout
  294. // )
  295. //
  296. // Description:
  297. // Uses the NTBUILD generated ntstatusSymbolicNames table to lookup
  298. // the symbolic name for the status code. The name will be returned in
  299. // pszNameOut. pcchNameInout should indicate the size of the buffer that
  300. // pszNameOut points too. pcchNameInout will return the number of
  301. // characters copied out.
  302. //
  303. // Arguments:
  304. // dwStatusIn - Status code to lookup.
  305. // pszNameOut - Buffer to store the string name
  306. // pcchNameInout - The length of the buffer in and the size out.
  307. //
  308. // Return Values:
  309. // None.
  310. //
  311. //--
  312. //////////////////////////////////////////////////////////////////////////////
  313. void
  314. DebugFindNTStatusSymbolicName(
  315. NTSTATUS dwStatusIn,
  316. LPTSTR pszNameOut,
  317. LPDWORD pcchNameInout
  318. )
  319. {
  320. Assert( pszNameOut != NULL );
  321. Assert( pcchNameInout != NULL );
  322. int idx = 0;
  323. while ( ntstatusSymbolicNames[ idx ].SymbolicName
  324. )
  325. {
  326. if ( ntstatusSymbolicNames[ idx ].MessageId == dwStatusIn
  327. )
  328. {
  329. #if defined ( UNICODE )
  330. *pcchNameInout = mbstowcs( pszNameOut, ntstatusSymbolicNames[ idx ].SymbolicName, *pcchNameInout );
  331. Assert( *pcchNameInout != -1 );
  332. #else // ASCII
  333. _tcsncpy( pszNameOut, ntstatusSymbolicNames[ idx ].SymbolicName, *pcchNameInout );
  334. *pcchNameInout = lstrlen( pszNameOut );
  335. #endif // UNICODE
  336. return;
  337. } // if: matched
  338. idx++;
  339. } // while: entries in list
  340. //
  341. // If we made it here, we did not find an entry.
  342. //
  343. _tcsncpy( pszNameOut, TEXT("<unknown>"), *pcchNameInout );
  344. *pcchNameInout = StrLen( pszNameOut );
  345. return;
  346. } //*** DebugFindNTStatusSymbolicName()
  347. */
  348. #endif
  349. //////////////////////////////////////////////////////////////////////////////
  350. //++
  351. // void
  352. // DebugFindWinerrorSymbolicName(
  353. // DWORD dwErrIn,
  354. // LPTSTR pszNameOut,
  355. // LPDWORD pcchNameInout
  356. // )
  357. //
  358. // Description:
  359. // Uses the NTBUILD generated winerrorSymbolicNames table to lookup
  360. // the symbolic name for the error code. The name will be returned in
  361. // pszNameOut. pcchNameInout should indicate the size of the buffer that
  362. // pszNameOut points too. pcchNameInout will return the number of
  363. // characters copied out.
  364. //
  365. // Arguments:
  366. // dwErrIn - Error code to lookup.
  367. // pszNameOut - Buffer to store the string name
  368. // pcchNameInout - The length of the buffer in and the size out.
  369. //
  370. // Return Values:
  371. // None.
  372. //
  373. //--
  374. //////////////////////////////////////////////////////////////////////////////
  375. void
  376. DebugFindWinerrorSymbolicName(
  377. DWORD dwErrIn,
  378. LPTSTR pszNameOut,
  379. LPDWORD pcchNameInout
  380. )
  381. {
  382. Assert( pszNameOut != NULL );
  383. Assert( pcchNameInout != NULL );
  384. int idx = 0;
  385. DWORD scode;
  386. static LPCTSTR s_pszS_FALSE = TEXT("S_FALSE / ERROR_INVALID_FUNCTION");
  387. //
  388. // If this is a Win32 wrapped in HRESULT stuff, remove the
  389. // HRESULT stuff so that the code will be found in the table.
  390. //
  391. if ( SCODE_FACILITY( dwErrIn ) == FACILITY_WIN32 )
  392. {
  393. scode = SCODE_CODE( dwErrIn );
  394. } // if: Win32 error code
  395. else
  396. {
  397. scode = dwErrIn;
  398. } // else: not Win32 error code
  399. if ( scode == S_FALSE )
  400. {
  401. StringCchCopy( pszNameOut, *pcchNameInout, s_pszS_FALSE );
  402. *pcchNameInout = lstrlen( pszNameOut );
  403. return;
  404. }
  405. while ( winerrorSymbolicNames[ idx ].SymbolicName )
  406. {
  407. if ( winerrorSymbolicNames[ idx ].MessageId == scode )
  408. {
  409. #if defined ( UNICODE )
  410. *pcchNameInout = mbstowcs( pszNameOut, winerrorSymbolicNames[ idx ].SymbolicName, *pcchNameInout );
  411. Assert( *pcchNameInout != -1 );
  412. #else // ASCII
  413. StringCchCopy( pszNameOut, *pcchNameInout, winerrorSymbolicNames[ idx ].SymbolicName );
  414. *pcchNameInout = lstrlen( pszNameOut );
  415. #endif // UNICODE
  416. return;
  417. } // if: matched
  418. idx++;
  419. } // while: entries in list
  420. //
  421. // If we made it here, we did not find an entry.
  422. //
  423. StringCchCopy( pszNameOut, *pcchNameInout, TEXT("<unknown>") );
  424. *pcchNameInout = lstrlen( pszNameOut );
  425. return;
  426. } //*** DebugFindWinerrorSymbolicName()
  427. //////////////////////////////////////////////////////////////////////////////
  428. //++
  429. //
  430. // void
  431. // DebugReturnMessage(
  432. // LPCTSTR pszFileIn,
  433. // const int nLineIn,
  434. // LPCTSTR pszModuleIn,
  435. // LPTSTR pszBufIn,
  436. // INT * pcchInout,
  437. // LPTSTR * ppszBufOut
  438. // )
  439. //
  440. // Description:
  441. // Prints the spew for a function return with error code.
  442. //
  443. // The primary reason for doing this is to isolate the stack from adding
  444. // the extra size of szSymbolicName to every function.
  445. //
  446. // Argument:
  447. // pszFileIn - File path to insert
  448. // nLineIn - Line number to insert
  449. // pszModuleIn - Module name to insert
  450. // pszBufIn - The buffer to initialize
  451. // pcchInout - IN: Size of the buffer in pszBufIn
  452. // - OUT: Remaining characters in buffer not used.
  453. // ppszBufOut - Next location to write to append more text
  454. //
  455. // Return Values:
  456. // None.
  457. //
  458. //--
  459. //////////////////////////////////////////////////////////////////////////////
  460. void
  461. DebugReturnMessage(
  462. LPCTSTR pszFileIn,
  463. const int nLineIn,
  464. LPCTSTR pszModuleIn,
  465. LPCTSTR pszMessageIn,
  466. DWORD dwErrIn
  467. )
  468. {
  469. TCHAR szSymbolicName[ 64 ]; // random
  470. DWORD cchSymbolicName;
  471. cchSymbolicName = ARRAYSIZE( szSymbolicName );
  472. DebugFindWinerrorSymbolicName( dwErrIn, szSymbolicName, &cchSymbolicName );
  473. Assert( cchSymbolicName != ARRAYSIZE( szSymbolicName ) );
  474. TraceMessage( pszFileIn, nLineIn, pszModuleIn, mtfFUNC, pszMessageIn, dwErrIn, szSymbolicName );
  475. } //*** DebugReturnMessage()
  476. //////////////////////////////////////////////////////////////////////////////
  477. //++
  478. //
  479. // void
  480. // DebugInitializeBuffer(
  481. // LPCTSTR pszFileIn,
  482. // const int nLineIn,
  483. // LPCTSTR pszModuleIn,
  484. // LPTSTR pszBufIn,
  485. // INT * pcchInout,
  486. // LPTSTR * ppszBufOut
  487. // )
  488. //
  489. // Description:
  490. // Intializes the output buffer with "File(Line) Module ".
  491. //
  492. // Argument:
  493. // pszFileIn - File path to insert
  494. // nLineIn - Line number to insert
  495. // pszModuleIn - Module name to insert
  496. // pszBufIn - The buffer to initialize
  497. // pcchInout - IN: Size of the buffer in pszBufIn
  498. // - OUT: Remaining characters in buffer not used.
  499. // ppszBufOut - Next location to write to append more text
  500. //
  501. // Return Values:
  502. // None.
  503. //
  504. //--
  505. //////////////////////////////////////////////////////////////////////////////
  506. void
  507. DebugInitializeBuffer(
  508. LPCTSTR pszFileIn,
  509. const int nLineIn,
  510. LPCTSTR pszModuleIn,
  511. LPTSTR pszBufIn,
  512. INT * pcchInout,
  513. LPTSTR * ppszBufOut
  514. )
  515. {
  516. INT cch = 0;
  517. static TCHAR szBarSpace[] =
  518. TEXT("| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ");
  519. // 1 2 3 4 5
  520. // 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
  521. //
  522. // Add date/time stamp
  523. //
  524. if ( IsTraceFlagSet( mtfADDTIMEDATE ) )
  525. {
  526. static TCHAR szBuffer[ 25 ];
  527. static SYSTEMTIME OldSystemTime = { 0 };
  528. SYSTEMTIME SystemTime;
  529. int iCmp;
  530. GetLocalTime( &SystemTime );
  531. //
  532. // Avoid expensive printf by comparing times
  533. //
  534. iCmp = memcmp( (PVOID)&SystemTime, (PVOID)&OldSystemTime, sizeof( SYSTEMTIME ) );
  535. if ( iCmp != 0 )
  536. {
  537. cch = StringCchPrintf( szBuffer,
  538. ARRAYSIZE(szBuffer),
  539. TEXT("%02u/%02u/%04u %02u:%02u:%02u.%03u "),
  540. SystemTime.wMonth,
  541. SystemTime.wDay,
  542. SystemTime.wYear,
  543. SystemTime.wHour,
  544. SystemTime.wMinute,
  545. SystemTime.wSecond,
  546. SystemTime.wMilliseconds
  547. );
  548. if ( cch != 24 )
  549. {
  550. DEBUG_BREAK; // can't assert!
  551. } // if: cch != 24
  552. } // if: didn't match
  553. StringCchCopy( pszBufIn, *pcchInout, szBuffer );
  554. cch = 24;
  555. } // if: time/date
  556. else
  557. {
  558. //
  559. // Add the filepath and line number
  560. //
  561. if ( pszFileIn != NULL )
  562. {
  563. cch = StringCchPrintf( pszBufIn, *pcchInout, g_szFileLine, pszFileIn, nLineIn );
  564. if ( cch < 0 )
  565. {
  566. cch = lstrlen( pszBufIn );
  567. } // if: error
  568. }
  569. if ( ( IsDebugFlagSet( mtfSTACKSCOPE )
  570. && IsDebugFlagSet( mtfFUNC )
  571. )
  572. || pszFileIn != NULL
  573. )
  574. {
  575. LPTSTR psz;
  576. for ( psz = pszBufIn + cch; cch < cchFILEPATHLINESIZE; cch++ )
  577. {
  578. *psz = 32;
  579. psz++;
  580. } // for: cch
  581. *psz = 0;
  582. if ( cch != cchFILEPATHLINESIZE )
  583. {
  584. DEBUG_BREAK; // can't assert!
  585. } // if: cch != cchFILEPATHLINESIZE
  586. } // if: have a filepath or ( scoping and func is on )
  587. } // else: normal (no time/date)
  588. //
  589. // Add module name
  590. //
  591. if ( IsTraceFlagSet( mtfBYMODULENAME ) )
  592. {
  593. if ( pszModuleIn == NULL )
  594. {
  595. StringCchCopy( pszBufIn + cch, *pcchInout - cch, g_szUnknown );
  596. cch += ARRAYSIZE( g_szUnknown ) - 1;
  597. } // if:
  598. else
  599. {
  600. static LPCTSTR pszLastTime = NULL;
  601. static DWORD cchLastTime = 0;
  602. StringCchCopy( pszBufIn + cch, *pcchInout - cch, pszModuleIn );
  603. if ( pszLastTime != pszModuleIn )
  604. {
  605. pszLastTime = pszModuleIn;
  606. cchLastTime = lstrlen( pszModuleIn );
  607. } // if: not the same as last time
  608. cch += cchLastTime;
  609. } // else:
  610. StringCchCopy( pszBufIn + cch, *pcchInout - cch, TEXT(": ") );
  611. cch += 2;
  612. } // if: add module name
  613. //
  614. // Add the thread id if "per thread" tracing is on.
  615. //
  616. if ( g_tfModule & mtfPERTHREADTRACE )
  617. {
  618. //
  619. // And check the "per thread" to see if this particular thread
  620. // is supposed to be displaying its ID.
  621. //
  622. SPerThreadDebug * ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  623. if ( ptd != NULL
  624. && ptd->dwFlags & mtfPERTHREADTRACE
  625. )
  626. {
  627. int cchPlus;
  628. cchPlus = StringCchPrintf( pszBufIn + cch,
  629. *pcchInout - cch,
  630. TEXT("~%08x~ "),
  631. GetCurrentThreadId()
  632. );
  633. if ( cchPlus < 0 )
  634. {
  635. cch = lstrlen( pszBufIn );
  636. } // if: failure
  637. else
  638. {
  639. cch += cchPlus;
  640. } // else: success
  641. } // if: turned on in the thread
  642. } // if: tracing by thread
  643. *ppszBufOut = pszBufIn + cch;
  644. *pcchInout -= cch;
  645. //
  646. // Add the "Bar Space" for stack scoping
  647. //
  648. // Both flags must be set
  649. if ( IsDebugFlagSet( mtfSTACKSCOPE )
  650. && IsDebugFlagSet( mtfFUNC )
  651. )
  652. {
  653. DWORD dwCounter;
  654. //
  655. // Choose "per thread" or "global" counter.
  656. //
  657. if ( g_tfModule & mtfPERTHREADTRACE )
  658. {
  659. SPerThreadDebug * ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  660. if ( ptd != NULL )
  661. {
  662. dwCounter = ptd->dwStackCounter;
  663. } // if: ptd
  664. else
  665. {
  666. dwCounter = 0;
  667. } // else: assume its not initialized yet
  668. } // if: per thread
  669. else
  670. {
  671. dwCounter = g_dwCounter;
  672. } // else: global counter
  673. if ( dwCounter >= 50 )
  674. {
  675. DEBUG_BREAK; // can't assert!
  676. } // if: dwCounter not vaild
  677. if ( dwCounter > 1
  678. && dwCounter < 50
  679. )
  680. {
  681. INT nCount = ( dwCounter - 1 ) * 2;
  682. StringCchCopy( *ppszBufOut, nCount, szBarSpace );
  683. *ppszBufOut += nCount;
  684. *pcchInout -= nCount;
  685. } // if: within range
  686. } // if: stack scoping on
  687. } //*** DebugInitializeBuffer()
  688. #if defined(IMAGEHLP_ENABLED)
  689. /*
  690. //////////////////////////////////////////////////////////////////////////////
  691. //++
  692. //
  693. // FALSE
  694. // DebugNoOp( void )
  695. //
  696. // Description:
  697. // Returns FALSE. Used to replace ImageHlp routines it they weren't
  698. // loaded or not found.
  699. //
  700. // Arguments:
  701. // None.
  702. //
  703. // Return Values:
  704. // FALSE, always.
  705. //
  706. //--
  707. //////////////////////////////////////////////////////////////////////////////
  708. BOOL
  709. DebugNoOp( void )
  710. {
  711. return FALSE;
  712. } //*** DebugNoOp()
  713. */
  714. #endif // IMAGEHLP_ENABLED
  715. //////////////////////////////////////////////////////////////////////////////
  716. //++
  717. //
  718. // void
  719. // DebugInitializeTraceFlags( void )
  720. //
  721. // Description:
  722. // Retrieves the default tracing flags for this module from an INI file
  723. // that is named the same as the EXE file (e.g. MMC.EXE -> MMC.INI).
  724. // Typically, this is called from the TraceInitializeProcess() macro.
  725. //
  726. // Arguments:
  727. // None.
  728. //
  729. // Return Values:
  730. // None.
  731. //
  732. //--
  733. //////////////////////////////////////////////////////////////////////////////
  734. void
  735. DebugInitializeTraceFlags( void )
  736. {
  737. TCHAR szSection[ 64 ];
  738. TCHAR szFiles[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  739. TCHAR szPath[ MAX_PATH ];
  740. LPTSTR psz;
  741. DWORD dwLen;
  742. //
  743. // Allocate TLS for memory tracking
  744. //
  745. Assert( g_TraceMemoryIndex == -1 );
  746. g_TraceMemoryIndex = TlsAlloc();
  747. TlsSetValue( g_TraceMemoryIndex, NULL);
  748. //
  749. // Initialize module trace flags
  750. //
  751. //
  752. // Get the EXEs filename and change the extension to INI.
  753. //
  754. dwLen = GetModuleFileName( NULL, szPath, MAX_PATH );
  755. Assert( dwLen != 0 ); // error in GetModuleFileName
  756. StringCchCopy( &szPath[ dwLen - 3 ], 4, TEXT("ini") );
  757. g_tfModule = (TRACEFLAG) GetPrivateProfileInt( __MODULE__,
  758. TEXT("TraceFlags"),
  759. 0,
  760. szPath
  761. );
  762. DebugMsg( TEXT("DEBUG: Reading %s") SZ_NEWLINE
  763. TEXT("%s: DEBUG: g_tfModule = 0x%08x"),
  764. szPath,
  765. __MODULE__,
  766. g_tfModule
  767. );
  768. //
  769. // Initialize thread trace flags
  770. //
  771. if ( g_tfModule & mtfPERTHREADTRACE )
  772. {
  773. Assert( g_TraceFlagsIndex == -1 );
  774. g_TraceFlagsIndex = TlsAlloc();
  775. DebugInitializeThreadTraceFlags( NULL );
  776. } // if: per thread tracing
  777. //
  778. // Force the loading of certain modules
  779. //
  780. GetPrivateProfileString( __MODULE__, TEXT("ForcedDLLsSection"), g_szNULL, szSection, 64, szPath );
  781. ZeroMemory( szFiles, sizeof( szFiles ) );
  782. GetPrivateProfileSection( szSection, szFiles, ARRAYSIZE( szFiles ), szPath );
  783. psz = szFiles;
  784. while ( *psz )
  785. {
  786. TCHAR szExpandedPath[ MAX_PATH ];
  787. ExpandEnvironmentStrings( psz, szExpandedPath, MAX_PATH );
  788. DebugMsg( TEXT("DEBUG: Forcing %s to be loaded."), szExpandedPath );
  789. LoadLibrary( szExpandedPath );
  790. psz += lstrlen( psz ) + 1;
  791. } // while: entry found
  792. #if defined(IMAGEHLP_ENABLED)
  793. /*
  794. //
  795. // Load symbols for our module
  796. //
  797. g_hImageHlp = LoadLibraryEx( TEXT("imagehlp.dll"), NULL, 0 );
  798. if ( g_hImageHlp != NULL )
  799. {
  800. // Typedef this locally since it is only needed once.
  801. typedef BOOL (*PFNSYMINITIALIZE)(HANDLE, PSTR, BOOL);
  802. PFNSYMINITIALIZE pfnSymInitialize;
  803. pfnSymInitialize = (PFNSYMINITIALIZE) GetProcAddress( g_hImageHlp, "SymInitialize" );
  804. if ( pfnSymInitialize != NULL )
  805. {
  806. pfnSymInitialize( GetCurrentProcess(), NULL, TRUE );
  807. } // if: got address
  808. //
  809. // Grab the other addresses we need. Replace them with a "no op" if they are not found
  810. //
  811. g_pfnSymGetSymFromAddr = (PFNSYMGETSYMFROMADDR) GetProcAddress( g_hImageHlp, "SymGetSymFromAddr" );
  812. g_pfnSymGetLineFromAddr = (PFNSYMGETLINEFROMADDR) GetProcAddress( g_hImageHlp, "SymGetLineFromAddr" );
  813. g_pfnSymGetModuleInfo = (PFNSYMGETMODULEINFO) GetProcAddress( g_hImageHlp, "SymGetModuleInfo" );
  814. } // if: imagehlp loaded
  815. //
  816. // If loading IMAGEHLP failed, we need to point these to the "no op" routine.
  817. //
  818. if ( g_pfnSymGetSymFromAddr == NULL )
  819. {
  820. g_pfnSymGetSymFromAddr = (PFNSYMGETSYMFROMADDR) &DebugNoOp;
  821. } // if: failed
  822. if ( g_pfnSymGetLineFromAddr == NULL )
  823. {
  824. g_pfnSymGetLineFromAddr = (PFNSYMGETLINEFROMADDR) &DebugNoOp;
  825. } // if: failed
  826. if ( g_pfnSymGetModuleInfo == NULL )
  827. {
  828. g_pfnSymGetModuleInfo = (PFNSYMGETMODULEINFO) &DebugNoOp;
  829. } // if: failed
  830. HINSTANCE hMod = LoadLibrary( TEXT("NTDLL.DLL") );
  831. g_pfnRtlGetCallersAddress = (PFNRTLGETCALLERSADDRESS) GetProcAddress( hMod, "RtlGetCallersAddress" );
  832. if ( g_pfnRtlGetCallersAddress == NULL )
  833. {
  834. g_pfnRtlGetCallersAddress = (PFNRTLGETCALLERSADDRESS) &DebugNoOp;
  835. } // if: failed
  836. */
  837. #endif // IMAGEHLP_ENABLED
  838. } //*** DebugInitializeTraceFlags()
  839. //////////////////////////////////////////////////////////////////////////////
  840. //++
  841. //
  842. // void
  843. // DebugTerminateProcess( void )
  844. //
  845. // Description:
  846. // Cleans up anything that the debugging routines allocated or
  847. // initialized. Typically, you should call the TraceTerminateProcess()
  848. // macro just before your process exits.
  849. //
  850. // Arguments:
  851. // None.
  852. //
  853. // Return Values:
  854. // None.
  855. //
  856. //--
  857. //////////////////////////////////////////////////////////////////////////////
  858. void
  859. DebugTerminateProcess( void )
  860. {
  861. #if defined(IMAGEHLP_ENABLED)
  862. /*
  863. //
  864. // ImageHlp Cleanup
  865. //
  866. if ( g_hImageHlp != NULL )
  867. {
  868. // Typedef this locally since it is only needed once.
  869. typedef BOOL (*PFNSYMCLEANUP)(HANDLE);
  870. PFNSYMCLEANUP pfnSymCleanup;
  871. pfnSymCleanup = (PFNSYMCLEANUP) GetProcAddress( g_hImageHlp, "SymCleanup" );
  872. if ( pfnSymCleanup != NULL )
  873. {
  874. pfnSymCleanup( GetCurrentProcess() );
  875. } // if: found proc
  876. FreeLibrary( g_hImageHlp );
  877. } // if: imagehlp loaded
  878. */
  879. #endif // IMAGEHLP_ENABLED
  880. //
  881. // Free the TLS storage
  882. //
  883. if ( g_tfModule & mtfPERTHREADTRACE )
  884. {
  885. TlsFree( g_TraceFlagsIndex );
  886. } // if: per thread tracing
  887. TlsFree( g_TraceMemoryIndex );
  888. } //*** DebugTerminateProcess()
  889. #if defined(IMAGEHLP_ENABLED)
  890. /*
  891. //////////////////////////////////////////////////////////////////////////////
  892. //++
  893. //
  894. // void
  895. // DebugGetFunctionName(
  896. // LPSTR pszNameOut,
  897. // DWORD cchNameIn
  898. // )
  899. //
  900. // Description:
  901. // Retrieves the calling functions name.
  902. //
  903. // Arguments:
  904. // pszNameOut - The buffer that will contain the functions name.
  905. // cchNameIn - The size of the the out buffer.
  906. //
  907. // Return Values:
  908. // None.
  909. //
  910. //--
  911. //////////////////////////////////////////////////////////////////////////////
  912. void
  913. DebugGetFunctionName(
  914. LPSTR pszNameOut,
  915. DWORD cchNameIn
  916. )
  917. {
  918. PVOID CallersAddress;
  919. PVOID CallersCaller;
  920. BOOL fSuccess;
  921. union
  922. {
  923. IMAGEHLP_SYMBOL sym;
  924. BYTE buf[ 255 ];
  925. } SymBuf;
  926. SymBuf.sym.SizeOfStruct = sizeof( SymBuf );
  927. g_pfnRtlGetCallersAddress( &CallersAddress, &CallersCaller );
  928. fSuccess = g_pfnSymGetSymFromAddr( GetCurrentProcess(), (LONG) CallersAddress, 0, (PIMAGEHLP_SYMBOL) &SymBuf );
  929. if ( fSuccess )
  930. {
  931. StrCpyNA( pszNameOut, SymBuf.sym.Name, cchNameIn );
  932. } // if: success
  933. else
  934. {
  935. DWORD dwErr = GetLastError();
  936. StrCpyNA( pszNameOut, "<unknown>", cchNameIn );
  937. } // if: failed
  938. } //*** DebugGetFunctionName()
  939. */
  940. #endif // IMAGEHLP_ENABLED
  941. //////////////////////////////////////////////////////////////////////////////
  942. //++
  943. //
  944. // void
  945. // DebugInitializeThreadTraceFlags(
  946. // LPCTSTR pszThreadNameIn
  947. // )
  948. //
  949. // Description:
  950. // If enabled (g_tfModule & mtfPERTHREADTRACE), retrieves the default
  951. // tracing flags for this thread from an INI file that is named the
  952. // same as the EXE file (e.g. MMC.EXE -> MMC.INI). The particular
  953. // TraceFlag level is determined by either the thread name (handed in
  954. // as a parameter) or by the thread counter ID which is incremented
  955. // every time a new thread is created and calls this routine. The
  956. // incremental name is "ThreadTraceFlags%u".
  957. //
  958. // This routine is called from the TraceInitliazeThread() macro.
  959. //
  960. // Arguments:
  961. // pszThreadNameIn
  962. // - If the thread has an assoc. name with it, use it instead of the
  963. // incremented version. NULL indicate no naming.
  964. //
  965. //
  966. // Return Values:
  967. // None.
  968. //
  969. //--
  970. //////////////////////////////////////////////////////////////////////////////
  971. void
  972. DebugInitializeThreadTraceFlags(
  973. LPCTSTR pszThreadNameIn
  974. )
  975. {
  976. //
  977. // Read per thread flags
  978. //
  979. if ( g_tfModule & mtfPERTHREADTRACE )
  980. {
  981. TCHAR szPath[ MAX_PATH ];
  982. DWORD dwTraceFlags;
  983. DWORD dwLen;
  984. SPerThreadDebug * ptd;
  985. LPCTSTR pszThreadTraceFlags;
  986. //
  987. // Get the EXEs filename and change the extension to INI.
  988. //
  989. dwLen = GetModuleFileName( NULL, szPath, ARRAYSIZE( szPath ) );
  990. Assert( dwLen != 0 ); // error in GetModuleFileName
  991. StringCchCopy( &szPath[ dwLen - 3 ], 4, TEXT("ini") );
  992. if ( pszThreadNameIn == NULL )
  993. {
  994. TCHAR szThreadTraceFlags[ 50 ];
  995. //
  996. // No name thread - use generic name
  997. //
  998. StringCchPrintf( szThreadTraceFlags, ARRAYSIZE( szThreadTraceFlags ), TEXT("ThreadTraceFlags%u"), g_ThreadCounter );
  999. dwTraceFlags = GetPrivateProfileInt( __MODULE__, szThreadTraceFlags, 0, szPath );
  1000. InterlockedIncrement( (LONG *) &g_ThreadCounter );
  1001. pszThreadTraceFlags = szThreadTraceFlags;
  1002. } // if: no thread name
  1003. else
  1004. {
  1005. //
  1006. // Named thread
  1007. //
  1008. dwTraceFlags = GetPrivateProfileInt( __MODULE__, pszThreadNameIn, 0, szPath );
  1009. pszThreadTraceFlags = pszThreadNameIn;
  1010. } // else: named thread
  1011. Assert( g_TraceFlagsIndex != 0 );
  1012. ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  1013. if ( ptd == NULL )
  1014. {
  1015. // don't track this.
  1016. ptd = (SPerThreadDebug *) HeapAlloc( GetProcessHeap(), 0, sizeof( SPerThreadDebug ) );
  1017. ptd->dwStackCounter = 0;
  1018. TlsSetValue( g_TraceFlagsIndex, ptd );
  1019. } // if: ptd
  1020. if ( ptd != NULL )
  1021. {
  1022. ptd->dwFlags = dwTraceFlags;
  1023. if ( pszThreadNameIn == NULL )
  1024. {
  1025. ptd->pcszName = g_szUnknown;
  1026. } // if: no name
  1027. else
  1028. {
  1029. ptd->pcszName = pszThreadNameIn;
  1030. } // else: give it a name
  1031. } // if: ptd
  1032. DebugMsg( TEXT("DEBUG: Starting ThreadId = 0x%08x - %s = 0x%08x"),
  1033. GetCurrentThreadId(),
  1034. pszThreadTraceFlags,
  1035. dwTraceFlags
  1036. );
  1037. } // if: per thread tracing turned on
  1038. } //*** DebugInitializeThreadTraceFlags()
  1039. //////////////////////////////////////////////////////////////////////////////
  1040. //++
  1041. //
  1042. // void
  1043. // DebugTerminiateThreadTraceFlags( void )
  1044. //
  1045. // Description:
  1046. // Cleans up the mess create by DebugInitializeThreadTraceFlags(). One
  1047. // should use the TraceTerminateThread() macro instead of calling this
  1048. // directly.
  1049. //
  1050. // Arguments:
  1051. // None.
  1052. //
  1053. // Return Values:
  1054. // None.
  1055. //
  1056. //--
  1057. //////////////////////////////////////////////////////////////////////////////
  1058. void
  1059. DebugTerminiateThreadTraceFlags( void )
  1060. {
  1061. //
  1062. // If "per thread" is on, clean up the memory allocation.
  1063. //
  1064. if ( g_tfModule & mtfPERTHREADTRACE )
  1065. {
  1066. Assert( g_TraceFlagsIndex != -1 );
  1067. SPerThreadDebug * ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  1068. if ( ptd != NULL )
  1069. {
  1070. HeapFree( GetProcessHeap(), 0, ptd );
  1071. TlsSetValue( g_TraceFlagsIndex, NULL );
  1072. } // if: ptd
  1073. } // if: per thread
  1074. } // DebugTerminiateThreadTraceFlags()
  1075. //////////////////////////////////////////////////////////////////////////////
  1076. //++
  1077. //
  1078. // ASCII version
  1079. //
  1080. // void
  1081. // TraceMsg(
  1082. // TRACEFLAG tfIn,
  1083. // LPCSTR pszFormatIn,
  1084. // ...
  1085. // )
  1086. //
  1087. // Description:
  1088. // If any of the flags in trace flags match any of the flags set in
  1089. // tfIn, the formatted string will be printed to the debugger.
  1090. //
  1091. // Arguments:
  1092. // tfIn - Flags to be checked.
  1093. // pszFormatIn - Formatted string to spewed to the debugger.
  1094. // ... - message arguments
  1095. //
  1096. // Return Values:
  1097. // None.
  1098. //
  1099. //--
  1100. //////////////////////////////////////////////////////////////////////////////
  1101. void
  1102. __cdecl
  1103. TraceMsg(
  1104. TRACEFLAG tfIn,
  1105. LPCSTR pszFormatIn,
  1106. ...
  1107. )
  1108. {
  1109. va_list valist;
  1110. if ( IsDebugFlagSet( tfIn ) )
  1111. {
  1112. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1113. LPTSTR pszBuf;
  1114. int cchSize = ARRAYSIZE( szBuf );
  1115. DebugInitializeBuffer( NULL, 0, __MODULE__, szBuf, &cchSize, &pszBuf );
  1116. #ifdef UNICODE
  1117. //
  1118. // Convert the format buffer to wide chars
  1119. //
  1120. WCHAR szFormat[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1121. mbstowcs( szFormat, pszFormatIn, strlen( pszFormatIn ) + 1 );
  1122. va_start( valist, pszFormatIn );
  1123. StringCchVPrintf( pszBuf, cchSize, szFormat, valist );
  1124. va_end( valist );
  1125. StringCchCat( pszBuf, cchSize, SZ_NEWLINE );
  1126. #else
  1127. va_start( valist, pszFormatIn );
  1128. StringCchVPrintf( pszBuf, cchSize, pszFormatIn, valist );
  1129. va_end( valist );
  1130. StringCchCat( pszBuf, cchSize, ASZ_NEWLINE );
  1131. #endif // UNICODE
  1132. DebugOutputString( szBuf );
  1133. } // if: flags set
  1134. } //*** TraceMsg() - ASCII
  1135. //////////////////////////////////////////////////////////////////////////////
  1136. //++
  1137. //
  1138. // UNICODE version
  1139. //
  1140. // void
  1141. // TraceMsg(
  1142. // TRACEFLAG tfIn,
  1143. // LPCWSTR pszFormatIn,
  1144. // ...
  1145. // )
  1146. //
  1147. // Description:
  1148. // If any of the flags in trace flags match any of the flags set in
  1149. // tfIn, the formatted string will be printed to the debugger.
  1150. //
  1151. // Arguments:
  1152. // tfIn - Flags to be checked.
  1153. // pszFormatIn - Formatted string to spewed to the debugger.
  1154. // ... - message arguments
  1155. //
  1156. // Return Values:
  1157. // None.
  1158. //
  1159. //--
  1160. //////////////////////////////////////////////////////////////////////////////
  1161. void
  1162. __cdecl
  1163. TraceMsg(
  1164. TRACEFLAG tfIn,
  1165. LPCWSTR pszFormatIn,
  1166. ...
  1167. )
  1168. {
  1169. va_list valist;
  1170. if ( IsDebugFlagSet( tfIn ) )
  1171. {
  1172. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1173. LPTSTR pszBuf;
  1174. int cchSize = ARRAYSIZE( szBuf );
  1175. DebugInitializeBuffer( NULL, 0, __MODULE__, szBuf, &cchSize, &pszBuf );
  1176. #ifndef UNICODE
  1177. //
  1178. // Convert the format buffer to ascii chars
  1179. //
  1180. CHAR szFormat[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1181. wcstombs( szFormat, pszFormatIn, StrLenW( pszFormatIn ) + 1 );
  1182. va_start( valist, pszFormatIn );
  1183. StringCchVPrintf( pszBuf, cchSize, szFormat, valist );
  1184. va_end( valist );
  1185. StringCchCat( pszBuf, cchSize, ASZ_NEWLINE );
  1186. #else
  1187. va_start( valist, pszFormatIn );
  1188. StringCchVPrintf( pszBuf, cchSize, pszFormatIn, valist );
  1189. va_end( valist );
  1190. StringCchCat( pszBuf, cchSize, SZ_NEWLINE );
  1191. #endif // UNICODE
  1192. DebugOutputString( szBuf );
  1193. } // if: flags set
  1194. } //*** TraceMsg() - UNICODE
  1195. //////////////////////////////////////////////////////////////////////////////
  1196. //++
  1197. //
  1198. // void
  1199. // TraceMessage(
  1200. // LPCTSTR pszFileIn,
  1201. // const int nLineIn,
  1202. // LPCTSTR pszModuleIn,
  1203. // TRACEFLAG tfIn,
  1204. // LPCTSTR pszFormatIn,
  1205. // ...
  1206. // )
  1207. //
  1208. // Description:
  1209. // If any of the flags in trace flags match any of the flags set in
  1210. // tfIn, the formatted string will be printed to the debugger
  1211. // along with the filename, line number and module name supplied. This is
  1212. // used by many of the debugging macros.
  1213. //
  1214. // Arguments:
  1215. // pszFileIn - Source filename.
  1216. // nLineIn - Source line number.
  1217. // pszModuleIn - Source module.
  1218. // tfIn - Flags to be checked.
  1219. // pszFormatIn - Formatted message to be printed.
  1220. // ... - message arguments
  1221. //
  1222. // Return Values:
  1223. // None.
  1224. //
  1225. //--
  1226. //////////////////////////////////////////////////////////////////////////////
  1227. void
  1228. __cdecl
  1229. TraceMessage(
  1230. LPCTSTR pszFileIn,
  1231. const int nLineIn,
  1232. LPCTSTR pszModuleIn,
  1233. TRACEFLAG tfIn,
  1234. LPCTSTR pszFormatIn,
  1235. ...
  1236. )
  1237. {
  1238. va_list valist;
  1239. if ( IsDebugFlagSet( tfIn ) )
  1240. {
  1241. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1242. INT cchSize = ARRAYSIZE( szBuf );
  1243. LPTSTR psz;
  1244. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &psz );
  1245. va_start( valist, pszFormatIn );
  1246. StringCchVPrintf( psz, cchSize, pszFormatIn, valist );
  1247. va_end( valist );
  1248. StringCchCat( psz, cchSize, SZ_NEWLINE );
  1249. DebugOutputString( szBuf );
  1250. } // if: flags set
  1251. } //*** TraceMessage()
  1252. //////////////////////////////////////////////////////////////////////////////
  1253. //++
  1254. //
  1255. // void
  1256. // TraceMessageDo(
  1257. // LPCTSTR pszFileIn,
  1258. // const int nLineIn,
  1259. // LPCTSTR pszModuleIn,
  1260. // TRACEFLAG tfIn,
  1261. // LPCTSTR pszFormatIn,
  1262. // LPCTSTR pszFuncIn,
  1263. // ...
  1264. // )
  1265. //
  1266. // Description:
  1267. // Works like TraceMessage() but takes has a function argument that is
  1268. // broken into call/result in the debug spew. This is called from the
  1269. // TraceMsgDo macro.
  1270. //
  1271. // Arguments:
  1272. // pszFileIn - Source filename.
  1273. // nLineIn - Source line number.
  1274. // pszModuleIn - Source module.
  1275. // tfIn - Flags to be checked
  1276. // pszFormatIn - Formatted return value string
  1277. // pszFuncIn - The string version of the function call.
  1278. // ... - Return value from call.
  1279. //
  1280. // Return Values:
  1281. // None.
  1282. //
  1283. //--
  1284. //////////////////////////////////////////////////////////////////////////////
  1285. void
  1286. __cdecl
  1287. TraceMessageDo(
  1288. LPCTSTR pszFileIn,
  1289. const int nLineIn,
  1290. LPCTSTR pszModuleIn,
  1291. TRACEFLAG tfIn,
  1292. LPCTSTR pszFormatIn,
  1293. LPCTSTR pszFuncIn,
  1294. ...
  1295. )
  1296. {
  1297. va_list valist;
  1298. if ( IsDebugFlagSet( tfIn ) )
  1299. {
  1300. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1301. INT cchSize = ARRAYSIZE( szBuf );
  1302. LPTSTR pszBuf;
  1303. int nLen;
  1304. LPCTSTR psz = pszFuncIn;
  1305. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &pszBuf );
  1306. //
  1307. // Prime the buffer
  1308. //
  1309. StringCchCopy( pszBuf, ARRAYSIZE(szBuf) - cchSize, TEXT("V ") );
  1310. pszBuf += 2;
  1311. cchSize += 2;
  1312. //
  1313. // Copy the l-var part of the expression
  1314. //
  1315. while ( *psz
  1316. && *psz != TEXT('=')
  1317. )
  1318. {
  1319. *pszBuf = *psz;
  1320. psz++;
  1321. pszBuf++;
  1322. } // while:
  1323. //
  1324. // Add the " = "
  1325. //
  1326. StringCchCopy( pszBuf, ARRAYSIZE(szBuf) - cchSize, TEXT(" = ") );
  1327. pszBuf += 3;
  1328. cchSize += 3;
  1329. //
  1330. // Add the formatted result
  1331. //
  1332. va_start( valist, pszFuncIn );
  1333. nLen = StringCchVPrintf( pszBuf, ARRAYSIZE(szBuf) - cchSize, pszFormatIn, valist );
  1334. va_end( valist );
  1335. StringCchCat( szBuf, ARRAYSIZE(szBuf), SZ_NEWLINE );
  1336. DebugOutputString( szBuf );
  1337. } // if: flags set
  1338. } //*** TraceMessageDo()
  1339. //////////////////////////////////////////////////////////////////////////////
  1340. //++
  1341. //
  1342. // void
  1343. // DebugMessage(
  1344. // LPCTSTR pszFileIn,
  1345. // const int nLineIn,
  1346. // LPCTSTR pszModuleIn,
  1347. // LPCTSTR pszFormatIn,
  1348. // ...
  1349. // )
  1350. //
  1351. // Description:
  1352. // Displays a message only in CHKed/DEBUG builds. Also appends the source
  1353. // filename, linenumber and module name to the ouput.
  1354. //
  1355. // Arguments:
  1356. // pszFileIn - Source filename.
  1357. // nLineIn - Source line number.
  1358. // pszModuleIn - Source module name.
  1359. // pszFormatIn - Formatted message to be printed.
  1360. // ... - message arguments
  1361. //
  1362. // Return Values:
  1363. // None.
  1364. //
  1365. //--
  1366. //////////////////////////////////////////////////////////////////////////////
  1367. void
  1368. __cdecl
  1369. DebugMessage(
  1370. LPCTSTR pszFileIn,
  1371. const int nLineIn,
  1372. LPCTSTR pszModuleIn,
  1373. LPCTSTR pszFormatIn,
  1374. ...
  1375. )
  1376. {
  1377. va_list valist;
  1378. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1379. INT cchSize = ARRAYSIZE( szBuf );
  1380. LPTSTR pszBuf;
  1381. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &pszBuf );
  1382. va_start( valist, pszFormatIn );
  1383. StringCchVPrintf( pszBuf, cchSize, pszFormatIn, valist );
  1384. va_end( valist );
  1385. StringCchCat( szBuf, ARRAYSIZE(szBuf), SZ_NEWLINE );
  1386. DebugOutputString( szBuf );
  1387. } //*** DebugMessage()
  1388. //////////////////////////////////////////////////////////////////////////////
  1389. //++
  1390. //
  1391. // void
  1392. // DebugMessageDo(
  1393. // LPCTSTR pszFileIn,
  1394. // const int nLineIn,
  1395. // LPCTSTR pszModuleIn,
  1396. // LPCTSTR pszFormatIn,
  1397. // LPCTSTR pszFuncIn,
  1398. // ...
  1399. // )
  1400. //
  1401. // Description:
  1402. // Just like TraceMessageDo() except in CHKed/DEBUG version it will
  1403. // always spew. The DebugMsgDo macros uses this function.
  1404. //
  1405. // Arguments:
  1406. // pszFileIn - Source filename.
  1407. // nLineIn - Source line number.
  1408. // pszModuleIn - Source module name.
  1409. // pszFormatIn - Formatted result message.
  1410. // pszFuncIn - The string version of the function call.
  1411. // ... - The return value of the function call.
  1412. //
  1413. // Return Values:
  1414. // None.
  1415. //
  1416. //--
  1417. //////////////////////////////////////////////////////////////////////////////
  1418. void
  1419. __cdecl
  1420. DebugMessageDo(
  1421. LPCTSTR pszFileIn,
  1422. const int nLineIn,
  1423. LPCTSTR pszModuleIn,
  1424. LPCTSTR pszFormatIn,
  1425. LPCTSTR pszFuncIn,
  1426. ...
  1427. )
  1428. {
  1429. va_list valist;
  1430. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1431. INT cchSize = ARRAYSIZE( szBuf );
  1432. LPTSTR pszBuf;
  1433. int nLen;
  1434. LPCTSTR psz = pszFuncIn;
  1435. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &pszBuf );
  1436. //
  1437. // Prime the buffer
  1438. //
  1439. StringCchCopy( pszBuf, ARRAYSIZE(szBuf) - cchSize, TEXT("V ") );
  1440. pszBuf += 2;
  1441. cchSize += 2;
  1442. //
  1443. // Copy the l-var part of the expression
  1444. //
  1445. while ( *psz
  1446. && *psz != TEXT('=')
  1447. )
  1448. {
  1449. *pszBuf = *psz;
  1450. psz++;
  1451. pszBuf++;
  1452. } // while:
  1453. //
  1454. // Add the " = "
  1455. //
  1456. StringCchCopy( pszBuf, ARRAYSIZE(szBuf) - cchSize, TEXT(" = ") );
  1457. pszBuf += 3;
  1458. cchSize += 3;
  1459. //
  1460. // Add the formatted result
  1461. //
  1462. va_start( valist, pszFuncIn );
  1463. nLen = StringCchVPrintf( pszBuf, ARRAYSIZE(szBuf) - cchSize, pszFormatIn, valist );
  1464. va_end( valist );
  1465. StringCchCat( pszBuf, ARRAYSIZE(szBuf), SZ_NEWLINE );
  1466. DebugOutputString( szBuf );
  1467. } //*** DebugMessageDo()
  1468. //////////////////////////////////////////////////////////////////////////////
  1469. //++
  1470. //
  1471. // ASCII version
  1472. //
  1473. // void
  1474. // DebugMsg(
  1475. // LPCSTR pszFormatIn,
  1476. // ...
  1477. // )
  1478. //
  1479. // Description:
  1480. // In CHKed/DEBUG version, prints a formatted message to the debugger. This
  1481. // is a NOP in REAIL version. Helpful for putting in quick debugging
  1482. // comments. Adds a newline.
  1483. //
  1484. // Arguments:
  1485. // pszFormatIn - Formatted message to be printed.
  1486. // ... - Arguments for the message.
  1487. //
  1488. // Return Values:
  1489. // None.
  1490. //
  1491. //--
  1492. //////////////////////////////////////////////////////////////////////////////
  1493. void
  1494. __cdecl
  1495. DebugMsg(
  1496. LPCSTR pszFormatIn,
  1497. ...
  1498. )
  1499. {
  1500. va_list valist;
  1501. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1502. int cchSize = ARRAYSIZE( szBuf );
  1503. LPTSTR pszBuf;
  1504. DebugInitializeBuffer( NULL, 0, __MODULE__, szBuf, &cchSize, &pszBuf );
  1505. // CScutaru 25-APR-2000:
  1506. // Added this assert. Maybe Geoff will figure out better what to do with this case.
  1507. Assert( pszFormatIn != NULL );
  1508. #ifdef UNICODE
  1509. //
  1510. // Convert the format buffer to wide chars
  1511. //
  1512. WCHAR szFormat[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1513. mbstowcs( szFormat, pszFormatIn, strlen( pszFormatIn ) + 1 );
  1514. va_start( valist, pszFormatIn );
  1515. StringCchVPrintf( pszBuf, cchSize, szFormat, valist );
  1516. va_end( valist );
  1517. StringCchCat( szBuf, ARRAYSIZE(szBuf), SZ_NEWLINE );
  1518. #else
  1519. va_start( valist, pszFormatIn );
  1520. StringCchVPrintf( pszBuf, cchSize, pszFormatIn, valist );
  1521. va_end( valist );
  1522. StringCchCat( szBuf, ARRAYSIZE(szBuf), ASZ_NEWLINE );
  1523. #endif // UNICODE
  1524. DebugOutputString( szBuf );
  1525. } //*** DebugMsg() - ASCII version
  1526. //////////////////////////////////////////////////////////////////////////////
  1527. //++
  1528. //
  1529. // UNICODE version
  1530. //
  1531. // void
  1532. // DebugMsg(
  1533. // LPCWSTR pszFormatIn,
  1534. // ...
  1535. // )
  1536. //
  1537. // Description:
  1538. // In CHKed/DEBUG version, prints a formatted message to the debugger. This
  1539. // is a NOP in REAIL version. Helpful for putting in quick debugging
  1540. // comments. Adds a newline.
  1541. //
  1542. // Arguments:
  1543. // pszFormatIn - Formatted message to be printed.
  1544. // ... - Arguments for the message.
  1545. //
  1546. // Return Values:
  1547. // None.
  1548. //
  1549. //--
  1550. //////////////////////////////////////////////////////////////////////////////
  1551. void
  1552. __cdecl
  1553. DebugMsg(
  1554. LPCWSTR pszFormatIn,
  1555. ...
  1556. )
  1557. {
  1558. va_list valist;
  1559. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1560. int cchSize = ARRAYSIZE( szBuf );
  1561. LPTSTR pszBuf;
  1562. DebugInitializeBuffer( NULL, 0, __MODULE__, szBuf, &cchSize, &pszBuf );
  1563. // CScutaru 25-APR-2000:
  1564. // Added this assert. Maybe Geoff will figure out better what to do with this case.
  1565. Assert( pszFormatIn != NULL );
  1566. #ifndef UNICODE
  1567. //
  1568. // Convert the format buffer to ascii chars
  1569. //
  1570. CHAR szFormat[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1571. wcstombs( szFormat, pszFormatIn, StrLenW( pszFormatIn ) + 1 );
  1572. va_start( valist, pszFormatIn );
  1573. StringCchVPrintf( pszBuf, cchSize, szFormat, valist );
  1574. va_end( valist );
  1575. StringCchCat( szBuf, ARRAYSIZE(szBuf), ASZ_NEWLINE );
  1576. #else
  1577. va_start( valist, pszFormatIn );
  1578. StringCchVPrintf( pszBuf, cchSize, pszFormatIn, valist );
  1579. va_end( valist );
  1580. StringCchCat( szBuf, ARRAYSIZE(szBuf), SZ_NEWLINE );
  1581. #endif // UNICODE
  1582. DebugOutputString( szBuf );
  1583. } //*** DebugMsg() - UNICODE version
  1584. //////////////////////////////////////////////////////////////////////////////
  1585. //++
  1586. //
  1587. // ASCII version
  1588. //
  1589. // void
  1590. // DebugMsgNoNewline(
  1591. // LPCSTR pszFormatIn,
  1592. // ...
  1593. // )
  1594. //
  1595. // Description:
  1596. // In CHKed/DEBUG version, prints a formatted message to the debugger. This
  1597. // is a NOP in REAIL version. Helpful for putting in quick debugging
  1598. // comments. Does not add a newline.
  1599. //
  1600. // Arguments:
  1601. // pszFormatIn - Formatted message to be printed.
  1602. // ... - Arguments for the message.
  1603. //
  1604. // Return Values:
  1605. // None.
  1606. //
  1607. //--
  1608. //////////////////////////////////////////////////////////////////////////////
  1609. void
  1610. __cdecl
  1611. DebugMsgNoNewline(
  1612. LPCSTR pszFormatIn,
  1613. ...
  1614. )
  1615. {
  1616. va_list valist;
  1617. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1618. int cchSize = ARRAYSIZE( szBuf );
  1619. LPTSTR pszBuf;
  1620. DebugInitializeBuffer( NULL, 0, __MODULE__, szBuf, &cchSize, &pszBuf );
  1621. // CScutaru 25-APR-2000:
  1622. // Added this assert. Maybe Geoff will figure out better what to do with this case.
  1623. Assert( pszFormatIn != NULL );
  1624. #ifdef UNICODE
  1625. //
  1626. // Convert the format buffer to wide chars
  1627. //
  1628. WCHAR szFormat[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1629. mbstowcs( szFormat, pszFormatIn, strlen( pszFormatIn ) + 1 );
  1630. va_start( valist, pszFormatIn );
  1631. StringCchVPrintf( pszBuf, cchSize, szFormat, valist);
  1632. va_end( valist );
  1633. #else
  1634. va_start( valist, pszFormatIn );
  1635. StringCchVPrintf( pszBuf, cchSize, pszFormatIn, valist);
  1636. va_end( valist );
  1637. #endif // UNICODE
  1638. DebugOutputString( szBuf );
  1639. } //*** DebugMsgNoNewline() - ASCII version
  1640. //////////////////////////////////////////////////////////////////////////////
  1641. //++
  1642. //
  1643. // UNICODE version
  1644. //
  1645. // void
  1646. // DebugMsgNoNewline(
  1647. // LPCWSTR pszFormatIn,
  1648. // ...
  1649. // )
  1650. //
  1651. // Description:
  1652. // In CHKed/DEBUG version, prints a formatted message to the debugger. This
  1653. // is a NOP in REAIL version. Helpful for putting in quick debugging
  1654. // comments. Does not add a newline.
  1655. //
  1656. // Arguments:
  1657. // pszFormatIn - Formatted message to be printed.
  1658. // ... - Arguments for the message.
  1659. //
  1660. // Return Values:
  1661. // None.
  1662. //
  1663. //--
  1664. //////////////////////////////////////////////////////////////////////////////
  1665. void
  1666. __cdecl
  1667. DebugMsgNoNewline(
  1668. LPCWSTR pszFormatIn,
  1669. ...
  1670. )
  1671. {
  1672. va_list valist;
  1673. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1674. int cchSize = ARRAYSIZE( szBuf );
  1675. LPTSTR pszBuf;
  1676. DebugInitializeBuffer( NULL, 0, __MODULE__, szBuf, &cchSize, &pszBuf );
  1677. // CScutaru 25-APR-2000:
  1678. // Added this assert. Maybe Geoff will figure out better what to do with this case.
  1679. Assert( pszFormatIn != NULL );
  1680. #ifndef UNICODE
  1681. //
  1682. // Convert the format buffer to ascii chars
  1683. //
  1684. CHAR szFormat[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1685. wcstombs( szFormat, pszFormatIn, StrLenW( pszFormatIn ) + 1 );
  1686. va_start( valist, pszFormatIn );
  1687. StringCchVPrintf( pszBuf, cchSize, szFormat, valist);
  1688. va_end( valist );
  1689. #else
  1690. va_start( valist, pszFormatIn );
  1691. StringCchVPrintf( pszBuf, cchSize, pszFormatIn, valist);
  1692. va_end( valist );
  1693. #endif // UNICODE
  1694. DebugOutputString( szBuf );
  1695. } //*** DebugMsgNoNewline() - UNICODE version
  1696. //////////////////////////////////////////////////////////////////////////////
  1697. //++
  1698. //
  1699. // BOOL
  1700. // AssertMessage(
  1701. // LPCTSTR pszFileIn,
  1702. // const int nLineIn,
  1703. // LPCTSTR pszModuleIn,
  1704. // LPCTSTR pszfnIn,
  1705. // BOOL fTrueIn
  1706. // )
  1707. //
  1708. // Description:
  1709. // Displays a dialog box with the failed assertion. User has the option of
  1710. // breaking. The Assert macro calls this to display assertion failures.
  1711. //
  1712. // Arguments:
  1713. // pszFileIn - Source filename.
  1714. // nLineIn - Source line number.
  1715. // pszModuleIn - Source module name.
  1716. // pszfnIn - String version of the expression to assert.
  1717. // fTrueIn - Result of the evaluation of the expression.
  1718. //
  1719. // Return Values:
  1720. // TRUE - Caller should call DEBUG_BREAK.
  1721. // FALSE - Caller should not call DEBUG_BREAK.
  1722. //
  1723. //--
  1724. //////////////////////////////////////////////////////////////////////////////
  1725. BOOL
  1726. AssertMessage(
  1727. LPCTSTR pszFileIn,
  1728. const int nLineIn,
  1729. LPCTSTR pszModuleIn,
  1730. LPCTSTR pszfnIn,
  1731. BOOL fTrueIn
  1732. )
  1733. {
  1734. BOOL fTrue = fTrueIn;
  1735. if ( ! fTrueIn )
  1736. {
  1737. LRESULT lResult;
  1738. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1739. int cchSize = ARRAYSIZE( szBuf );
  1740. LPTSTR pszBuf;
  1741. LPCTSTR pszfn = pszfnIn;
  1742. //
  1743. // Output a debug message.
  1744. //
  1745. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &pszBuf );
  1746. StringCchPrintf( pszBuf, cchSize, TEXT("ASSERT: %s") SZ_NEWLINE, pszfn );
  1747. DebugOutputString( szBuf );
  1748. //
  1749. // Display an assert message.
  1750. //
  1751. StringCchPrintf( szBuf,
  1752. ARRAYSIZE( szBuf ),
  1753. TEXT("Module:\t%s\t\n")
  1754. TEXT("Line:\t%u\t\n")
  1755. TEXT("File:\t%s\t\n\n")
  1756. TEXT("Assertion:\t%s\t\n\n")
  1757. TEXT("Do you want to break here?"),
  1758. pszModuleIn,
  1759. nLineIn,
  1760. pszFileIn,
  1761. pszfn
  1762. );
  1763. lResult = MessageBox( NULL, szBuf, TEXT("Assertion Failed!"), MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND );
  1764. if ( lResult == IDNO )
  1765. {
  1766. fTrue = TRUE; // don't break
  1767. } // if:
  1768. } // if: assert false
  1769. return ! fTrue;
  1770. } //*** AssertMessage()
  1771. //////////////////////////////////////////////////////////////////////////////
  1772. //++
  1773. //
  1774. // HRESULT
  1775. // TraceBOOL(
  1776. // LPCTSTR pszFileIn,
  1777. // const int nLineIn,
  1778. // LPCTSTR pszModuleIn,
  1779. // LPCTSTR pszfnIn,
  1780. // BOOL bIn,
  1781. // )
  1782. //
  1783. // Description:
  1784. // Traces BOOLs. A dialog will appear if the bIn is equal to FALSE (0).
  1785. // The dialog will ask if the user wants to break-in or continue
  1786. // execution. This is called from the TBOOL macro.
  1787. //
  1788. // Arguments:
  1789. // pszFileIn - Source filename.
  1790. // nLineIn - Source line number.
  1791. // pszModuleIn - Source module name.
  1792. // pszfnIn - String version of the function call.
  1793. // bIn - BOOL result of the function call.
  1794. //
  1795. // Return Values:
  1796. // Whatever bIn is.
  1797. //
  1798. //--
  1799. //////////////////////////////////////////////////////////////////////////////
  1800. BOOL
  1801. TraceBOOL(
  1802. LPCTSTR pszFileIn,
  1803. const int nLineIn,
  1804. LPCTSTR pszModuleIn,
  1805. LPCTSTR pszfnIn,
  1806. BOOL bIn
  1807. )
  1808. {
  1809. if ( !bIn )
  1810. {
  1811. LPTSTR pszBuf;
  1812. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1813. int cchSize = ARRAYSIZE( szBuf );
  1814. Assert( pszFileIn != NULL );
  1815. Assert( pszModuleIn != NULL );
  1816. Assert( pszfnIn != NULL );
  1817. //
  1818. // Spew it to the debugger.
  1819. //
  1820. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &pszBuf );
  1821. StringCchPrintf( pszBuf,
  1822. cchSize,
  1823. TEXT("*BOOL* b = %s (%#x)") SZ_NEWLINE,
  1824. BOOLTOSTRING( bIn ),
  1825. bIn
  1826. );
  1827. DebugOutputString( szBuf );
  1828. //
  1829. // If trace flag set, generate a pop-up.
  1830. //
  1831. if ( IsTraceFlagSet( mtfASSERT_HR ) )
  1832. {
  1833. LRESULT lResult;
  1834. StringCchPrintf( szBuf,
  1835. ARRAYSIZE( szBuf ),
  1836. TEXT("Module:\t%s\t\n")
  1837. TEXT("Line:\t%u\t\n")
  1838. TEXT("File:\t%s\t\n\n")
  1839. TEXT("Function:\t%s\t\n")
  1840. TEXT("b =\t%s (%#x)\t\n")
  1841. TEXT("Do you want to break here?"),
  1842. pszModuleIn,
  1843. nLineIn,
  1844. pszFileIn,
  1845. pszfnIn,
  1846. BOOLTOSTRING( bIn ),
  1847. bIn
  1848. );
  1849. lResult = MessageBox( NULL, szBuf, TEXT("Trace BOOL"), MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND );
  1850. if ( lResult == IDYES )
  1851. {
  1852. DEBUG_BREAK;
  1853. } // if: break
  1854. } // if: asserting on non-success
  1855. } // if: !bIn
  1856. return bIn;
  1857. } //*** TraceBOOL()
  1858. //////////////////////////////////////////////////////////////////////////////
  1859. //++
  1860. //
  1861. // HRESULT
  1862. // TraceHR(
  1863. // LPCTSTR pszFileIn,
  1864. // const int nLineIn,
  1865. // LPCTSTR pszModuleIn,
  1866. // LPCTSTR pszfnIn,
  1867. // HRESULT hrIn,
  1868. // BOOL fSuccessIn
  1869. // HRESULT hrIgnoreIn
  1870. // )
  1871. //
  1872. // Description:
  1873. // Traces HRESULT errors. A dialog will appear if the hrIn is not equal
  1874. // to S_OK. The dialog will ask if the user wants to break-in or continue
  1875. // execution. This is called from the THR macro.
  1876. //
  1877. // Arguments:
  1878. // pszFileIn - Source filename.
  1879. // nLineIn - Source line number.
  1880. // pszModuleIn - Source module name.
  1881. // pszfnIn - String version of the function call.
  1882. // hrIn - HRESULT of the function call.
  1883. // fSuccessIn - If TRUE, only if FAILED( hr ) is TRUE will it report.
  1884. // hrIgnoreIn - HRESULT to ignore.
  1885. //
  1886. // Return Values:
  1887. // Whatever hrIn is.
  1888. //
  1889. //--
  1890. //////////////////////////////////////////////////////////////////////////////
  1891. HRESULT
  1892. TraceHR(
  1893. LPCTSTR pszFileIn,
  1894. const int nLineIn,
  1895. LPCTSTR pszModuleIn,
  1896. LPCTSTR pszfnIn,
  1897. HRESULT hrIn,
  1898. BOOL fSuccessIn,
  1899. HRESULT hrIgnoreIn
  1900. )
  1901. {
  1902. HRESULT hr;
  1903. static LPCTSTR s_szS_FALSE = TEXT("S_FALSE");
  1904. // If ignoring success statuses and no failure occurred, set hrIn to
  1905. // something we always ignore (S_OK). This simplifies the if condition
  1906. // below.
  1907. if ( fSuccessIn && ! FAILED( hrIn ) )
  1908. {
  1909. hr = S_OK;
  1910. }
  1911. else
  1912. {
  1913. hr = hrIn;
  1914. }
  1915. if ( ( hr != S_OK )
  1916. && ( hr != hrIgnoreIn )
  1917. )
  1918. {
  1919. TCHAR szSymbolicName[ 64 ]; // random
  1920. DWORD cchSymbolicName;
  1921. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  1922. int cchSize = ARRAYSIZE( szBuf );
  1923. LPTSTR pszBuf;
  1924. LPTSTR pszMsgBuf;
  1925. LRESULT lResult;
  1926. bool fAllocatedMsg = false;
  1927. switch ( hr )
  1928. {
  1929. case S_FALSE:
  1930. pszMsgBuf = (LPTSTR) s_szS_FALSE;
  1931. //
  1932. // Find the symbolic name for this error.
  1933. //
  1934. cchSymbolicName = ARRAYSIZE( s_szS_FALSE );
  1935. Assert( cchSymbolicName <= ARRAYSIZE( szSymbolicName ) );
  1936. StringCchCopy( szSymbolicName, ARRAYSIZE(szSymbolicName), s_szS_FALSE );
  1937. break;
  1938. default:
  1939. FormatMessage(
  1940. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1941. | FORMAT_MESSAGE_FROM_SYSTEM,
  1942. NULL,
  1943. hr,
  1944. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
  1945. (LPTSTR) &pszMsgBuf,
  1946. 0,
  1947. NULL
  1948. );
  1949. //
  1950. // Make sure everything is cool before we blow up somewhere else.
  1951. //
  1952. if ( pszMsgBuf == NULL )
  1953. {
  1954. pszMsgBuf = TEXT("<unknown error code returned>");
  1955. } // if: status code not found
  1956. else
  1957. {
  1958. fAllocatedMsg = true;
  1959. } // else: found the status code
  1960. //
  1961. // Find the symbolic name for this error.
  1962. //
  1963. cchSymbolicName = ARRAYSIZE( szSymbolicName );
  1964. DebugFindWinerrorSymbolicName( hr, szSymbolicName, &cchSymbolicName );
  1965. Assert( cchSymbolicName != ARRAYSIZE( szSymbolicName ) );
  1966. break;
  1967. } // switch: hr
  1968. Assert( pszFileIn != NULL );
  1969. Assert( pszModuleIn != NULL );
  1970. Assert( pszfnIn != NULL );
  1971. //
  1972. // Spew it to the debugger.
  1973. //
  1974. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &pszBuf );
  1975. StringCchPrintf( pszBuf,
  1976. cchSize,
  1977. TEXT("*HRESULT* hr = 0x%08x (%s) - %s") SZ_NEWLINE,
  1978. hr,
  1979. szSymbolicName,
  1980. pszMsgBuf
  1981. );
  1982. DebugOutputString( szBuf );
  1983. //
  1984. // If trace flag set, generate a pop-up.
  1985. //
  1986. if ( IsTraceFlagSet( mtfASSERT_HR ) )
  1987. {
  1988. StringCchPrintf( szBuf,
  1989. ARRAYSIZE( szBuf ),
  1990. TEXT("Module:\t%s\t\n")
  1991. TEXT("Line:\t%u\t\n")
  1992. TEXT("File:\t%s\t\n\n")
  1993. TEXT("Function:\t%s\t\n")
  1994. TEXT("hr =\t0x%08x (%s) - %s\t\n")
  1995. TEXT("Do you want to break here?"),
  1996. pszModuleIn,
  1997. nLineIn,
  1998. pszFileIn,
  1999. pszfnIn,
  2000. hr,
  2001. szSymbolicName,
  2002. pszMsgBuf
  2003. );
  2004. lResult = MessageBox( NULL, szBuf, TEXT("Trace HRESULT"), MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND );
  2005. if ( lResult == IDYES )
  2006. {
  2007. DEBUG_BREAK;
  2008. } // if: break
  2009. } // if: asserting on non-success HRESULTs
  2010. if ( fAllocatedMsg )
  2011. {
  2012. HeapFree( GetProcessHeap(), 0, pszMsgBuf );
  2013. } // if: message buffer was allocated by FormateMessage()
  2014. } // if: hr != S_OK
  2015. return hrIn;
  2016. } //*** TraceHR()
  2017. //////////////////////////////////////////////////////////////////////////////
  2018. //++
  2019. //
  2020. // ULONG
  2021. // TraceWin32(
  2022. // LPCTSTR pszFileIn,
  2023. // const int nLineIn,
  2024. // LPCTSTR pszModuleIn,
  2025. // LPCTSTR pszfnIn,
  2026. // ULONG ulErrIn
  2027. // )
  2028. //
  2029. // Description:
  2030. // Traces WIN32 errors. A dialog will appear is the ulErrIn is not equal
  2031. // to ERROR_SUCCESS. The dialog will ask if the user wants to break-in or
  2032. // continue execution.
  2033. //
  2034. // Arguments:
  2035. // pszFileIn - Source filename.
  2036. // nLineIn - Source line number.
  2037. // pszModuleIn - Source module name.
  2038. // pszfnIn - String version of the function call.
  2039. // ulErrIn - Error code to check.
  2040. // ulErrIgnoreIn - Error code to ignore.
  2041. //
  2042. // Return Values:
  2043. // Whatever ulErrIn is.
  2044. //
  2045. //--
  2046. //////////////////////////////////////////////////////////////////////////////
  2047. ULONG
  2048. TraceWin32(
  2049. LPCTSTR pszFileIn,
  2050. const int nLineIn,
  2051. LPCTSTR pszModuleIn,
  2052. LPCTSTR pszfnIn,
  2053. ULONG ulErrIn,
  2054. ULONG ulErrIgnoreIn
  2055. )
  2056. {
  2057. if ( ( ulErrIn != ERROR_SUCCESS )
  2058. && ( ulErrIn != ulErrIgnoreIn ) )
  2059. {
  2060. TCHAR szSymbolicName[ 64 ]; // random
  2061. DWORD cchSymbolicName;
  2062. TCHAR szBuf[ cchDEBUG_OUTPUT_BUFFER_SIZE ];
  2063. int cchSize = ARRAYSIZE( szBuf );
  2064. LPTSTR pszBuf;
  2065. LPTSTR pszMsgBuf;
  2066. LRESULT lResult;
  2067. bool fAllocatedMsg = false;
  2068. FormatMessage(
  2069. FORMAT_MESSAGE_ALLOCATE_BUFFER
  2070. | FORMAT_MESSAGE_FROM_SYSTEM,
  2071. NULL,
  2072. ulErrIn,
  2073. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
  2074. (LPTSTR) &pszMsgBuf,
  2075. 0,
  2076. NULL
  2077. );
  2078. //
  2079. // Make sure everything is cool before we blow up somewhere else.
  2080. //
  2081. if ( pszMsgBuf == NULL )
  2082. {
  2083. pszMsgBuf = TEXT("<unknown error code returned>");
  2084. } // if: status code not found
  2085. else
  2086. {
  2087. fAllocatedMsg = true;
  2088. } // else: found the status code
  2089. Assert( pszFileIn != NULL );
  2090. Assert( pszModuleIn != NULL );
  2091. Assert( pszfnIn != NULL );
  2092. //
  2093. // Find the symbolic name for this error.
  2094. //
  2095. cchSymbolicName = ARRAYSIZE( szSymbolicName );
  2096. DebugFindWinerrorSymbolicName( ulErrIn, szSymbolicName, &cchSymbolicName );
  2097. Assert( cchSymbolicName != ARRAYSIZE( szSymbolicName ) );
  2098. //
  2099. // Spew it to the debugger.
  2100. //
  2101. DebugInitializeBuffer( pszFileIn, nLineIn, pszModuleIn, szBuf, &cchSize, &pszBuf );
  2102. StringCchPrintf( pszBuf,
  2103. cchSize,
  2104. TEXT("*WIN32Err* ulErr = %u (%s) - %s") SZ_NEWLINE,
  2105. ulErrIn,
  2106. szSymbolicName,
  2107. pszMsgBuf
  2108. );
  2109. DebugOutputString( szBuf );
  2110. //
  2111. // If trace flag set, invoke a pop-up.
  2112. //
  2113. if ( IsTraceFlagSet( mtfASSERT_HR ) )
  2114. {
  2115. StringCchPrintf( szBuf,
  2116. ARRAYSIZE( szBuf ),
  2117. TEXT("Module:\t%s\t\n")
  2118. TEXT("Line:\t%u\t\n")
  2119. TEXT("File:\t%s\t\n\n")
  2120. TEXT("Function:\t%s\t\n")
  2121. TEXT("ulErr =\t%u (%s) - %s\t\n")
  2122. TEXT("Do you want to break here?"),
  2123. pszModuleIn,
  2124. nLineIn,
  2125. pszFileIn,
  2126. pszfnIn,
  2127. ulErrIn,
  2128. szSymbolicName,
  2129. pszMsgBuf
  2130. );
  2131. lResult = MessageBox( NULL, szBuf, TEXT("Trace Win32"), MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND );
  2132. if ( lResult == IDYES )
  2133. {
  2134. DEBUG_BREAK;
  2135. } // if: break
  2136. } // if: asserting on non-success status codes
  2137. if ( fAllocatedMsg )
  2138. {
  2139. HeapFree( GetProcessHeap(), 0, pszMsgBuf );
  2140. } // if: message buffer was allocated by FormateMessage()
  2141. } // if: ulErrIn != ERROR_SUCCESS && != ulErrIgnoreIn
  2142. return ulErrIn;
  2143. } //*** TraceWin32()
  2144. //////////////////////////////////////////////////////////////////////////////
  2145. //++
  2146. //
  2147. // HRESULT
  2148. // HrTraceLogOpen( void )
  2149. //
  2150. // Description:
  2151. // This function:
  2152. // - initializes the trace log critical section
  2153. // - enters the trace log critical section assuring only one thread is
  2154. // writing to the trace log at a time
  2155. // - creates the directory tree to the trace log file (if needed)
  2156. // - initializes the trace log file by:
  2157. // - creating a new trace log file if one doesn't exist.
  2158. // - opens an existing trace log file (for append)
  2159. // - appends a time/date stamp that the trace log was (re)opened.
  2160. //
  2161. // Use HrTraceLogClose() to exit the log critical section.
  2162. //
  2163. // If there is a failure inside this function, the trace log critical
  2164. // section will be released before returning.
  2165. //
  2166. // Arguments:
  2167. // None.
  2168. //
  2169. // Return Values:
  2170. // S_OK - log critical section held and trace log open successfully
  2171. // Otherwize HRESULT error code.
  2172. //
  2173. //--
  2174. //////////////////////////////////////////////////////////////////////////////
  2175. HRESULT
  2176. HrTraceLogOpen( void )
  2177. {
  2178. TCHAR szFilePath[ MAX_PATH ];
  2179. TCHAR szModulePath[ MAX_PATH ];
  2180. CHAR szBuffer[ TRACE_OUTPUT_BUFFER_SIZE ];
  2181. DWORD dwWritten;
  2182. BOOL fReturn;
  2183. HRESULT hr;
  2184. SYSTEMTIME SystemTime;
  2185. //
  2186. // Create a critical section to prevent lines from being fragmented.
  2187. //
  2188. if ( g_pcsTraceLog == NULL )
  2189. {
  2190. PCRITICAL_SECTION pNewCritSect =
  2191. (PCRITICAL_SECTION) HeapAlloc( GetProcessHeap(), 0, sizeof( CRITICAL_SECTION ) );
  2192. if ( pNewCritSect == NULL )
  2193. {
  2194. DebugMsg( "DEBUG: Out of Memory. Tracing disabled." );
  2195. hr = E_OUTOFMEMORY;
  2196. goto Cleanup;
  2197. } // if: creation failed
  2198. InitializeCriticalSection( pNewCritSect );
  2199. // Make sure we only have one trace log critical section
  2200. InterlockedCompareExchangePointer( (PVOID *) &g_pcsTraceLog, pNewCritSect, 0 );
  2201. if ( g_pcsTraceLog != pNewCritSect )
  2202. {
  2203. DebugMsg( "DEBUG: Another thread already created the CS. Deleting this one." );
  2204. DeleteCriticalSection( pNewCritSect );
  2205. HeapFree( GetProcessHeap(), 0, pNewCritSect );
  2206. } // if: already have another critical section
  2207. } // if: no critical section created yet
  2208. Assert( g_pcsTraceLog != NULL );
  2209. EnterCriticalSection( g_pcsTraceLog );
  2210. //
  2211. // Make sure the trace log file is open
  2212. //
  2213. if ( g_hTraceLogFile == INVALID_HANDLE_VALUE )
  2214. {
  2215. DWORD dwLen;
  2216. LPTSTR psz;
  2217. //
  2218. // Create the directory tree
  2219. //
  2220. ExpandEnvironmentStrings( TEXT("%windir%\\debug"), szFilePath, MAX_PATH );
  2221. //
  2222. // Add filename
  2223. //
  2224. dwLen = GetModuleFileName( g_hInstance, szModulePath, ARRAYSIZE( szModulePath ) );
  2225. Assert( dwLen != 0 );
  2226. StringCchCopy( &szModulePath[ dwLen - 3 ], 4, TEXT("log") );
  2227. psz = StrRChr( szModulePath, &szModulePath[ dwLen ], TEXT('\\') );
  2228. Assert( psz != NULL );
  2229. if ( psz == NULL )
  2230. {
  2231. hr = E_POINTER;
  2232. goto Error;
  2233. }
  2234. StringCchCat( szFilePath, ARRAYSIZE(szFilePath), psz );
  2235. //
  2236. // Create it
  2237. //
  2238. g_hTraceLogFile = CreateFile( szFilePath,
  2239. GENERIC_WRITE,
  2240. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2241. NULL,
  2242. OPEN_ALWAYS,
  2243. FILE_FLAG_WRITE_THROUGH,
  2244. NULL
  2245. );
  2246. if ( g_hTraceLogFile == INVALID_HANDLE_VALUE )
  2247. {
  2248. if ( !( g_tfModule & mtfOUTPUTTODISK ) )
  2249. {
  2250. DebugMsg( "*ERROR* Failed to create trace log at %s", szFilePath );
  2251. } // if: not tracing to disk
  2252. DWORD dwErr = TW32( GetLastError( ) );
  2253. hr = HRESULT_FROM_WIN32( dwErr );
  2254. goto Error;
  2255. } // if: failed
  2256. // Seek to the end
  2257. SetFilePointer( g_hTraceLogFile, 0, NULL, FILE_END );
  2258. //
  2259. // Write the time/date the trace log was (re)openned.
  2260. //
  2261. GetLocalTime( &SystemTime );
  2262. StringCbPrintfA( szBuffer,
  2263. ARRAYSIZE( szBuffer ),
  2264. "*" ASZ_NEWLINE
  2265. "* %02u/%02u/%04u %02u:%02u:%02u.%03u" ASZ_NEWLINE
  2266. "*" ASZ_NEWLINE,
  2267. SystemTime.wMonth,
  2268. SystemTime.wDay,
  2269. SystemTime.wYear,
  2270. SystemTime.wHour,
  2271. SystemTime.wMinute,
  2272. SystemTime.wSecond,
  2273. SystemTime.wMilliseconds
  2274. );
  2275. fReturn = WriteFile( g_hTraceLogFile, szBuffer, strlen(szBuffer), &dwWritten, NULL );
  2276. if ( ! fReturn )
  2277. {
  2278. DWORD dwErr = TW32( GetLastError( ) );
  2279. hr = HRESULT_FROM_WIN32( dwErr );
  2280. goto Error;
  2281. } // if: failed
  2282. DebugMsg( "DEBUG: Created trace log at %s", szFilePath );
  2283. } // if: file not already openned
  2284. hr = S_OK;
  2285. Cleanup:
  2286. return hr;
  2287. Error:
  2288. DebugMsg( "HrTaceLogOpen: Failed hr = 0x%08x", hr );
  2289. if ( g_hTraceLogFile != INVALID_HANDLE_VALUE )
  2290. {
  2291. CloseHandle( g_hTraceLogFile );
  2292. g_hTraceLogFile = INVALID_HANDLE_VALUE;
  2293. } // if: handle was open
  2294. LeaveCriticalSection( g_pcsTraceLog );
  2295. goto Cleanup;
  2296. } //*** HrTraceLogOpen()
  2297. //////////////////////////////////////////////////////////////////////////////
  2298. //++
  2299. //
  2300. // HRESULT
  2301. // HrTraceLogClose( void )
  2302. //
  2303. // Description:
  2304. // This actually just leaves the log critical section.
  2305. //
  2306. // Arguments:
  2307. // None.
  2308. //
  2309. // Return Values:
  2310. // S_OK always.
  2311. //
  2312. //--
  2313. //////////////////////////////////////////////////////////////////////////////
  2314. HRESULT
  2315. HrTraceLogClose( void )
  2316. {
  2317. Assert( g_pcsTraceLog != NULL );
  2318. LeaveCriticalSection( g_pcsTraceLog );
  2319. return S_OK;
  2320. } //*** HrTraceLogClose()
  2321. //////////////////////////////////////////////////////////////////////////////
  2322. //++
  2323. //
  2324. // ASCII
  2325. //
  2326. // void
  2327. // TraceLogMsgNoNewline(
  2328. // LPCSTR pszFormat,
  2329. // ...
  2330. // )
  2331. //
  2332. // Description:
  2333. // Writes a message to the trace log file without adding a newline.
  2334. //
  2335. // Arguments:
  2336. // pszFormat - A printf format string to be printed.
  2337. // ,,, - Arguments for the printf string.
  2338. //
  2339. // Return Values:
  2340. // None.
  2341. //
  2342. //--
  2343. //////////////////////////////////////////////////////////////////////////////
  2344. void
  2345. __cdecl
  2346. TraceLogMsgNoNewline(
  2347. LPCSTR pszFormat,
  2348. ...
  2349. )
  2350. {
  2351. va_list valist;
  2352. CHAR szBuf[ TRACE_OUTPUT_BUFFER_SIZE ];
  2353. DWORD dwWritten;
  2354. HRESULT hr;
  2355. #ifdef UNICODE
  2356. WCHAR szFormat[ TRACE_OUTPUT_BUFFER_SIZE ];
  2357. WCHAR szTmpBuf[ TRACE_OUTPUT_BUFFER_SIZE ];
  2358. mbstowcs( szFormat, pszFormat, strlen( pszFormat ) + 1 );
  2359. va_start( valist, pszFormat );
  2360. StringCchVPrintf( szTmpBuf, ARRAYSIZE(szTmpBuf), szFormat, valist);
  2361. va_end( valist );
  2362. dwWritten = wcstombs( szBuf, szTmpBuf, wcslen( szTmpBuf ) + 1 );
  2363. if ( dwWritten == - 1 )
  2364. {
  2365. dwWritten = strlen( szBuf );
  2366. } // if: bad character found
  2367. #else
  2368. va_start( valist, pszFormat );
  2369. StringCchVPrintf( szBuf, ARRAYSIZE(szBuf), pszFormat, valist);
  2370. dwWritten = lstrlen( szBuf );
  2371. va_end( valist );
  2372. #endif // UNICODE
  2373. hr = HrTraceLogOpen();
  2374. if ( hr != S_OK )
  2375. {
  2376. return;
  2377. } // if: failed
  2378. WriteFile( g_hTraceLogFile, szBuf, dwWritten, &dwWritten, NULL );
  2379. HrTraceLogClose();
  2380. } //*** TraceLogMsgNoNewline() ASCII
  2381. //////////////////////////////////////////////////////////////////////////////
  2382. //++
  2383. //
  2384. // UNICODE
  2385. //
  2386. // void
  2387. // TraceLogMsgNoNewline(
  2388. // LPCWSTR pszFormat,
  2389. // ...
  2390. // )
  2391. //
  2392. // Description:
  2393. // Writes a message to the trace log file without adding a newline.
  2394. //
  2395. // Arguments:
  2396. // pszFormat - A printf format string to be printed.
  2397. // ,,, - Arguments for the printf string.
  2398. //
  2399. // Return Values:
  2400. // None.
  2401. //
  2402. //--
  2403. //////////////////////////////////////////////////////////////////////////////
  2404. void
  2405. __cdecl
  2406. TraceLogMsgNoNewline(
  2407. LPCWSTR pszFormat,
  2408. ...
  2409. )
  2410. {
  2411. va_list valist;
  2412. CHAR szBuf[ TRACE_OUTPUT_BUFFER_SIZE ];
  2413. DWORD dwWritten;
  2414. HRESULT hr;
  2415. #ifdef UNICODE
  2416. WCHAR szTmpBuf[ TRACE_OUTPUT_BUFFER_SIZE ];
  2417. va_start( valist, pszFormat );
  2418. StringCchPrintf( szTmpBuf, ARRAYSIZE(szTmpBuf), pszFormat, valist);
  2419. va_end( valist );
  2420. dwWritten = wcstombs( szBuf, szTmpBuf, wcslen( szTmpBuf ) + 1 );
  2421. if ( dwWritten == -1 )
  2422. {
  2423. dwWritten = strlen( szBuf );
  2424. } // if: bad character found
  2425. #else
  2426. CHAR szFormat[ TRACE_OUTPUT_BUFFER_SIZE ];
  2427. wcstombs( szFormat, pszFormat, wcslen( pszFormat ) + 1 );
  2428. va_start( valist, pszFormat );
  2429. StringCchPrintf( szBuf, ARRAYSIZE(szBuf), szFormat, valist);
  2430. dwWritten = lstrlen( szBuf );
  2431. va_end( valist );
  2432. #endif // UNICODE
  2433. hr = HrTraceLogOpen();
  2434. if ( hr != S_OK )
  2435. {
  2436. return;
  2437. } // if: failed
  2438. WriteFile( g_hTraceLogFile, szBuf, dwWritten, &dwWritten, NULL );
  2439. HrTraceLogClose();
  2440. } //*** TraceLogMsgNoNewline() UNICODE
  2441. //****************************************************************************
  2442. //****************************************************************************
  2443. //
  2444. // Memory allocation and tracking
  2445. //
  2446. //****************************************************************************
  2447. //****************************************************************************
  2448. //
  2449. // This is a private structure and should not be known to the application.
  2450. //
  2451. typedef struct MEMORYBLOCK
  2452. {
  2453. EMEMORYBLOCKTYPE mbtType; // What type of memory this is tracking
  2454. union
  2455. {
  2456. void * pvMem; // pointer/object to allocated memory to track
  2457. BSTR bstr; // BSTR to allocated memory
  2458. };
  2459. DWORD dwBytes; // size of the memory
  2460. LPCTSTR pszFile; // source filename where memory was allocated
  2461. int nLine; // source line number where memory was allocated
  2462. LPCTSTR pszModule; // source module name where memory was allocated
  2463. LPCTSTR pszComment; // optional comments about the memory
  2464. MEMORYBLOCK * pNext; // pointer to next MEMORYBLOCK structure
  2465. } MEMORYBLOCK;
  2466. typedef struct MEMORYBLOCKLIST
  2467. {
  2468. LONG lSpinLock; // Spin lock protecting the list
  2469. MEMORYBLOCK * pmbList; // List of MEMORYBLOCKs.
  2470. BOOL fDeadList; // The list is dead.
  2471. } MEMORYBLOCKLIST;
  2472. //////////////////////////////////////////////////////////////////////////////
  2473. //++
  2474. //
  2475. // void
  2476. // DebugMemorySpew(
  2477. // MEMORYBLOCK * pmb,
  2478. // LPTSTR pszMessage
  2479. // )
  2480. //
  2481. // Description:
  2482. // Displays a message about the memory block.
  2483. //
  2484. // Arugments:
  2485. // pmb - pointer to MEMORYBLOCK desciptor.
  2486. // pszMessage - message to display
  2487. //
  2488. // Return Values:
  2489. // None.
  2490. //
  2491. //--
  2492. //////////////////////////////////////////////////////////////////////////////
  2493. void
  2494. DebugMemorySpew(
  2495. MEMORYBLOCK * pmb,
  2496. LPTSTR pszMessage
  2497. )
  2498. {
  2499. switch ( pmb->mbtType )
  2500. {
  2501. case mmbtMEMORYALLOCATION:
  2502. DebugMessage( pmb->pszFile,
  2503. pmb->nLine,
  2504. pmb->pszModule,
  2505. TEXT("%s 0x%08x (%u bytes) - %s"),
  2506. pszMessage,
  2507. pmb->pvMem,
  2508. pmb->dwBytes,
  2509. pmb->pszComment
  2510. );
  2511. break;
  2512. default:
  2513. DebugMessage( pmb->pszFile,
  2514. pmb->nLine,
  2515. pmb->pszModule,
  2516. TEXT("%s 0x%08x - %s"),
  2517. pszMessage,
  2518. pmb->pvMem,
  2519. pmb->pszComment
  2520. );
  2521. break;
  2522. } // switch: pmb->mbtType
  2523. } //*** DebugMemorySpew()
  2524. //////////////////////////////////////////////////////////////////////////////
  2525. //++
  2526. //
  2527. // void *
  2528. // DebugMemoryAdd(
  2529. // EMEMORYBLOCKTYPE mbtType,
  2530. // void * hMemIn,
  2531. // LPCTSTR pszFileIn,
  2532. // const int nLineIn,
  2533. // LPCTSTR pszModuleIn,
  2534. // DWORD dwBytesIn,
  2535. // LPCTSTR pszCommentIn
  2536. // )
  2537. //
  2538. // Description:
  2539. // Adds memory to be tracked to the memory tracking list.
  2540. //
  2541. // Arguments:
  2542. // mbtType - Type of memory block of the memory to track.
  2543. // hMemIn - Pointer to memory to track.
  2544. // pszFileIn - Source filename where memory was allocated.
  2545. // nLineIn - Source line number where memory was allocated.
  2546. // pszModuleIn - Source module where memory was allocated.
  2547. // dwBytesIn - Size of the allocation.
  2548. // pszCommentIn - Optional comments about the memory.
  2549. //
  2550. // Return Values:
  2551. // Whatever was in pvMemIn.
  2552. //
  2553. //--
  2554. //////////////////////////////////////////////////////////////////////////////
  2555. void *
  2556. DebugMemoryAdd(
  2557. EMEMORYBLOCKTYPE mbtType,
  2558. void * pvMemIn,
  2559. LPCTSTR pszFileIn,
  2560. const int nLineIn,
  2561. LPCTSTR pszModuleIn,
  2562. DWORD dwBytesIn,
  2563. LPCTSTR pszCommentIn
  2564. )
  2565. {
  2566. if ( pvMemIn != NULL )
  2567. {
  2568. MEMORYBLOCK * pmbHead = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  2569. MEMORYBLOCK * pmb = (MEMORYBLOCK *) HeapAlloc( GetProcessHeap(), 0, sizeof( MEMORYBLOCK ) );
  2570. if ( pmb == NULL )
  2571. {
  2572. HeapFree( GetProcessHeap(), 0, pvMemIn );
  2573. return NULL;
  2574. } // if: memory block allocation failed
  2575. pmb->mbtType = mbtType;
  2576. pmb->pvMem = pvMemIn;
  2577. pmb->dwBytes = dwBytesIn;
  2578. pmb->pszFile = pszFileIn;
  2579. pmb->nLine = nLineIn;
  2580. pmb->pszModule = pszModuleIn;
  2581. pmb->pszComment = pszCommentIn;
  2582. pmb->pNext = pmbHead;
  2583. TlsSetValue( g_TraceMemoryIndex, pmb );
  2584. //
  2585. // Spew if needed
  2586. //
  2587. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  2588. {
  2589. DebugMemorySpew( pmb, TEXT("Alloced") );
  2590. } // if: tracing
  2591. } // if: something to trace
  2592. return pvMemIn;
  2593. } //*** DebugMemoryAdd()
  2594. //////////////////////////////////////////////////////////////////////////////
  2595. //++
  2596. //
  2597. // void
  2598. // DebugMemoryDelete(
  2599. // EMEMORYBLOCKTYPE mbtTypeIn,
  2600. // void * pvMemIn
  2601. // LPCTSTR pszFileIn,
  2602. // const int nLineIn,
  2603. // LPCTSTR pszModuleIn,
  2604. // BOOL fClobberIn
  2605. // )
  2606. //
  2607. // Description:
  2608. // Removes a MEMORYBLOCK to the memory tracking list.
  2609. //
  2610. // Arguments:
  2611. // mbtTypeIn - Memory block type.
  2612. // pvMemIn - Pointer to memory block to stop tracking.
  2613. // pszFileIn - Source file that is deleteing.
  2614. // nLineIn - Source line number that is deleteing.
  2615. // pszModuleIn - Source module name that is deleteing.
  2616. // fClobberIn - True is memory should be scrambled.
  2617. //
  2618. // Return Values:
  2619. // None.
  2620. //
  2621. //--
  2622. //////////////////////////////////////////////////////////////////////////////
  2623. void
  2624. DebugMemoryDelete(
  2625. EMEMORYBLOCKTYPE mbtTypeIn,
  2626. void * pvMemIn,
  2627. LPCTSTR pszFileIn,
  2628. const int nLineIn,
  2629. LPCTSTR pszModuleIn,
  2630. BOOL fClobberIn
  2631. )
  2632. {
  2633. if ( pvMemIn != NULL )
  2634. {
  2635. MEMORYBLOCK * pmbHead = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  2636. MEMORYBLOCK * pmbLast = NULL;
  2637. //
  2638. // Find the memory in the memory block list
  2639. //
  2640. if ( mbtTypeIn == mmbtMEMORYALLOCATION )
  2641. {
  2642. while ( pmbHead != NULL
  2643. && !( pmbHead->pvMem == pvMemIn
  2644. && pmbHead->mbtType == mbtTypeIn
  2645. )
  2646. )
  2647. {
  2648. AssertMsg( !( pmbHead->pvMem == pvMemIn && pmbHead->mbtType == mmbtSYSALLOCSTRING ),
  2649. "Should be freed by SysAllocFreeString()." );
  2650. pmbLast = pmbHead;
  2651. pmbHead = pmbLast->pNext;
  2652. } // while: finding the entry in the list
  2653. } // if: memory allocation type
  2654. else if ( mbtTypeIn == mmbtSYSALLOCSTRING )
  2655. {
  2656. while ( pmbHead != NULL
  2657. && !( pmbHead->pvMem == pvMemIn
  2658. && pmbHead->mbtType == mbtTypeIn
  2659. )
  2660. )
  2661. {
  2662. AssertMsg( !( pmbHead->pvMem == pvMemIn && pmbHead->mbtType == mmbtMEMORYALLOCATION ),
  2663. "Should be freed by TraceFree()." );
  2664. pmbLast = pmbHead;
  2665. pmbHead = pmbLast->pNext;
  2666. } // while: finding the entry in the list
  2667. } // if: SysAllocString type
  2668. else if ( mbtTypeIn == mmbtUNKNOWN )
  2669. {
  2670. while ( pmbHead != NULL
  2671. && pmbHead->pvMem != pvMemIn
  2672. )
  2673. {
  2674. pmbLast = pmbHead;
  2675. pmbHead = pmbLast->pNext;
  2676. } // while: finding the entry in the list
  2677. } // if: don't care what type
  2678. else
  2679. {
  2680. while ( pmbHead != NULL
  2681. && !( pmbHead->pvMem == pvMemIn
  2682. && pmbHead->mbtType == mbtTypeIn
  2683. )
  2684. )
  2685. {
  2686. pmbLast = pmbHead;
  2687. pmbHead = pmbLast->pNext;
  2688. } // while: finding the entry in the list
  2689. } // else: other types, but they must match
  2690. if ( pmbHead != NULL )
  2691. {
  2692. //
  2693. // Remove the memory block from the tracking list
  2694. //
  2695. if ( pmbLast != NULL )
  2696. {
  2697. pmbLast->pNext = pmbHead->pNext;
  2698. } // if: not first entry
  2699. else
  2700. {
  2701. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  2702. } // else: first entry
  2703. //
  2704. // Spew if needed
  2705. //
  2706. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  2707. {
  2708. DebugMemorySpew( pmbHead, TEXT("Freeing") );
  2709. } // if: tracing
  2710. //
  2711. // Nuke the memory
  2712. //
  2713. if ( fClobberIn
  2714. && pmbHead->mbtType == mmbtMEMORYALLOCATION
  2715. )
  2716. {
  2717. memset( pmbHead->pvMem, 0xFA, pmbHead->dwBytes );
  2718. } // if: fixed memory
  2719. //
  2720. // Nuke the memory tracking block
  2721. //
  2722. memset( pmbHead, 0xFB, sizeof( MEMORYBLOCK ) );
  2723. HeapFree( GetProcessHeap(), 0, pmbHead );
  2724. } // if: found entry
  2725. else
  2726. {
  2727. DebugMessage( pszFileIn,
  2728. nLineIn,
  2729. pszModuleIn,
  2730. TEXT("***** Attempted to free 0x%08x not owned by thread (ThreadID = 0x%08x) *****"),
  2731. pvMemIn,
  2732. GetCurrentThreadId()
  2733. );
  2734. } // else: entry not found
  2735. } // if: something to delete
  2736. } //*** DebugMemoryDelete()
  2737. //////////////////////////////////////////////////////////////////////////////
  2738. //++
  2739. //
  2740. // void *
  2741. // DebugAlloc(
  2742. // LPCTSTR pszFileIn,
  2743. // const int nLineIn,
  2744. // LPCTSTR pszModuleIn,
  2745. // UINT uFlagsIn,
  2746. // DWORD dwBytesIn,
  2747. // LPCTSTR pszCommentIn
  2748. // )
  2749. //
  2750. // Description:
  2751. // Replacement for LocalAlloc, GlobalAlloc, and malloc for CHKed/DEBUG
  2752. // builds. Memoryallocations be tracked. Use the TraceAlloc macro to make
  2753. // memoryallocations switch in RETAIL.
  2754. //
  2755. // Arguments:
  2756. // pszFileIn - Source filename where memory was allocated.
  2757. // nLineIn - Source line number where memory was allocated.
  2758. // pszModuleIn - Source module where memory was allocated.
  2759. // uFlagsIn - Flags used to allocate the memory.
  2760. // dwBytesIn - Size of the allocation.
  2761. // pszCommentIn - Optional comments about the memory.
  2762. //
  2763. // Return Values:
  2764. // Pointer to the new allocation. NULL if allocation failed.
  2765. //
  2766. //--
  2767. //////////////////////////////////////////////////////////////////////////////
  2768. void *
  2769. DebugAlloc(
  2770. LPCTSTR pszFileIn,
  2771. const int nLineIn,
  2772. LPCTSTR pszModuleIn,
  2773. UINT uFlagsIn,
  2774. DWORD dwBytesIn,
  2775. LPCTSTR pszCommentIn
  2776. )
  2777. {
  2778. Assert( ( uFlagsIn & LMEM_MOVEABLE ) == 0 );
  2779. void * pv = HeapAlloc( GetProcessHeap(), uFlagsIn, dwBytesIn );
  2780. //
  2781. // Initialize the memory if needed
  2782. //
  2783. if ( IsTraceFlagSet( mtfMEMORYINIT )
  2784. && !( uFlagsIn & HEAP_ZERO_MEMORY )
  2785. )
  2786. {
  2787. //
  2788. // KB: gpease 8-NOV-1999
  2789. // Initialize to anything but ZERO. We will use 0xAA to
  2790. // indicate "Available Address". Initializing to zero
  2791. // is bad because it usually has meaning.
  2792. //
  2793. memset( pv, 0xAA, dwBytesIn );
  2794. } // if: zero memory requested
  2795. return DebugMemoryAdd( mmbtMEMORYALLOCATION,
  2796. pv,
  2797. pszFileIn,
  2798. nLineIn,
  2799. pszModuleIn,
  2800. dwBytesIn,
  2801. pszCommentIn
  2802. );
  2803. } //*** DebugAlloc()
  2804. //////////////////////////////////////////////////////////////////////////////
  2805. //++
  2806. //
  2807. // void *
  2808. // DebugReAlloc(
  2809. // LPCTSTR pszFileIn,
  2810. // const int nLineIn,
  2811. // LPCTSTR pszModuleIn,
  2812. // void * pvMemIn,
  2813. // UINT uFlagsIn,
  2814. // DWORD dwBytesIn,
  2815. // LPCTSTR pszCommentIn
  2816. // )
  2817. //
  2818. // Description:
  2819. // Replacement for LocalReAlloc, GlobalReAlloc, and realloc for CHKed/DEBUG
  2820. // builds. Memoryallocations be tracked. Use the TraceAlloc macro to make
  2821. // memoryallocations switch in RETAIL.
  2822. //
  2823. // Arguments:
  2824. // pszFileIn - Source filename where memory was allocated.
  2825. // nLineIn - Source line number where memory was allocated.
  2826. // pszModuleIn - Source module where memory was allocated.
  2827. // pvMemIn - Pointer to the source memory.
  2828. // uFlagsIn - Flags used to allocate the memory.
  2829. // dwBytesIn - Size of the allocation.
  2830. // pszCommentIn - Optional comments about the memory.
  2831. //
  2832. // Return Values:
  2833. // Pointer to the new allocation.
  2834. // NULL if allocation failed.
  2835. //
  2836. //--
  2837. //////////////////////////////////////////////////////////////////////////////
  2838. void *
  2839. DebugReAlloc(
  2840. LPCTSTR pszFileIn,
  2841. const int nLineIn,
  2842. LPCTSTR pszModuleIn,
  2843. void * pvMemIn,
  2844. UINT uFlagsIn,
  2845. DWORD dwBytesIn,
  2846. LPCTSTR pszCommentIn
  2847. )
  2848. {
  2849. MEMORYBLOCK * pmbHead = NULL;
  2850. void * pvOld = pvMemIn;
  2851. MEMORYBLOCK * pmbLast = NULL;
  2852. void * pv;
  2853. AssertMsg( !( uFlagsIn & GMEM_MODIFY ), "This doesn't handle modified memory blocks, yet." );
  2854. if ( pvMemIn == NULL )
  2855. {
  2856. //
  2857. // To duplicate the behavior of realloc we need to do an alloc when
  2858. // pvMemIn is NULL.
  2859. //
  2860. pv = DebugAlloc( pszFileIn, nLineIn, pszModuleIn, uFlagsIn, dwBytesIn, pszCommentIn );
  2861. goto Exit;
  2862. } // if:
  2863. pmbHead = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  2864. //
  2865. // Find the memory in the memory block list
  2866. //
  2867. while ( pmbHead != NULL
  2868. && pmbHead->pvMem != pvMemIn
  2869. )
  2870. {
  2871. pmbLast = pmbHead;
  2872. pmbHead = pmbLast->pNext;
  2873. } // while: finding the entry in the list
  2874. if ( pmbHead != NULL )
  2875. {
  2876. AssertMsg( pmbHead->mbtType == mmbtMEMORYALLOCATION, "You can only realloc memory allocations!" );
  2877. //
  2878. // Remove the memory from the tracking list
  2879. //
  2880. if ( pmbLast != NULL )
  2881. {
  2882. pmbLast->pNext = pmbHead->pNext;
  2883. } // if: not first entry
  2884. else
  2885. {
  2886. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  2887. } // else: first entry
  2888. //
  2889. // Spew if needed
  2890. //
  2891. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  2892. {
  2893. DebugMemorySpew( pmbHead, TEXT("Freeing") );
  2894. } // if: tracing
  2895. //
  2896. // Force the programmer to handle a real realloc by moving the
  2897. // memory first.
  2898. //
  2899. pvOld = HeapAlloc( GetProcessHeap(), uFlagsIn, pmbHead->dwBytes );
  2900. if ( pvOld != NULL )
  2901. {
  2902. CopyMemory( pvOld, pvMemIn, pmbHead->dwBytes );
  2903. //
  2904. // Nuke the old memory if the allocation is to be smaller.
  2905. //
  2906. if ( dwBytesIn < pmbHead->dwBytes )
  2907. {
  2908. LPBYTE pb = (LPBYTE) pvOld + dwBytesIn;
  2909. memset( pb, 0xFA, pmbHead->dwBytes - dwBytesIn );
  2910. } // if: smaller memory
  2911. pmbHead->pvMem = pvOld;
  2912. } // if: got new memory
  2913. else
  2914. {
  2915. pvOld = pvMemIn;
  2916. } // else: allocation failed
  2917. } // if: found entry
  2918. else
  2919. {
  2920. DebugMessage( pszFileIn,
  2921. nLineIn,
  2922. pszModuleIn,
  2923. TEXT("***** Attempted to realloc 0x%08x not owned by thread (ThreadID = 0x%08x) *****"),
  2924. pvMemIn,
  2925. GetCurrentThreadId()
  2926. );
  2927. } // else: entry not found
  2928. //
  2929. // We do this any way because the flags and input still need to be
  2930. // verified by HeapReAlloc().
  2931. //
  2932. pv = HeapReAlloc( GetProcessHeap(), uFlagsIn, pvOld, dwBytesIn );
  2933. if ( pv == NULL )
  2934. {
  2935. DWORD dwErr = TW32( GetLastError() );
  2936. AssertMsg( dwErr == 0, "HeapReAlloc() failed!" );
  2937. if ( pvMemIn != pvOld )
  2938. {
  2939. HeapFree( GetProcessHeap(), 0, pvOld );
  2940. } // if: forced a move
  2941. SetLastError( dwErr );
  2942. if ( pmbHead != NULL )
  2943. {
  2944. //
  2945. // Continue tracking the memory by re-adding it to the tracking list.
  2946. //
  2947. pmbHead->pvMem = pvMemIn;
  2948. pmbHead->pNext = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  2949. TlsSetValue( g_TraceMemoryIndex, (LPVOID) pmbHead );
  2950. } // if: reuse the old entry
  2951. else
  2952. {
  2953. //
  2954. // Create a new block
  2955. //
  2956. DebugMemoryAdd( mmbtMEMORYALLOCATION,
  2957. pvOld,
  2958. pszFileIn,
  2959. nLineIn,
  2960. pszModuleIn,
  2961. dwBytesIn,
  2962. pszCommentIn
  2963. );
  2964. } // else: make new entry
  2965. } // if: allocation failed
  2966. else
  2967. {
  2968. if ( pv != pvMemIn )
  2969. {
  2970. if ( pmbHead != NULL )
  2971. {
  2972. //
  2973. // Nuke the old memory
  2974. //
  2975. memset( pvMemIn, 0xFA, pmbHead->dwBytes );
  2976. } // if: entry found
  2977. //
  2978. // Free the old memory
  2979. //
  2980. HeapFree( GetProcessHeap(), 0, pvMemIn );
  2981. } // if: new memory location
  2982. //
  2983. // Add the allocation to the tracking table.
  2984. //
  2985. if ( pmbHead != NULL )
  2986. {
  2987. //
  2988. // If the block is bigger, initialize the "new" memory
  2989. //
  2990. if ( IsTraceFlagSet( mtfMEMORYINIT )
  2991. && dwBytesIn > pmbHead->dwBytes
  2992. )
  2993. {
  2994. //
  2995. // Initialize the expaned memory block
  2996. //
  2997. LPBYTE pb = (LPBYTE) pv + pmbHead->dwBytes;
  2998. memset( pb, 0xAA, dwBytesIn - pmbHead->dwBytes );
  2999. } // if: initialize memory
  3000. //
  3001. // Re-add the tracking block by reusing the old tracking block
  3002. //
  3003. pmbHead->pvMem = pv;
  3004. pmbHead->dwBytes = dwBytesIn;
  3005. pmbHead->pszFile = pszFileIn;
  3006. pmbHead->nLine = nLineIn;
  3007. pmbHead->pszModule = pszModuleIn;
  3008. pmbHead->pszComment = pszCommentIn;
  3009. pmbHead->pNext = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3010. TlsSetValue( g_TraceMemoryIndex, (LPVOID) pmbHead );
  3011. //
  3012. // Spew if needed
  3013. //
  3014. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  3015. {
  3016. DebugMemorySpew( pmbHead, TEXT("ReAlloced") );
  3017. } // if: tracing
  3018. } // if: entry found
  3019. else
  3020. {
  3021. //
  3022. // Create a new block
  3023. //
  3024. DebugMemoryAdd( mmbtMEMORYALLOCATION,
  3025. pvOld,
  3026. pszFileIn,
  3027. nLineIn,
  3028. pszModuleIn,
  3029. dwBytesIn,
  3030. pszCommentIn
  3031. );
  3032. } // else: make new entry
  3033. } // else: allocation succeeded
  3034. Exit:
  3035. return pv;
  3036. } //*** DebugRealloc()
  3037. //////////////////////////////////////////////////////////////////////////////
  3038. //++
  3039. //
  3040. // void *
  3041. // DebugFree(
  3042. // void * pvMemIn
  3043. // LPCTSTR pszFileIn,
  3044. // const int nLineIn,
  3045. // LPCTSTR pszModuleIn,
  3046. // )
  3047. //
  3048. // Description:
  3049. // Replacement for LocalFree for CHKed/DEBUG builds. Removes the
  3050. // memory allocation for the memory tracking list. Use the TraceFree
  3051. // macro to make memory allocation switch in RETAIL. The memory of the
  3052. // freed block will be set to 0xFE.
  3053. //
  3054. // Arguments:
  3055. // pvMemIn - Pointer to memory block to free.
  3056. // pszFileIn - Source file path to the caller
  3057. // nLineIn - Line number of the caller in the source file
  3058. // pszModuleIn - Source module name of the caller
  3059. //
  3060. // Return Values: (see HeapFree())
  3061. // TRUE
  3062. // Memory was freed.
  3063. //
  3064. // FALSE
  3065. // An Error occured. Use GetLastError() to determine the failure.
  3066. //
  3067. //--
  3068. //////////////////////////////////////////////////////////////////////////////
  3069. BOOL
  3070. DebugFree(
  3071. void * pvMemIn,
  3072. LPCTSTR pszFileIn,
  3073. const int nLineIn,
  3074. LPCTSTR pszModuleIn
  3075. )
  3076. {
  3077. DebugMemoryDelete( mmbtMEMORYALLOCATION, pvMemIn, pszFileIn, nLineIn, pszModuleIn, TRUE );
  3078. return HeapFree( GetProcessHeap(), 0, pvMemIn );
  3079. } //*** DebugFree()
  3080. //////////////////////////////////////////////////////////////////////////////
  3081. //++
  3082. //
  3083. // void
  3084. // DebugMemoryCheck(
  3085. // LPVOID pvListIn,
  3086. // LPCTSTR pszListNameIn
  3087. // )
  3088. //
  3089. // Description:
  3090. // Called just before a thread/process dies to verify that all the memory
  3091. // allocated by the thread/process was properly freed. Anything that was
  3092. // not freed will be listed in the debugger.
  3093. //
  3094. // If pmbListIn is NULL, it will check the current threads tracking list.
  3095. // The list is destroyed as it is checked.
  3096. //
  3097. // Arguments:
  3098. // pvListIn - The list to check.
  3099. // pszListNameIn - The name of the list.
  3100. //
  3101. // Return Values:
  3102. // None.
  3103. //
  3104. //--
  3105. //////////////////////////////////////////////////////////////////////////////
  3106. void
  3107. DebugMemoryCheck(
  3108. LPVOID pvListIn,
  3109. LPCTSTR pszListNameIn
  3110. )
  3111. {
  3112. BOOL fFoundLeak = FALSE;
  3113. MEMORYBLOCK * pmb;
  3114. SPerThreadDebug * ptd = NULL;
  3115. if ( IsTraceFlagSet( mtfPERTHREADTRACE ) )
  3116. {
  3117. Assert( g_TraceFlagsIndex != -1 );
  3118. ptd = (SPerThreadDebug *) TlsGetValue( g_TraceFlagsIndex );
  3119. } // if: per thread tracing
  3120. //
  3121. // Determine which list to use.
  3122. //
  3123. if ( pvListIn == NULL )
  3124. {
  3125. Assert( g_TraceMemoryIndex != -1 );
  3126. pmb = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3127. } // if: use the thread list
  3128. else
  3129. {
  3130. MEMORYBLOCKLIST * pmbl = (MEMORYBLOCKLIST *) pvListIn;
  3131. Assert( pszListNameIn != NULL );
  3132. //
  3133. // Make sure nobody tries to use the list again.
  3134. //
  3135. DebugAcquireSpinLock( &pmbl->lSpinLock );
  3136. pmbl->fDeadList = TRUE;
  3137. DebugReleaseSpinLock( &pmbl->lSpinLock );
  3138. pmb = pmbl->pmbList;
  3139. } // else: use the given list
  3140. //
  3141. // Print banner if needed.
  3142. //
  3143. if ( pmb != NULL )
  3144. {
  3145. if ( pvListIn == NULL )
  3146. {
  3147. if ( ptd != NULL && ptd->pcszName != NULL )
  3148. {
  3149. DebugMsg( TEXT("DEBUG: ******** Memory leak detected ***** %s, ThreadID = %#x ********"), ptd->pcszName, GetCurrentThreadId() );
  3150. } // if: named thread
  3151. else
  3152. {
  3153. DebugMsg( "DEBUG: ******** Memory leak detected ******************* ThreadID = 0x%08x ********", GetCurrentThreadId() );
  3154. } // else: unnamed thread
  3155. DebugMsg( "DEBUG: M = Moveable, A = Address, O = Object(new), P = Punk, H = Handle, B = BSTR" );
  3156. DebugMsg( "Module Addr/Hndl/Obj Size Comment" );
  3157. //" 1 2 3 4 5 6 7 8 "
  3158. //"12345678901234567890123456789012345678901234567890123456789012345678901234567890 1234567890 X 0x12345678 12345 1....."
  3159. } // if: thread leak
  3160. else
  3161. {
  3162. DebugMsg( TEXT("DEBUG: ******** Memory leak detected ******************* %s ********"), pszListNameIn );
  3163. DebugMsg( "DEBUG: M = Moveable, A = Address, O = Object(new), P = Punk, H = Handle, B = BSTR" );
  3164. DebugMsg( "Module Addr/Hndl/Obj Size Comment" );
  3165. //" 1 2 3 4 5 6 7 8 "
  3166. //"12345678901234567890123456789012345678901234567890123456789012345678901234567890 1234567890 X 0x12345678 12345 1....."
  3167. } // else: list leak
  3168. fFoundLeak = TRUE;
  3169. } // if: leak found
  3170. //
  3171. // Dump the entries.
  3172. //
  3173. while ( pmb != NULL )
  3174. {
  3175. LPCTSTR pszFormat;
  3176. switch ( pmb->mbtType )
  3177. {
  3178. case mmbtMEMORYALLOCATION:
  3179. {
  3180. pszFormat = TEXT("%10s A 0x%08x %-5u \"%s\"");
  3181. }
  3182. break;
  3183. case mmbtOBJECT:
  3184. pszFormat = TEXT("%10s O 0x%08x %-5u \"%s\"");
  3185. break;
  3186. case mmbtPUNK:
  3187. pszFormat = TEXT("%10s P 0x%08x %-5u \"%s\"");
  3188. break;
  3189. case mmbtHANDLE:
  3190. pszFormat = TEXT("%10s H 0x%08x %-5u \"%s\"");
  3191. break;
  3192. case mmbtSYSALLOCSTRING:
  3193. pszFormat = TEXT("%10s B 0x%08x %-5u \"%s\"");
  3194. break;
  3195. default:
  3196. AssertMsg( 0, "Unknown memory block type!" );
  3197. break;
  3198. } // switch: pmb->mbtType
  3199. DebugMessage( pmb->pszFile, pmb->nLine, pmb->pszModule, pszFormat, pmb->pszModule, pmb->pvMem, pmb->dwBytes, pmb->pszComment );
  3200. pmb = pmb->pNext;
  3201. } // while: something in the list
  3202. //
  3203. // Print trailer if needed.
  3204. //
  3205. if ( fFoundLeak == TRUE )
  3206. {
  3207. // Add an extra newline to the end of this message.
  3208. DebugMsg( TEXT("DEBUG: ***************************** Memory leak detected *****************************") SZ_NEWLINE );
  3209. } // if: leaking
  3210. //
  3211. // Assert if needed.
  3212. //
  3213. if ( IsDebugFlagSet( mtfMEMORYLEAKS ) )
  3214. {
  3215. Assert( !fFoundLeak );
  3216. } // if: yell at leaks
  3217. } //*** DebugMemoryCheck()
  3218. //////////////////////////////////////////////////////////////////////////////
  3219. //++
  3220. //
  3221. // void
  3222. // DebugCreateMemoryList(
  3223. // LPCTSTR pszFileIn,
  3224. // const int nLineIn,
  3225. // LPCTSTR pszModuleIn,
  3226. // LPVOID * ppvListOut,
  3227. // LPCTSTR pszListNameIn
  3228. // )
  3229. //
  3230. // Description:
  3231. // Creates a memory block list for tracking possible "global" scope
  3232. // memory allocations.
  3233. //
  3234. // Arguments:
  3235. // pszFileIn - Source file of caller.
  3236. // nLineIn - Source line number of caller.
  3237. // pszModuleIn - Source module name of caller.
  3238. // ppvListOut - Location to the store address of the list head.
  3239. // pszListNameIn - Name of the list.
  3240. //
  3241. // Return Values:
  3242. // None.
  3243. //
  3244. //--
  3245. //////////////////////////////////////////////////////////////////////////////
  3246. void
  3247. DebugCreateMemoryList(
  3248. LPCTSTR pszFileIn,
  3249. const int nLineIn,
  3250. LPCTSTR pszModuleIn,
  3251. LPVOID * ppvListOut,
  3252. LPCTSTR pszListNameIn
  3253. )
  3254. {
  3255. MEMORYBLOCKLIST * pmbl;
  3256. Assert( ppvListOut != NULL );
  3257. Assert( *ppvListOut == NULL );
  3258. *ppvListOut = DebugAlloc( pszFileIn, nLineIn, pszModuleIn, HEAP_ZERO_MEMORY, sizeof(MEMORYBLOCKLIST), TEXT("Memory Tracking List") );
  3259. if ( NULL != *ppvListOut )
  3260. {
  3261. pmbl = (MEMORYBLOCKLIST*) *ppvListOut;
  3262. Assert( pmbl->lSpinLock == FALSE );
  3263. Assert( pmbl->pmbList == NULL );
  3264. Assert( pmbl->fDeadList == FALSE );
  3265. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  3266. {
  3267. DebugMessage( pszFileIn, nLineIn, pszModuleIn, TEXT("Created new memory list %s"), pszListNameIn );
  3268. } // if: tracing
  3269. }
  3270. } // DebugCreateMemoryList()
  3271. //////////////////////////////////////////////////////////////////////////////
  3272. //++
  3273. //
  3274. // void
  3275. // DebugMemoryListDelete(
  3276. // LPCTSTR pszFileIn,
  3277. // const int nLineIn,
  3278. // LPCTSTR pszModuleIn,
  3279. // void * pvMemIn,
  3280. // LPVOID pvListIn,
  3281. // LPCTSTR pszListNameIn,
  3282. // BOOL fClobberIn
  3283. // )
  3284. //
  3285. // Description:
  3286. // Removes the memory from the tracking list and adds it back to the
  3287. // "per thread" tracking list in order to called DebugMemoryDelete()
  3288. // to do the proper destruction of the memory. Not highly efficent, but
  3289. // reduces code maintenance by having "destroy" code in one (the most
  3290. // used) location.
  3291. //
  3292. // Arguments:
  3293. // pszFileIn - Source file of caller.
  3294. // nLineIn - Source line number of caller.
  3295. // pszModuleIn - Source module name of caller.
  3296. // pvMemIn - Memory to be freed.
  3297. // pvListIn - List from which the memory is to be freed.
  3298. // pvListNameIn - Name of the list.
  3299. // fClobberIn - TRUE - destroys memory; FALSE just removes from list.
  3300. //
  3301. // Return Values:
  3302. // None.
  3303. //
  3304. //--
  3305. //////////////////////////////////////////////////////////////////////////////
  3306. void
  3307. DebugMemoryListDelete(
  3308. LPCTSTR pszFileIn,
  3309. const int nLineIn,
  3310. LPCTSTR pszModuleIn,
  3311. void * pvMemIn,
  3312. LPVOID pvListIn,
  3313. LPCTSTR pszListNameIn,
  3314. BOOL fClobberIn
  3315. )
  3316. {
  3317. if ( pvMemIn != NULL
  3318. && pvListIn != NULL
  3319. )
  3320. {
  3321. MEMORYBLOCK * pmbHead;
  3322. MEMORYBLOCKLIST * pmbl = (MEMORYBLOCKLIST *) pvListIn;
  3323. MEMORYBLOCK * pmbLast = NULL;
  3324. Assert( pszListNameIn != NULL );
  3325. DebugAcquireSpinLock( &pmbl->lSpinLock );
  3326. AssertMsg( pmbl->fDeadList == FALSE, "List was terminated." );
  3327. AssertMsg( pmbl->pmbList != NULL, "Memory tracking problem detecting. Nothing in list to delete." );
  3328. pmbHead = pmbl->pmbList;
  3329. //
  3330. // Find the memory in the memory block list
  3331. //
  3332. while ( pmbHead != NULL
  3333. && pmbHead->pvMem != pvMemIn
  3334. )
  3335. {
  3336. pmbLast = pmbHead;
  3337. pmbHead = pmbLast->pNext;
  3338. } // while: finding the entry in the list
  3339. //
  3340. // Remove the memory block from the tracking list.
  3341. //
  3342. if ( pmbHead != NULL )
  3343. {
  3344. if ( pmbLast != NULL )
  3345. {
  3346. pmbLast->pNext = pmbHead->pNext;
  3347. } // if: not first entry
  3348. else
  3349. {
  3350. pmbl->pmbList = pmbHead->pNext;
  3351. } // else: first entry
  3352. } // if: got entry
  3353. DebugReleaseSpinLock( &pmbl->lSpinLock );
  3354. if ( pmbHead != NULL )
  3355. {
  3356. //
  3357. // Add it back to the per thread list.
  3358. //
  3359. pmbLast = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3360. pmbHead->pNext = pmbLast;
  3361. TlsSetValue( g_TraceMemoryIndex, pmbHead );
  3362. //
  3363. // Finally delete it.
  3364. //
  3365. DebugMemoryDelete( pmbHead->mbtType, pmbHead->pvMem, pszFileIn, nLineIn, pszModuleIn, fClobberIn );
  3366. }
  3367. else
  3368. {
  3369. //
  3370. // Not from the provided list. Try a thread delete any way.
  3371. //
  3372. DebugMemoryDelete( mmbtUNKNOWN, pvMemIn, pszFileIn, nLineIn, pszModuleIn, fClobberIn );
  3373. }
  3374. } // if: pvIn != NULL
  3375. } // DebugMemoryListDelete()
  3376. //////////////////////////////////////////////////////////////////////////////
  3377. //++
  3378. //
  3379. // void
  3380. // DebugMoveToMemoryList(
  3381. // LPCTSTR pszFileIn,
  3382. // const int nLineIn,
  3383. // LPCTSTR pszModuleIn,
  3384. // void * pvMemIn,
  3385. // LPVOID pvListIn,
  3386. // LPCTSTR pszListNameIn
  3387. // )
  3388. //
  3389. // Description:
  3390. // Moves the memory pvIn from the per thread tracking list to the thread
  3391. // independent list "pmbListIn". Useful when memory is being handed from
  3392. // one thread to another. Also useful for objects that live past the
  3393. // lifetime of the thread that created them.
  3394. //
  3395. // Arguments:
  3396. // LPCTSTR pszFileIn - Source file of the caller.
  3397. // const int nLineIn - Source line number of the caller.
  3398. // LPCTSTR pszModuleIn - Source module name of the caller.
  3399. // pvMemIn - Memory to move to list.
  3400. // pvListIn - The list to move to.
  3401. // pszListNameIn - The name of the list.
  3402. //
  3403. // Return Values:
  3404. // None.
  3405. //
  3406. //--
  3407. //////////////////////////////////////////////////////////////////////////////
  3408. void
  3409. DebugMoveToMemoryList(
  3410. LPCTSTR pszFileIn,
  3411. const int nLineIn,
  3412. LPCTSTR pszModuleIn,
  3413. void * pvMemIn,
  3414. LPVOID pvListIn,
  3415. LPCTSTR pszListNameIn
  3416. )
  3417. {
  3418. if ( pvMemIn != NULL
  3419. && pvListIn != NULL
  3420. )
  3421. {
  3422. MEMORYBLOCKLIST * pmbl = (MEMORYBLOCKLIST *) pvListIn;
  3423. MEMORYBLOCK * pmbHead = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3424. MEMORYBLOCK * pmbLast = NULL;
  3425. Assert( pszListNameIn != NULL );
  3426. //
  3427. // Find the memory in the memory block list
  3428. //
  3429. while ( pmbHead != NULL
  3430. && pmbHead->pvMem != pvMemIn
  3431. )
  3432. {
  3433. pmbLast = pmbHead;
  3434. pmbHead = pmbLast->pNext;
  3435. } // while: finding the entry in the list
  3436. AssertMsg( pmbHead != NULL, "Memory not in list. Check your code." );
  3437. //
  3438. // Remove the memory block from the "per thread" tracking list.
  3439. //
  3440. if ( pmbLast != NULL )
  3441. {
  3442. pmbLast->pNext = pmbHead->pNext;
  3443. } // if: not first entry
  3444. else
  3445. {
  3446. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  3447. } // else: first entry
  3448. //
  3449. // Update the "source" data.
  3450. //
  3451. pmbHead->pszFile = pszFileIn;
  3452. pmbHead->nLine = nLineIn;
  3453. pmbHead->pszModule = pszModuleIn;
  3454. //
  3455. // Spew if needed.
  3456. //
  3457. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  3458. {
  3459. TCHAR szMessage[ 128 ]; // random
  3460. StringCchCopy( szMessage, ARRAYSIZE(szMessage), TEXT("Transferring to ") );
  3461. StringCchCat( szMessage, ARRAYSIZE(szMessage), pszListNameIn );
  3462. DebugMemorySpew( pmbHead, szMessage );
  3463. } // if: tracing
  3464. //
  3465. // Add to list.
  3466. //
  3467. AssertMsg( pmbl->fDeadList == FALSE, "List was terminated." );
  3468. DebugAcquireSpinLock( &pmbl->lSpinLock );
  3469. pmbHead->pNext = pmbl->pmbList;
  3470. pmbl->pmbList = pmbHead;
  3471. DebugReleaseSpinLock( &pmbl->lSpinLock );
  3472. } // if: pvIn != NULL
  3473. } // DebugMoveToMemoryList()
  3474. //////////////////////////////////////////////////////////////////////////////
  3475. //++
  3476. //
  3477. // void
  3478. // DebugMoveFromMemoryList(
  3479. // LPCTSTR pszFileIn,
  3480. // const int nLineIn,
  3481. // LPCTSTR pszModuleIn,
  3482. // LPVOID pvMemIn,
  3483. // LPVOID pvListIn,
  3484. // LPCTSTR pszListNameIn
  3485. // )
  3486. //
  3487. // Description:
  3488. // Moves the memory pvIn from the per thread tracking list to the thread
  3489. // independent list "pmbListIn". Useful when memory is being handed from
  3490. // one thread to another. Also useful for objects that live past the
  3491. // lifetime of the thread that created them.
  3492. //
  3493. // Arguments:
  3494. // LPCTSTR pszFileIn - Source file of the caller.
  3495. // const int nLineIn - Source line number of the caller.
  3496. // LPCTSTR pszModuleIn - Source module name of the caller.
  3497. // pvMemIn - Memory to move to list.
  3498. // pvListIn - The list to move to.
  3499. // pszListNameIn - The name of the list.
  3500. //
  3501. // Return Values:
  3502. // None.
  3503. //
  3504. //--
  3505. //////////////////////////////////////////////////////////////////////////////
  3506. void
  3507. DebugMoveFromMemoryList(
  3508. LPCTSTR pszFileIn,
  3509. const int nLineIn,
  3510. LPCTSTR pszModuleIn,
  3511. LPVOID pvMemIn,
  3512. LPVOID pvListIn,
  3513. LPCTSTR pszListNameIn
  3514. )
  3515. {
  3516. if ( pvMemIn != NULL
  3517. && pvListIn != NULL
  3518. )
  3519. {
  3520. MEMORYBLOCK * pmbHead;
  3521. MEMORYBLOCKLIST * pmbl = (MEMORYBLOCKLIST *) pvListIn;
  3522. MEMORYBLOCK * pmbLast = NULL;
  3523. Assert( pszListNameIn != NULL );
  3524. DebugAcquireSpinLock( &pmbl->lSpinLock );
  3525. AssertMsg( pmbl->fDeadList == FALSE, "List was terminated." );
  3526. AssertMsg( pmbl->pmbList != NULL, "Memory tracking problem detecting. Nothing in list to delete." );
  3527. pmbHead = pmbl->pmbList;
  3528. //
  3529. // Find the memory in the memory block list
  3530. //
  3531. while ( pmbHead != NULL
  3532. && pmbHead->pvMem != pvMemIn
  3533. )
  3534. {
  3535. pmbLast = pmbHead;
  3536. pmbHead = pmbLast->pNext;
  3537. } // while: finding the entry in the list
  3538. AssertMsg( pmbHead != NULL, "Memory not in tracking list. Use TraceMemoryAddxxxx() or add it to the memory list." );
  3539. //
  3540. // Remove the memory block from the tracking list.
  3541. //
  3542. if ( pmbLast != NULL )
  3543. {
  3544. pmbLast->pNext = pmbHead->pNext;
  3545. } // if: not first entry
  3546. else
  3547. {
  3548. pmbl->pmbList = pmbHead->pNext;
  3549. } // else: first entry
  3550. DebugReleaseSpinLock( &pmbl->lSpinLock );
  3551. //
  3552. // Add it back to the per thread list.
  3553. //
  3554. pmbLast = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3555. pmbHead->pNext = pmbLast;
  3556. TlsSetValue( g_TraceMemoryIndex, pmbHead );
  3557. } // if: pvIn != NULL
  3558. } // DebugMoveFromMemoryList()
  3559. #if defined( USES_SYSALLOCSTRING )
  3560. //////////////////////////////////////////////////////////////////////////////
  3561. //++
  3562. //
  3563. // INT
  3564. // DebugSysReAllocString(
  3565. // LPCTSTR pszFileIn,
  3566. // const int nLineIn,
  3567. // LPCTSTR pszModuleIn,
  3568. // BSTR * pbstrIn,
  3569. // const OLECHAR * pszIn,
  3570. // LPCTSTR pszCommentIn
  3571. // )
  3572. //
  3573. // Description:
  3574. // Adds memory tracing to SysReAllocString().
  3575. //
  3576. // Arguments:
  3577. // pszFileIn - Source file path
  3578. // nLineIn - Source line number
  3579. // pszModuleIn - Source module name
  3580. // pbstrIn - Pointer to the BSTR to realloc
  3581. // pszIn - String to be copied (see SysReAllocString)
  3582. // pszCommentIn - Comment about alloction
  3583. //
  3584. // Return Values:
  3585. // None.
  3586. //
  3587. //--
  3588. //////////////////////////////////////////////////////////////////////////////
  3589. INT
  3590. DebugSysReAllocString(
  3591. LPCTSTR pszFileIn,
  3592. const int nLineIn,
  3593. LPCTSTR pszModuleIn,
  3594. BSTR * pbstrIn,
  3595. const OLECHAR * pszIn,
  3596. LPCTSTR pszCommentIn
  3597. )
  3598. {
  3599. BSTR bstrOld;
  3600. MEMORYBLOCK * pmbHead = NULL;
  3601. BOOL fReturn = FALSE;
  3602. //
  3603. // Some assertions that SysReAllocString() makes. These would be fatal
  3604. // in retail.
  3605. //
  3606. Assert( pbstrIn != NULL );
  3607. Assert( pszIn != NULL );
  3608. Assert( *pbstrIn == NULL || ( pszIn < *pbstrIn || pszIn > *pbstrIn + wcslen( *pbstrIn ) + 1 ) );
  3609. bstrOld = *pbstrIn;
  3610. if ( bstrOld != NULL )
  3611. {
  3612. MEMORYBLOCK * pmbLast = NULL;
  3613. pmbHead = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3614. //
  3615. // Find the memory in the memory block list
  3616. //
  3617. while ( pmbHead != NULL
  3618. && pmbHead->bstr != bstrOld
  3619. )
  3620. {
  3621. pmbLast = pmbHead;
  3622. pmbHead = pmbLast->pNext;
  3623. } // while: finding the entry in the list
  3624. if ( pmbHead != NULL )
  3625. {
  3626. AssertMsg( pmbHead->mbtType == mmbtSYSALLOCSTRING, "You can only SysReAlloc sysstring allocations!" );
  3627. //
  3628. // Remove the memory from the tracking list
  3629. //
  3630. if ( pmbLast != NULL )
  3631. {
  3632. pmbLast->pNext = pmbHead->pNext;
  3633. } // if: not first entry
  3634. else
  3635. {
  3636. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  3637. } // else: first entry
  3638. //
  3639. // Spew if needed
  3640. //
  3641. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  3642. {
  3643. DebugMemorySpew( pmbHead, TEXT("Freeing") );
  3644. } // if: tracing
  3645. //
  3646. // Force the programmer to handle a real realloc by moving the
  3647. // memory first.
  3648. //
  3649. bstrOld = SysAllocString( *pbstrIn );
  3650. if ( bstrOld != NULL )
  3651. {
  3652. StringCchCopy( bstrOld, SysStringLen( bstrOld ), *pbstrIn );
  3653. pmbHead->bstr = bstrOld;
  3654. } // if: success
  3655. else
  3656. {
  3657. bstrOld = *pbstrIn;
  3658. } // else: failed
  3659. } // if: found entry
  3660. else
  3661. {
  3662. DebugMessage( pszFileIn,
  3663. nLineIn,
  3664. pszModuleIn,
  3665. TEXT("***** Attempted to SysReAlloc 0x%08x not owned by thread (ThreadID = 0x%08x) *****"),
  3666. bstrOld,
  3667. GetCurrentThreadId()
  3668. );
  3669. } // else: entry not found
  3670. } // if: something to delete
  3671. //
  3672. // We do this any way because the flags and input still need to be
  3673. // verified by SysReAllocString().
  3674. //
  3675. fReturn = SysReAllocString( &bstrOld, pszIn );
  3676. if ( ! fReturn )
  3677. {
  3678. DWORD dwErr = GetLastError();
  3679. AssertMsg( dwErr == 0, "SysReAllocString() failed!" );
  3680. if ( *pbstrIn != bstrOld )
  3681. {
  3682. SysFreeString( bstrOld );
  3683. } // if: forced a move
  3684. SetLastError( dwErr );
  3685. } // if: allocation failed
  3686. else
  3687. {
  3688. if ( bstrOld != *pbstrIn )
  3689. {
  3690. if ( pmbHead != NULL )
  3691. {
  3692. //
  3693. // Nuke the old memory
  3694. //
  3695. Assert( pmbHead->dwBytes != 0 ); // invalid string
  3696. memset( *pbstrIn, 0xFA, pmbHead->dwBytes );
  3697. } // if: entry found
  3698. //
  3699. // Free the old memory
  3700. //
  3701. SysFreeString( *pbstrIn );
  3702. } // if: new memory location
  3703. if ( pmbHead != NULL )
  3704. {
  3705. //
  3706. // Re-add the tracking block by reusing the old tracking block
  3707. //
  3708. pmbHead->bstr = bstrOld;
  3709. pmbHead->dwBytes = wcslen( pszIn ) + 1;
  3710. pmbHead->pszFile = pszFileIn;
  3711. pmbHead->nLine = nLineIn;
  3712. pmbHead->pszModule = pszModuleIn;
  3713. pmbHead->pszComment = pszCommentIn;
  3714. pmbHead->pNext = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3715. TlsSetValue( g_TraceMemoryIndex, (LPVOID) pmbHead );
  3716. //
  3717. // Spew if needed
  3718. //
  3719. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  3720. {
  3721. DebugMemorySpew( pmbHead, TEXT("SysReAlloced") );
  3722. } // if: tracing
  3723. } // if: entry found
  3724. else
  3725. {
  3726. //
  3727. // Create a new block
  3728. //
  3729. DebugMemoryAdd( mmbtSYSALLOCSTRING,
  3730. bstrOld,
  3731. pszFileIn,
  3732. nLineIn,
  3733. pszModuleIn,
  3734. wcslen( pszIn ) + 1,
  3735. pszCommentIn
  3736. );
  3737. } // else: make new entry
  3738. } // else: allocation succeeded
  3739. *pbstrIn = bstrOld;
  3740. return fReturn;
  3741. } //*** DebugSysReAllocString()
  3742. //////////////////////////////////////////////////////////////////////////////
  3743. //++
  3744. //
  3745. // INT
  3746. // DebugSysReAllocStringLen(
  3747. // LPCTSTR pszFileIn,
  3748. // const int nLineIn,
  3749. // LPCTSTR pszModuleIn,
  3750. // BSTR * pbstrIn,
  3751. // const OLECHAR * pszIn,
  3752. // LPCTSTR pszCommentIn
  3753. // )
  3754. //
  3755. // Description:
  3756. // Adds memory tracing to SysReAllocString().
  3757. //
  3758. // Arguments:
  3759. // pszFileIn - Source file path
  3760. // nLineIn - Source line number
  3761. // pszModuleIn - Source module name
  3762. // pbstrIn - Pointer to the BSTR to realloc
  3763. // pszIn - String to be copied (see SysReAllocString)
  3764. // pszCommentIn - Comment about alloction
  3765. //
  3766. // Return Values:
  3767. // None.
  3768. //
  3769. //--
  3770. //////////////////////////////////////////////////////////////////////////////
  3771. INT
  3772. DebugSysReAllocStringLen(
  3773. LPCTSTR pszFileIn,
  3774. const int nLineIn,
  3775. LPCTSTR pszModuleIn,
  3776. BSTR * pbstrIn,
  3777. const OLECHAR * pszIn,
  3778. unsigned int ucchIn,
  3779. LPCTSTR pszCommentIn
  3780. )
  3781. {
  3782. BSTR bstrOld;
  3783. MEMORYBLOCK * pmbHead = NULL;
  3784. BOOL fReturn = FALSE;
  3785. //
  3786. // Some assertions that SysReAllocStringLen() makes. These would be fatal
  3787. // in retail.
  3788. //
  3789. Assert( pbstrIn != NULL );
  3790. Assert( pszIn != NULL );
  3791. Assert( *pbstrIn == NULL || ( pszIn < *pbstrIn || pszIn > *pbstrIn + wcslen( *pbstrIn ) + 1 ) );
  3792. bstrOld = *pbstrIn;
  3793. if ( bstrOld != NULL )
  3794. {
  3795. MEMORYBLOCK * pmbLast = NULL;
  3796. pmbHead = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3797. //
  3798. // Find the memory in the memory block list
  3799. //
  3800. while ( pmbHead != NULL
  3801. && pmbHead->bstr != bstrOld
  3802. )
  3803. {
  3804. pmbLast = pmbHead;
  3805. pmbHead = pmbLast->pNext;
  3806. } // while: finding the entry in the list
  3807. if ( pmbHead != NULL )
  3808. {
  3809. AssertMsg( pmbHead->mbtType == mmbtSYSALLOCSTRING, "You can only SysReAlloc sysstring allocations!" );
  3810. //
  3811. // Remove the memory from the tracking list
  3812. //
  3813. if ( pmbLast != NULL )
  3814. {
  3815. pmbLast->pNext = pmbHead->pNext;
  3816. } // if: not first entry
  3817. else
  3818. {
  3819. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  3820. } // else: first entry
  3821. //
  3822. // Spew if needed
  3823. //
  3824. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  3825. {
  3826. DebugMemorySpew( pmbHead, TEXT("Freeing") );
  3827. } // if: tracing
  3828. //
  3829. // Force the programmer to handle a real realloc by moving the
  3830. // memory first.
  3831. //
  3832. bstrOld = SysAllocString( *pbstrIn );
  3833. if ( bstrOld != NULL )
  3834. {
  3835. StringCchCopy( bstrOld, SysStringLen( bstrOld ), *pbstrIn );
  3836. pmbHead->bstr = bstrOld;
  3837. } // if: success
  3838. else
  3839. {
  3840. bstrOld = *pbstrIn;
  3841. } // else: failed
  3842. } // if: found entry
  3843. else
  3844. {
  3845. DebugMessage( pszFileIn,
  3846. nLineIn,
  3847. pszModuleIn,
  3848. TEXT("***** Attempted to SysReAlloc 0x%08x not owned by thread (ThreadID = 0x%08x) *****"),
  3849. bstrOld,
  3850. GetCurrentThreadId()
  3851. );
  3852. } // else: entry not found
  3853. } // if: something to delete
  3854. //
  3855. // We do this any way because the flags and input still need to be
  3856. // verified by SysReAllocString().
  3857. //
  3858. fReturn = SysReAllocStringLen( &bstrOld, pszIn, ucchIn );
  3859. if ( ! fReturn )
  3860. {
  3861. DWORD dwErr = GetLastError();
  3862. AssertMsg( dwErr == 0, "SysReAllocStringLen() failed!" );
  3863. if ( *pbstrIn != bstrOld )
  3864. {
  3865. SysFreeString( bstrOld );
  3866. } // if: forced a move
  3867. SetLastError( dwErr );
  3868. } // if: allocation failed
  3869. else
  3870. {
  3871. if ( bstrOld != *pbstrIn )
  3872. {
  3873. if ( pmbHead != NULL )
  3874. {
  3875. //
  3876. // Nuke the old memory
  3877. //
  3878. Assert( pmbHead->dwBytes != 0 ); // invalid string
  3879. memset( *pbstrIn, 0xFA, pmbHead->dwBytes );
  3880. } // if: entry found
  3881. //
  3882. // Free the old memory
  3883. //
  3884. SysFreeString( *pbstrIn );
  3885. } // if: new memory location
  3886. if ( pmbHead != NULL )
  3887. {
  3888. //
  3889. // Re-add the tracking block by reusing the old tracking block
  3890. //
  3891. pmbHead->bstr = bstrOld;
  3892. pmbHead->dwBytes = ucchIn;
  3893. pmbHead->pszFile = pszFileIn;
  3894. pmbHead->nLine = nLineIn;
  3895. pmbHead->pszModule = pszModuleIn;
  3896. pmbHead->pszComment = pszCommentIn;
  3897. pmbHead->pNext = (MEMORYBLOCK *) TlsGetValue( g_TraceMemoryIndex );
  3898. TlsSetValue( g_TraceMemoryIndex, (LPVOID) pmbHead );
  3899. //
  3900. // Spew if needed
  3901. //
  3902. if ( IsTraceFlagSet( mtfMEMORYALLOCS ) )
  3903. {
  3904. DebugMemorySpew( pmbHead, TEXT("SysReAlloced") );
  3905. } // if: tracing
  3906. } // if: entry found
  3907. else
  3908. {
  3909. //
  3910. // Create a new block
  3911. //
  3912. DebugMemoryAdd( mmbtSYSALLOCSTRING,
  3913. bstrOld,
  3914. pszFileIn,
  3915. nLineIn,
  3916. pszModuleIn,
  3917. ucchIn + 1,
  3918. pszCommentIn
  3919. );
  3920. } // else: make new entry
  3921. } // else: allocation succeeded
  3922. *pbstrIn = bstrOld;
  3923. return fReturn;
  3924. } //*** DebugSysReAllocStringLen()
  3925. #endif // USES_SYSALLOCSTRING
  3926. //****************************************************************************
  3927. //
  3928. // Global Management Functions -
  3929. //
  3930. // These are in debug and retail but internally they change
  3931. // depending on the build.
  3932. //
  3933. //****************************************************************************
  3934. //////////////////////////////////////////////////////////////////////////////
  3935. //++
  3936. //
  3937. // DEBUG version
  3938. //
  3939. // void *
  3940. // _cdecl
  3941. // operator new(
  3942. // size_t stSizeIn,
  3943. // LPCTSTR pszFileIn,
  3944. // const int nLineIn,
  3945. // LPCTSTR pszModuleIn
  3946. // )
  3947. //
  3948. // Description:
  3949. // Replacment for the operator new() in the CRTs. This should be used
  3950. // in conjunction with the "new" macro. It will track the allocations.
  3951. //
  3952. // Arguments:
  3953. // stSizeIn - Size of the object to create.
  3954. // pszFileIn - Source filename where the call was made.
  3955. // nLineIn - Source line number where the call was made.
  3956. // pszModuleIn - Source module name where the call was made.
  3957. //
  3958. // Return Values:
  3959. // Void pointer to the new object.
  3960. //
  3961. //--
  3962. //////////////////////////////////////////////////////////////////////////////
  3963. #undef new
  3964. void *
  3965. __cdecl
  3966. operator new(
  3967. size_t stSizeIn,
  3968. LPCTSTR pszFileIn,
  3969. const int nLineIn,
  3970. LPCTSTR pszModuleIn
  3971. )
  3972. {
  3973. void * pv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, stSizeIn );
  3974. return DebugMemoryAdd( mmbtOBJECT,
  3975. pv,
  3976. pszFileIn,
  3977. nLineIn,
  3978. pszModuleIn,
  3979. stSizeIn,
  3980. TEXT(" new() ")
  3981. );
  3982. } //*** operator new( pszFileIn, etc. ) - DEBUG
  3983. //////////////////////////////////////////////////////////////////////////////
  3984. //++
  3985. //
  3986. // DEBUG version
  3987. //
  3988. // void *
  3989. // __cdecl
  3990. // operator new(
  3991. // size_t stSizeIn
  3992. // )
  3993. //
  3994. // Description:
  3995. // Stub to prevent someone from not using the "new" macro or if somehow
  3996. // the new macro was undefined. It routine will always Assert if called.
  3997. //
  3998. // Arguments:
  3999. // stSizeIn - Not used.
  4000. //
  4001. // Return Values:
  4002. // NULL always.
  4003. //
  4004. //--
  4005. //////////////////////////////////////////////////////////////////////////////
  4006. void *
  4007. __cdecl
  4008. operator new(
  4009. size_t stSizeIn
  4010. )
  4011. {
  4012. #if 1
  4013. void * pv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, stSizeIn );
  4014. AssertMsg( 0, "New Macro failure" );
  4015. return DebugMemoryAdd( mmbtOBJECT,
  4016. pv,
  4017. g_szUnknown,
  4018. 0,
  4019. g_szUnknown,
  4020. stSizeIn,
  4021. TEXT(" new() ")
  4022. );
  4023. #else
  4024. AssertMsg( 0, "New Macro failure" );
  4025. return NULL;
  4026. #endif
  4027. } //*** operator new() - DEBUG
  4028. /*
  4029. //////////////////////////////////////////////////////////////////////////////
  4030. //++
  4031. //
  4032. // DEBUG version
  4033. //
  4034. // void *
  4035. // _cdecl
  4036. // operator new [](
  4037. // size_t stSizeIn,
  4038. // LPCTSTR pszFileIn,
  4039. // const int nLineIn,
  4040. // LPCTSTR pszModuleIn
  4041. // )
  4042. //
  4043. // Description:
  4044. // Replacment for the operator new() in the CRTs. This should be used
  4045. // in conjunction with the "new" macro. It will track the allocations.
  4046. //
  4047. // Arguments:
  4048. // stSizeIn - Size of the object to create.
  4049. // pszFileIn - Source filename where the call was made.
  4050. // nLineIn - Source line number where the call was made.
  4051. // pszModuleIn - Source module name where the call was made.
  4052. //
  4053. // Return Values:
  4054. // Void pointer to the new object.
  4055. //
  4056. //--
  4057. //////////////////////////////////////////////////////////////////////////////
  4058. void *
  4059. __cdecl
  4060. operator new [](
  4061. size_t stSizeIn,
  4062. LPCTSTR pszFileIn,
  4063. const int nLineIn,
  4064. LPCTSTR pszModuleIn
  4065. )
  4066. {
  4067. void * pv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, stSizeIn );
  4068. return DebugMemoryAdd( mmbtOBJECT,
  4069. pv,
  4070. pszFileIn,
  4071. nLineIn,
  4072. pszModuleIn,
  4073. stSizeIn,
  4074. TEXT(" new []() ")
  4075. );
  4076. } //*** operator new []( pszFileIn, etc. ) - DEBUG
  4077. //////////////////////////////////////////////////////////////////////////////
  4078. //++
  4079. //
  4080. // DEBUG version
  4081. //
  4082. // void *
  4083. // __cdecl
  4084. // operator new [](
  4085. // size_t stSizeIn
  4086. // )
  4087. //
  4088. // Description:
  4089. // Stub to prevent someone from not using the "new" macro or if somehow
  4090. // the new macro was undefined. It routine will always Assert if called.
  4091. //
  4092. // Arguments:
  4093. // stSizeIn - Not used.
  4094. //
  4095. // Return Values:
  4096. // NULL always.
  4097. //
  4098. //--
  4099. //////////////////////////////////////////////////////////////////////////////
  4100. void *
  4101. __cdecl
  4102. operator new [](
  4103. size_t stSizeIn
  4104. )
  4105. {
  4106. #if 1
  4107. void * pv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, stSizeIn );
  4108. AssertMsg( 0, "New Macro failure" );
  4109. return DebugMemoryAdd( mmbtOBJECT,
  4110. pv,
  4111. g_szUnknown,
  4112. 0,
  4113. g_szUnknown,
  4114. stSizeIn,
  4115. TEXT(" new() ")
  4116. );
  4117. #else
  4118. AssertMsg( 0, "New Macro failure" );
  4119. return NULL;
  4120. #endif
  4121. } //*** operator new []() - DEBUG
  4122. */
  4123. //////////////////////////////////////////////////////////////////////////////
  4124. //++
  4125. //
  4126. // DEBUG version
  4127. //
  4128. // void
  4129. // _cdecl
  4130. // operator delete(
  4131. // void * pvIn,
  4132. // LPCTSTR pszFileIn,
  4133. // const int nLineIn,
  4134. // LPCTSTR pszModuleIn
  4135. // )
  4136. //
  4137. // Description:
  4138. // Replacment for the operator delete() in the CRTs. It will remove the
  4139. // object from the memory allocation tracking table.
  4140. //
  4141. // Arguments:
  4142. // pvIn - Pointer to object being destroyed.
  4143. // pszFileIn - Source filename where the call was made.
  4144. // nLineIn - Source line number where the call was made.
  4145. // pszModuleIn - Source module name where the call was made.
  4146. //
  4147. // Return Value:
  4148. // None.
  4149. //
  4150. //--
  4151. //////////////////////////////////////////////////////////////////////////////
  4152. void
  4153. __cdecl
  4154. operator delete(
  4155. void * pvIn,
  4156. LPCTSTR pszFileIn,
  4157. const int nLineIn,
  4158. LPCTSTR pszModuleIn
  4159. )
  4160. {
  4161. DebugMemoryDelete( mmbtOBJECT, pvIn, pszFileIn, nLineIn, pszModuleIn, TRUE );
  4162. HeapFree( GetProcessHeap(), 0, pvIn );
  4163. } //*** operator delete( pszFileIn, etc. ) - DEBUG
  4164. //////////////////////////////////////////////////////////////////////////////
  4165. //++
  4166. //
  4167. // DEBUG version
  4168. //
  4169. // void
  4170. // __cdecl
  4171. // operator delete(
  4172. // void * pvIn
  4173. // )
  4174. //
  4175. // Description:
  4176. // Replacment for the operator delete() in the CRTs. It will remove the
  4177. // object from the memory allocation tracking table.
  4178. //
  4179. // Arguments:
  4180. // pvIn - Pointer to object being destroyed.
  4181. //
  4182. // Return Value:
  4183. // None.
  4184. //
  4185. //--
  4186. //////////////////////////////////////////////////////////////////////////////
  4187. void
  4188. __cdecl
  4189. operator delete(
  4190. void * pvIn
  4191. )
  4192. {
  4193. DebugMemoryDelete( mmbtOBJECT, pvIn, g_szUnknown, 0, g_szUnknown, TRUE );
  4194. HeapFree( GetProcessHeap(), 0, pvIn );
  4195. } //*** operator delete() - DEBUG
  4196. /*
  4197. //////////////////////////////////////////////////////////////////////////////
  4198. //++
  4199. //
  4200. // DEBUG version
  4201. //
  4202. // void
  4203. // _cdecl
  4204. // operator delete [](
  4205. // void * pvIn,
  4206. // LPCTSTR pszFileIn,
  4207. // const int nLineIn,
  4208. // LPCTSTR pszModuleIn
  4209. // )
  4210. //
  4211. // Description:
  4212. // Replacment for the operator delete() in the CRTs. It will remove the
  4213. // object from the memory allocation tracking table.
  4214. //
  4215. // Arguments:
  4216. // pvIn - Pointer to object being destroyed.
  4217. // pszFileIn - Source filename where the call was made.
  4218. // nLineIn - Source line number where the call was made.
  4219. // pszModuleIn - Source module name where the call was made.
  4220. //
  4221. // Return Value:
  4222. // None.
  4223. //
  4224. //--
  4225. //////////////////////////////////////////////////////////////////////////////
  4226. void
  4227. __cdecl
  4228. operator delete [](
  4229. void * pvIn,
  4230. size_t stSizeIn,
  4231. LPCTSTR pszFileIn,
  4232. const int nLineIn,
  4233. LPCTSTR pszModuleIn
  4234. )
  4235. {
  4236. DebugMemoryDelete( mmbtOBJECT, pvIn, pszFileIn, nLineIn, pszModuleIn, TRUE );
  4237. HeapFree( GetProcessHeap(), 0, pvIn );
  4238. } //*** operator delete( pszFileIn, etc. ) - DEBUG
  4239. */
  4240. //////////////////////////////////////////////////////////////////////////////
  4241. //++
  4242. //
  4243. // DEBUG version
  4244. //
  4245. // void
  4246. // __cdecl
  4247. // operator delete [](
  4248. // void * pvIn
  4249. // )
  4250. //
  4251. // Description:
  4252. // Replacment for the operator delete() in the CRTs. It will remove the
  4253. // object from the memory allocation tracking table.
  4254. //
  4255. // Arguments:
  4256. // pvIn - Pointer to object being destroyed.
  4257. //
  4258. // Return Value:
  4259. // None.
  4260. //
  4261. //--
  4262. //////////////////////////////////////////////////////////////////////////////
  4263. void
  4264. __cdecl
  4265. operator delete [](
  4266. void * pvIn
  4267. )
  4268. {
  4269. DebugMemoryDelete( mmbtOBJECT, pvIn, g_szUnknown, 0, g_szUnknown, TRUE );
  4270. HeapFree( GetProcessHeap(), 0, pvIn );
  4271. } //*** operator delete []() - DEBUG
  4272. #if !defined(ENTRY_PREFIX)
  4273. //////////////////////////////////////////////////////////////////////////////
  4274. //++
  4275. //
  4276. // DEBUG version
  4277. //
  4278. // int
  4279. // __cdecl
  4280. // _purecall( void )
  4281. //
  4282. // Description:
  4283. // Stub for purecall functions. It will always Assert.
  4284. //
  4285. // Arguments:
  4286. // None.
  4287. //
  4288. // Return Values:
  4289. // E_UNEXPECTED always.
  4290. //
  4291. //////////////////////////////////////////////////////////////////////////////
  4292. int
  4293. __cdecl
  4294. _purecall( void )
  4295. {
  4296. AssertMsg( 0, "Purecall" );
  4297. return E_UNEXPECTED;
  4298. } //*** _purecall() - DEBUG
  4299. #endif // !defined(ENTRY_PREFIX)
  4300. #else // ! DEBUG -- It's retail
  4301. //****************************************************************************
  4302. //
  4303. // Global Management Functions -
  4304. //
  4305. // These are the retail version.
  4306. //
  4307. //****************************************************************************
  4308. //////////////////////////////////////////////////////////////////////////////
  4309. //++
  4310. //
  4311. // RETAIL version
  4312. //
  4313. // void *
  4314. // _cdecl
  4315. // operator new(
  4316. // size_t stSizeIn,
  4317. // )
  4318. //
  4319. // Description:
  4320. // Replacment for the operator new() in the CRTs. Simply allocates a
  4321. // block of memory for the object to use.
  4322. //
  4323. // Arguments:
  4324. // stSizeIn - Size of the object to create.
  4325. //
  4326. // Return Values:
  4327. // Void pointer to the new object.
  4328. //
  4329. //--
  4330. //////////////////////////////////////////////////////////////////////////////
  4331. void *
  4332. __cdecl
  4333. operator new(
  4334. size_t stSizeIn
  4335. )
  4336. {
  4337. return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, stSizeIn );
  4338. } //*** operator new() - RETAIL
  4339. //////////////////////////////////////////////////////////////////////////////
  4340. //++
  4341. //
  4342. // RETAIL version
  4343. //
  4344. // void
  4345. // __cdecl
  4346. // operator delete(
  4347. // void * pvIn
  4348. // )
  4349. //
  4350. // Description:
  4351. // Replacment for the operator delete() in the CRTs. Simply frees the
  4352. // memory.
  4353. //
  4354. // Arguments:
  4355. // pvIn - Pointer to object being destroyed.
  4356. //
  4357. // Return Values:
  4358. // None.
  4359. //
  4360. //--
  4361. //////////////////////////////////////////////////////////////////////////////
  4362. void
  4363. __cdecl
  4364. operator delete(
  4365. void * pv
  4366. )
  4367. {
  4368. HeapFree( GetProcessHeap(), 0, pv );
  4369. } //*** operator delete() - RETAIL
  4370. #if !defined(ENTRY_PREFIX)
  4371. //////////////////////////////////////////////////////////////////////////////
  4372. //++
  4373. //
  4374. // RETAIL version
  4375. //
  4376. // int
  4377. // __cdecl
  4378. // _purecall( void )
  4379. //
  4380. // Description:
  4381. // Stub for purecall functions.
  4382. //
  4383. // Arguments:
  4384. // None.
  4385. //
  4386. // Return Values:
  4387. // E_UNEXPECTED always.
  4388. //
  4389. //--
  4390. //////////////////////////////////////////////////////////////////////////////
  4391. int
  4392. __cdecl
  4393. _purecall( void )
  4394. {
  4395. // BUGBUG: DavidP 08-DEC-1999 Shouldn't we assert?
  4396. return E_UNEXPECTED;
  4397. } //*** _purecall() - RETAIL
  4398. #endif // !defined(ENTRY_PREFIX)
  4399. #define __MODULE__ NULL
  4400. #endif // DEBUG