//+--------------------------------------------------------------------------- // // File: combase.cpp // // Contents: COM server functionality. // //---------------------------------------------------------------------------- #include "private.h" #include "combase.h" #include "regsvr.h" extern CClassFactory *g_ObjectInfo[]; LONG g_cRefDll = -1; // -1 /w no refs, for win95 InterlockedIncrement/Decrement compat void FreeGlobalObjects(void); //+--------------------------------------------------------------------------- // // DllAddRef // //---------------------------------------------------------------------------- void DllAddRef(void) { if (InterlockedIncrement(&g_cRefDll) == 0) // g_cRefDll == -1 with zero refs { DllInit(); } } //+--------------------------------------------------------------------------- // // DllRelease // //---------------------------------------------------------------------------- void DllRelease(void) { if (InterlockedDecrement(&g_cRefDll) < 0) // g_cRefDll == -1 with zero refs { EnterCriticalSection(GetServerCritSec()); // need to check ref again after grabbing mutex if (g_ObjectInfo[0] != NULL) { FreeGlobalObjects(); } Assert(g_cRefDll == -1); LeaveCriticalSection(GetServerCritSec()); DllUninit(); } } //+--------------------------------------------------------------------------- // // CClassFactory declaration with IClassFactory Interface // //---------------------------------------------------------------------------- class CClassFactory : public IClassFactory { public: // IUnknown methods STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IClassFactory methods STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj); STDMETHODIMP LockServer(BOOL fLock); // Constructor CClassFactory(const CLSID *pclsid, HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)) : _pclsid(pclsid) { _pfnCreateInstance = pfnCreateInstance; } public: const CLSID *_pclsid; HRESULT (*_pfnCreateInstance)(IUnknown *pUnkOuter, REFIID riid, void **ppvObj); }; //+--------------------------------------------------------------------------- // // CClassFactory::QueryInterface // //---------------------------------------------------------------------------- STDAPI CClassFactory::QueryInterface(REFIID riid, void **ppvObj) { if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown)) { *ppvObj = this; DllAddRef(); return NOERROR; } *ppvObj = NULL; return E_NOINTERFACE; } //+--------------------------------------------------------------------------- // // CClassFactory::AddRef // //---------------------------------------------------------------------------- STDAPI_(ULONG) CClassFactory::AddRef() { DllAddRef(); return g_cRefDll+1; // -1 w/ no refs } //+--------------------------------------------------------------------------- // // CClassFactory::Release // //---------------------------------------------------------------------------- STDAPI_(ULONG) CClassFactory::Release() { DllRelease(); return g_cRefDll+1; // -1 w/ no refs } //+--------------------------------------------------------------------------- // // CClassFactory::CreateInstance // //---------------------------------------------------------------------------- STDAPI CClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj) { return _pfnCreateInstance(pUnkOuter, riid, ppvObj); } //+--------------------------------------------------------------------------- // // CClassFactory::LockServer // //---------------------------------------------------------------------------- STDAPI CClassFactory::LockServer(BOOL fLock) { if (fLock) { DllAddRef(); } else { DllRelease(); } return S_OK; } //+--------------------------------------------------------------------------- // // BuildGlobalObjects // //---------------------------------------------------------------------------- void BuildGlobalObjects(void) { const OBJECT_ENTRY *pEntry; int i; // Build CClassFactory Objects i = 0; for (pEntry = &c_rgCoClassFactoryTable[0]; pEntry->pfnCreateInstance != NULL; pEntry++) { g_ObjectInfo[i++] = new CClassFactory(pEntry->pclsid, pEntry->pfnCreateInstance); } // You can add more object info here. // Don't forget to increase number of item for g_ObjectInfo[], } //+--------------------------------------------------------------------------- // // FreeGlobalObjects // //---------------------------------------------------------------------------- void FreeGlobalObjects(void) { const OBJECT_ENTRY *pEntry; pEntry = &c_rgCoClassFactoryTable[0]; // Free CClassFactory Objects // we know the size of g_ObjectInfo must match c_rgCoClassFactoryTable, which is null terminated for (int i = 0; pEntry->pfnCreateInstance != NULL; i++, pEntry++) { if (NULL != g_ObjectInfo[i]) { delete g_ObjectInfo[i]; g_ObjectInfo[i] = NULL; } } } //+--------------------------------------------------------------------------- // // DllGetClassObject // //---------------------------------------------------------------------------- HRESULT COMBase_DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppvObj) { const OBJECT_ENTRY *pEntry; if (ppvObj == NULL) return E_INVALIDARG; if (g_ObjectInfo[0] == NULL) { EnterCriticalSection(GetServerCritSec()); // need to check ref again after grabbing mutex if (g_ObjectInfo[0] == NULL) { BuildGlobalObjects(); } LeaveCriticalSection(GetServerCritSec()); } if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown)) { // we know the size of g_ObjectInfo must match c_rgCoClassFactoryTable, which is null terminated pEntry = &c_rgCoClassFactoryTable[0]; for (int i = 0; pEntry->pfnCreateInstance != NULL; i++, pEntry++) { if (NULL != g_ObjectInfo[i] && IsEqualGUID(rclsid, *g_ObjectInfo[i]->_pclsid)) { *ppvObj = (void *)g_ObjectInfo[i]; DllAddRef(); // class factory holds DLL ref count return NOERROR; } } } *ppvObj = NULL; return CLASS_E_CLASSNOTAVAILABLE; } //+--------------------------------------------------------------------------- // // DllCanUnloadNow // //---------------------------------------------------------------------------- HRESULT COMBase_DllCanUnloadNow(void) { if (g_cRefDll >= 0) // -1 with no refs return S_FALSE; return S_OK; } //+--------------------------------------------------------------------------- // // DllRegisterServer // //---------------------------------------------------------------------------- HRESULT COMBase_DllRegisterServer(void) { const OBJECT_ENTRY *pEntry; TCHAR achPath[MAX_PATH+1]; HRESULT hr = E_FAIL; if (GetModuleFileName(GetServerHINSTANCE(), achPath, ARRAYSIZE(achPath)) == 0) goto Exit; achPath[ARRAYSIZE(achPath)-1] = 0; for (pEntry = &c_rgCoClassFactoryTable[0]; pEntry->pfnCreateInstance != NULL; pEntry++) { if (!RegisterServer(*pEntry->pclsid, pEntry->pszDesc, achPath, TEXT("Apartment"), NULL)) goto Exit; } hr = S_OK; Exit: return hr; } //+--------------------------------------------------------------------------- // // DllUnregisterServer // //---------------------------------------------------------------------------- HRESULT COMBase_DllUnregisterServer(void) { const OBJECT_ENTRY *pEntry; HRESULT hr = E_FAIL; for (pEntry = &c_rgCoClassFactoryTable[0]; pEntry->pfnCreateInstance != NULL; pEntry++) { if (FAILED(hr = RegisterServer(*pEntry->pclsid, NULL, NULL, NULL, NULL) ? S_OK : E_FAIL)) goto Exit; } hr = S_OK; Exit: return hr; }