home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
msdn_vcb
/
samples
/
vc98
/
sdk
/
com
/
inole2
/
chap12
/
datatran
/
idataobj.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
11KB
|
431 lines
/*
* IDATAOBJ.CPP
* Data Transfer Object Chapter 12
*
* Implementation of the IDataObject interface for CDataObject.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "dataobj.h"
/*
* CImpIDataObject::CImpIDataObject
* CImpIDataObject::~CImpIDataObject
*
* Parameters (Constructor):
* pObj PCDataObject of the object we're in.
* pUnkOuter LPUNKNOWN to which we delegate.
*/
CImpIDataObject::CImpIDataObject(PCDataObject pObj
, LPUNKNOWN pUnkOuter)
{
m_cRef=0;
m_pObj=pObj;
m_pUnkOuter=pUnkOuter;
return;
}
CImpIDataObject::~CImpIDataObject(void)
{
return;
}
/*
* CImpIDataObject::QueryInterface
* CImpIDataObject::AddRef
* CImpIDataObject::Release
*
* Purpose:
* IUnknown members for CImpIDataObject object.
*/
STDMETHODIMP CImpIDataObject::QueryInterface(REFIID riid, PPVOID ppv)
{
return m_pUnkOuter->QueryInterface(riid, ppv);
}
STDMETHODIMP_(ULONG) CImpIDataObject::AddRef(void)
{
++m_cRef;
return m_pUnkOuter->AddRef();
}
STDMETHODIMP_(ULONG) CImpIDataObject::Release(void)
{
--m_cRef;
return m_pUnkOuter->Release();
}
/*
* CImpIDataObject::GetData
*
* Purpose:
* Retrieves data described by a specific FormatEtc into a StgMedium
* allocated by this function. Used like GetClipboardData.
*
* Parameters:
* pFE LPFORMATETC describing the desired data.
* pSTM LPSTGMEDIUM in which to return the data.
*
* Return Value:
* HRESULT NOERROR or a general error value.
*/
STDMETHODIMP CImpIDataObject::GetData(LPFORMATETC pFE
, LPSTGMEDIUM pSTM)
{
UINT i, cItems;
PRENDERING pRen;
DWORD cb;
HWND hList;
if (NULL==m_pObj->m_hList || NULL==pFE || NULL==pSTM)
return ResultFromScode(DATA_E_FORMATETC);
hList=m_pObj->m_hList;
cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);
for (i=0; i < cItems; i++)
{
cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen);
if (LB_ERR!=cb)
{
/*
* Check if the requested FORMATETC is the same as one
* that we already have. If so, then copy that STGMEDIUM
* to pSTM and AddRef ourselves for pUnkForRelease.
*/
if (pFE->cfFormat==pRen->fe.cfFormat
&& (pFE->tymed & pRen->fe.tymed)
&& pFE->dwAspect==pRen->fe.dwAspect)
{
/*
* ReleaseStgMedium will Release both storage
* and stream elements regardless of the value
* of pUnkForRelease, so we have to AddRef the
* element and bump our own ref count here.
*/
if (TYMED_ISTORAGE==pRen->fe.tymed)
pRen->stm.pstg->AddRef();
if (TYMED_ISTREAM==pRen->fe.tymed)
pRen->stm.pstm->AddRef();
*pSTM=pRen->stm;
AddRef();
return NOERROR;
}
}
}
return ResultFromScode(DATA_E_FORMATETC);
}
/*
* CImpIDataObject::GetDataHere
*
* Purpose:
* Copies a piece of data in this data object to another
* STGMEDIUM. This is only supported for TYMED_ISTORAGE
* and TYMED_ISTREAM.
*
* Parameters:
* pFE LPFORMATETC describing the desired data.
* pSTM LPSTGMEDIUM pointing to the medium into which
* we copy.
*
* Return Value:
* HRESULT NOERROR or a general error value.
*/
STDMETHODIMP CImpIDataObject::GetDataHere(LPFORMATETC pFE
, LPSTGMEDIUM pSTM)
{
UINT i, cItems;
PRENDERING pRen;
DWORD cb;
HWND hList;
if (NULL==m_pObj->m_hList || NULL==pFE || NULL==pSTM)
return ResultFromScode(DATA_E_FORMATETC);
//We only support IStorage and IStream
if (!(TYMED_ISTORAGE & pFE->tymed)
&& !(TYMED_ISTREAM & pFE->tymed))
return ResultFromScode(DATA_E_FORMATETC);
hList=m_pObj->m_hList;
cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);
for (i=0; i < cItems; i++)
{
cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen);
if (LB_ERR!=cb)
{
/*
* When we find a matching FORMATETC, we know we're
* only looking for IStorage or IStream (we checked
* above), so use IStorage::CopyTo or IStream::CopyTo
* to make the copy.
*/
if (pFE->cfFormat==pRen->fe.cfFormat
&& (pFE->tymed & pRen->fe.tymed)
&& pFE->dwAspect==pRen->fe.dwAspect)
{
if (TYMED_ISTORAGE==pFE->tymed)
{
pSTM->tymed=TYMED_ISTORAGE;
return pRen->stm.pstg->CopyTo(NULL, NULL
, NULL, pSTM->pstg);
}
else
{
STATSTG st;
pRen->stm.pstm->Stat(&st, STATFLAG_NONAME);
pSTM->tymed=TYMED_ISTREAM;
return pRen->stm.pstm->CopyTo(pSTM->pstm
, st.cbSize, NULL, NULL);
}
}
}
}
return ResultFromScode(DATA_E_FORMATETC);
}
/*
* CImpIDataObject::QueryGetData
*
* Purpose:
* Tests if a call to GetData with this FormatEtc will provide
* any rendering; used like IsClipboardFormatAvailable.
*
* Parameters:
* pFE LPFORMATETC describing the desired data.
*
* Return Value:
* HRESULT NOERROR or a general error value.
*/
STDMETHODIMP CImpIDataObject::QueryGetData(LPFORMATETC pFE)
{
UINT i, cItems;
PRENDERING pRen;
DWORD cb;
HWND hList;
if (NULL==m_pObj->m_hList || NULL==pFE)
return ResultFromScode(S_FALSE);
hList=m_pObj->m_hList;
cItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);
for (i=0; i < cItems; i++)
{
cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen);
if (LB_ERR!=cb)
{
/*
* Check if the requested FORMATETC is the same as one
* that we already have.
*/
if (pFE->cfFormat==pRen->fe.cfFormat
&& (pFE->tymed & pRen->fe.tymed)
&& pFE->dwAspect==pRen->fe.dwAspect)
{
return NOERROR;
}
}
}
return ResultFromScode(S_FALSE);
}
/*
* CImpIDataObject::SetData
*
* Purpose:
* Places data described by a FormatEtc and living in a StgMedium
* into the object. The object may be responsible to clean up the
* StgMedium before exiting.
*
* Parameters:
* pFE LPFORMATETC describing the data to set.
* pSTM LPSTGMEDIUM containing the data.
* fRelease BOOL indicating if this function is responsible
* for freeing the data.
*
* Return Value:
* HRESULT NOERROR or a general error value.
*/
STDMETHODIMP CImpIDataObject::SetData(LPFORMATETC pFE
, LPSTGMEDIUM pSTM, BOOL fRelease)
{
PRENDERING prn;
//We have to remain responsible for the data.
if (!fRelease)
return ResultFromScode(E_FAIL);
//If we're handed NULLs, that means clean out the list.
if (NULL==pFE || NULL==pSTM)
{
m_pObj->Purge();
return NOERROR;
}
/*
* Here we take the rendering we're given and attach it to the
* end of the list. We save the original pSTM->pUnkForRelease
* and replace it with our own such that each 'copy' of this
* data is actually just a reference count.
*/
prn=new RENDERING;
if (NULL==prn)
return ResultFromScode(E_OUTOFMEMORY);
prn->fe=*pFE;
prn->stm=*pSTM;
prn->pUnkOrg=pSTM->pUnkForRelease;
prn->stm.pUnkForRelease=this;
SendMessage(m_pObj->m_hList, LB_ADDSTRING, 0, (LONG)prn);
return NOERROR;
}
/*
* CImpIDataObject::EnumFormatEtc
*
* Purpose:
* Returns an IEnumFORMATETC object through which the caller can
* iterate to learn about all the data formats this object can
* provide through either GetData[Here] or SetData.
*
* Parameters:
* dwDir DWORD describing a data direction, either
* DATADIR_SET or DATADIR_GET.
* ppEnum LPENUMFORMATETC * in which to return the
* pointer to the enumerator.
*
* Return Value:
* HRESULT NOERROR or a general error value.
*/
STDMETHODIMP CImpIDataObject::EnumFormatEtc(DWORD dwDir
, LPENUMFORMATETC *ppEnum)
{
PCEnumFormatEtc pEnum;
*ppEnum=NULL;
/*
* From an external point of view there are no SET formats,
* because we want to allow the user of this component object
* to be able to stuff ANY format in via Set. Only external
* users will call EnumFormatEtc and they can only Get.
*/
switch (dwDir)
{
case DATADIR_GET:
pEnum=new CEnumFormatEtc(m_pUnkOuter);
break;
case DATADIR_SET:
default:
pEnum=NULL;
break;
}
if (NULL==pEnum)
return ResultFromScode(E_FAIL);
else
{
//Let the enumerator copy our format list.
if (!pEnum->Init(m_pObj->m_hList))
{
delete pEnum;
return ResultFromScode(E_FAIL);
}
pEnum->AddRef();
}
*ppEnum=pEnum;
return NOERROR;
}
/*
* CImpIDataObject::GetCanonicalFormatEtc
* CImpIDataObject::DAdvise
* CImpIDataObject::DUnadvise
* CImpIDataObject::EnumDAdvise
*
* Trivial member functions.
*/
STDMETHODIMP CImpIDataObject::GetCanonicalFormatEtc
(LPFORMATETC pFEIn, LPFORMATETC pFEOut)
{
return ResultFromScode(DATA_S_SAMEFORMATETC);
}
STDMETHODIMP CImpIDataObject::DAdvise(LPFORMATETC pFE
, DWORD dwFlags, LPADVISESINK pIAdviseSink, LPDWORD pdwConn)
{
return ResultFromScode(E_FAIL);
}
STDMETHODIMP CImpIDataObject::DUnadvise(DWORD dwConn)
{
return ResultFromScode(E_FAIL);
}
STDMETHODIMP CImpIDataObject::EnumDAdvise(LPENUMSTATDATA *ppEnum)
{
return ResultFromScode(E_FAIL);
}