Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5178 lines
152 KiB

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