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.

792 lines
20 KiB

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