/*
* DATATRAN.CPP
* Data Transfer Object Chapter 12
*
* Transfer data object implemented in a DLL. This data object will
* cache specific formats and renderings such that its IDataObject
* interface could be plopped on the clipboard or used in drag-drop.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#define INITGUIDS
#include "datatran.h"
//Count number of objects and number of locks.
ULONG g_cObj=0;
ULONG g_cLock=0;
//Make this global for the data object to create listboxes.
HINSTANCE g_hInst=NULL;
/*
* LibMain(32)
*
* Purpose:
* Entry point conditionally compiled for Windows NT and Windows
* 3.1. Provides the proper structure for each environment.
*/
#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;
}
return TRUE;
}
#else
int PASCAL LibMain(HINSTANCE hInstance, WORD wDataSeg
, WORD cbHeapSize, LPSTR lpCmdLine)
{
if (0!=cbHeapSize)
UnlockData(0);
g_hInst=hInstance;
return (int)hInstance;
}
#endif
/*
* DllGetClassObject
*
* Purpose:
* Provides an IClassFactory for a given CLSID that this DLL is
* registered to support. This DLL is placed under the CLSID
* in the registration database as the InProcServer.
*
* Parameters:
* clsID REFCLSID that identifies the class factory
* desired. Since this parameter is passed this
* DLL can handle any number of objects simply
* by returning different class factories here
* for different CLSIDs.
*
* riid REFIID specifying the interface the caller wants
* on the class object, usually IID_ClassFactory.
*
* ppv PPVOID in which to return the interface
* pointer.
*
* Return Value:
* HRESULT NOERROR on success, otherwise an error code.
*/
HRESULT APIENTRY DllGetClassObject(REFCLSID rclsid
, REFIID riid, PPVOID ppv)
{
//Check that we can provide the interface
if (IID_IUnknown!=riid && IID_IClassFactory!=riid)
return ResultFromScode(E_NOINTERFACE);
*ppv=NULL;
//Check each of the three CLSIDs we support.
if (CLSID_DataTransferObject==rclsid)
*ppv=new CDataTransferClassFactory();
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 && 0L==g_cLock) ? S_OK : S_FALSE;
return ResultFromScode(sc);
}
/*
* ObjectDestroyed
*
* Purpose:
* Function for the DataObject 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;
}
/*
* CDataTransferClassFactory::CDataTransferClassFactory
* CDataTransferClassFactory::~CDataTransferClassFactory
*
* Constructor Parameters:
* None
*/
CDataTransferClassFactory::CDataTransferClassFactory(void)
{
m_cRef=0L;
return;
}
CDataTransferClassFactory::~CDataTransferClassFactory(void)
{
return;
}
/*
* CDataTransferClassFactory::QueryInterface
* CDataTransferClassFactory::AddRef
* CDataTransferClassFactory::Release
*/
STDMETHODIMP CDataTransferClassFactory::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) CDataTransferClassFactory::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CDataTransferClassFactory::Release(void)
{
if (0!=--m_cRef)
return m_cRef;
delete this;
ObjectDestroyed();
return 0;
}
/*
* CDataTransferClassFactory::CreateInstance
*
* Purpose:
* Instantiates a DataObject object that supports the IDataObject
* 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 E_NOINTERFACE
* if we cannot support the requested interface.
*/
STDMETHODIMP CDataTransferClassFactory::CreateInstance
(LPUNKNOWN pUnkOuter, REFIID riid, PPVOID ppvObj)
{
PCDataObject pObj;
HRESULT hr;
*ppvObj=NULL;
hr=ResultFromScode(E_OUTOFMEMORY);
if (NULL!=pUnkOuter && IID_IUnknown!=riid)
return ResultFromScode(E_NOINTERFACE);
//Create the object telling it the data size to work with
pObj=new CDataObject(pUnkOuter, ObjectDestroyed);
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;
}
/*
* CDataTransferClassFactory::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 CDataTransferClassFactory::LockServer(BOOL fLock)
{
if (fLock)
g_cLock++;
else
g_cLock--;
return NOERROR;
}