/* * clsfact.cpp - IClassFactory implementation. * * Taken from URL code - essentially identical to DavidDi's original code * * Created: ChrisPi 9-11-95 * */ /* Headers **********/ #include "precomp.h" #include "CLinkID.h" #include "clrefcnt.hpp" #include "clenumft.hpp" #include "clCnfLnk.hpp" #include "clclsfct.h" #define INITGUID #include #include #include // from niMgr.cpp PIUnknown NewNmManager(OBJECTDESTROYEDPROC ObjectDestroyed); // from imconfmg.cpp PIUnknown NewConfMgr(OBJECTDESTROYEDPROC ObjectDestroyed); /* Module Constants *******************/ #pragma data_seg(DATA_SEG_READ_ONLY) CCLASSCONSTRUCTOR s_cclscnstr[] = { // { &CLSID_ConferenceManager, &NewNmManager }, { &CLSID_ConfLink, &NewConfLink }, // { &CLSID_NmManager, &NewNmManager }, // { &CLSID_MIMEFileTypesPropSheetHook, &NewMIMEHook }, // { &CLSID_Internet, &NewInternet }, }; #pragma data_seg() /* Module Variables *******************/ #pragma data_seg(DATA_SEG_PER_INSTANCE) // DLL reference count == number of class factories + // number of URLs + // LockServer() count ULONG s_ulcDLLRef = 0; #pragma data_seg() /***************************** Private Functions *****************************/ 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(); } PIUnknown NewConfLink(OBJECTDESTROYEDPROC ObjectDestroyed) { ASSERT(! ObjectDestroyed || IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC)); TRACE_OUT(("NewConfLink(): Creating a new ConfLink.")); return((PIUnknown) (PIConferenceLink) new CConfLink(ObjectDestroyed)); } #if 0 PIUnknown NewMIMEHook(OBJECTDESTROYEDPROC ObjectDestroyed) { ASSERT(! ObjectDestroyed || IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC)); TRACE_OUT(("NewMIMEHook(): Creating a new MIMEHook.")); return((PIUnknown)(PIShellPropSheetExt)new(MIMEHook(ObjectDestroyed))); } PIUnknown NewInternet(OBJECTDESTROYEDPROC ObjectDestroyed) { ASSERT(! ObjectDestroyed || IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC)); TRACE_OUT(("NewInternet(): Creating a new Internet.")); return((PIUnknown)(PIShellPropSheetExt)new(Internet(ObjectDestroyed))); } #endif // 0 #ifdef DEBUG BOOL IsValidPCCCLClassFactory(PCCCLClassFactory pccf) { return(IS_VALID_READ_PTR(pccf, CCCLClassFactory) && IS_VALID_CODE_PTR(pccf->m_NewObject, NEWOBJECTPROC) && IS_VALID_STRUCT_PTR((PCRefCount)pccf, CRefCount) && IS_VALID_INTERFACE_PTR((PCIClassFactory)pccf, IClassFactory)); } #endif /****************************** Public Functions *****************************/ ULONG DLLAddRef(void) { ULONG ulcRef; ASSERT(s_ulcDLLRef < ULONG_MAX); ulcRef = ++s_ulcDLLRef; TRACE_OUT(("DLLAddRef(): DLL reference count is now %lu.", ulcRef)); return(ulcRef); } ULONG DLLRelease(void) { ULONG ulcRef; if (EVAL(s_ulcDLLRef > 0)) s_ulcDLLRef--; ulcRef = s_ulcDLLRef; TRACE_OUT(("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) { DebugEntry(CCLClassFactory::CCLClassFactory); // Don't validate this until after construction. ASSERT(IS_VALID_CODE_PTR(NewObject, NEWOBJECTPROC)); m_NewObject = NewObject; ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); DebugExitVOID(CCLClassFactory::CCLClassFactory); return; } CCLClassFactory::~CCLClassFactory(void) { DebugEntry(CCLClassFactory::~CCLClassFactory); ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); m_NewObject = NULL; // Don't validate this after destruction. DebugExitVOID(CCLClassFactory::~CCLClassFactory); return; } ULONG STDMETHODCALLTYPE CCLClassFactory::AddRef(void) { ULONG ulcRef; DebugEntry(CCLClassFactory::AddRef); ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); ulcRef = RefCount::AddRef(); ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); DebugExitULONG(CCLClassFactory::AddRef, ulcRef); return(ulcRef); } ULONG STDMETHODCALLTYPE CCLClassFactory::Release(void) { ULONG ulcRef; DebugEntry(CCLClassFactory::Release); ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); ulcRef = RefCount::Release(); DebugExitULONG(CCLClassFactory::Release, ulcRef); return(ulcRef); } HRESULT STDMETHODCALLTYPE CCLClassFactory::QueryInterface(REFIID riid, PVOID *ppvObject) { HRESULT hr = S_OK; DebugEntry(CCLClassFactory::QueryInterface); 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)); // removed by ChrisPi CINTERFACE undeclared identifier // ASSERT(FAILED(hr) || // IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE)); DebugExitHRESULT(CCLClassFactory::QueryInterface, hr); return(hr); } HRESULT STDMETHODCALLTYPE CCLClassFactory::CreateInstance(PIUnknown piunkOuter, REFIID riid, PVOID *ppvObject) { HRESULT hr; DebugEntry(CCLClassFactory::CreateInstance); 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 (! piunkOuter) { PIUnknown piunk; piunk = (*m_NewObject)( (void(__stdcall *)(void)) &DLLObjectDestroyed); if (piunk) { DllLock(); hr = piunk->QueryInterface(riid, ppvObject); // N.b., the Release() method will destroy the object if the // QueryInterface() method failed. piunk->Release(); } else hr = E_OUTOFMEMORY; } else { hr = CLASS_E_NOAGGREGATION; WARNING_OUT(("CCLClassFactory::CreateInstance(): Aggregation not supported.")); } ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); // removed by ChrisPi - see above // ASSERT(FAILED(hr) || // IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE)); DebugExitHRESULT(CCLClassFactory::CreateInstance, hr); return(hr); } HRESULT STDMETHODCALLTYPE CCLClassFactory::LockServer(BOOL bLock) { HRESULT hr; DebugEntry(CCLClassFactory::LockServer); ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); // bLock may be any value. if (bLock) DllLock(); else DllRelease(); hr = S_OK; ASSERT(IS_VALID_STRUCT_PTR(this, CCCLClassFactory)); DebugExitHRESULT(CCLClassFactory::LockServer, hr); return(hr); } /***************************** Exported Functions ****************************/ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PVOID *ppvObject) { HRESULT hr = S_OK; NEWOBJECTPROC NewObject; DebugEntry(DllGetClassObject); ASSERT(IsValidREFCLSID(rclsid)); ASSERT(IsValidREFIID(riid)); ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID)); *ppvObject = NULL; hr = GetClassConstructor(rclsid, &NewObject); if (hr == S_OK) { if (riid == IID_IUnknown || riid == IID_IClassFactory) { PCCLClassFactory pcf; pcf = new CCLClassFactory(NewObject, (void(__stdcall *)(void)) &DLLObjectDestroyed); if (pcf) { 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(); hr = S_OK; TRACE_OUT(("DllGetClassObject(): Created a new class factory.")); } else hr = E_OUTOFMEMORY; } else { WARNING_OUT(("DllGetClassObject(): Called on unknown interface.")); hr = E_NOINTERFACE; } } else WARNING_OUT(("DllGetClassObject(): Called on unknown class.")); // removed by ChrisPi - see above // ASSERT(FAILED(hr) || // IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE)); DebugExitHRESULT(DllGetClassObject, hr); return(hr); } STDAPI DllCanUnloadNow(void) { HRESULT hr; DebugEntry(DllCanUnloadNow); hr = (s_ulcDLLRef > 0) ? S_FALSE : S_OK; TRACE_OUT(("DllCanUnloadNow(): DLL reference count is %lu.", s_ulcDLLRef)); DebugExitHRESULT(DllCanUnloadNow, hr); return(hr); } void DllLock(void) { InterlockedIncrement((LPLONG) &s_ulcDLLRef); DBGAPI_TRACE("Ref: DllLock count=%d", s_ulcDLLRef); } void DllRelease(void) { LONG cRef = InterlockedDecrement((LPLONG) &s_ulcDLLRef); #ifdef DEBUG DBGAPI_TRACE("Ref: DllLock count=%d", s_ulcDLLRef); if (0 == cRef) WARNING_OUT(("MSCONF.DLL Can now be unloaded")); #endif }