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.
 
 
 
 
 
 

456 lines
12 KiB

/****************************************************************************
* $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 <assert.h>
//***************************************************************************
// 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
//
*/