|
|
// File: clclsfct.cpp
//
// IClassFactory and related routines
//
// ULONG DLLAddRef(void);
// ULONG DLLRelease(void);
//
// STDAPI DllCanUnloadNow(void);
// VOID DllLock(void);
// VOID DllRelease(void);
//
//////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "clclsfct.h"
// from imanager.cpp
PIUnknown NewNmManager(OBJECTDESTROYEDPROC ObjectDestroyed);
CCLASSCONSTRUCTOR s_cclscnstr[] = { {&CLSID_NmManager2, &NewNmManager}, };
// DLL reference count == number of class factories +
// number of URLs +
// LockServer() count
ULONG s_ulcDLLRef = 0;
///////////////////////////////////////////////////////////////////////////
/* G E T C L A S S C O N S T R U C T O R */ /*-------------------------------------------------------------------------
%%Function: GetClassConstructor -------------------------------------------------------------------------*/ HRESULT GetClassConstructor(REFCLSID rclsid, PNEWOBJECTPROC pNewObject) { HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; UINT u;
ASSERT(IsValidREFCLSID(rclsid)); ASSERT(IS_VALID_WRITE_PTR(pNewObject, NEWOBJECTPROC));
*pNewObject = NULL;
for (u = 0; u < ARRAY_ELEMENTS(s_cclscnstr); u++) { if (rclsid == *(s_cclscnstr[u].pcclsid)) { *pNewObject = s_cclscnstr[u].NewObject; hr = S_OK; } }
ASSERT((hr == S_OK && IS_VALID_CODE_PTR(*pNewObject, NEWOBJECTPROC)) || (hr == CLASS_E_CLASSNOTAVAILABLE && ! *pNewObject));
return hr; }
VOID STDMETHODCALLTYPE DLLObjectDestroyed(void) { TRACE_OUT(("DLLObjectDestroyed(): Object destroyed."));
DllRelease(); }
/****************************** Public Functions *****************************/
ULONG DLLAddRef(void) { ASSERT(s_ulcDLLRef < ULONG_MAX);
ULONG ulcRef = ++s_ulcDLLRef;
DbgMsgRefCount("DLLAddRef(): DLL reference count is now %lu.", ulcRef);
return ulcRef; }
ULONG DLLRelease(void) { ULONG ulcRef;
if (s_ulcDLLRef > 0) { s_ulcDLLRef--; }
ulcRef = s_ulcDLLRef;
DbgMsgRefCount("DLLRelease(): DLL reference count is now %lu.", ulcRef);
return ulcRef; }
PULONG GetDLLRefCountPtr(void) { return(&s_ulcDLLRef); }
/********************************** Methods **********************************/
CCLClassFactory::CCLClassFactory(NEWOBJECTPROC NewObject, OBJECTDESTROYEDPROC ObjectDestroyed) : RefCount(ObjectDestroyed) { // Don't validate this until after construction.
ASSERT(IS_VALID_CODE_PTR(NewObject, NEWOBJECTPROC));
m_NewObject = NewObject;
ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); }
CCLClassFactory::~CCLClassFactory(void) { ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory));
m_NewObject = NULL; }
ULONG STDMETHODCALLTYPE CCLClassFactory::AddRef(void) { ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory));
ULONG ulcRef = RefCount::AddRef();
ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); return ulcRef; }
ULONG STDMETHODCALLTYPE CCLClassFactory::Release(void) { ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory));
ULONG ulcRef = RefCount::Release(); return ulcRef; }
HRESULT STDMETHODCALLTYPE CCLClassFactory::QueryInterface(REFIID riid, PVOID *ppvObject) { HRESULT hr = S_OK;
ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); ASSERT(IsValidREFIID(riid)); ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
if (riid == IID_IClassFactory) { *ppvObject = (PIClassFactory)this; ASSERT(IS_VALID_INTERFACE_PTR((PIClassFactory)*ppvObject, IClassFactory)); TRACE_OUT(("CCLClassFactory::QueryInterface(): Returning IClassFactory.")); } else if (riid == IID_IUnknown) { *ppvObject = (PIUnknown)this; ASSERT(IS_VALID_INTERFACE_PTR((PIUnknown)*ppvObject, IUnknown)); TRACE_OUT(("CCLClassFactory::QueryInterface(): Returning IUnknown.")); } else { *ppvObject = NULL; hr = E_NOINTERFACE; TRACE_OUT(("CCLClassFactory::QueryInterface(): Called on unknown interface.")); }
if (hr == S_OK) { AddRef(); }
ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); return hr; }
HRESULT STDMETHODCALLTYPE CCLClassFactory::CreateInstance(PIUnknown piunkOuter, REFIID riid, PVOID *ppvObject) { ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); ASSERT(! piunkOuter || IS_VALID_INTERFACE_PTR(piunkOuter, IUnknown)); ASSERT(IsValidREFIID(riid)); ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
*ppvObject = NULL;
if (NULL != piunkOuter) { WARNING_OUT(("CCLClassFactory::CreateInstance(): Aggregation not supported.")); return CLASS_E_NOAGGREGATION; }
PIUnknown piunk = (*m_NewObject)( (void(__stdcall *)(void)) &DLLObjectDestroyed); if (NULL == piunk) { return E_OUTOFMEMORY; } DllLock(); HRESULT hr = piunk->QueryInterface(riid, ppvObject);
// N.b., the Release() method will destroy the object if the
// QueryInterface() method failed.
piunk->Release();
ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); return hr; }
HRESULT STDMETHODCALLTYPE CCLClassFactory::LockServer(BOOL fLock) { ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory));
if (fLock) { DllLock(); } else { DllRelease(); }
ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); return S_OK; }
/***************************** Exported Functions ****************************/
/* D L L G E T C L A S S O B J E C T */ /*-------------------------------------------------------------------------
%%Function: DllGetClassObject -------------------------------------------------------------------------*/ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PVOID *ppvObject) {
ASSERT(IsValidREFCLSID(rclsid)); ASSERT(IsValidREFIID(riid)); ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
*ppvObject = NULL;
NEWOBJECTPROC NewObject; HRESULT hr = GetClassConstructor(rclsid, &NewObject); if (S_OK != hr) { WARNING_OUT(("DllGetClassObject(): Called on unknown class.")); return hr; }
if ((riid != IID_IUnknown) && (riid != IID_IClassFactory)) { WARNING_OUT(("DllGetClassObject(): Called on unknown interface.")); return E_NOINTERFACE; }
PCCLClassFactory pcf = new CCLClassFactory(NewObject, (void(__stdcall *)(void)) &DLLObjectDestroyed); if (NULL == pcf) { return E_OUTOFMEMORY; }
if (riid == IID_IClassFactory) { *ppvObject = (PIClassFactory)pcf; ASSERT(IS_VALID_INTERFACE_PTR((PIClassFactory)*ppvObject, IClassFactory)); TRACE_OUT(("DllGetClassObject(): Returning IClassFactory.")); } else { ASSERT(riid == IID_IUnknown); *ppvObject = (PIUnknown)pcf; ASSERT(IS_VALID_INTERFACE_PTR((PIUnknown)*ppvObject, IUnknown)); TRACE_OUT(("DllGetClassObject(): Returning IUnknown.")); }
DllLock();
TRACE_OUT(("DllGetClassObject(): Created a new class factory.")); return S_OK; }
/* D L L C A N U N L O A D N O W */ /*-------------------------------------------------------------------------
%%Function: DllCanUnloadNow -------------------------------------------------------------------------*/ STDAPI DllCanUnloadNow(void) { HRESULT hr = (s_ulcDLLRef > 0) ? S_FALSE : S_OK; TRACE_OUT(("DllCanUnloadNow(): DLL reference count is %lu.", s_ulcDLLRef)); return hr; }
/* D L L L O C K */ /*-------------------------------------------------------------------------
%%Function: DllLock -------------------------------------------------------------------------*/ VOID DllLock(void) { InterlockedIncrement((LPLONG) &s_ulcDLLRef); DbgMsgRefCount("Ref: DllLock count=%d", s_ulcDLLRef); }
/* D L L R E L E A S E */ /*-------------------------------------------------------------------------
%%Function: DllRelease -------------------------------------------------------------------------*/ VOID DllRelease(void) { LONG cRef = InterlockedDecrement((LPLONG) &s_ulcDLLRef);
#ifdef DEBUG
DbgMsgRefCount("Ref: DllLock count=%d", s_ulcDLLRef); if (0 == cRef) { WARNING_OUT(("NMCOM.DLL Can now be unloaded")); } #endif
}
|