//=--------------------------------------------------------------------------=
// ClassF.Cpp
//=--------------------------------------------------------------------------=
// Copyright 1995 - 1998 Microsoft Corporation. All Rights Reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//=--------------------------------------------------------------------------=
//
// contains the implementation of the ClassFactory object. we support
// IClassFactory and IClassFactory2
//
#include "IPServer.H"
#include "LocalSrv.H"
#include "ClassF.H"
#include "Globals.H"
#include "Unknown.H" // for CREATEFNOFOBJECT
//=--------------------------------------------------------------------------=
// private module level data
//=--------------------------------------------------------------------------=
//
// ASSERT and FAIL require this
//
SZTHISFILE
// private routines for this file
//
HRESULT CreateOleObjectFromIndex(IUnknown *, int Index, void **, REFIID);
//=--------------------------------------------------------------------------=
// CClassFactory::CClassFactory
//=--------------------------------------------------------------------------=
// create the object and initialize the refcount
//
// Parameters:
// int - [in] index into our global table of objects for this guy
//
// Notes:
//
CClassFactory::CClassFactory
(
int iIndex
)
: m_iIndex(iIndex)
{
m_cRefs = 1;
}
//=--------------------------------------------------------------------------=
// CClassFactory::CClassFactory
//=--------------------------------------------------------------------------=
// "Life levels all men. Death reveals the eminent."
// - George Bernard Shaw (1856 - 1950)
//
// Notes:
//
CClassFactory::~CClassFactory ()
{
ASSERT(m_cRefs == 0, "Object being deleted with refs!");
return;
}
//=--------------------------------------------------------------------------=
// CClassFactory::QueryInterface
//=--------------------------------------------------------------------------=
// the user wants another interface. we won't give 'em. very many.
//
// Parameters:
// REFIID - [in] interface they want
// void ** - [out] where they want to put the resulting object ptr.
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
//
STDMETHODIMP CClassFactory::QueryInterface
(
REFIID riid,
void **ppvObjOut
)
{
void *pv;
CHECK_POINTER(ppvObjOut);
// we support IUnknown, and the two CF interfaces
//
if (DO_GUIDS_MATCH(riid, IID_IClassFactory)) {
pv = (void *)(IClassFactory *)this;
} else if (DO_GUIDS_MATCH(riid, IID_IClassFactory2)) {
pv = (void *)(IClassFactory2 *)this;
} else if (DO_GUIDS_MATCH(riid, IID_IUnknown)) {
pv = (void *)(IUnknown *)this;
} else {
*ppvObjOut = NULL;
return E_NOINTERFACE;
}
((IUnknown *)pv)->AddRef();
*ppvObjOut = pv;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CClassFactory::AddRef
//=--------------------------------------------------------------------------=
// adds a tick to the current reference count.
//
// Output:
// ULONG - the new reference count
//
// Notes:
//
ULONG CClassFactory::AddRef
(
void
)
{
return ++m_cRefs;
}
//=--------------------------------------------------------------------------=
// CClassFactory::Release
//=--------------------------------------------------------------------------=
// removes a tick from the count, and delets the object if necessary
//
// Output:
// ULONG - remaining refs
//
// Notes:
//
ULONG CClassFactory::Release
(
void
)
{
ASSERT(m_cRefs, "No Refs, and we're being released!");
if(--m_cRefs)
return m_cRefs;
delete this;
return 0;
}
//=--------------------------------------------------------------------------=
// CClassFactory::CreateInstance
//=--------------------------------------------------------------------------=
// create an instance of some sort of object.
//
// Parameters:
// IUnknown * - [in] controlling IUknonwn for aggregation
// REFIID - [in] interface id for new object
// void ** - [out] pointer to new interface object.
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE, E_UNEXPECTED,
// E_OUTOFMEMORY, E_INVALIDARG
//
// Notes:
//
STDMETHODIMP CClassFactory::CreateInstance
(
IUnknown *pUnkOuter,
REFIID riid,
void **ppvObjOut
)
{
// check args
//
if (!ppvObjOut)
return E_INVALIDARG;
// check to see if we've done our licensing work. we do this as late
// as possible that people calling CreateInstanceLic don't suffer from
// a performance hit here.
//
// crit sect this for apartment threading, since it's global
//
EnterCriticalSection(&g_CriticalSection);
if (!g_fCheckedForLicense) {
g_fMachineHasLicense = CheckForLicense();
g_fCheckedForLicense = TRUE;
}
LeaveCriticalSection(&g_CriticalSection);
// check to see if they have the appropriate license to create this stuff
//
if (!g_fMachineHasLicense)
return CLASS_E_NOTLICENSED;
// try to create one of the objects that we support
//
return CreateOleObjectFromIndex(pUnkOuter, m_iIndex, ppvObjOut, riid);
}
//=--------------------------------------------------------------------------=
// CClassFactory::LockServer
//=--------------------------------------------------------------------------=
// lock the server so we can't unload
//
// Parameters:
// BOOL - [in] TRUE means addref, false means release lock count.
//
// Output:
// HRESULT - S_OK, E_FAIL, E_OUTOFMEMORY, E_UNEXPECTED
//
// Notes:
//
STDMETHODIMP CClassFactory::LockServer
(
BOOL fLock
)
{
// update the lock count. crit sect these in case of another thread.
//
if (fLock)
InterlockedIncrement(&g_cLocks);
else {
ASSERT(g_cLocks, "D'oh! Lock Counting Problem");
InterlockedDecrement(&g_cLocks);
}
return S_OK;
}
//=--------------------------------------------------------------------------=
// CClassFactory::GetLicInfo
//=--------------------------------------------------------------------------=
// IClassFactory2 GetLicInfo
//
// Parameters:
// LICINFO * - unclear
//
// Output:
// HRESULT - unclear
//
// Notes:
//
STDMETHODIMP CClassFactory::GetLicInfo
(
LICINFO *pLicInfo
)
{
CHECK_POINTER(pLicInfo);
pLicInfo->cbLicInfo = sizeof(LICINFO);
// This says whether RequestLicKey will work
//
pLicInfo->fRuntimeKeyAvail = g_fMachineHasLicense;
// This says whether the standard CreateInstance will work
//
pLicInfo->fLicVerified = g_fMachineHasLicense;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CClassFactory::RequestLicKey
//=--------------------------------------------------------------------------=
// IClassFactory2 RequestLicKey
//
// Parameters:
// DWORD - [in] reserved
// BSTR * - [out] unclear
//
// Output:
// HRESULT - unclear
//
// Notes:
//
STDMETHODIMP CClassFactory::RequestLicKey
(
DWORD dwReserved,
BSTR *pbstr
)
{
// if the machine isn't licensed, then we're not about to give this to them !
//
if (!g_fMachineHasLicense)
return CLASS_E_NOTLICENSED;
*pbstr = GetLicenseKey();
return (*pbstr) ? S_OK : E_OUTOFMEMORY;
}
//=--------------------------------------------------------------------------=
// CClassFactory::CreateInstanceLic
//=--------------------------------------------------------------------------=
// create a new instance given a licensing key, etc ...
//
// Parameters:
// IUnknown * - [in] controlling IUnknown for aggregation
// IUnknown * - [in] reserved, must be NULL
// REFIID - [in] IID We're looking for.
// BSTR - [in] license key
// void ** - [out] where to put the new object.
//
// Output:
// HRESULT - unclear
//
// Notes:
//
STDMETHODIMP CClassFactory::CreateInstanceLic
(
IUnknown *pUnkOuter,
IUnknown *pUnkReserved,
REFIID riid,
BSTR bstrKey,
void **ppvObjOut
)
{
*ppvObjOut = NULL;
// go and see if the key they gave us matches.
//
if (!CheckLicenseKey(bstrKey))
return CLASS_E_NOTLICENSED;
// if it does, then go and create the object.
//
return CreateOleObjectFromIndex(pUnkOuter, m_iIndex, ppvObjOut, riid);
}
//=--------------------------------------------------------------------------=
// CreateOleObjectFromIndex
//=--------------------------------------------------------------------------=
// given an index in our object table, create an object from it.
//
// Parameters:
// IUnknown * - [in] Controlling Unknown, if any, for aggregation
// int - [in] index into our global table
// void ** - [out] where to put resulting object.
// REFIID - [in] the interface they want resulting object to be.
//
// Output:
// HRESULT - S_OK, E_OUTOFMEMORY, E_NOINTERFACE
//
// Notes:
//
HRESULT CreateOleObjectFromIndex
(
IUnknown *pUnkOuter,
int iIndex,
void **ppvObjOut,
REFIID riid
)
{
IUnknown *pUnk = NULL;
HRESULT hr;
// go and create the object
//
ASSERT(CREATEFNOFOBJECT(iIndex), "All creatable objects must have creation fn!");
pUnk = CREATEFNOFOBJECT(iIndex)(pUnkOuter);
// sanity check and make sure the object actually got allocated.
//
RETURN_ON_NULLALLOC(pUnk);
// make sure we support aggregation here properly -- if they gave us
// a controlling unknown, then they -must- ask for IUnknown, and we'll
// give them the private unknown the object gave us.
//
if (pUnkOuter) {
if (!DO_GUIDS_MATCH(riid, IID_IUnknown)) {
pUnk->Release();
return E_INVALIDARG;
}
*ppvObjOut = (void *)pUnk;
hr = S_OK;
} else {
// QI for whatever the user wants.
//
hr = pUnk->QueryInterface(riid, ppvObjOut);
pUnk->Release();
RETURN_ON_FAILURE(hr);
}
return hr;
}