Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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