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.
317 lines
8.4 KiB
317 lines
8.4 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|