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.
443 lines
12 KiB
443 lines
12 KiB
//=--------------------------------------------------------------------------=
|
|
// ClassFactory.Cpp
|
|
//=--------------------------------------------------------------------------=
|
|
// Copyright 1995 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 "pch.h"
|
|
#include "LocalSrv.H"
|
|
|
|
#include "ClassF.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);
|
|
|
|
// This is the GUID for a "phantom" interface which VB5 UserControls query
|
|
// for to determine if the control doesn't require its license key to be
|
|
// present if it's part of a composite UserControl being used in the
|
|
// design environment.
|
|
//
|
|
static const GUID IID_ILicOnCompositeCtl =
|
|
{ 0x6e6e9780, 0x165d, 0x11d0, { 0xb3, 0xe6, 0x00, 0xa0, 0xc9, 0x0f, 0x27, 0x31 } };
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// 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)
|
|
{
|
|
InterlockedIncrement(&g_cLocks);
|
|
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!");
|
|
InterlockedDecrement(&g_cLocks);
|
|
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 if (g_fUseRuntimeLicInCompositeCtl && riid == IID_ILicOnCompositeCtl) {
|
|
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
|
|
//
|
|
ENTERCRITICALSECTION1(&g_CriticalSection);
|
|
if (!g_fCheckedForLicense) {
|
|
g_fMachineHasLicense = CheckForLicense();
|
|
g_fCheckedForLicense = TRUE;
|
|
}
|
|
LEAVECRITICALSECTION1(&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);
|
|
|
|
// crit sect this for apartment threading, since it's global
|
|
//
|
|
ENTERCRITICALSECTION1(&g_CriticalSection);
|
|
if (!g_fCheckedForLicense) {
|
|
g_fMachineHasLicense = CheckForLicense();
|
|
g_fCheckedForLicense = TRUE;
|
|
}
|
|
LEAVECRITICALSECTION1(&g_CriticalSection);
|
|
|
|
// 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
|
|
)
|
|
{
|
|
// crit sect this for apartment threading, since it's global
|
|
//
|
|
ENTERCRITICALSECTION1(&g_CriticalSection);
|
|
if (!g_fCheckedForLicense) {
|
|
g_fMachineHasLicense = CheckForLicense();
|
|
g_fCheckedForLicense = TRUE;
|
|
}
|
|
LEAVECRITICALSECTION1(&g_CriticalSection);
|
|
|
|
// 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;
|
|
|
|
// crit sect this for apartment threading, since it's global
|
|
//
|
|
ENTERCRITICALSECTION1(&g_CriticalSection);
|
|
if (!g_fCheckedForLicense) {
|
|
g_fMachineHasLicense = CheckForLicense();
|
|
g_fCheckedForLicense = TRUE;
|
|
}
|
|
LEAVECRITICALSECTION1(&g_CriticalSection);
|
|
|
|
// 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;
|
|
|
|
// If the object specifies a pre-Create static function call that first.
|
|
//
|
|
if (PRECREATEFNOFOBJECT(iIndex) != NULL) {
|
|
hr = PRECREATEFNOFOBJECT(iIndex)();
|
|
IfFailRet(hr);
|
|
}
|
|
|
|
// go and create the object
|
|
//
|
|
ASSERT(CREATEFNOFOBJECT(iIndex), "WARNING: Attempt to create an object that doesn't have a Create function.");
|
|
if (!CREATEFNOFOBJECT(iIndex))
|
|
return E_FAIL;
|
|
|
|
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;
|
|
}
|
|
|