HCOSMO.CPP

/* 
* HCOSMO.CPP
* Cosmo Handler Chapter 19
*
* DLL exports for an object handler as well as class factory.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/


#define INITGUIDS
#include "hcosmo.h"


//Count number of objects and number of locks.
ULONG g_cObj=0;
ULONG g_cLock=0;

//DLL Instance handle
HINSTANCE g_hInst=0;


/*
* LibMain(32)
*
* Purpose:
* Entry point for Win32 or Win16 DLLs.
*/

#ifdef WIN32
BOOL WINAPI LibMain32(HINSTANCE hInstance, ULONG ulReason
, LPVOID pvReserved)
{
if (DLL_PROCESS_DETACH==ulReason)
{
return TRUE;
}
else
{
if (DLL_PROCESS_ATTACH!=ulReason)
return TRUE;
}

g_hInst=hInstance;
return TRUE;
}

#else

/*
* LibMain (also called from Win32 LibMain32)
*
* Purpose:
* DLL-specific entry point called from LibEntry.
*/

int PASCAL LibMain(HINSTANCE hInst, WORD wDataSeg
, WORD cbHeapSize, LPSTR lpCmdLine)
{
if (0!=cbHeapSize)
UnlockData(0);

g_hInst=hInst;
return (int)hInst;
}

#endif




/*
* DllGetClassObject
*
* Purpose:
* Standard export for DLL component objects.
*/

HRESULT APIENTRY DllGetClassObject(REFCLSID rclsid
, REFIID riid, PPVOID ppv)
{
if (CLSID_CosmoFigure!=rclsid)
return ResultFromScode(E_FAIL);

//Check that we can provide the interface
if (IID_IUnknown!=riid && IID_IClassFactory!=riid)
return ResultFromScode(E_NOINTERFACE);

//Return our IClassFactory for Figure objects
*ppv=new CFigureClassFactory;

if (NULL==*ppv)
return ResultFromScode(E_OUTOFMEMORY);

((LPUNKNOWN)*ppv)->AddRef();
g_cObj++;
return NOERROR;
}





/*
* DllCanUnloadNow
*
* Purpose:
* Answers if the DLL can be freed, that is, if there are no
* references to anything this DLL provides.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if nothing is using us, FALSE otherwise.
*/

STDAPI DllCanUnloadNow(void)
{
SCODE sc;

//Our answer is whether there are any object or locks
sc=(0L==g_cObj && 0==g_cLock) ? S_OK : S_FALSE;
return ResultFromScode(sc);
}




/*
* ObjectDestroyed
*
* Purpose:
* Function for the Figure object to call when it gets destroyed.
* Since we're in a DLL we only track the number of objects here
* letting DllCanUnloadNow take care of the rest.
*/

void ObjectDestroyed(void)
{
g_cObj--;
return;
}






/*
* CFigureClassFactory::CFigureClassFactory
* CFigureClassFactory::~CFigureClassFactory
*/

CFigureClassFactory::CFigureClassFactory(void)
{
m_cRef =0L;
return;
}

CFigureClassFactory::~CFigureClassFactory(void)
{
return;
}



/*
* CFigureClassFactory::QueryInterface
* CFigureClassFactory::AddRef
* CFigureClassFactory::Release
*/

STDMETHODIMP CFigureClassFactory::QueryInterface(REFIID riid
, PPVOID ppv)
{
*ppv=NULL;

//Any interface on this object is the object pointer.
if (IID_IUnknown==riid || IID_IClassFactory==riid)
*ppv=this;

if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}

return ResultFromScode(E_NOINTERFACE);
}


STDMETHODIMP_(ULONG) CFigureClassFactory::AddRef(void)
{
return ++m_cRef;
}


STDMETHODIMP_(ULONG) CFigureClassFactory::Release(void)
{
if (0!=--m_cRef)
return m_cRef;

delete this;
ObjectDestroyed();
return 0;
}





/*
* CFigureClassFactory::CreateInstance
*
* Purpose:
* Instantiates a Figure object that supports the IFigure
* and IUnknown interfaces. If the caller asks for a different
* interface than these two then we fail.
*
* Parameters:
* pUnkOuter LPUNKNOWN to the controlling IUnknown if we are
* being used in an aggregation.
* riid REFIID identifying the interface the caller
* desires to have for the new object.
* ppvObj PPVOID in which to store the desired interface
* pointer for the new object.
*
* Return Value:
* HRESULT NOERROR if successful, otherwise contains
* E_NOINTERFACE if we cannot support the requested
* interface.
*/

STDMETHODIMP CFigureClassFactory::CreateInstance(LPUNKNOWN pUnkOuter
, REFIID riid, PPVOID ppvObj)
{
PCFigure pObj;
HRESULT hr;

*ppvObj=NULL;
hr=ResultFromScode(E_OUTOFMEMORY);

//Verify that a controlling unknown is asking for IUnknown
if (NULL!=pUnkOuter && IID_IUnknown!=riid)
return ResultFromScode(E_NOINTERFACE);

//Create the object. This also creates a window.
pObj=new CFigure(pUnkOuter, ObjectDestroyed, g_hInst);

if (NULL==pObj)
return hr;

if (pObj->Init())
hr=pObj->QueryInterface(riid, ppvObj);

//Kill the object if initial creation or Init failed.
if (FAILED(hr))
delete pObj;
else
g_cObj++;

return hr;
}






/*
* CFigureClassFactory::LockServer
*
* Purpose:
* Increments or decrements the lock count of the DLL. If the lock
* count goes to zero and there are no objects, the DLL is allowed
* to unload. See DllCanUnloadNow.
*
* Parameters:
* fLock BOOL specifying whether to increment or
* decrement the lock count.
*
* Return Value:
* HRESULT NOERROR always.
*/

STDMETHODIMP CFigureClassFactory::LockServer(BOOL fLock)
{
if (fLock)
g_cLock++;
else
g_cLock--;

return NOERROR;
}