/**************************************************************************** * $Header: J:\rtp\src\ppm\fact.cpv 1.3 20 Mar 1997 18:32:04 lscline $ * * INTEL Corporation Proprietary Information * * This listing is supplied under the terms of a license agreement * with INTEL Corporation and may not be copied nor disclosed except * in accordance with the terms of that agreement. * * Copyright (c) 1995, 1996 Intel Corporation. All rights reserved. * * $Revision: 1.3 $ * $Date: 20 Mar 1997 18:32:04 $ * $Author: lscline $ * * Log at end of file. * * Module Name: psfact.cpp * Abstract: common OLE 2 class factory * Environment: MSVC 4.0, OLE 2 * Notes: * ***************************************************************************/ //#include "_stable.h" // standard precompiled headers #include "core.h" #include //*************************************************************************** // CClassFactory // ///////////////////////////////////////////////////////////////////////////// // static data members ULONG NEAR CClassFactory::s_cLockServer = 0; ULONG NEAR CClassFactory::s_cObjects = 0; UNLOADSERVERPROC NEAR CClassFactory::s_pfnUnloadServer = NULL; UINT NEAR CClassFactory::s_nRegistry = 0; // registry defined by REGISTER_CLASS macros ///////////////////////////////////////////////////////////////////////////// // ctor, dtor CClassFactory::CClassFactory( Registry* pReg ) { m_cRef = 0; ++s_cObjects; assert( pReg ); assert( ! pReg->pFactory ); m_pReg = pReg; m_pReg->pFactory = this; } CClassFactory::~CClassFactory() { assert( m_pReg ); assert( m_pReg->pFactory == this ); m_pReg->pFactory = NULL; --s_cObjects; } ///////////////////////////////////////////////////////////////////////////// // IUnknown implementation // STDMETHODIMP CClassFactory::QueryInterface( REFIID riid, LPVOID FAR* ppvObj ) { if( riid == IID_IClassFactory || riid == IID_IUnknown ) { *ppvObj = this; } else return ResultFromScode( E_NOINTERFACE ); LPUNKNOWN( *ppvObj )->AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CClassFactory::AddRef( void ) { return ++m_cRef; } STDMETHODIMP_(ULONG) CClassFactory::Release( void ) { if( ! --m_cRef ) { delete this; CanUnloadNow(); return 0; } return m_cRef; } ///////////////////////////////////////////////////////////////////////////// // IClassFactory implementation // STDMETHODIMP CClassFactory::CreateInstance( LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppvObj ) { HRESULT hr; assert( ! IsBadWritePtr( ppvObj, sizeof( LPVOID FAR* ) ) ); *ppvObj = NULL; // verify that IUnknown is requested when being aggregated if( pUnkOuter && riid != IID_IUnknown ) return ResultFromScode( E_INVALIDARG ); assert( m_pReg ); // if it's a single instance class, return an existing instance if there is one if( m_pReg->regCls == REGCLS_SINGLEUSE ) { if( m_pReg->pUnkSingle ) { assert( 1 == m_pReg->cObjects ); return m_pReg->pUnkSingle->QueryInterface( riid, ppvObj ); } } // create the object LPUNKNOWN pUnkInner; hr = m_pReg->pfnCreate( pUnkOuter, ObjectDestroyed, &pUnkInner ); if( FAILED( hr ) ) return hr; if( ! pUnkInner ) return ResultFromScode( E_UNEXPECTED ); // ref count should now be 1, by our convention // If the riid is not implemented, the object will be destroyed, at which time // these variables will be decremented (see ObjectDestroyed). If // these aren't incremented here we get ASSERTs in ObjectDestroyed. // This happens more often now that PsCreateInstance is used to // create the Settings object as it passes in IPsObject which is // not implemented by Settings. m_pReg->cObjects++; s_cObjects++; hr = pUnkInner->QueryInterface( riid, ppvObj ); if( FAILED( hr ) ) { // delete object; ref count should be 1 here pUnkInner->Release(); return hr; } // release object to account for extra reference on creation pUnkInner->Release(); if( m_pReg->regCls == REGCLS_SINGLEUSE ) { m_pReg->pUnkSingle = pUnkInner; } return NOERROR; } STDMETHODIMP CClassFactory::LockServer( BOOL fLock ) { if( fLock ) { ++s_cLockServer; // check for overflow if( ! s_cLockServer ) return ResultFromScode( E_UNEXPECTED ); } else { // check for lock if( ! s_cLockServer ) return ResultFromScode( E_UNEXPECTED ); --s_cLockServer; // might be time to unload CanUnloadNow(); } return NOERROR; } ///////////////////////////////////////////////////////////////////////////// // Check if server can be unloaded (no locks and no objects serviced). // Calls s_pfnUnloadServer proc if provided // STDMETHODIMP CClassFactory::CanUnloadNow( void ) { if( ! s_cLockServer && ! s_cObjects ) { if( s_pfnUnloadServer ) s_pfnUnloadServer(); return ResultFromScode( S_OK ); } return ResultFromScode( S_FALSE ); } ///////////////////////////////////////////////////////////////////////////// // Callback from class when an object is destroyed. Allows server to be // unloaded when no objects are being serviced // STDMETHODIMP_( void ) CClassFactory::ObjectDestroyed( REFCLSID rclsid ) { Registry* pReg = FindClass( &rclsid ); if( pReg ) { assert( pReg->cObjects ); pReg->cObjects--; if( pReg->regCls == REGCLS_SINGLEUSE ) { assert( ! pReg->cObjects ); assert( pReg->pUnkSingle ); pReg->pUnkSingle = NULL; } } assert( s_cObjects ); s_cObjects--; // might be time to unload CanUnloadNow(); } ///////////////////////////////////////////////////////////////////////////// // Find a class in the registry // CClassFactory::Registry* CClassFactory::FindClass( const CLSID* pClsid ) { return (Registry*) bsearch( (const void*) &pClsid, (const void*) s_registry, s_nRegistry, sizeof( Registry ), CompareClsids ); } ///////////////////////////////////////////////////////////////////////////// // qsort/bsearch comparison function - compare class ids (or Registry entries) // #ifndef _DEBUG #pragma function( memcmp ) // specifies that memcmp will be normal #endif int __cdecl CClassFactory::CompareClsids( const void* pClsid1, const void* pClsid2 ) { return memcmp( *(const CLSID**)pClsid1, *(const CLSID**)pClsid2, sizeof( CLSID ) ); } #ifndef _DEBUG #pragma intrinsic( memcmp ) // specifies that memcmp will be intrinsic #endif ///////////////////////////////////////////////////////////////////////////// // sort the registry by clsid // void CClassFactory::SortRegistry( void ) { if( ! s_nRegistry ) { // count the registry for( Registry* pReg = s_registry; pReg->pClsid != &CLSID_NULL; pReg++ ) { s_nRegistry++; } // sort the registry qsort( (void*) s_registry, s_nRegistry, sizeof( Registry ), CompareClsids ); } } ///////////////////////////////////////////////////////////////////////////// // EXE server helper functions; set unload server callback proc, // CoRegister/CoRevoke all classes registered with the class factory // void CClassFactory::SetUnloadServerProc( UNLOADSERVERPROC pfnUnloadServer ) { assert( ! IsBadCodePtr( (FARPROC) pfnUnloadServer ) ); s_pfnUnloadServer = pfnUnloadServer; } STDMETHODIMP CClassFactory::RegisterAllClasses( DWORD dwClsContext ) { SortRegistry(); Registry* pReg = s_registry; Registry* pEnd = s_registry + s_nRegistry; for( ; pReg < pEnd; pReg++ ) { LPCLASSFACTORY pFactory = pReg->pFactory ? pReg->pFactory : newCClassFactory( pReg ); if( ! pFactory ) return ResultFromScode( E_OUTOFMEMORY ); pFactory->AddRef(); HRESULT hr = CoRegisterClassObject( *pReg->pClsid, pFactory, dwClsContext, pReg->regCls, &pReg->dwRegister ); if( FAILED( hr ) ) { pFactory->Release(); return hr; } } return NOERROR; } STDMETHODIMP CClassFactory::RevokeAllClasses( void ) { Registry* pReg = s_registry; Registry* pEnd = s_registry + s_nRegistry; for( ; pReg < pEnd; pReg++ ) { HRESULT hr = CoRevokeClassObject( pReg->dwRegister ); if( FAILED( hr ) ) return hr; if( pReg->pFactory ) pReg->pFactory->Release(); } return NOERROR; } ///////////////////////////////////////////////////////////////////////////// // DLL server helper function; call from DllGetClassObject // STDMETHODIMP CClassFactory::GetClassObject( REFCLSID rclsid, REFIID riid, LPVOID FAR* ppvObj ) { assert( ! IsBadWritePtr( ppvObj, sizeof( LPVOID FAR* ) ) ); SortRegistry(); Registry* pReg = FindClass( &rclsid ); if( ! pReg ) return ResultFromScode( CLASS_E_CLASSNOTAVAILABLE ); CClassFactory* pFactory = pReg->pFactory ? pReg->pFactory : newCClassFactory( pReg ); if( ! pFactory ) return ResultFromScode( E_OUTOFMEMORY ); HRESULT hr = pFactory->QueryInterface( riid, ppvObj ); if( FAILED( hr ) ) { // if we just created the factory its ref count will be 0 and we // need to delete it. Otherwise it must continue to exist. pFactory->AddRef(); pFactory->Release(); } return hr; } ///////////////////////////////////////////////////////////////////////////// // local CoCreateInstance; call when creating come objects locally // (not via CoCreateInstance) // STDMETHODIMP CClassFactory::LocalCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID FAR* ppvObj ) { dwClsContext; // to statisfy the compiler // get the class factory for the requested object LPCLASSFACTORY lpClassFactory; HRESULT hr = GetClassObject( rclsid, IID_IClassFactory, (LPVOID FAR*) &lpClassFactory ); if( FAILED( hr ) ) return hr; // create an instance of the requested object and get the requested interface hr = lpClassFactory->CreateInstance( pUnkOuter, riid, ppvObj ); lpClassFactory->Release(); return hr; } ///////////////////////////////////////////////////////////////////////////// // Method to help with dynamic memory allocation of a CClassFactory object. // CClassFactory* CClassFactory::newCClassFactory( Registry* pReg ) { CClassFactory *p = NULL; // TRY // { p = new CClassFactory( pReg ); // } // CATCH( CMemoryException, e ) // { // TRACE0( "Caught memory exception in CClassFactory::newCClassFactory\n" ); // } // END_CATCH return p; } /* ///////////////////////////////////////////////////////////////////////////// // $Log: J:\rtp\src\ppm\fact.cpv $ Rev 1.3 20 Mar 1997 18:32:04 lscline Merged small change differences for MS NT 5.0 build environment. Rev 1.2 05 Apr 1996 16:46:00 LSCLINE Copyright Rev 1.1 Dec 11 1995 13:39:08 rnegrin Fixed the PVCS log at end of file Rev 1.0 Dec 08 1995 16:41:06 rnegrin Initial revision. // // Rev 1.12 20 Sep 1995 16:05:14 PCRUTCHE // OLEFHK32 // // Rev 1.11 13 Jun 1995 19:36:00 DEDEN // Dynamic object allocation helper functions\macros // // Rev 1.10 06 Jan 1995 09:56:44 PCRUTCHE // Changed registry data structure // // Rev 1.9 02 Nov 1994 10:50:00 JDELLIOT // get rid of compiler warnings // // Rev 1.8 28 Oct 1994 13:51:16 JDELLIOT // added LocalCreateInstance for creating local COM objects (not via // CoCreateInstance) // // Rev 1.7 26 Oct 1994 17:52:44 JDELLIOT // in CreateInstance after calling _CreateObject the object now has a ref count // of 1. As such when we QueryInterface the ref count goes to 2 and we need // to Release it back down to one. This was added for aggregation. // // Rev 1.6 25 Oct 1994 14:42:42 KAWATTS // Removed TRACEs again // // Rev 1.5 25 Oct 1994 10:21:02 JDELLIOT // added TRACEs for s_cObjects // // Rev 1.4 19 Oct 1994 14:57:48 JDELLIOT // minor changes // // Rev 1.3 12 Oct 1994 18:11:58 JDELLIOT // changed params to CClassFactory::FindClass // fixed AddRef inside CClassFactory::QueryInterface // // Rev 1.2 07 Oct 1994 11:26:46 KAWATTS // All rights reserved // // Rev 1.1 07 Oct 1994 09:51:14 JDELLIOT // fixed PVCS keywords // */