/***************************************************************************
 *
 *  Copyright (C) 1998-2001 Microsoft Corporation.  All Rights Reserved.
 *
 *  File:		dp8simclassfac.cpp
 *
 *  Content:	a generic class factory.
 *
 *
 *	This is a generic C++ class factory.  All you need to do is implement
 *	a function called DoCreateInstance that will create an instance of
 *	your object.
 *
 *	GP_ stands for "General Purpose"
 *
 *
 *  History:
 *   Date      By        Reason
 *  ========  ========  =========
 *  04/23/01  VanceO    Copied from DPNHUPNP.
 *
 ***************************************************************************/


#include "dp8simi.h"



#ifdef __MWERKS__
	#define EXP __declspec(dllexport)
#else
	#define EXP
#endif


//**********************************************************************
// Constant definitions
//**********************************************************************

//**********************************************************************
// Macro definitions
//**********************************************************************

//**********************************************************************
// Structure definitions
//**********************************************************************

//
// class factory class definition
//
typedef class GPClassFactory:public IClassFactory
{
	public:
		GPClassFactory(const CLSID * pclsid)	{ m_dwRefCnt = 0; memcpy(&m_clsid, pclsid, sizeof(CLSID)); };
		~GPClassFactory(void)				{};


		STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
		STDMETHODIMP_(ULONG) AddRef(void);
		STDMETHODIMP_(ULONG) Release(void);
		STDMETHODIMP CreateInstance(IUnknown * pUnkOuter, REFIID riid, void ** ppvObject);
		STDMETHODIMP LockServer(BOOL fLock);


	private:
		DWORD		m_dwRefCnt;
		CLSID		m_clsid;
} GPCLASSFACTORY, *LPGPCLASSFACTORY;


//
// function prototype for CoLockObjectExternal()
//
typedef	HRESULT (WINAPI * PCOLOCKOBJECTEXTERNAL)(LPUNKNOWN, BOOL, BOOL );

//**********************************************************************
// Variable definitions
//**********************************************************************

//
// count of outstanding COM interfaces, defined in dpnathlpdllmain.cpp
//
extern volatile LONG	g_lOutstandingInterfaceCount;



//**********************************************************************
// Function prototypes
//**********************************************************************


//**********************************************************************
// Function definitions
//**********************************************************************




/*
 * GPClassFactory::QueryInterface
 */
STDMETHODIMP GPClassFactory::QueryInterface(
											REFIID riid,
											LPVOID *ppvObj )
{
	HRESULT hr;

    *ppvObj = NULL;


    if( IsEqualIID(riid, IID_IClassFactory) ||
                    IsEqualIID(riid, IID_IUnknown))
    {
        this->m_dwRefCnt++;
        *ppvObj = this;
		hr = S_OK;
    }
    else
    {
		hr = E_NOINTERFACE;
    }


	return hr;

} /* GPClassFactory::QueryInterface */


/*
 * GPClassFactory::AddRef
 */
STDMETHODIMP_(ULONG) GPClassFactory::AddRef( void )
{
    this->m_dwRefCnt++;
    return this->m_dwRefCnt;
} /* GPClassFactory::AddRef */



/*
 * GPClassFactory::Release
 */
STDMETHODIMP_(ULONG) GPClassFactory::Release( void )
{
    this->m_dwRefCnt--;

    if( this->m_dwRefCnt != 0 )
    {
        return this->m_dwRefCnt;
    }

    delete this;
    return 0;

} /* GPClassFactory::Release */




/*
 * GPClassFactory::CreateInstance
 *
 * Creates an instance of the object
 */
STDMETHODIMP GPClassFactory::CreateInstance(
											LPUNKNOWN pUnkOuter,
											REFIID riid,
    										LPVOID *ppvObj
											)
{
    HRESULT					hr = S_OK;

    if( pUnkOuter != NULL )
    {
        return CLASS_E_NOAGGREGATION;
    }

	*ppvObj = NULL;


    /*
     * create the object by calling DoCreateInstance.  This function
     *	must be implemented specifically for your COM object
     */
	hr = DoCreateInstance(this, pUnkOuter, this->m_clsid, riid, ppvObj);
	if (FAILED(hr))
	{
		*ppvObj = NULL;
		return hr;
	}

    return S_OK;

} /* GPClassFactory::CreateInstance */



/*
 * GPClassFactory::LockServer
 *
 * Called to force our DLL to stayed loaded
 */
STDMETHODIMP GPClassFactory::LockServer(
                BOOL fLock
				)
{
    HRESULT		hr;
    HINSTANCE	hdll;


    /*
     * call CoLockObjectExternal
     */
    hr = E_UNEXPECTED;
    hdll = LoadLibraryA( "OLE32.DLL" );
    if( hdll != NULL )
    {
        PCOLOCKOBJECTEXTERNAL	lpCoLockObjectExternal;


		lpCoLockObjectExternal = reinterpret_cast<PCOLOCKOBJECTEXTERNAL>( GetProcAddress( hdll, "CoLockObjectExternal" ) );
        if( lpCoLockObjectExternal != NULL )
        {
            hr = lpCoLockObjectExternal( (LPUNKNOWN) this, fLock, TRUE );
        }
        else
        {
        }
    }
    else
    {
    }

	return hr;

} /* GPClassFactory::LockServer */



/*
 * DllGetClassObject
 *
 * Entry point called by COM to get a ClassFactory pointer
 */
EXP STDAPI  DllGetClassObject(
                REFCLSID rclsid,
                REFIID riid,
                LPVOID *ppvObj )
{
    LPGPCLASSFACTORY	pcf;
    HRESULT		hr;

    *ppvObj = NULL;

    /*
     * is this our class id?
     */
//	you must implement GetClassID() for your specific COM object
	if (!IsClassImplemented(rclsid))
    {
		return CLASS_E_CLASSNOTAVAILABLE;
	}

    /*
     * only allow IUnknown and IClassFactory
     */
    if( !IsEqualIID( riid, IID_IUnknown ) &&
	    !IsEqualIID( riid, IID_IClassFactory ) )
    {
        return E_NOINTERFACE;
    }

    /*
     * create a class factory object
     */
    pcf = new GPClassFactory(&rclsid);
    if( NULL == pcf)
    {
        return E_OUTOFMEMORY;
    }

    hr = pcf->QueryInterface( riid, ppvObj );
    if( FAILED( hr ) )
    {
        delete pcf;
        *ppvObj = NULL;
    }
    else
    {
    }

    return hr;

} /* DllGetClassObject */

/*
 * DllCanUnloadNow
 *
 * Entry point called by COM to see if it is OK to free our DLL
 */
EXP STDAPI DllCanUnloadNow( void )
{
    HRESULT	hr = S_FALSE;

	
	if ( g_lOutstandingInterfaceCount == 0 )
	{
		hr = S_OK;
	}

    return hr;

} /* DllCanUnloadNow */