// // DATAOBJECT.CPP // // Implementation of the IDataObject COM interface // // By J Brown 2004 // // www.catch22.net // //#define STRICT #include "stdafx.h" #include "dataobject.h" const ULONG MAX_FORMATS = 100; HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc); // // Constructors // CDataObject::CDataObject(const FORMATETC *fmtetc, const STGMEDIUM *stgmed, int count) { m_lRefCount = 1; m_nNumFormats = count; m_pFormatEtc = new FORMATETC[count]; m_pStgMedium = new STGMEDIUM[count]; for (int i = 0; i < count; i++) { m_pFormatEtc[i] = fmtetc[i]; m_pStgMedium[i] = stgmed[i]; } } CDataObject::CDataObject() { m_lRefCount = 1; m_nNumFormats = 0; m_pFormatEtc = nullptr; m_pStgMedium = nullptr; } // // Destructor // CDataObject::~CDataObject() { if (m_pFormatEtc) delete[] m_pFormatEtc; if (m_pStgMedium) delete[] m_pStgMedium; } // for use in child's void CDataObject::UpdateData(const FORMATETC *fmtetc, const STGMEDIUM *stgmed, int count) { m_lRefCount = 1; m_nNumFormats = count; if (m_pFormatEtc) delete[] m_pFormatEtc; if (m_pStgMedium) delete[] m_pStgMedium; m_pFormatEtc = new FORMATETC[count]; m_pStgMedium = new STGMEDIUM[count]; for (int i = 0; i < count; i++) { m_pFormatEtc[i] = fmtetc[i]; m_pStgMedium[i] = stgmed[i]; } } // // IUnknown::AddRef // ULONG __stdcall CDataObject::AddRef(void) { // increment object reference count return InterlockedIncrement(&m_lRefCount); } // // IUnknown::Release // ULONG __stdcall CDataObject::Release(void) { // decrement object reference count LONG count = InterlockedDecrement(&m_lRefCount); if (count == 0) { delete this; return 0; } return count; } // // IUnknown::QueryInterface // HRESULT __stdcall CDataObject::QueryInterface(REFIID iid, void **ppvObject) { // check to see what interface has been requested if (iid == IID_IDataObject || iid == IID_IUnknown) { AddRef(); *ppvObject = this; return S_OK; } *ppvObject = nullptr; return E_NOINTERFACE; } int CDataObject::LookupFormatEtc(FORMATETC *pFormatEtc) { for (int i = 0; i < m_nNumFormats; i++) { if ((pFormatEtc->tymed & m_pFormatEtc[i].tymed) && pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat && pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect) { return i; } } return -1; } // // IDataObject::GetData // HRESULT __stdcall CDataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { int idx; // // try to match the requested FORMATETC with one of our supported formats // if ((idx = LookupFormatEtc(pFormatEtc)) == -1) return DV_E_FORMATETC; // // found a match! transfer the data into the supplied storage-medium // pMedium->tymed = m_pFormatEtc[idx].tymed; pMedium->pUnkForRelease = nullptr; switch (pMedium->tymed) { case TYMED_HGLOBAL: case TYMED_GDI: case TYMED_ENHMF: pMedium->hBitmap = m_pStgMedium[idx].hBitmap; break; default: return DV_E_FORMATETC; } if (pMedium->hBitmap == nullptr) return STG_E_MEDIUMFULL; return S_OK; } // // IDataObject::GetDataHere // HRESULT __stdcall CDataObject::GetDataHere(FORMATETC *, STGMEDIUM *) { // GetDataHere is only required for IStream and IStorage mediums // It is an error to call GetDataHere for things like HGLOBAL and other clipboard formats // // OleFlushClipboard // return DATA_E_FORMATETC; } // // IDataObject::QueryGetData // // Called to see if the IDataObject supports the specified format of data // HRESULT __stdcall CDataObject::QueryGetData(FORMATETC *pFormatEtc) { return (LookupFormatEtc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK; } // // IDataObject::GetCanonicalFormatEtc // HRESULT __stdcall CDataObject::GetCanonicalFormatEtc(FORMATETC *, FORMATETC *pFormatEtcOut) { // Apparently we have to set this field to NULL even though we don't do anything else pFormatEtcOut->ptd = nullptr; return E_NOTIMPL; } // // IDataObject::SetData // HRESULT __stdcall CDataObject::SetData(FORMATETC *, STGMEDIUM *, BOOL) { return E_NOTIMPL; } // // IDataObject::EnumFormatEtc // HRESULT __stdcall CDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc) { if (dwDirection == DATADIR_GET) { // for Win2k+ you can use the SHCreateStdEnumFmtEtc API call, however // to support all Windows platforms we need to implement IEnumFormatEtc ourselves. return CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc); } else { // the direction specified is not support for drag+drop return E_NOTIMPL; } } // // IDataObject::DAdvise // HRESULT __stdcall CDataObject::DAdvise(FORMATETC *, DWORD, IAdviseSink *, DWORD *) { return OLE_E_ADVISENOTSUPPORTED; } // // IDataObject::DUnadvise // HRESULT __stdcall CDataObject::DUnadvise(DWORD) { return OLE_E_ADVISENOTSUPPORTED; } // // IDataObject::EnumDAdvise // HRESULT __stdcall CDataObject::EnumDAdvise(IEnumSTATDATA **) { return OLE_E_ADVISENOTSUPPORTED; } // // Helper function // HRESULT CreateDataObject(const FORMATETC *fmtetc, const STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject) { if (ppDataObject == nullptr) return E_INVALIDARG; *ppDataObject = new CDataObject(fmtetc, stgmeds, count); return (*ppDataObject) ? S_OK : E_OUTOFMEMORY; } // CEMFObject // Constructor CEMFObject::CEMFObject(HENHMETAFILE hEmf) { static const FORMATETC lc_format[] = { { CF_ENHMETAFILE, nullptr, DVASPECT_CONTENT, -1, TYMED_ENHMF } }; STGMEDIUM lc_stgmed[] = { { TYMED_ENHMF, { (HBITMAP)hEmf }, nullptr } }; UpdateData(lc_format, lc_stgmed, 1); m_hEmf = hEmf; } // Destructor CEMFObject::~CEMFObject() { DeleteEnhMetaFile(m_hEmf); } // GetData HRESULT __stdcall CEMFObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { HRESULT hr; hr = CDataObject::GetData(pFormatEtc, pMedium); if (hr == S_OK) { // we are responsible for releasing EMF object, not OLE client, so set pointer to IUnknown to us and Add a new reference pMedium->pUnkForRelease = this; AddRef(); } return hr; }