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

874 lines
24 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999 - 2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CITracker.CPP
  7. //
  8. // Description:
  9. // Implementation of a COM interface tracker.
  10. //
  11. // [Documentation:]
  12. // Debugging.PPT - A power-point presentation of the debug utilities.
  13. //
  14. // Maintained By:
  15. // Geoffrey Pease (gpease) 19-NOV-1999
  16. //
  17. // Notes:
  18. // Define NO_TRACE_INTERFACES to disable interface tracking in DEBUG
  19. // builds.
  20. //
  21. // Define TRACE_INTERFACES_ENABLED to enable interface tracking in RETAIL
  22. // builds.
  23. //
  24. // Define FULL_TRACE_INTERFACES_ENABLED to enable full interface
  25. // tracking in RETAIL builds. Full interface tracking is enabled if
  26. // interface tracking is enabled and building for X86.
  27. // Full interface tracking is X86 specific for now. It can be adapted for
  28. // other platforms as required. Since today, most of our developement is
  29. // done on the X86 platform, there is not a need to do this (yet).
  30. //
  31. //////////////////////////////////////////////////////////////////////////////
  32. //#include "pch.h"
  33. #include <shlwapi.h>
  34. #if defined( TRACE_INTERFACES_ENABLED )
  35. ///////////////////////////////////////
  36. //
  37. // BEGIN TRACE_INTERFACES_ENABLED
  38. //
  39. #if defined( DEBUG )
  40. //////////////////////////////////////////////////////////////////////////////
  41. //
  42. // LPCTSTR
  43. // PszDebugFindInterface(
  44. // REFIID riidIn,
  45. // LPTSTR pszBufOut
  46. // )
  47. //
  48. // Description:
  49. // Uses the Interface Tracking Table (g_itTable) to lookup a human
  50. // readable name for the riidIn. If no matching interface is found. it
  51. // will use the pszBufOut to format a GUID string and return it.
  52. //
  53. // Arguments:
  54. // riidIn - The interface ID to lookup.
  55. // pszBufOut - Buffer to use if interface not found to format GUID.
  56. //
  57. // Return Value:
  58. // Never NULL. It will always a valid string pointer to either the
  59. // interface name or to pszBufOut.
  60. //
  61. // Notes:
  62. // pszBufOut must be at least cchGUID_STRING_SIZE in size.
  63. //
  64. //////////////////////////////////////////////////////////////////////////////
  65. LPCTSTR
  66. PszDebugFindInterface(
  67. REFIID riidIn,
  68. LPTSTR pszBufOut
  69. )
  70. {
  71. if ( IsTraceFlagSet( mtfQUERYINTERFACE ) )
  72. {
  73. int idx;
  74. for ( idx = 0; g_itTable[ idx ].riid != NULL; idx++ )
  75. {
  76. if ( riidIn == *g_itTable[ idx ].riid )
  77. {
  78. return g_itTable[ idx ].pszName;
  79. } // if: found interface
  80. } // for: searching for interface
  81. wnsprintf( pszBufOut,
  82. cchGUID_STRING_SIZE,
  83. TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
  84. riidIn.Data1,
  85. riidIn.Data2,
  86. riidIn.Data3,
  87. riidIn.Data4[0],
  88. riidIn.Data4[1],
  89. riidIn.Data4[2],
  90. riidIn.Data4[3],
  91. riidIn.Data4[4],
  92. riidIn.Data4[5],
  93. riidIn.Data4[6],
  94. riidIn.Data4[7]
  95. );
  96. } // if: query interface is on
  97. else
  98. {
  99. return TEXT("riid");
  100. } // else: just print riid
  101. return pszBufOut;
  102. } //*** PszDebugFindInterface( )
  103. #endif // DEBUG
  104. //
  105. // END TRACE_INTERFACES_ENABLED
  106. //
  107. ///////////////////////////////////////
  108. #endif // TRACE_INTERFACES_ENABLED
  109. // ************************************************************************
  110. #if defined( FULL_TRACE_INTERFACES_ENABLED )
  111. ///////////////////////////////////////
  112. //
  113. // BEGIN FULL_TRACE_INTERFACES_ENABLED
  114. //
  115. //
  116. // Globals
  117. //
  118. static IDeadObjTracker * g_pidoTracker = NULL; // dead object - there is only one.
  119. #ifndef NOISY_TRACE_INTERFACES
  120. ///////////////////////////////////////
  121. //
  122. // DEBUG !NOISY_TRACE_INTERFACES
  123. //
  124. //
  125. // Undefining these macros to make the CITracker quiet.
  126. //
  127. #undef TraceFunc
  128. #define TraceFunc 1 ? (void)0 : (void)
  129. #undef TraceFunc1
  130. #define TraceFunc1 1 ? (void)0 : (void)
  131. #undef TraceFunc2
  132. #define TraceFunc2 1 ? (void)0 : (void)
  133. #undef TraceFunc3
  134. #define TraceFunc3 1 ? (void)0 : (void)
  135. #undef TraceFunc4
  136. #define TraceFunc4 1 ? (void)0 : (void)
  137. #undef TraceFunc5
  138. #define TraceFunc5 1 ? (void)0 : (void)
  139. #undef TraceFunc6
  140. #define TraceFunc6 1 ? (void)0 : (void)
  141. #undef TraceQIFunc
  142. #define TraceQIFunc 1 ? (void)0 : (void)
  143. #undef TraceFuncExit
  144. #define TraceFuncExit()
  145. #undef FRETURN
  146. #define FRETURN( _u )
  147. #undef HRETURN
  148. #define HRETURN(_hr) return(_hr)
  149. #undef RETURN
  150. #define RETURN(_fn) return(_fn)
  151. #undef RRETURN
  152. #define RRETURN( _fn ) return(_fn)
  153. //
  154. // END !NOISY_TRACE_INTERFACES
  155. //
  156. ///////////////////////////////////////
  157. #endif // NOISY_TRACE_INTERFACES
  158. #if defined( DEBUG )
  159. //
  160. // These are internal to debug.cpp but not published in debug.h.
  161. //
  162. BOOL
  163. IsDebugFlagSet(
  164. TRACEFLAG tfIn
  165. );
  166. void
  167. DebugInitializeBuffer(
  168. LPCTSTR pszFileIn,
  169. const int nLineIn,
  170. LPCTSTR pszModuleIn,
  171. LPTSTR pszBufIn,
  172. INT * pcchInout,
  173. LPTSTR * ppszBufOut
  174. );
  175. #endif // DEBUG
  176. ///////////////////////////////////////
  177. //
  178. // CITracker Definition
  179. //
  180. //
  181. DEFINE_THISCLASS("CITracker");
  182. #define THISCLASS CITracker
  183. #define LPTHISCLASS CITracker*
  184. // ************************************************************************
  185. //
  186. // Constructor / Destructor
  187. //
  188. // ************************************************************************
  189. //////////////////////////////////////////////////////////////////////////////
  190. //
  191. // Special new( ) for CITracker
  192. //
  193. // Description:
  194. // Creates an object the size of the object plus nExtraIn bytes. This
  195. // allows the Vtable that the CITracker object is tracking to be
  196. // appended to the end of the CITracker object.
  197. //
  198. //////////////////////////////////////////////////////////////////////////////
  199. #ifdef new
  200. #undef new
  201. #endif
  202. void*
  203. __cdecl
  204. operator new(
  205. unsigned int nSizeIn,
  206. LPCTSTR pszFileIn,
  207. const int nLineIn,
  208. LPCTSTR pszModuleIn,
  209. UINT nExtraIn,
  210. LPCTSTR pszNameIn
  211. )
  212. {
  213. void * pv = HeapAlloc( GetProcessHeap(), 0, nSizeIn + nExtraIn );
  214. return TraceMemoryAdd( mmbtOBJECT, pv, pszFileIn, nLineIn, pszModuleIn, nSizeIn + nExtraIn, TEXT("CITracker") );
  215. } //*** operator new( )
  216. //////////////////////////////////////////////////////////////////////////////
  217. //
  218. // LPUNKNOWN
  219. // DebugTrackInterface(
  220. // LPCTSTR pszNameIn,
  221. // REFIID riidIn,
  222. // LPUNKNOWN punkIn,
  223. // LONG cRefIn
  224. // )
  225. //
  226. // Description:
  227. // Create an interface tracker for the given interface.
  228. //
  229. // Arguments:
  230. // pszNameIn - Name to associate with object that the punk references.
  231. // riidIn - Interface IID of the interface to be tracked.
  232. // punkIn - Interface pointer to track.
  233. // cRefIn - Initialize ref count on the interface.
  234. //
  235. // Return Type:
  236. // On failure, this will be punkIn.
  237. // On success, pointer to an object that implements the interface to
  238. // be tracked.
  239. //
  240. //////////////////////////////////////////////////////////////////////////////
  241. LPUNKNOWN
  242. DebugTrackInterface(
  243. LPCTSTR pszFileIn,
  244. const int nLineIn,
  245. LPCTSTR pszModuleIn,
  246. LPCTSTR pszNameIn,
  247. REFIID riidIn,
  248. LPUNKNOWN punkIn,
  249. LONG cRefIn
  250. )
  251. {
  252. TraceFunc3( "pszNameIn = '%s', riidIn, punkIn = 0x%08x, cRefIn = %u",
  253. pszNameIn,
  254. punkIn,
  255. cRefIn
  256. );
  257. UINT nEntry = 0;
  258. LPUNKNOWN punkOut = punkIn;
  259. //
  260. // Scan the table looking for the matching interface definition.
  261. //
  262. for( nEntry = 0; g_itTable[ nEntry ].riid != NULL; nEntry++ )
  263. {
  264. if ( riidIn == *g_itTable[ nEntry ].riid )
  265. {
  266. //
  267. // Figure out how much "extra" to allocate onto the CITracker.
  268. //
  269. UINT nExtra = ( 3 + g_itTable[ nEntry ].cFunctions ) * sizeof(LPVOID);
  270. //
  271. // Create a name for the tracker.
  272. //
  273. // TODO: gpease 19-NOV-1999
  274. // Maybe merge this in with the nExtra(??).
  275. //
  276. LPTSTR psz;
  277. LPTSTR pszName =
  278. (LPTSTR) HeapAlloc( GetProcessHeap(), 0,
  279. ( lstrlen( g_itTable[ nEntry ].pszName ) + lstrlen( pszNameIn ) + 3 + 2 ) * sizeof(TCHAR) );
  280. psz = StrCpy( pszName, pszNameIn ); // object name
  281. psz = StrCat( psz, TEXT("::[") ); // + 3
  282. psz = StrCat( psz, g_itTable[ nEntry ].pszName ); // + interface name
  283. psz = StrCat( psz, TEXT("]") ); // + 2
  284. //
  285. // Create the tracker.
  286. //
  287. LPTHISCLASS pc = new( pszFileIn, nLineIn, pszModuleIn, nExtra, pszName ) THISCLASS( );
  288. if ( pc != NULL )
  289. {
  290. HRESULT hr;
  291. //
  292. // Initialize the tracker.
  293. //
  294. hr = THR( pc->Init( &punkOut, punkIn, &g_itTable[ nEntry ], pszName, cRefIn ) );
  295. if ( FAILED( hr ) )
  296. {
  297. //
  298. // If it failed, delete it.
  299. //
  300. delete pc;
  301. } // if: failed to initialize
  302. } // if: got memory
  303. break; // exit loop
  304. } // if: matched interface
  305. } // for: more entries in table
  306. AssertMsg( g_itTable[ nEntry ].riid != NULL, "There has been a request to track an interface that is not in the interface table." );
  307. RETURN( punkOut );
  308. } //*** DebugTrackInterface( )
  309. //////////////////////////////////////////////////////////////////////////////
  310. //
  311. // CITracker::CITracker( void )
  312. //
  313. //////////////////////////////////////////////////////////////////////////////
  314. CITracker::CITracker( void )
  315. {
  316. TraceFunc( "" );
  317. //
  318. // KB: gpease 10-OCT-1998
  319. // This class will leak objects to help catch bad components
  320. // that call back into released interfaces therefore this
  321. // DLL will not be able to be released.
  322. //
  323. if ( g_tfModule & mtfCITRACKERS )
  324. {
  325. //
  326. // Only count CITrackers if tracking is enabled.
  327. //
  328. InterlockedIncrement( &g_cObjects );
  329. }
  330. TraceFuncExit();
  331. } //*** CITracker::ctor( )
  332. //////////////////////////////////////////////////////////////////////////////
  333. //
  334. // STDMETHODIMP
  335. // CITracker::Init(
  336. // LPUNKNOWN * ppunkOut,
  337. // LPUNKNOWN punkIn,
  338. // const INTERFACE_TABLE_ENTRY * piteIn,
  339. // LPCTSTR pszNameIn,
  340. // BOOL fAddRefIn
  341. // )
  342. //
  343. // Description:
  344. // Initializes the CITracker object. It creates a copy of the VTable
  345. // of the interface to be tracked replacing the QI, AddRef and Release
  346. // methods with its own IUnknown. This allows CITracker to be "in the
  347. // loop" for those calls.
  348. //
  349. // Arguments:
  350. // ppunkOut - The "punk" to be passed around.
  351. // punkIn - The interface to be copied and tracked.
  352. // piteIn - The interface table entry for the interface.
  353. // pszNameIn - The name to be given to this CITracker.
  354. // fAddRefIn - TRUE is the CITracker should start with a Ref Count of 1.
  355. //
  356. // Return Value:
  357. // S_OK - Success.
  358. //
  359. //////////////////////////////////////////////////////////////////////////////
  360. STDMETHODIMP
  361. CITracker::Init(
  362. LPUNKNOWN * ppunkOut,
  363. LPUNKNOWN punkIn,
  364. const INTERFACE_TABLE_ENTRY * piteIn,
  365. LPCTSTR pszNameIn,
  366. LONG cRefIn
  367. )
  368. {
  369. HRESULT hr = S_OK;
  370. TraceFunc5( "ppunkOut = 0x%08x, punkIn = 0x%08x, iteIn = %s, pszNameIn = '%s', cRefIn = %u",
  371. ppunkOut,
  372. punkIn,
  373. piteIn->pszName,
  374. pszNameIn,
  375. cRefIn
  376. );
  377. //
  378. // Generate new Vtbls for each interface
  379. //
  380. LPVOID * pthisVtbl = (LPVOID*) (IUnknownTracker *) this;
  381. LPVOID * ppthatVtbl = (LPVOID*) punkIn;
  382. DWORD dwSize = ( 3 + piteIn->cFunctions ) * sizeof(LPVOID);
  383. AssertMsg( dwSize < 30 * sizeof(LPVOID), "Need to make Dead Obj and IUnknownTracker larger!" );
  384. //
  385. // Interface tracking information initialization
  386. //
  387. m_vtbl.cRef = cRefIn;
  388. m_vtbl.pszInterface = pszNameIn;
  389. m_vtbl.dwSize = dwSize;
  390. //
  391. // Copy our IUnknownTracker vtbl to our "fix-up-able" vtbl
  392. //
  393. CopyMemory( &m_vtbl.lpfnQueryInterface, *pthisVtbl, dwSize );
  394. //
  395. // Remember the "punk" pointer so we can pass it back in when
  396. // we jump to the orginal objects IUnknown functions.
  397. //
  398. m_vtbl.punk = (LPUNKNOWN) punkIn;
  399. //
  400. // And finally, point the objects vtbl for this interface to
  401. // our newly created vtbl.
  402. //
  403. m_vtbl.pNewVtbl = (VTBL *) &m_vtbl.lpfnQueryInterface;
  404. *pthisVtbl = m_vtbl.pNewVtbl;
  405. *ppunkOut = (LPUNKNOWN) (IUnknownTracker *) this;
  406. TraceMsg( mtfCITRACKERS, L"TRACK: Tracking %s Interface (%#x)", m_vtbl.pszInterface, punkIn );
  407. HRETURN( hr );
  408. } //*** CITracker::Init( )
  409. //////////////////////////////////////////////////////////////////////////////
  410. //
  411. // CITracker::~CITracker( void )
  412. //
  413. //////////////////////////////////////////////////////////////////////////////
  414. CITracker::~CITracker( void )
  415. {
  416. TraceFunc1( "for %s", m_vtbl.pszInterface );
  417. if ( m_vtbl.pszInterface != NULL )
  418. {
  419. HeapFree( GetProcessHeap(), 0, (LPVOID) m_vtbl.pszInterface );
  420. } // if: have interface pointer
  421. if ( g_tfModule & mtfCITRACKERS )
  422. {
  423. //
  424. // Only count CITrackers if tracking is enabled.
  425. //
  426. InterlockedDecrement( &g_cObjects );
  427. }
  428. TraceFuncExit();
  429. } //*** CITracker::dtor( )
  430. // ************************************************************************
  431. //
  432. // IUnknownTracker
  433. //
  434. // ************************************************************************
  435. ///////////////////////////////////////////////////////////////////////////////
  436. //
  437. // STDMETHODIMP
  438. // CITracker::QueryInterface(
  439. // REFIID riid,
  440. // LPVOID * ppv
  441. // )
  442. //
  443. ///////////////////////////////////////////////////////////////////////////////
  444. STDMETHODIMP
  445. CITracker::QueryInterface(
  446. REFIID riid,
  447. LPVOID * ppv
  448. )
  449. {
  450. TraceFunc1( "{%s}", m_vtbl.pszInterface );
  451. TraceMsg( mtfCITRACKERS, "TRACK: + %s::QueryInterface( )", m_vtbl.pszInterface );
  452. //
  453. // Call the punk's QueryInterface( ).
  454. //
  455. HRESULT hr = m_vtbl.punk->QueryInterface( riid, ppv );
  456. //
  457. // KB: TRACK_ALL_QIED_INTERFACES gpease 25-NOV-1999
  458. // Thinking out loud, should we track all interfaces QI'ed from
  459. // a tracked interface auto-magically? If so, turn this #define
  460. // on.
  461. //
  462. // #define TRACK_ALL_QIED_INTERFACES
  463. #if defined( TRACK_ALL_QIED_INTERFACES )
  464. if ( !IsEqualIID( riid, IID_IUnknown )
  465. )
  466. {
  467. *ppv = DebugTrackInterface( TEXT("<Unknown>"),
  468. 0,
  469. __MODULE__,
  470. m_vtbl.pszInterface,
  471. riid,
  472. (IUnknown*) *ppv,
  473. TRUE
  474. );
  475. } // if: not the IUnknown
  476. #endif
  477. TraceMsg( mtfCITRACKERS,
  478. "TRACK: V %s::QueryInterface( ) [ *ppv = %#x ]",
  479. m_vtbl.pszInterface,
  480. *ppv
  481. );
  482. HRETURN( hr );
  483. } //*** CITracker::QueryInterface( )
  484. ///////////////////////////////////////////////////////////////////////////////
  485. //
  486. // STDMETHODIMP_( ULONG )
  487. // CITracker::AddRef( void )
  488. //
  489. ///////////////////////////////////////////////////////////////////////////////
  490. STDMETHODIMP_( ULONG )
  491. CITracker::AddRef( void )
  492. {
  493. TraceFunc1( "{%s}", m_vtbl.pszInterface );
  494. TraceMsg( mtfCITRACKERS, "TRACK: + %s AddRef( ) [ CITracker = %#08x ]", m_vtbl.pszInterface, this );
  495. //
  496. // Call the punk's AddRef( ).
  497. //
  498. ULONG ul = m_vtbl.punk->AddRef( );
  499. //
  500. // Increment our counter.
  501. //
  502. ULONG ulvtbl = InterlockedIncrement( (LONG *) &m_vtbl.cRef );
  503. TraceMsg( mtfCITRACKERS,
  504. "TRACK: V %s AddRef( ) [ I = %u, O = %u, CITracker = %#08x ]",
  505. m_vtbl.pszInterface,
  506. ulvtbl,
  507. ul,
  508. this
  509. );
  510. AssertMsg( ul >= ulvtbl, "The objects ref should be higher than the interfaces." );
  511. RETURN( ul );
  512. } //*** CITracker::AddRef( )
  513. ///////////////////////////////////////////////////////////////////////////////
  514. //
  515. // STDMETHODIMP_( ULONG )
  516. // CITracker::Release( void )
  517. //
  518. ///////////////////////////////////////////////////////////////////////////////
  519. STDMETHODIMP_( ULONG )
  520. CITracker::Release( void )
  521. {
  522. TraceFunc1( "{%s}", m_vtbl.pszInterface );
  523. TraceMsg( mtfCITRACKERS, "TRACK: + %s Release( ) [ CITracker = %#08x ]", m_vtbl.pszInterface, this );
  524. //
  525. // Call the punk's Release( ).
  526. //
  527. ULONG ul = m_vtbl.punk->Release( );
  528. //
  529. // Decrement our counter.
  530. //
  531. ULONG ulvtbl = InterlockedDecrement( (LONG *) &m_vtbl.cRef );
  532. TraceMsg( mtfCITRACKERS,
  533. "TRACK: V %s Release( ) [ I = %u, O = %u, CITracker = %#08x ]",
  534. m_vtbl.pszInterface,
  535. ulvtbl,
  536. ul,
  537. this
  538. );
  539. //
  540. // Our ref count should always be less than the punk's ref count.
  541. //
  542. AssertMsg( ul >= ulvtbl, "The objects ref should be higher than the interfaces." );
  543. if ( ulvtbl )
  544. {
  545. RETURN( ulvtbl );
  546. } // if: we still have a ref
  547. if ( g_pidoTracker == NULL )
  548. {
  549. //
  550. // Create a dead object - if more than one is created at a time, we might leak it.
  551. //
  552. // TODO: gpease 19-NOV-1999
  553. // Work on not leaking "extra" dead objects.
  554. //
  555. g_pidoTracker = new( TEXT(__FILE__), __LINE__, __MODULE__, 0, TEXT("Dead Object") ) IDeadObjTracker( );
  556. // Don't track this object
  557. TraceMemoryDelete( g_pidoTracker, FALSE );
  558. } // if: no dead object
  559. Assert( g_pidoTracker != NULL );
  560. if ( g_pidoTracker != NULL )
  561. {
  562. LPVOID * pthisVtbl = (LPVOID *) (IUnknownTracker *) this;
  563. LPVOID * ppthatVtbl = (LPVOID *) (IDeadObjTracker *) g_pidoTracker;
  564. // Copy the DeadObj vtbl.
  565. CopyMemory( &m_vtbl.lpfnQueryInterface, *ppthatVtbl, m_vtbl.dwSize );
  566. //
  567. // Don't really delete it, but fake the debug output as if we did.
  568. //
  569. TraceFunc1( "for %s", m_vtbl.pszInterface );
  570. TraceMsg( mtfCITRACKERS, "TRACK: # %s set to dead object [ punk = %#08x ]", m_vtbl.pszInterface, pthisVtbl );
  571. FRETURN( 0 );
  572. // Stop tracking this object.
  573. TraceMemoryDelete( this, FALSE );
  574. } // if: dead object created
  575. else
  576. {
  577. //
  578. // No dead object; nuke ourselves. This will at least cause an AV if
  579. // the program tries to call on our interface alerting the programmer
  580. // that somethings wrong.
  581. //
  582. delete this;
  583. } // else: no dead object
  584. RETURN(0);
  585. } //*** CITracker::Release( )
  586. //****************************************************************************
  587. //
  588. // IDeadObjTracker - The dead interface object tracker.
  589. //
  590. // This object is shunted into release interfaces that were being tracked by
  591. // the CITracker class. Any calls to a released interface will end up causing
  592. // an Assert and if execution continues it will return E_FAIL.
  593. //
  594. //****************************************************************************
  595. //////////////////////////////////////////////////////////////////////////////
  596. //
  597. // IDeadObjTracker:Stub(x)
  598. //
  599. //////////////////////////////////////////////////////////////////////////////
  600. #define IDeadObjTrackerStub( _iStubNum ) \
  601. STDMETHODIMP \
  602. IDeadObjTracker::Stub##_iStubNum( LPVOID* punk ) \
  603. { \
  604. const int cchDebugMessageSize = 255; \
  605. TCHAR szMessage[ cchDebugMessageSize ]; \
  606. LRESULT lResult;\
  607. \
  608. DebugMsg( "*ERROR* %s: Entered %s (%#08x) after it was released. Returning E_FAIL.", \
  609. __MODULE__, \
  610. m_vtbl.pszInterface, \
  611. this \
  612. ); \
  613. \
  614. wnsprintf( szMessage, \
  615. cchDebugMessageSize, \
  616. TEXT("Entered %s (%#08x) after it was released.\n\nDo you want to break here?\n\n(If you do not break, E_FAIL will be returned.)"), \
  617. m_vtbl.pszInterface, \
  618. this \
  619. );\
  620. \
  621. lResult = MessageBox( NULL, szMessage, TEXT("Dead Interface"), MB_YESNO | MB_ICONWARNING );\
  622. if ( lResult == IDYES \
  623. ) \
  624. { \
  625. DEBUG_BREAK; \
  626. } \
  627. \
  628. return E_FAIL; \
  629. }
  630. IDeadObjTrackerStub(0);
  631. IDeadObjTrackerStub(1);
  632. IDeadObjTrackerStub(2);
  633. IDeadObjTrackerStub(3);
  634. IDeadObjTrackerStub(4);
  635. IDeadObjTrackerStub(5);
  636. IDeadObjTrackerStub(6);
  637. IDeadObjTrackerStub(7);
  638. IDeadObjTrackerStub(8);
  639. IDeadObjTrackerStub(9);
  640. IDeadObjTrackerStub(10);
  641. IDeadObjTrackerStub(11);
  642. IDeadObjTrackerStub(12);
  643. IDeadObjTrackerStub(13);
  644. IDeadObjTrackerStub(14);
  645. IDeadObjTrackerStub(15);
  646. IDeadObjTrackerStub(16);
  647. IDeadObjTrackerStub(17);
  648. IDeadObjTrackerStub(18);
  649. IDeadObjTrackerStub(19);
  650. IDeadObjTrackerStub(20);
  651. IDeadObjTrackerStub(21);
  652. IDeadObjTrackerStub(22);
  653. IDeadObjTrackerStub(23);
  654. IDeadObjTrackerStub(24);
  655. IDeadObjTrackerStub(25);
  656. IDeadObjTrackerStub(26);
  657. IDeadObjTrackerStub(27);
  658. IDeadObjTrackerStub(28);
  659. IDeadObjTrackerStub(29);
  660. IDeadObjTrackerStub(30);
  661. //****************************************************************************
  662. //
  663. // IUnknownTracker stub
  664. //
  665. // This merely directs the incoming call back to the orginal object. The
  666. // IUnknown methods will be remapped the the CITracker methods.
  667. //
  668. //****************************************************************************
  669. //////////////////////////////////////////////////////////////////////////////
  670. //
  671. // STDMETHODIMP
  672. // IUnknownTracker::QueryInterface(
  673. // REFIID riid,
  674. // LPVOID * ppv
  675. // )
  676. //
  677. //////////////////////////////////////////////////////////////////////////////
  678. STDMETHODIMP
  679. IUnknownTracker::QueryInterface(
  680. REFIID riid,
  681. LPVOID * ppv
  682. )
  683. {
  684. ErrorMsg( "How did you get here?", 0 );
  685. AssertMsg( 0, "You shouldn't be here!" );
  686. return E_FAIL;
  687. } //*** IUnknownTracker::QueryInterface( )
  688. //////////////////////////////////////////////////////////////////////////////
  689. //
  690. // STDMETHODIMP_( ULONG )
  691. // IUnknownTracker::AddRef( void )
  692. //
  693. //////////////////////////////////////////////////////////////////////////////
  694. STDMETHODIMP_( ULONG )
  695. IUnknownTracker::AddRef( void )
  696. {
  697. ErrorMsg( "How did you get here?", 0 );
  698. AssertMsg( 0, "You shouldn't be here!" );
  699. return -1;
  700. } //*** IUnknownTracker::AddRef( )
  701. //////////////////////////////////////////////////////////////////////////////
  702. //
  703. // STDMETHODIMP_( ULONG )
  704. // IUnknownTracker::Release( void )
  705. //
  706. //////////////////////////////////////////////////////////////////////////////
  707. STDMETHODIMP_( ULONG )
  708. IUnknownTracker::Release( void )
  709. {
  710. ErrorMsg( "How did you get here?", 0 );
  711. AssertMsg( 0, "You shouldn't be here!" );
  712. return -1;
  713. } //*** IUnknownTracker::Release( )
  714. //////////////////////////////////////////////////////////////////////////////
  715. //
  716. // STDMETHODIMP_(void)
  717. // IUnknownTracker::Stub(x)
  718. //
  719. // These are just stubs to redirect the call to the "real" method on the punk.
  720. // We actually dissappear from the call stack.
  721. //
  722. //////////////////////////////////////////////////////////////////////////////
  723. #define IUnknownTrackerStub( i ) \
  724. void \
  725. _declspec(naked) \
  726. IUnknownTracker::Stub##i() \
  727. { \
  728. _asm mov eax, ss:4[esp] \
  729. _asm mov ecx, 8[eax] \
  730. _asm mov eax, [ecx] \
  731. _asm mov ss:4[esp], ecx \
  732. _asm jmp dword ptr cs:(4*i)[eax] \
  733. }
  734. IUnknownTrackerStub(3);
  735. IUnknownTrackerStub(4);
  736. IUnknownTrackerStub(5);
  737. IUnknownTrackerStub(6);
  738. IUnknownTrackerStub(7);
  739. IUnknownTrackerStub(8);
  740. IUnknownTrackerStub(9);
  741. IUnknownTrackerStub(10);
  742. IUnknownTrackerStub(11);
  743. IUnknownTrackerStub(12);
  744. IUnknownTrackerStub(13);
  745. IUnknownTrackerStub(14);
  746. IUnknownTrackerStub(15);
  747. IUnknownTrackerStub(16);
  748. IUnknownTrackerStub(17);
  749. IUnknownTrackerStub(18);
  750. IUnknownTrackerStub(19);
  751. IUnknownTrackerStub(20);
  752. IUnknownTrackerStub(21);
  753. IUnknownTrackerStub(22);
  754. IUnknownTrackerStub(23);
  755. IUnknownTrackerStub(24);
  756. IUnknownTrackerStub(25);
  757. IUnknownTrackerStub(26);
  758. IUnknownTrackerStub(27);
  759. IUnknownTrackerStub(28);
  760. IUnknownTrackerStub(29);
  761. IUnknownTrackerStub(30);
  762. //
  763. // END FULL_TRACE_INTERFACES_ENABLED
  764. //
  765. ///////////////////////////////////////
  766. #endif // FULL_TRACE_INTERFACES_ENABLED