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.
351 lines
8.2 KiB
351 lines
8.2 KiB
// 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
|
|
}
|
|
|