// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"

#ifdef AFX_OLE3_SEG
#pragma code_seg(AFX_OLE3_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// COleObjectFactory implementation

BEGIN_INTERFACE_MAP(COleObjectFactory, CCmdTarget)
	INTERFACE_PART(COleObjectFactory, IID_IClassFactory, ClassFactory)
	INTERFACE_PART(COleObjectFactory, IID_IClassFactory2, ClassFactory)
END_INTERFACE_MAP()

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

COleObjectFactory::COleObjectFactory(REFCLSID clsid,
	CRuntimeClass* pRuntimeClass, BOOL bMultiInstance, LPCTSTR lpszProgID)
{
	ASSERT(pRuntimeClass == NULL ||
		pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CCmdTarget)));
	ASSERT(AfxIsValidAddress(&clsid, sizeof(CLSID), FALSE));
	ASSERT(lpszProgID == NULL || AfxIsValidString(lpszProgID));

	// initialize to unregistered state
	m_dwRegister = 0;   // not registered yet
	m_bRegistered = FALSE;
	m_clsid = clsid;
	m_pRuntimeClass = pRuntimeClass;
	m_bMultiInstance = bMultiInstance;
	m_lpszProgID = lpszProgID;
	m_bOAT = (BYTE) OAT_UNKNOWN;

	// licensing information
	m_bLicenseChecked = FALSE;
	m_bLicenseValid = FALSE;

	// add this factory to the list of factories
	m_pNextFactory = NULL;
	AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
	AfxLockGlobals(CRIT_OBJECTFACTORYLIST);
	pModuleState->m_factoryList.AddHead(this);
	AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);

	ASSERT_VALID(this);
}

#ifdef AFX_TERM_SEG
#pragma code_seg(AFX_TERM_SEG)
#endif

COleObjectFactory::~COleObjectFactory()
{
	ASSERT_VALID(this);

#ifdef _AFXDLL
	if (m_pModuleState == NULL)
		return;
#endif

	// deregister this class factory
	Revoke();

	// remove this class factory from the list of active class factories
#ifdef _AFXDLL
	AFX_MODULE_STATE* pModuleState = m_pModuleState;
#else
	AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
#endif
	AfxLockGlobals(CRIT_OBJECTFACTORYLIST);
	BOOL bResult = pModuleState->m_factoryList.Remove(this);
	AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);
	if (bResult)
		return;

	// check CDynLinkLibrary objects in case it was transfered during init
#ifdef _AFXDLL
	AfxLockGlobals(CRIT_DYNLINKLIST);
	for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
		pDLL = pDLL->m_pNextDLL)
	{
		if (pDLL->m_factoryList.Remove(this))
		{
			AfxUnlockGlobals(CRIT_DYNLINKLIST);
			return;
		}
	}
	AfxUnlockGlobals(CRIT_DYNLINKLIST);
#endif
}

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

BOOL COleObjectFactory::Unregister()
{
	return TRUE;
}

BOOL COleObjectFactory::Register()
{
	ASSERT_VALID(this);
	ASSERT(!m_bRegistered);  // registering server/factory twice?
	ASSERT(m_clsid != CLSID_NULL);

	if (!afxContextIsDLL)
	{
		// In the application variants, the IClassFactory is registered
		//  with the OLE DLLs.

		SCODE sc = ::CoRegisterClassObject(m_clsid, &m_xClassFactory,
			CLSCTX_LOCAL_SERVER,
			m_bMultiInstance ? REGCLS_SINGLEUSE : REGCLS_MULTIPLEUSE,
			&m_dwRegister);
		if (sc != S_OK)
		{
#ifdef _DEBUG
			TRACE1("Warning: CoRegisterClassObject failed scode = %s.\n",
				::AfxGetFullScodeString(sc));
#endif
			// registration failed.
			return FALSE;
		}
		ASSERT(m_dwRegister != 0);
	}

	++m_bRegistered;
	return TRUE;
}

BOOL PASCAL COleObjectFactory::UnregisterAll()
{
	BOOL bResult = TRUE;
	// register application factories
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
	AfxLockGlobals(CRIT_OBJECTFACTORYLIST);
	for (COleObjectFactory* pFactory = pModuleState->m_factoryList;
		pFactory != NULL; pFactory = pFactory->m_pNextFactory)
	{
		// unregister any registered, non-doctemplate factories
		if (pFactory->IsRegistered() && !pFactory->Unregister())
		{
			bResult = FALSE;
		}
	}
	AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);
	return bResult;
}

BOOL PASCAL COleObjectFactory::RegisterAll()
{
	BOOL bResult = TRUE;
	// register application factories
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
	AfxLockGlobals(CRIT_OBJECTFACTORYLIST);
	for (COleObjectFactory* pFactory = pModuleState->m_factoryList;
		pFactory != NULL; pFactory = pFactory->m_pNextFactory)
	{
		// register any non-registered, non-doctemplate factories
		if (!pFactory->IsRegistered() &&
			pFactory->m_clsid != CLSID_NULL && !pFactory->Register())
		{
			bResult = FALSE;
		}
	}
	AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);
#ifdef _AFXDLL
	// register extension DLL factories
	AfxLockGlobals(CRIT_DYNLINKLIST);
	for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
		pDLL = pDLL->m_pNextDLL)
	{
		for (pFactory = pDLL->m_factoryList;
			pFactory != NULL; pFactory = pFactory->m_pNextFactory)
		{
			// register any non-registered, non-doctemplate factories
			if (!pFactory->IsRegistered() &&
				pFactory->m_clsid != CLSID_NULL && !pFactory->Register())
			{
				bResult = FALSE;
			}
		}
	}
	AfxUnlockGlobals(CRIT_DYNLINKLIST);
#endif
	return bResult;
}

#ifdef AFX_TERM_SEG
#pragma code_seg(AFX_TERM_SEG)
#endif

void COleObjectFactory::Revoke()
{
	ASSERT_VALID(this);

	if (m_bRegistered)
	{
		// revoke the registration of the class itself
		if (m_dwRegister != 0)
		{
			::CoRevokeClassObject(m_dwRegister);
			m_dwRegister = 0;
		}
		m_bRegistered = FALSE;
	}
}

void PASCAL COleObjectFactory::RevokeAll()
{
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
	AfxLockGlobals(CRIT_OBJECTFACTORYLIST);
	for (COleObjectFactory* pFactory = pModuleState->m_factoryList;
		pFactory != NULL; pFactory = pFactory->m_pNextFactory)
	{
		pFactory->Revoke();
	}
	AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);
#ifdef _AFXDLL
	AfxLockGlobals(CRIT_DYNLINKLIST);
	// register extension DLL factories
	for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
		pDLL = pDLL->m_pNextDLL)
	{
		for (pFactory = pDLL->m_factoryList;
			pFactory != NULL; pFactory = pFactory->m_pNextFactory)
		{
			pFactory->Revoke();
		}
	}
	AfxUnlockGlobals(CRIT_DYNLINKLIST);
#endif
}

#ifdef AFX_OLE3_SEG
#pragma code_seg(AFX_OLE3_SEG)
#endif

void COleObjectFactory::UpdateRegistry(LPCTSTR lpszProgID)
{
	ASSERT_VALID(this);
	ASSERT(lpszProgID == NULL || AfxIsValidString(lpszProgID));

	// use default prog-id if specific prog-id not given
	if (lpszProgID == NULL)
	{
		lpszProgID = m_lpszProgID;
		if (lpszProgID == NULL) // still no valid progID?
			return;
	}

	// call global helper to modify system registry
	//  (progid, shortname, and long name are all equal in this case)
	AfxOleRegisterServerClass(m_clsid, lpszProgID, lpszProgID, lpszProgID,
		OAT_DISPATCH_OBJECT);
}

BOOL PASCAL COleObjectFactory::UpdateRegistryAll(BOOL bRegister)
{
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
	AfxLockGlobals(CRIT_OBJECTFACTORYLIST);
	for (COleObjectFactory* pFactory = pModuleState->m_factoryList;
		pFactory != NULL; pFactory = pFactory->m_pNextFactory)
	{
		if (!pFactory->UpdateRegistry(bRegister))
		{
			AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);
			return FALSE;
		}
	}
	AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);
#ifdef _AFXDLL
	AfxLockGlobals(CRIT_DYNLINKLIST);
	// register extension DLL factories
	for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
		pDLL = pDLL->m_pNextDLL)
	{
		for (pFactory = pDLL->m_factoryList;
			pFactory != NULL; pFactory = pFactory->m_pNextFactory)
		{
			if (!pFactory->UpdateRegistry(bRegister))
			{
				AfxUnlockGlobals(CRIT_DYNLINKLIST);
				return FALSE;
			}
		}
	}
	AfxUnlockGlobals(CRIT_DYNLINKLIST);
#endif

	return TRUE;
}

CCmdTarget* COleObjectFactory::OnCreateObject()
{
	ASSERT_VALID(this);
	ASSERT(AfxIsValidAddress(m_pRuntimeClass, sizeof(CRuntimeClass), FALSE));
		// this implementation needs a runtime class

	// allocate object, throw exception on failure
	CCmdTarget* pTarget = (CCmdTarget*)m_pRuntimeClass->CreateObject();
	if (pTarget == NULL)
		AfxThrowMemoryException();

	// make sure it is a CCmdTarget
	ASSERT_KINDOF(CCmdTarget, pTarget);
	ASSERT_VALID(pTarget);

	// return the new CCmdTarget object
	return pTarget;
}

BOOL COleObjectFactory::IsLicenseValid()
{
	if (!m_bLicenseChecked)
	{
		m_bLicenseValid = (BYTE)VerifyUserLicense();
		m_bLicenseChecked = TRUE;
	}
	return m_bLicenseValid;
}

BOOL COleObjectFactory::UpdateRegistry(BOOL bRegister)
{
	if (bRegister)
		UpdateRegistry();   // will register with default m_lpszProgID

	return TRUE;
}

BOOL COleObjectFactory::VerifyUserLicense()
{
	// May be overridden by subclass
	return TRUE;
}

BOOL COleObjectFactory::GetLicenseKey(DWORD, BSTR*)
{
	// May be overridden by subclass
	return FALSE;
}

BOOL COleObjectFactory::VerifyLicenseKey(BSTR bstrKey)
{
	// May be overridden by subclass

	BOOL bLicensed = FALSE;
	BSTR bstr = NULL;

	if ((bstrKey != NULL) && GetLicenseKey(0, &bstr))
	{
		ASSERT(bstr != NULL);

		// if length and content match, it's good!

		UINT cch = SysStringByteLen(bstr);
		if ((cch == SysStringByteLen(bstrKey)) &&
			(memcmp(bstr, bstrKey, cch) == 0))
		{
			bLicensed = TRUE;
		}

		SysFreeString(bstr);
	}

	return bLicensed;
}

/////////////////////////////////////////////////////////////////////////////
// Implementation of COleObjectFactory::IClassFactory interface

STDMETHODIMP_(ULONG) COleObjectFactory::XClassFactory::AddRef()
{
	METHOD_PROLOGUE_EX_(COleObjectFactory, ClassFactory)
	return pThis->InternalAddRef();
}

STDMETHODIMP_(ULONG) COleObjectFactory::XClassFactory::Release()
{
	METHOD_PROLOGUE_EX_(COleObjectFactory, ClassFactory)
	return pThis->InternalRelease();
}

STDMETHODIMP COleObjectFactory::XClassFactory::QueryInterface(
	REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE_EX_(COleObjectFactory, ClassFactory)
	return pThis->InternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP COleObjectFactory::XClassFactory::CreateInstance(
	IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject)
{
	return CreateInstanceLic(pUnkOuter, NULL, riid, NULL, ppvObject);
}

STDMETHODIMP COleObjectFactory::XClassFactory::LockServer(BOOL fLock)
{
	METHOD_PROLOGUE_EX(COleObjectFactory, ClassFactory)
	ASSERT_VALID(pThis);

	SCODE sc = E_UNEXPECTED;
	TRY
	{
		if (fLock)
			AfxOleLockApp();
		else
			AfxOleUnlockApp();
		sc = S_OK;
	}
	END_TRY

	return sc;
}

STDMETHODIMP COleObjectFactory::XClassFactory::GetLicInfo(
	LPLICINFO pLicInfo)
{
	METHOD_PROLOGUE_EX(COleObjectFactory, ClassFactory)
	ASSERT_VALID(pThis);

	BSTR bstr = NULL;
	pLicInfo->fLicVerified = pThis->IsLicenseValid();
	pLicInfo->fRuntimeKeyAvail = pThis->GetLicenseKey(0, &bstr);
	if (bstr != NULL)
		SysFreeString(bstr);

	return S_OK;
}

STDMETHODIMP COleObjectFactory::XClassFactory::RequestLicKey(
	DWORD dwReserved, BSTR* pbstrKey)
{
	METHOD_PROLOGUE_EX(COleObjectFactory, ClassFactory)
	ASSERT_VALID(pThis);

	ASSERT(pbstrKey != NULL);

	*pbstrKey = NULL;

	if (pThis->IsLicenseValid())
	{
		if (pThis->GetLicenseKey(dwReserved, pbstrKey))
			return S_OK;
		else
			return E_FAIL;
	}
	else
		return CLASS_E_NOTLICENSED;
}

STDMETHODIMP COleObjectFactory::XClassFactory::CreateInstanceLic(
	LPUNKNOWN pUnkOuter, LPUNKNOWN /* pUnkReserved */, REFIID riid,
	BSTR bstrKey, LPVOID* ppvObject)
{
	METHOD_PROLOGUE_EX(COleObjectFactory, ClassFactory)
	ASSERT_VALID(pThis);

	if (ppvObject == NULL)
		return E_POINTER;
	*ppvObject = NULL;

	if (((bstrKey != NULL) && !pThis->VerifyLicenseKey(bstrKey)) ||
		((bstrKey == NULL) && !pThis->IsLicenseValid()))
		return CLASS_E_NOTLICENSED;

	// outer objects must ask for IUnknown only
	ASSERT(pUnkOuter == NULL || riid == IID_IUnknown);

	// attempt to create the object
	CCmdTarget* pTarget = NULL;
	SCODE sc = E_OUTOFMEMORY;
	TRY
	{
		// attempt to create the object
		pTarget = pThis->OnCreateObject();
		if (pTarget != NULL)
		{
			// check for aggregation on object not supporting it
			sc = CLASS_E_NOAGGREGATION;
			if (pUnkOuter == NULL || pTarget->m_xInnerUnknown != 0)
			{
				// create aggregates used by the object
				pTarget->m_pOuterUnknown = pUnkOuter;
				sc = E_OUTOFMEMORY;
				if (pTarget->OnCreateAggregates())
					sc = S_OK;
			}
		}
	}
	END_TRY

	// finish creation
	if (sc == S_OK)
	{
		DWORD dwRef = 1;
		if (pUnkOuter != NULL)
		{
			// return inner unknown instead of IUnknown
			*ppvObject = &pTarget->m_xInnerUnknown;
		}
		else
		{
			// query for requested interface
			sc = pTarget->InternalQueryInterface(&riid, ppvObject);
			if (sc == S_OK)
			{
				dwRef = pTarget->InternalRelease();
				ASSERT(dwRef != 0);
			}
		}
		if (dwRef != 1)
			TRACE1("Warning: object created with reference of %ld\n", dwRef);
	}

	// cleanup in case of errors
	if (sc != S_OK)
		delete pTarget;

	return sc;
}

//////////////////////////////////////////////////////////////////////////////
// Diagnostics

#ifdef _DEBUG
void COleObjectFactory::AssertValid() const
{
	CCmdTarget::AssertValid();
	ASSERT(m_lpszProgID == NULL || AfxIsValidString(m_lpszProgID));
	ASSERT(m_pRuntimeClass == NULL ||
		AfxIsValidAddress(m_pRuntimeClass, sizeof(CRuntimeClass), FALSE));
	ASSERT(m_pNextFactory == NULL ||
		AfxIsValidAddress(m_pNextFactory, sizeof(COleObjectFactory)));
}

void COleObjectFactory::Dump(CDumpContext& dc) const
{
	USES_CONVERSION;

	CCmdTarget::Dump(dc);

	dc << "m_pNextFactory = " << (void*)m_pNextFactory;
	dc << "\nm_dwRegister = " << m_dwRegister;
	dc << "\nm_bRegistered = " << m_bRegistered;
	LPOLESTR lpszClassID = NULL;
	if (StringFromCLSID(m_clsid, &lpszClassID) == S_OK)
	{
		dc << "\nm_clsid = " << OLE2CT(lpszClassID);
		CoTaskMemFree(lpszClassID);
	}
	dc << "\nm_pRuntimeClass = " << m_pRuntimeClass;
	dc << "\nm_bMultiInstance = " << m_bMultiInstance;
	dc << "\nm_lpszProgID = " << m_lpszProgID;
	dc << "\nm_bLicenseChecked = " << m_bLicenseChecked;
	dc << "\nm_bLicenseValid = " << m_bLicenseValid;

	dc << "\n";
}
#endif //_DEBUG

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

IMPLEMENT_DYNAMIC(COleObjectFactory, CCmdTarget)

/////////////////////////////////////////////////////////////////////////////
