1.参考内容:
2.拖动涉及:源、目标、数据对象
2.1 鼠标左键按下并且移动,触发拖动。
构建源和数据对象。调用拖放函数DoDragDrop。
case WM_MOUSEMOVE: // if the mouse is held down then start a drag-drop if(fMouseDown) { IDataObject *pDataObject; IDropSource *pDropSource; DWORD dwEffect; DWORD dwResult; FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stgmed = { TYMED_HGLOBAL, { 0 }, 0 }; // transfer the current selection into the IDataObject stgmed.hGlobal = CopySelection(hwndEdit); // Create IDataObject and IDropSource COM objects CreateDropSource(&pDropSource); CreateDataObject(&fmtetc, &stgmed, 1, &pDataObject); // // ** ** ** The drag-drop operation starts here! ** ** ** // dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY|DROPEFFECT_MOVE, &dwEffect); // success! if(dwResult == DRAGDROP_S_DROP) { if(dwEffect & DROPEFFECT_MOVE) { // remove selection from edit control } } // cancelled else if(dwResult == DRAGDROP_S_CANCEL) { } pDataObject->Release(); pDropSource->Release(); ReleaseCapture(); fMouseDown = FALSE; fDidDragDrop = TRUE; }
2.拖放的目标程序,需要调用RegisterDragDrop,为拖放注册。
void RegisterDropWindow(HWND hwnd, IDropTarget **ppDropTarget) { CDropTarget *pDropTarget = new CDropTarget(hwnd); // acquire a strong lock CoLockObjectExternal(pDropTarget, TRUE, FALSE); // tell OLE that the window is a drop target RegisterDragDrop(hwnd, pDropTarget); *ppDropTarget = pDropTarget; } case WM_CREATE: hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL, 0,0,0,0, hwnd, 0, hInstance, 0); SendMessage(hwndEdit, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), 0); // make the Edit control into a DropTarget RegisterDropWindow(hwndEdit, &pDropTarget);
注意:如果你的程序是直接继承自IDropTarget,CoLockObjectExternal(this, TRUE, FALSE);这么写的话,紧接着的下面一句(RegisterDropWindow(hwndEdit, &pDropTarget);)可能就不会执行。换句话说,拖放可能会失败。
3.所有的一切,都由DoDragDrop发轫。这个函数,会调用一些虚函数。如:CDataObject::EnumFormatEtc
4.CDropTarget::Drop中响应事件操作。
注意: 初始化 、反初始化
OleInitialize(0);
OleUninitialize();
源文件
dropsource.h
// // DROPSOURCE.H // // Implementation of the IDropSource COM interface // // By J Brown 2004 // // www.catch22.net // #include <windows.h> HANDLE StringToHandle(char *szText, int nTextLen); HRESULT CreateDropSource(IDropSource **ppDropSource); class CDropSource : public IDropSource { public: // // IUnknown members // HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject); ULONG __stdcall AddRef (void); ULONG __stdcall Release (void); // // IDropSource members // HRESULT __stdcall QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState); HRESULT __stdcall GiveFeedback (DWORD dwEffect); // // Constructor / Destructor // CDropSource(); ~CDropSource(); private: // // private members and functions // LONG m_lRefCount; };
dropsource.cpp
// // DROPSOURCE.CPP // // Implementation of the IDropSource COM interface // // By J Brown 2004 // // www.catch22.net // #include "../stdafx.h" #include "dropsource.h" HANDLE StringToHandle(char *szText, int nTextLen) { void *ptr; // if text length is -1 then treat as a nul-terminated string if(nTextLen == -1) nTextLen = lstrlen(szText) + 1; // allocate and lock a global memory buffer. Make it fixed // data so we don't have to use GlobalLock ptr = (void *)GlobalAlloc(GMEM_FIXED, nTextLen); // copy the string into the buffer memcpy(ptr, szText, nTextLen); return ptr; } // // Constructor // CDropSource::CDropSource() { m_lRefCount = 1; } // // Destructor // CDropSource::~CDropSource() { } // // IUnknown::AddRef // ULONG __stdcall CDropSource::AddRef(void) { // increment object reference count return InterlockedIncrement(&m_lRefCount); } // // IUnknown::Release // ULONG __stdcall CDropSource::Release(void) { // decrement object reference count LONG count = InterlockedDecrement(&m_lRefCount); if(count == 0) { delete this; return 0; } else { return count; } } // // IUnknown::QueryInterface // HRESULT __stdcall CDropSource::QueryInterface(REFIID iid, void **ppvObject) { // check to see what interface has been requested if(iid == IID_IDropSource || iid == IID_IUnknown) { AddRef(); *ppvObject = this; return S_OK; } else { *ppvObject = 0; return E_NOINTERFACE; } } // // CDropSource::QueryContinueDrag // // Called by OLE whenever Escape/Control/Shift/Mouse buttons have changed // HRESULT __stdcall CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { // if the <Escape> key has been pressed since the last call, cancel the drop if(fEscapePressed == TRUE) return DRAGDROP_S_CANCEL; // if the <LeftMouse> button has been released, then do the drop! if((grfKeyState & MK_LBUTTON) == 0) return DRAGDROP_S_DROP; // continue with the drag-drop return S_OK; } // // CDropSource::GiveFeedback // // Return either S_OK, or DRAGDROP_S_USEDEFAULTCURSORS to instruct OLE to use the // default mouse cursor images // HRESULT __stdcall CDropSource::GiveFeedback(DWORD dwEffect) { return DRAGDROP_S_USEDEFAULTCURSORS; } // // Helper routine to create an IDropSource object // HRESULT CreateDropSource(IDropSource **ppDropSource) { if(ppDropSource == 0) return E_INVALIDARG; *ppDropSource = new CDropSource(); return (*ppDropSource) ? S_OK : E_OUTOFMEMORY; }
droptarget.h
// // DROPTARGET.H // // By J Brown 2004 // // www.catch22.net // #pragma once #include <windows.h> void DropData(HWND hwnd, IDataObject *pDataObject); // // This is our definition of a class which implements // the IDropTarget interface // class CDropTarget : public IDropTarget { public: // IUnknown implementation HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject); ULONG __stdcall AddRef (void); ULONG __stdcall Release (void); // IDropTarget implementation HRESULT __stdcall DragEnter (IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); HRESULT __stdcall DragOver (DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); HRESULT __stdcall DragLeave (void); HRESULT __stdcall Drop (IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); virtual void DropData(HWND hwnd, IDataObject *pDataObject) = 0; virtual const HWND GetWnd() = 0; // Constructor CDropTarget(/*HWND hwnd*/); ~CDropTarget(); private: // internal helper function DWORD DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed); bool QueryDataObject(IDataObject *pDataObject); // Private member variables LONG m_lRefCount; bool m_fAllowDrop; IDataObject *m_pDataObject; };
droptarget.cpp
// // DROPTARGET.CPP // // By J Brown 2004 // // www.catch22.net // #include "../stdafx.h" #include "droptarget.h" // // Constructor for the CDropTarget class // CDropTarget::CDropTarget(/*HWND hwnd*/) { m_lRefCount = 1; m_fAllowDrop = false; } // // Destructor for the CDropTarget class // CDropTarget::~CDropTarget() { } // // Position the edit control's caret under the mouse // void PositionCursor(HWND hwndEdit, POINTL pt) { DWORD curpos; // get the character position of mouse ScreenToClient(hwndEdit, (POINT *)&pt); curpos = SendMessage(hwndEdit, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y)); // set cursor position SendMessage(hwndEdit, EM_SETSEL, LOWORD(curpos), LOWORD(curpos)); } // // IUnknown::QueryInterface // HRESULT __stdcall CDropTarget::QueryInterface (REFIID iid, void ** ppvObject) { if(iid == IID_IDropTarget || iid == IID_IUnknown) { AddRef(); *ppvObject = this; return S_OK; } else { *ppvObject = 0; return E_NOINTERFACE; } } // // IUnknown::AddRef // ULONG __stdcall CDropTarget::AddRef(void) { return InterlockedIncrement(&m_lRefCount); } // // IUnknown::Release // ULONG __stdcall CDropTarget::Release(void) { LONG count = InterlockedDecrement(&m_lRefCount); if(count == 0) { return 0; } else { return count; } } // // QueryDataObject private helper routine // bool CDropTarget::QueryDataObject(IDataObject *pDataObject) { FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; // does the data object support CF_TEXT using a HGLOBAL? return pDataObject->QueryGetData(&fmtetc) == S_OK ? true : false; } // // DropEffect private helper routine // DWORD CDropTarget::DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed) { DWORD dwEffect = 0; // 1. check "pt" -> do we allow a drop at the specified coordinates? // 2. work out that the drop-effect should be based on grfKeyState if(grfKeyState & MK_CONTROL) { dwEffect = dwAllowed & DROPEFFECT_COPY; } else if(grfKeyState & MK_SHIFT) { dwEffect = dwAllowed & DROPEFFECT_MOVE; } // 3. no key-modifiers were specified (or drop effect not allowed), so // base the effect on those allowed by the dropsource if(dwEffect == 0) { if(dwAllowed & DROPEFFECT_COPY) dwEffect = DROPEFFECT_COPY; if(dwAllowed & DROPEFFECT_MOVE) dwEffect = DROPEFFECT_MOVE; } return dwEffect; } // // IDropTarget::DragEnter // // // HRESULT __stdcall CDropTarget::DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) { // does the dataobject contain data we want? m_fAllowDrop = QueryDataObject(pDataObject); if(m_fAllowDrop) { // get the dropeffect based on keyboard state *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect); SetFocus(GetWnd()); PositionCursor(GetWnd(), pt); } else { *pdwEffect = DROPEFFECT_NONE; } return S_OK; } // // IDropTarget::DragOver // // // HRESULT __stdcall CDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) { if(m_fAllowDrop) { *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect); PositionCursor(GetWnd(), pt); } else { *pdwEffect = DROPEFFECT_NONE; } return S_OK; } // // IDropTarget::DragLeave // HRESULT __stdcall CDropTarget::DragLeave(void) { return S_OK; } // // IDropTarget::Drop // // HRESULT __stdcall CDropTarget::Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) { PositionCursor(GetWnd(), pt); if(m_fAllowDrop) { DropData(GetWnd(), pDataObject); *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect); } else { *pdwEffect = DROPEFFECT_NONE; } return S_OK; } void DropData(HWND hwnd, IDataObject *pDataObject) { // construct a FORMATETC object FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stgmed; // See if the dataobject contains any TEXT stored as a HGLOBAL if(pDataObject->QueryGetData(&fmtetc) == S_OK) { // Yippie! the data is there, so go get it! if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK) { // we asked for the data as a HGLOBAL, so access it appropriately PVOID data = GlobalLock(stgmed.hGlobal); SetWindowText(hwnd, (char *)data); GlobalUnlock(stgmed.hGlobal); // release the data using the COM API ReleaseStgMedium(&stgmed); } } }
dataobject.h
// // DATAOBJECT.H // // Implementation of the IDataObject COM interface // // By J Brown 2004 // // www.catch22.net // #include <windows.h> // defined in enumformat.cpp HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc); HRESULT CreateDataObject (FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject); class CDataObject : public IDataObject { public: // // IUnknown members // HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject); ULONG __stdcall AddRef (void); ULONG __stdcall Release (void); // // IDataObject members // HRESULT __stdcall GetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium); HRESULT __stdcall GetDataHere (FORMATETC *pFormatEtc, STGMEDIUM *pMedium); HRESULT __stdcall QueryGetData (FORMATETC *pFormatEtc); HRESULT __stdcall GetCanonicalFormatEtc (FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut); HRESULT __stdcall SetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease); HRESULT __stdcall EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc); HRESULT __stdcall DAdvise (FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection); HRESULT __stdcall DUnadvise (DWORD dwConnection); HRESULT __stdcall EnumDAdvise (IEnumSTATDATA **ppEnumAdvise); // // Constructor / Destructor // CDataObject(FORMATETC *fmt, STGMEDIUM *stgmed, int count); ~CDataObject(); private: int LookupFormatEtc(FORMATETC *pFormatEtc); // // any private members and functions // LONG m_lRefCount; FORMATETC *m_pFormatEtc; STGMEDIUM *m_pStgMedium; LONG m_nNumFormats; };
dataobject.cpp
// // DATAOBJECT.CPP // // Implementation of the IDataObject COM interface // // By J Brown 2004 // // www.catch22.net // #include "../stdafx.h" #include "dataobject.h" // // Constructor // CDataObject::CDataObject(FORMATETC *fmtetc, 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]; } } // // Destructor // CDataObject::~CDataObject() { // cleanup if(m_pFormatEtc) delete[] m_pFormatEtc; if(m_pStgMedium) delete[] m_pStgMedium; OutputDebugString("oof\n"); } // // 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; } else { 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; } else { *ppvObject = 0; return E_NOINTERFACE; } } HGLOBAL DupMem(HGLOBAL hMem) { // lock the source memory object DWORD len = GlobalSize(hMem); PVOID source = GlobalLock(hMem); // create a fixed "global" block - i.e. just // a regular lump of our process heap PVOID dest = GlobalAlloc(GMEM_FIXED, len); memcpy(dest, source, len); GlobalUnlock(hMem); return dest; } 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 = 0; switch(m_pFormatEtc[idx].tymed) { case TYMED_HGLOBAL: pMedium->hGlobal = DupMem(m_pStgMedium[idx].hGlobal); //return S_OK; break; default: return DV_E_FORMATETC; } return S_OK; } // // IDataObject::GetDataHere // HRESULT __stdcall CDataObject::GetDataHere (FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { // 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 *pFormatEct, FORMATETC *pFormatEtcOut) { // Apparently we have to set this field to NULL even though we don't do anything else pFormatEtcOut->ptd = NULL; return E_NOTIMPL; } // // IDataObject::SetData // HRESULT __stdcall CDataObject::SetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease) { 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 *pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) { return OLE_E_ADVISENOTSUPPORTED; } // // IDataObject::DUnadvise // HRESULT __stdcall CDataObject::DUnadvise (DWORD dwConnection) { return OLE_E_ADVISENOTSUPPORTED; } // // IDataObject::EnumDAdvise // HRESULT __stdcall CDataObject::EnumDAdvise (IEnumSTATDATA **ppEnumAdvise) { return OLE_E_ADVISENOTSUPPORTED; } // // Helper function // HRESULT CreateDataObject (FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject) { if(ppDataObject == 0) return E_INVALIDARG; *ppDataObject = new CDataObject(fmtetc, stgmeds, count); return (*ppDataObject) ? S_OK : E_OUTOFMEMORY; }
enumformat.h
// // ENUMFORMAT.H // // By J Brown 2004 // // www.catch22.net // // Implementation of the IEnumFORMATETC interface // // For Win2K and above look at the SHCreateStdEnumFmtEtc API call!! // // Apparently the order of formats in an IEnumFORMATETC object must be // the same as those that were stored in the clipboard // // #include <windows.h> class CEnumFormatEtc : public IEnumFORMATETC { public: // // IUnknown members // HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject); ULONG __stdcall AddRef (void); ULONG __stdcall Release (void); // // IEnumFormatEtc members // HRESULT __stdcall Next (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched); HRESULT __stdcall Skip (ULONG celt); HRESULT __stdcall Reset (void); HRESULT __stdcall Clone (IEnumFORMATETC ** ppEnumFormatEtc); // // Construction / Destruction // CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats); ~CEnumFormatEtc(); private: LONG m_lRefCount; // Reference count for this COM interface ULONG m_nIndex; // current enumerator index ULONG m_nNumFormats; // number of FORMATETC members FORMATETC * m_pFormatEtc; // array of FORMATETC objects };
enumformat.cpp
// // ENUMFORMAT.CPP // // By J Brown 2004 // // www.catch22.net // // Implementation of the IEnumFORMATETC interface // // For Win2K and above look at the SHCreateStdEnumFmtEtc API call!! // // Apparently the order of formats in an IEnumFORMATETC object must be // the same as those that were stored in the clipboard // // #include "../stdafx.h" #include "enumformat.h" // // "Drop-in" replacement for SHCreateStdEnumFmtEtc. Called by CDataObject::EnumFormatEtc // HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc) { if(nNumFormats == 0 || pFormatEtc == 0 || ppEnumFormatEtc == 0) return E_INVALIDARG; *ppEnumFormatEtc = new CEnumFormatEtc(pFormatEtc, nNumFormats); return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY; } // // Helper function to perform a "deep" copy of a FORMATETC // static void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source) { // copy the source FORMATETC into dest *dest = *source; if(source->ptd) { // allocate memory for the DVTARGETDEVICE if necessary dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); // copy the contents of the source DVTARGETDEVICE into dest->ptd *(dest->ptd) = *(source->ptd); } } // // Constructor // CEnumFormatEtc::CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats) { m_lRefCount = 1; m_nIndex = 0; m_nNumFormats = nNumFormats; m_pFormatEtc = new FORMATETC[nNumFormats]; // copy the FORMATETC structures for(int i = 0; i < nNumFormats; i++) { DeepCopyFormatEtc(&m_pFormatEtc[i], &pFormatEtc[i]); } } // // Destructor // CEnumFormatEtc::~CEnumFormatEtc() { if(m_pFormatEtc) { for(ULONG i = 0; i < m_nNumFormats; i++) { if(m_pFormatEtc[i].ptd) CoTaskMemFree(m_pFormatEtc[i].ptd); } delete[] m_pFormatEtc; } } // // IUnknown::AddRef // ULONG __stdcall CEnumFormatEtc::AddRef(void) { // increment object reference count return InterlockedIncrement(&m_lRefCount); } // // IUnknown::Release // ULONG __stdcall CEnumFormatEtc::Release(void) { // decrement object reference count LONG count = InterlockedDecrement(&m_lRefCount); if(count == 0) { delete this; return 0; } else { return count; } } // // IUnknown::QueryInterface // HRESULT __stdcall CEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject) { // check to see what interface has been requested if(iid == IID_IEnumFORMATETC || iid == IID_IUnknown) { AddRef(); *ppvObject = this; return S_OK; } else { *ppvObject = 0; return E_NOINTERFACE; } } // // IEnumFORMATETC::Next // // If the returned FORMATETC structure contains a non-null "ptd" member, then // the caller must free this using CoTaskMemFree (stated in the COM documentation) // HRESULT __stdcall CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG * pceltFetched) { ULONG copied = 0; // validate arguments if(celt == 0 || pFormatEtc == 0) return E_INVALIDARG; // copy FORMATETC structures into caller's buffer while(m_nIndex < m_nNumFormats && copied < celt) { DeepCopyFormatEtc(&pFormatEtc[copied], &m_pFormatEtc[m_nIndex]); copied++; m_nIndex++; } // store result if(pceltFetched != 0) *pceltFetched = copied; // did we copy all that was requested? return (copied == celt) ? S_OK : S_FALSE; } // // IEnumFORMATETC::Skip // HRESULT __stdcall CEnumFormatEtc::Skip(ULONG celt) { m_nIndex += celt; return (m_nIndex <= m_nNumFormats) ? S_OK : S_FALSE; } // // IEnumFORMATETC::Reset // HRESULT __stdcall CEnumFormatEtc::Reset(void) { m_nIndex = 0; return S_OK; } // // IEnumFORMATETC::Clone // HRESULT __stdcall CEnumFormatEtc::Clone(IEnumFORMATETC ** ppEnumFormatEtc) { HRESULT hResult; // make a duplicate enumerator hResult = CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc); if(hResult == S_OK) { // manually set the index state ((CEnumFormatEtc *) *ppEnumFormatEtc)->m_nIndex = m_nIndex; } return hResult; }
//
// DATAOBJECT.H
//
// Implementation of the IDataObject COM interface
//
// By J Brown 2004
//
// www.catch22.net
//
#include <windows.h>
// defined in enumformat.cpp
HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
HRESULT CreateDataObject (FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject);
class CDataObject : public IDataObject
{
public:
//
// IUnknown members
//
HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
ULONG __stdcall AddRef (void);
ULONG __stdcall Release (void);
//
// IDataObject members
//
HRESULT __stdcall GetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium);
HRESULT __stdcall GetDataHere (FORMATETC *pFormatEtc, STGMEDIUM *pMedium);
HRESULT __stdcall QueryGetData (FORMATETC *pFormatEtc);
HRESULT __stdcall GetCanonicalFormatEtc (FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut);
HRESULT __stdcall SetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease);
HRESULT __stdcall EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
HRESULT __stdcall DAdvise (FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
HRESULT __stdcall DUnadvise (DWORD dwConnection);
HRESULT __stdcall EnumDAdvise (IEnumSTATDATA **ppEnumAdvise);
//
// Constructor / Destructor
//
CDataObject(FORMATETC *fmt, STGMEDIUM *stgmed, int count);
~CDataObject();
private:
int LookupFormatEtc(FORMATETC *pFormatEtc);
//
// any private members and functions
//
LONG m_lRefCount;
FORMATETC *m_pFormatEtc;
STGMEDIUM *m_pStgMedium;
LONG m_nNumFormats;
};