// // Copyright 1997 - Microsoft // // // QI.CPP - Handles the QueryInterface // #include "pch.h" // // Begin Class Definitions // DEFINE_MODULE("IMADMUI") // // QueryInterface() // extern HRESULT QueryInterface( LPVOID that, LPQITABLE pQI, REFIID riid, LPVOID* ppv ) { TraceMsg( TF_FUNC, "[IUnknown] QueryInterface( riid=" ); HRESULT hr = E_NOINTERFACE; Assert( ppv != NULL ); *ppv = NULL; for( int i = 0; pQI[ i ].pvtbl; i++ ) { if ( riid == *pQI[ i ].riid ) { #ifdef DEBUG TraceMsg( TF_FUNC, "%s, ppv=0x%08x )\n", pQI[i].pszName, ppv ); #endif // DEBUG *ppv = pQI[ i ].pvtbl; hr = S_OK; break; } } if ( hr == E_NOINTERFACE ) { TraceMsgGUID( TF_FUNC, riid ); TraceMsg( TF_FUNC, ", ppv=0x%08x )\n", ppv ); } if ( SUCCEEDED( hr ) ) { ( (IUnknown *) *ppv )->AddRef(); } return hr; } /////////////////////////////////////// // // NOISY_QI // #ifndef NOISY_QI #undef TraceMsg #define TraceMsg 1 ? (void)0 : (void) #undef TraceFunc #define TraceFunc 1 ? (void)0 : (void) #undef TraceClsFunc #define TraceClsFunc 1 ? (void)0 : (void) #undef TraceFuncExit #define TraceFuncExit() #undef HRETURN #define HRETURN(_hr) return(_hr) #undef RETURN #define RETURN(_fn) return(_fn) #undef ErrorMsg #define ErrorMsg 1 ? (void)0 : (void) #endif // NOISY_QI // // END NOISY_QI // /////////////////////////////////////// #ifndef NO_TRACE_INTERFACES #ifdef DEBUG /////////////////////////////////////// // // BEGIN DEBUG // /////////////////////////////////////// // // CITracker // // DEFINE_THISCLASS("CITracker"); #define THISCLASS CITracker #define LPTHISCLASS LPITRACKER // ************************************************************************ // // Constructor / Destructor // // ************************************************************************ // // Special new( ) for CITracker // #undef new void* __cdecl operator new( unsigned int nSize, LPCTSTR pszFile, const int iLine, LPCTSTR pszModule, UINT nExtra ) { return DebugAlloc( pszFile, iLine, pszModule, GPTR, nSize + nExtra, __THISCLASS__ ); } #define new new( TEXT(__FILE__), __LINE__, __MODULE__, nExtra ) // // CreateInstance() // LPVOID CITracker_CreateInstance( LPQITABLE pQITable ) { TraceFunc( "CITracker_CreateInstance( " ); TraceMsg( TF_FUNC, "pQITable = 0x%08x )\n", pQITable ); if ( !pQITable ) { THR( E_POINTER ); RETURN(NULL); } HRESULT hr; // // Add up the space needed for all the vtbls // for( int i = 1; pQITable[i].riid; i++ ) { UINT nExtra = VTBL2OFFSET + (( 3 + pQITable[i].cFunctions ) * sizeof(LPVOID)); // The "new" below is a macro that needs "nExtra" defined. (see above) LPTHISCLASS lpc = new THISCLASS( ); if ( !lpc ) { hr = THR(E_OUTOFMEMORY); goto Error; } hr = THR( lpc->Init( &pQITable[i] ) ); if ( hr ) { delete lpc; lpc = NULL; goto Error; } // DebugMemoryDelete( lpc ); } Error: RETURN(NULL); } // // Constructor // THISCLASS::THISCLASS( ) { TraceClsFunc( "" ); TraceMsg( TF_FUNC, "%s()\n", __THISCLASS__ ); InterlockIncrement( g_cObjects ); TraceFuncExit(); } STDMETHODIMP THISCLASS::Init( LPQITABLE pQITable ) { HRESULT hr = S_OK; TraceClsFunc( "Init( " ); TraceMsg( TF_FUNC, "pQITable = 0x%08x )\n", pQITable ); // // Generate new Vtbls for each interface // LPVOID *pthisVtbl = (LPVOID*) (IUnknown*) this; LPVOID *ppthatVtbl = (LPVOID*) pQITable->pvtbl; DWORD dwSize = ( 3 + pQITable->cFunctions ) * sizeof(LPVOID); // Interface tracking information initialization Assert( _vtbl.cRef == 0 ); _vtbl.pszInterface = pQITable->pszName; // This is so we can get to our object's "this" pointer // after someone jumped to our IUnknown. _vtbl.pITracker = (LPUNKNOWN) this; // Copy the orginal vtbl. CopyMemory( &_vtbl.lpfnQueryInterface, *ppthatVtbl, dwSize ); // Copy our IUnknown vtbl to the beginning 3 entries. CopyMemory( &_vtbl.lpfnQueryInterface, *pthisVtbl, 3 * sizeof(LPVOID) ); // Remember the old vtbl so we can jump to the orginal objects // IUnknown functions. _vtbl.pOrginalVtbl = (LPVTBL) *ppthatVtbl; // Remember the "punk" pointer so we can pass it back in when // we jump to the orginal objects IUnknown functions. _vtbl.punk = (LPUNKNOWN) pQITable->pvtbl; // And finally, point the objects vtbl for this interface to // our newly created vtbl. *ppthatVtbl = &_vtbl.lpfnQueryInterface; TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, TF_FUNC, L"Tracking %s Interface...\n", _vtbl.pszInterface ); HRETURN(hr); } // // Destructor // THISCLASS::~THISCLASS( ) { TraceClsFunc( "" ); TraceMsg( TF_FUNC, "~%s()\n", __THISCLASS__ ); InterlockDecrement( g_cObjects ); TraceFuncExit(); }; // ************************************************************************ // // IUnknown // // ************************************************************************ // // QueryInterface() // STDMETHODIMP THISCLASS::QueryInterface( REFIID riid, LPVOID *ppv ) { // TraceClsFunc( "[IUnknown] QueryInterface( )\n" ); // // Translate call to get our this pointer // LPVOID* punk = (LPVOID*) (LPUNKNOWN) this; LPVTBL2 pvtbl = (LPVTBL2) ((LPBYTE)*punk - VTBL2OFFSET); LPTHISCLASS that = (LPTHISCLASS) pvtbl->pITracker; // // Jump to our real implementation // HRESULT hr = that->_QueryInterface( riid, ppv ); // HRETURN(hr); return hr; } // // AddRef() // STDMETHODIMP_(ULONG) THISCLASS::AddRef( void ) { // TraceClsFunc( "[IUnknown] AddRef( )\n" ); // // Translate call to get our this pointer // LPVOID* punk = (LPVOID*) (LPUNKNOWN) this; LPVTBL2 pvtbl = (LPVTBL2) ((LPBYTE)*punk - VTBL2OFFSET); LPTHISCLASS that = (LPTHISCLASS) pvtbl->pITracker; // // Jump to our real implementation // ULONG ul = that->_AddRef( ); // RETURN(ul); return ul; } // // Release() // STDMETHODIMP_(ULONG) THISCLASS::Release( void ) { // TraceClsFunc( "[IUnknown] Release( )\n" ); // // Translate call to get our this pointer // LPVOID* punk = (LPVOID*) (LPUNKNOWN) this; LPVTBL2 pvtbl = (LPVTBL2) ((LPBYTE)*punk - VTBL2OFFSET); LPTHISCLASS that = (LPTHISCLASS) pvtbl->pITracker; // // Jump to our real implementation // ULONG ul = that->_Release( ); // RETURN(ul); return ul; } // ************************************************************************ // // IUnknown2 // // ************************************************************************ // // _QueryInterface() // STDMETHODIMP THISCLASS::_QueryInterface( REFIID riid, LPVOID *ppv ) { #ifdef NOISY_QI TraceClsFunc( ""); TraceMsg( TF_FUNC, "{%s} QueryInterface( ... )\n", _vtbl.pszInterface ); #else InterlockIncrement(g_dwCounter) TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, TF_FUNC, L"{%s} QueryInterface( ... )\n", _vtbl.pszInterface ); #endif HRESULT hr = _vtbl.pOrginalVtbl->lpfnQueryInterface( _vtbl.punk, riid, ppv ); #ifdef NOISY_QI HRETURN(hr); #else TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V\n") ); InterlockDecrement(g_dwCounter); return(hr); #endif } // // _AddRef() // STDMETHODIMP_(ULONG) THISCLASS::_AddRef( void ) { #ifdef NOISY_QI TraceClsFunc( ""); TraceMsg( TF_FUNC, "{%s} AddRef( )\n", _vtbl.pszInterface ); #else InterlockIncrement(g_dwCounter) TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, TF_FUNC, L"{%s} AddRef()\n", _vtbl.pszInterface ); #endif ULONG ul = _vtbl.pOrginalVtbl->lpfnAddRef( _vtbl.punk ); InterlockIncrement( _vtbl.cRef ); #ifdef NOISY_QI RETURN(ul); #else TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V I=%u, O=%u\n"), _vtbl.cRef, ul ); InterlockDecrement(g_dwCounter); return ul; #endif } // // _Release() // STDMETHODIMP_(ULONG) THISCLASS::_Release( void ) { #ifdef NOISY_QI TraceClsFunc( ""); TraceMsg( TF_FUNC, "{%s} Release( )\n", _vtbl.pszInterface ); #else InterlockIncrement(g_dwCounter) TraceMessage( TEXT(__FILE__), __LINE__, __MODULE__, TF_FUNC, L"{%s} Release()\n", _vtbl.pszInterface ); #endif ULONG ul = _vtbl.pOrginalVtbl->lpfnRelease( _vtbl.punk ); InterlockDecrement( _vtbl.cRef ); if ( ul ) { #ifdef NOISY_QI RETURN(ul); #else TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V I=%u, O=%u\n"), _vtbl.cRef, ul ); InterlockDecrement(g_dwCounter); return ul; #endif } // // TODO: Figure out how to destroy the tracking objects. // #ifdef NOISY_QI RETURN(ul); #else TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V I=%u, O=%u\n"), _vtbl.cRef, ul ); InterlockDecrement(g_dwCounter); return ul; #endif } // // END DEBUG // /////////////////////////////////////// #endif // DEBUG #endif // NO_TRACE_INTERFACES