Leaked source code of windows server 2003
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.
 
 
 
 
 
 

480 lines
11 KiB

///////////////////////////////////////////////////////////////////////////////
// CCOMBaseFactory
// Base class for reusing a single class factory for all components in a DLL
#include "fact.h"
#include "unk.h"
#include "regsvr.h"
#include "dbg.h"
struct OUTPROCINFO
{
// Reserved (used only for COM Exe server)
IClassFactory* _pfact;
DWORD _dwRegister;
};
LONG CCOMBaseFactory::_cServerLocks = 0;
LONG CCOMBaseFactory::_cComponents = 0;
HMODULE CCOMBaseFactory::_hModule = NULL;
CRITICAL_SECTION CCOMBaseFactory::_cs = {0};
OUTPROCINFO* CCOMBaseFactory::_popinfo = NULL;
DWORD CCOMBaseFactory::_dwThreadID = 0;
BOOL CCOMBaseFactory::_fCritSectInit = FALSE;
///////////////////////////////////////////////////////////////////////////////
// IUnknown implementation
STDMETHODIMP CCOMBaseFactory::QueryInterface(REFIID iid, void** ppv)
{
IUnknown* punk = NULL;
HRESULT hres = S_OK;
if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))
{
punk = this;
punk->AddRef();
}
else
{
hres = E_NOINTERFACE;
}
*ppv = punk;
return hres;
}
STDMETHODIMP_(ULONG) CCOMBaseFactory::AddRef()
{
return ::InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CCOMBaseFactory::Release()
{
ASSERT( 0 != _cRef );
ULONG cRef = ::InterlockedDecrement(&_cRef);
if (!cRef)
{
delete this;
}
return cRef;
}
///////////////////////////////////////////////////////////////////////////////
// IFactory implementation
STDMETHODIMP CCOMBaseFactory::CreateInstance(IUnknown* pUnknownOuter,
REFIID riid, void** ppv)
{
HRESULT hres = CLASS_E_NOAGGREGATION;
// We don't support aggregation at all for now
if (!pUnknownOuter)
{
// Aggregate only if the requested IID is IID_IUnknown.
if ((pUnknownOuter != NULL) && (riid != IID_IUnknown))
{
hres = CLASS_E_NOAGGREGATION;
}
else
{
// Create the component.
IUnknown* punkNew;
hres = _pFactoryData->CreateInstance(
CCOMBaseFactory::_COMFactoryCB, pUnknownOuter, &punkNew);
if (SUCCEEDED(hres))
{
_COMFactoryCB(TRUE);
// Get the requested interface.
// hres = pNewComponent->NondelegatingQueryInterface(iid, ppv);
hres = punkNew->QueryInterface(riid, ppv);
// Release the reference held by the class factory.
// pNewComponent->NondelegatingRelease();
punkNew->Release();
}
}
}
return hres;
}
STDMETHODIMP CCOMBaseFactory::LockServer(BOOL fLock)
{
return _LockServer(fLock);
}
//static
HRESULT CCOMBaseFactory::DllAttach(HINSTANCE hinst)
{
HRESULT hr;
_hModule = (HMODULE)hinst;
if (InitializeCriticalSectionAndSpinCount(&_cs, 0))
{
_fCritSectInit = TRUE;
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
//static
HRESULT CCOMBaseFactory::DllDetach()
{
if (_fCritSectInit)
{
DeleteCriticalSection(&_cs);
_fCritSectInit = FALSE;
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// Install/Unintall
//static
HRESULT CCOMBaseFactory::_RegisterAll()
{
for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
{
RegisterServer(_hModule,
*(_pDLLFactoryData[dw]._pCLSID),
_pDLLFactoryData[dw]._pszRegistryName,
_pDLLFactoryData[dw]._pszVerIndProgID,
_pDLLFactoryData[dw]._pszProgID,
_pDLLFactoryData[dw]._dwThreadingModel,
_pDLLFactoryData[dw].IsInprocServer(),
_pDLLFactoryData[dw].IsLocalServer(),
_pDLLFactoryData[dw].IsLocalService(),
_pDLLFactoryData[dw]._pszLocalService,
_pDLLFactoryData[dw]._pAppID);
}
return S_OK;
}
//static
HRESULT CCOMBaseFactory::_UnregisterAll()
{
for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
{
UnregisterServer(*(_pDLLFactoryData[dw]._pCLSID),
_pDLLFactoryData[dw]._pszVerIndProgID,
_pDLLFactoryData[dw]._pszProgID);
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// CCOMBaseFactory implementation
CCOMBaseFactory::CCOMBaseFactory(const CFactoryData* pFactoryData) : _cRef(1),
_pFactoryData(pFactoryData)
{}
//static
BOOL CCOMBaseFactory::_IsLocked()
{
// Always need to be called from within Critical Section
return (_cServerLocks > 0);
}
//static
HRESULT CCOMBaseFactory::_CanUnloadNow()
{
HRESULT hres = S_OK;
// Always need to be called from within Critical Section
if (_IsLocked())
{
hres = S_FALSE;
}
else
{
if (_cComponents)
{
hres = S_FALSE;
}
}
return hres;
}
//static
HRESULT CCOMBaseFactory::_CheckForUnload()
{
// Always need to be called from within Critical Section
if (S_OK == _CanUnloadNow())
{
::PostThreadMessage(_dwThreadID, WM_QUIT, 0, 0);
}
return S_OK;
}
//static
HRESULT CCOMBaseFactory::_LockServer(BOOL fLock)
{
HRESULT hres = S_OK;
EnterCriticalSection(&_cs);
if (fLock)
{
++_cServerLocks;
}
else
{
--_cServerLocks;
hres = _CheckForUnload();
}
LeaveCriticalSection(&_cs);
return hres;
}
//static
void CCOMBaseFactory::_COMFactoryCB(BOOL fIncrement)
{
EnterCriticalSection(&_cs);
if (fIncrement)
{
++_cComponents;
}
else
{
--_cComponents;
_CheckForUnload();
}
LeaveCriticalSection(&_cs);
}
///////////////////////////////////////////////////////////////////////////////
//
// static
HRESULT CCOMBaseFactory::_GetClassObject(REFCLSID rclsid, REFIID riid,
void** ppv)
{
HRESULT hres = S_OK;
ASSERT(_fCritSectInit);
if ((riid != IID_IUnknown) && (riid != IID_IClassFactory))
{
hres = E_NOINTERFACE;
}
else
{
hres = CLASS_E_CLASSNOTAVAILABLE;
// Traverse the array of data looking for this class ID.
for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
{
const CFactoryData* pData = &_pDLLFactoryData[dw];
if (pData->IsClassID(rclsid) && pData->IsInprocServer())
{
// Found the ClassID in the array of components we can
// create. So create a class factory for this component.
// Pass the CDLLFactoryData structure to the class factory
// so that it knows what kind of components to create.
*ppv = (IUnknown*) new CCOMBaseFactory(pData);
if (*ppv == NULL)
{
hres = E_OUTOFMEMORY;
}
else
{
hres = S_OK;
}
break;
}
}
}
return hres;
}
//static
BOOL CCOMBaseFactory::_ProcessConsoleCmdLineParams(int argc, wchar_t* argv[],
BOOL* pfRun, BOOL* pfEmbedded)
{
_dwThreadID = GetCurrentThreadId();
if (argc > 1)
{
if (!lstrcmpi(argv[1], TEXT("-i")) ||
!lstrcmpi(argv[1], TEXT("/i")))
{
CCOMBaseFactory::_RegisterAll();
*pfRun = FALSE;
}
else
{
if (!lstrcmpi(argv[1], TEXT("-u")) ||
!lstrcmpi(argv[1], TEXT("/u")))
{
CCOMBaseFactory::_UnregisterAll();
*pfRun = FALSE;
}
else
{
if (!lstrcmpi(argv[1], TEXT("-Embedding")) ||
!lstrcmpi(argv[1], TEXT("/Embedding")))
{
*pfRun = TRUE;
*pfEmbedded = TRUE;
}
}
}
}
else
{
*pfEmbedded = FALSE;
*pfRun = TRUE;
}
return TRUE;
}
//static
BOOL CCOMBaseFactory::_RegisterFactories(BOOL fEmbedded)
{
HRESULT hres = S_OK;
if (!fEmbedded)
{
hres = _LockServer(TRUE);
}
_popinfo = (OUTPROCINFO*)LocalAlloc(LPTR, sizeof(OUTPROCINFO) * _cDLLFactoryData);
if (_popinfo)
{
for (DWORD dw = 0; SUCCEEDED(hres) && (dw < _cDLLFactoryData); ++dw)
{
const CFactoryData* pData = &_pDLLFactoryData[dw];
if (pData->IsLocalServer() || pData->IsLocalService())
{
_popinfo[dw]._pfact = NULL;
_popinfo[dw]._dwRegister = NULL;
IClassFactory* pfact = new CCOMBaseFactory(pData);
if (pfact)
{
DWORD dwRegister;
hres = ::CoRegisterClassObject(*pData->_pCLSID,
static_cast<IUnknown*>(pfact), pData->_dwClsContext,
pData->_dwFlags, &dwRegister);
if (SUCCEEDED(hres))
{
_popinfo[dw]._pfact = pfact;
_popinfo[dw]._dwRegister = dwRegister;
}
else
{
pfact->Release();
}
}
else
{
hres = E_OUTOFMEMORY;
}
}
}
}
else
{
hres = E_OUTOFMEMORY;
}
return SUCCEEDED(hres);
}
//static
BOOL CCOMBaseFactory::_SuspendFactories()
{
return SUCCEEDED(::CoSuspendClassObjects());
}
//static
BOOL CCOMBaseFactory::_ResumeFactories()
{
return SUCCEEDED(::CoResumeClassObjects());
}
//static
BOOL CCOMBaseFactory::_UnregisterFactories(BOOL fEmbedded)
{
HRESULT hres = S_OK;
ASSERT(_popinfo);
for (DWORD dw = 0; dw < _cDLLFactoryData; ++dw)
{
if (_popinfo[dw]._pfact)
{
_popinfo[dw]._pfact->Release();
HRESULT hresTmp = ::CoRevokeClassObject(_popinfo[dw]._dwRegister);
if (FAILED(hresTmp) && (S_OK == hres))
{
hres = hresTmp;
}
}
}
LocalFree(_popinfo);
_popinfo = NULL;
if (!fEmbedded)
{
HRESULT hresTmp = _LockServer(FALSE);
if (FAILED(hresTmp) && (S_OK == hres))
{
hres = hresTmp;
}
}
return SUCCEEDED(hres);
}
//static
void CCOMBaseFactory::_WaitForAllClientsToGo()
{
MSG msg;
while (::GetMessage(&msg, 0, 0, 0))
{
::DispatchMessage(&msg);
}
}