You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
6.7 KiB
258 lines
6.7 KiB
/////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// MODULE: dataobj.cpp
|
|
//
|
|
// PURPOSE: Implements a generic IDataObject that can be used for simple
|
|
// drag and drop scenarios.
|
|
//
|
|
// HISTORY:
|
|
//
|
|
|
|
#include "pch.hxx"
|
|
#include "dllmain.h"
|
|
#include "msoert.h"
|
|
#include <BadStrFunctions.h>
|
|
|
|
|
|
CDataObject::CDataObject ()
|
|
{
|
|
m_cRef = 1;
|
|
m_pInfo = 0;
|
|
m_celtInfo = 0;
|
|
m_pfnFree = 0;
|
|
}
|
|
|
|
CDataObject::~CDataObject ()
|
|
{
|
|
if (m_pfnFree)
|
|
m_pfnFree(m_pInfo, m_celtInfo);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: Init
|
|
//
|
|
// PURPOSE: Allows the caller to provide the object with data and formats.
|
|
//
|
|
// PARAMETERS:
|
|
// [in] pDataObjInfo - An array of DATAOBJINFO structs which contain the
|
|
// data and formats that the data object will provide.
|
|
// [in] celt - The number of elements in pDataObjInfo.
|
|
// [in] pfnFree - callback to free allocated data
|
|
//
|
|
// RETURNS:
|
|
// S_OK - The object is initialized OK.
|
|
// E_INVALIDARG - Either pDataObjInfo is NULL or celt is zero.
|
|
//
|
|
// COMMENTS:
|
|
// Note, after the caller gives the object pDataObjInfo, this object owns
|
|
// that data and will be responsible for freeing it.
|
|
//
|
|
HRESULT CDataObject::Init(PDATAOBJINFO pDataObjInfo, DWORD celt, PFNFREEDATAOBJ pfnFree)
|
|
{
|
|
if (!pDataObjInfo || celt == 0)
|
|
return (E_INVALIDARG);
|
|
|
|
// Hold on to the data
|
|
m_pInfo = pDataObjInfo;
|
|
m_celtInfo = celt;
|
|
m_pfnFree = pfnFree;
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDataObject::QueryInterface (REFIID riid, LPVOID* ppv)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppv = (LPVOID)(IUnknown*) this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IDataObject))
|
|
{
|
|
*ppv = (LPVOID)(IDataObject*) this;
|
|
}
|
|
|
|
if (NULL == *ppv)
|
|
return (E_NOINTERFACE);
|
|
|
|
((LPUNKNOWN) *ppv)->AddRef();
|
|
return (S_OK);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CDataObject::AddRef (void)
|
|
{
|
|
return (++m_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CDataObject::Release (void)
|
|
{
|
|
ULONG cRef = --m_cRef;
|
|
|
|
if (0 == m_cRef)
|
|
delete this;
|
|
|
|
return (cRef);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDataObject::GetData (LPFORMATETC pFE, LPSTGMEDIUM pStgMedium)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
Assert(pStgMedium && pFE);
|
|
if (pStgMedium && pFE)
|
|
{
|
|
HGLOBAL hGlobal = NULL;
|
|
LPVOID pv = NULL;
|
|
|
|
hr = DV_E_FORMATETC;
|
|
|
|
ZeroMemory(pStgMedium, sizeof(STGMEDIUM));
|
|
|
|
// Loop through the pInfo array to see if any of the elements has the
|
|
// same clipboard format as pFE
|
|
for (DWORD i = 0; i < m_celtInfo; i++)
|
|
{
|
|
if (pFE->cfFormat == m_pInfo[i].fe.cfFormat)
|
|
{
|
|
// Make a copy of the data for this pInfo
|
|
hGlobal = GlobalAlloc(GMEM_SHARE | GHND, m_pInfo[i].cbData);
|
|
if (!hGlobal)
|
|
return (E_OUTOFMEMORY);
|
|
|
|
pv = GlobalLock(hGlobal);
|
|
if (!pv)
|
|
{
|
|
hr = E_POINTER;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(pv, m_pInfo[i].pData, m_pInfo[i].cbData);
|
|
GlobalUnlock(hGlobal);
|
|
|
|
// Fill in the pStgMedium struct
|
|
if (pFE->tymed & TYMED_HGLOBAL)
|
|
{
|
|
pStgMedium->hGlobal = hGlobal;
|
|
pStgMedium->tymed = TYMED_HGLOBAL;
|
|
return (S_OK);
|
|
}
|
|
else if (pFE->tymed & TYMED_ISTREAM)
|
|
{
|
|
// If the user wants a stream, convert our HGLOBAL to a stream
|
|
if (SUCCEEDED(CreateStreamOnHGlobal(hGlobal, TRUE, &pStgMedium->pstm)))
|
|
{
|
|
pStgMedium->tymed = TYMED_ISTREAM;
|
|
return (S_OK);
|
|
}
|
|
else
|
|
{
|
|
return (STG_E_MEDIUMFULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(hGlobal);
|
|
return (DV_E_TYMED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pStgMedium)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC pFE)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
|
|
// Check the aspects we support. Implementations of this object will only
|
|
// support DVASPECT_CONTENT.
|
|
if (pFE && !(DVASPECT_CONTENT & pFE->dwAspect))
|
|
return (DV_E_DVASPECT);
|
|
|
|
if (pFE)
|
|
{
|
|
// Now check for an appropriate TYMED.
|
|
fReturn = (pFE->tymed & TYMED_HGLOBAL) || (pFE->tymed & TYMED_ISTREAM);
|
|
}
|
|
|
|
return (fReturn ? S_OK : DV_E_TYMED);
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::GetCanonicalFormatEtc(LPFORMATETC pFEIn,
|
|
LPFORMATETC pFEOut)
|
|
{
|
|
if (NULL == pFEOut)
|
|
return (E_INVALIDARG);
|
|
|
|
pFEOut->ptd = NULL;
|
|
return (DATA_S_SAMEFORMATETC);
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppEnum)
|
|
{
|
|
if (DATADIR_GET == dwDirection)
|
|
{
|
|
if (SUCCEEDED(CreateEnumFormatEtc(this, m_celtInfo, m_pInfo, NULL, ppEnum)))
|
|
return (S_OK);
|
|
else
|
|
return (E_FAIL);
|
|
}
|
|
else
|
|
{
|
|
*ppEnum = NULL;
|
|
return (E_NOTIMPL);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::SetData(LPFORMATETC pFE, LPSTGMEDIUM pStgMedium, BOOL fRelease)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::DAdvise(LPFORMATETC pFE, DWORD advf, IAdviseSink* ppAdviseSink, LPDWORD pdwConnection)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::DUnadvise(DWORD dwConnection)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CDataObject::EnumDAdvise(IEnumSTATDATA** ppEnumAdvise)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
OESTDAPI_(HRESULT) CreateDataObject(PDATAOBJINFO pDataObjInfo, DWORD celt, PFNFREEDATAOBJ pfnFree, IDataObject **ppDataObj)
|
|
{
|
|
CDataObject *pDataObj;
|
|
HRESULT hr;
|
|
|
|
pDataObj = new CDataObject();
|
|
if (!pDataObj)
|
|
return E_OUTOFMEMORY;
|
|
|
|
hr = pDataObj->Init(pDataObjInfo, celt, pfnFree);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = pDataObj->QueryInterface(IID_IDataObject, (LPVOID *)ppDataObj);
|
|
|
|
error:
|
|
pDataObj->Release();
|
|
return hr;
|
|
}
|