mirror of https://github.com/tongzx/nt5src
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
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
|
|
//
|
|
*/
|