///////////////////////////////////////////////////////////////////////////// // 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 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; }