1 /**************************************************************************
2 THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
3 ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
4 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
6 Author: Leon Finker 11/2000
7 Modifications: replaced ATL by STL, Martin Fuchs 7/2003
8 **************************************************************************/
10 // dragdropimp.cpp: implementation of the IDataObjectImpl class.
11 //////////////////////////////////////////////////////////////////////
15 #include "dragdropimpl.h"
17 //////////////////////////////////////////////////////////////////////
18 // IDataObjectImpl Class
19 //////////////////////////////////////////////////////////////////////
21 IDataObjectImpl::IDataObjectImpl(IDropSourceImpl* pDropSource):
23 m_pDropSource(pDropSource)
27 IDataObjectImpl::~IDataObjectImpl()
29 for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it)
30 ReleaseStgMedium(it->_medium);
33 STDMETHODIMP IDataObjectImpl::QueryInterface(/* [in] */ REFIID riid,
34 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
37 if (IID_IUnknown==riid || IID_IDataObject==riid)
39 /*if (riid == IID_IAsyncOperation)
40 *ppvObject=(IAsyncOperation*)this;*/
43 ((LPUNKNOWN)*ppvObject)->AddRef();
49 STDMETHODIMP_(ULONG) IDataObjectImpl::AddRef()
54 STDMETHODIMP_(ULONG) IDataObjectImpl::Release()
56 long nTemp = --m_cRefCount;
64 STDMETHODIMP IDataObjectImpl::GetData(
65 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,
66 /* [out] */ STGMEDIUM __RPC_FAR *pmedium)
68 if (pformatetcIn == NULL || pmedium == NULL)
71 pmedium->hGlobal = NULL;
73 for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it)
75 if (pformatetcIn->tymed & it->_format->tymed &&
76 pformatetcIn->dwAspect == it->_format->dwAspect &&
77 pformatetcIn->cfFormat == it->_format->cfFormat)
79 CopyMedium(pmedium, it->_medium, it->_format);
84 return DV_E_FORMATETC;
87 STDMETHODIMP IDataObjectImpl::GetDataHere(
88 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,
89 /* [out][in] */ STGMEDIUM __RPC_FAR *pmedium)
94 STDMETHODIMP IDataObjectImpl::QueryGetData(
95 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc)
97 if (pformatetc == NULL)
100 //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT
101 if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
102 return (DV_E_DVASPECT);
104 HRESULT hr = DV_E_TYMED;
106 for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it)
108 if (pformatetc->tymed & it->_format->tymed)
110 if (pformatetc->cfFormat == it->_format->cfFormat)
113 hr = DV_E_CLIPFORMAT;
121 STDMETHODIMP IDataObjectImpl::GetCanonicalFormatEtc(
122 /* [unique][in] */ FORMATETC __RPC_FAR *pformatectIn,
123 /* [out] */ FORMATETC __RPC_FAR *pformatetcOut)
125 if (pformatetcOut == NULL)
128 return DATA_S_SAMEFORMATETC;
131 STDMETHODIMP IDataObjectImpl::SetData(
132 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,
133 /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium,
134 /* [in] */ BOOL fRelease)
136 if (pformatetc == NULL || pmedium == NULL)
139 assert(pformatetc->tymed == pmedium->tymed);
140 FORMATETC* fetc=new FORMATETC;
141 STGMEDIUM* pStgMed = new STGMEDIUM;
143 if (fetc == NULL || pStgMed == NULL)
144 return E_OUTOFMEMORY;
146 ZeroMemory(fetc, sizeof(FORMATETC));
147 ZeroMemory(pStgMed, sizeof(STGMEDIUM));
154 CopyMedium(pStgMed, pmedium, pformatetc);
158 storage._format = fetc;
159 storage._medium = pStgMed;
161 _storage.push_back(storage);
166 void IDataObjectImpl::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
168 switch(pMedSrc->tymed)
171 pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0);
174 pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, 0);
177 pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0);
180 pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0);
183 pMedDest->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0);
186 pMedDest->pstm = pMedSrc->pstm;
187 pMedSrc->pstm->AddRef();
190 pMedDest->pstg = pMedSrc->pstg;
191 pMedSrc->pstg->AddRef();
197 pMedDest->tymed = pMedSrc->tymed;
198 pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
201 STDMETHODIMP IDataObjectImpl::EnumFormatEtc(
202 /* [in] */ DWORD dwDirection,
203 /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc)
205 if (ppenumFormatEtc == NULL)
208 *ppenumFormatEtc=NULL;
212 *ppenumFormatEtc = new EnumFormatEtcImpl(_storage);
214 if (!*ppenumFormatEtc)
215 return E_OUTOFMEMORY;
217 (*ppenumFormatEtc)->AddRef();
229 STDMETHODIMP IDataObjectImpl::DAdvise(
230 /* [in] */ FORMATETC __RPC_FAR *pformatetc,
231 /* [in] */ DWORD advf,
232 /* [unique][in] */ IAdviseSink __RPC_FAR *pAdvSink,
233 /* [out] */ DWORD __RPC_FAR *pdwConnection)
235 return OLE_E_ADVISENOTSUPPORTED;
238 STDMETHODIMP IDataObjectImpl::DUnadvise(
239 /* [in] */ DWORD dwConnection)
244 HRESULT STDMETHODCALLTYPE IDataObjectImpl::EnumDAdvise(
245 /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR *ppenumAdvise)
247 return OLE_E_ADVISENOTSUPPORTED;
250 //////////////////////////////////////////////////////////////////////
251 // IDropSourceImpl Class
252 //////////////////////////////////////////////////////////////////////
254 STDMETHODIMP IDropSourceImpl::QueryInterface(/* [in] */ REFIID riid,
255 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
258 if (IID_IUnknown==riid || IID_IDropSource==riid)
261 if (*ppvObject != NULL)
263 ((LPUNKNOWN)*ppvObject)->AddRef();
266 return E_NOINTERFACE;
269 STDMETHODIMP_(ULONG) IDropSourceImpl::AddRef()
271 return ++m_cRefCount;
274 STDMETHODIMP_(ULONG) IDropSourceImpl::Release()
276 long nTemp = --m_cRefCount;
286 STDMETHODIMP IDropSourceImpl::QueryContinueDrag(
287 /* [in] */ BOOL fEscapePressed,
288 /* [in] */ DWORD grfKeyState)
291 return DRAGDROP_S_CANCEL;
292 if (!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))
295 return DRAGDROP_S_DROP;
302 STDMETHODIMP IDropSourceImpl::GiveFeedback(
303 /* [in] */ DWORD dwEffect)
305 return DRAGDROP_S_USEDEFAULTCURSORS;
308 //////////////////////////////////////////////////////////////////////
309 // EnumFormatEtcImpl Class
310 //////////////////////////////////////////////////////////////////////
312 EnumFormatEtcImpl::EnumFormatEtcImpl(const FormatArray& ArrFE)
316 for(FormatArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it)
317 m_pFmtEtc.push_back(*it);
320 EnumFormatEtcImpl::EnumFormatEtcImpl(const StorageArray& ArrFE)
324 for(StorageArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it)
325 m_pFmtEtc.push_back(*it->_format);
328 STDMETHODIMP EnumFormatEtcImpl::QueryInterface(REFIID refiid, void** ppv)
331 if (IID_IUnknown==refiid || IID_IEnumFORMATETC==refiid)
336 ((LPUNKNOWN)*ppv)->AddRef();
339 return E_NOINTERFACE;
342 STDMETHODIMP_(ULONG) EnumFormatEtcImpl::AddRef(void)
344 return ++m_cRefCount;
347 STDMETHODIMP_(ULONG) EnumFormatEtcImpl::Release(void)
349 long nTemp = --m_cRefCount;
359 STDMETHODIMP EnumFormatEtcImpl::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG* pceltFetched)
361 if (pceltFetched != NULL)
364 ULONG cReturn = celt;
366 if (celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.size())
369 if (pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request
372 while (m_iCur < m_pFmtEtc.size() && cReturn > 0)
374 *lpFormatEtc++ = m_pFmtEtc[m_iCur++];
377 if (pceltFetched != NULL)
378 *pceltFetched = celt - cReturn;
380 return (cReturn == 0) ? S_OK : S_FALSE;
383 STDMETHODIMP EnumFormatEtcImpl::Skip(ULONG celt)
385 if ((m_iCur + int(celt)) >= m_pFmtEtc.size())
392 STDMETHODIMP EnumFormatEtcImpl::Reset(void)
398 STDMETHODIMP EnumFormatEtcImpl::Clone(IEnumFORMATETC** ppCloneEnumFormatEtc)
400 if (ppCloneEnumFormatEtc == NULL)
403 EnumFormatEtcImpl* newEnum = new EnumFormatEtcImpl(m_pFmtEtc);
406 return E_OUTOFMEMORY;
409 newEnum->m_iCur = m_iCur;
410 *ppCloneEnumFormatEtc = newEnum;
415 //////////////////////////////////////////////////////////////////////
416 // IDropTargetImpl Class
417 //////////////////////////////////////////////////////////////////////
418 IDropTargetImpl::IDropTargetImpl(HWND hTargetWnd):
419 m_hTargetWnd(hTargetWnd),
420 m_cRefCount(0), m_bAllowDrop(false),
421 m_pDropTargetHelper(NULL), m_pSupportedFrmt(NULL)
423 assert(m_hTargetWnd != NULL);
425 if (FAILED(CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER,
426 IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper)))
427 m_pDropTargetHelper = NULL;
430 IDropTargetImpl::~IDropTargetImpl()
432 if (m_pDropTargetHelper != NULL)
434 m_pDropTargetHelper->Release();
435 m_pDropTargetHelper = NULL;
439 HRESULT STDMETHODCALLTYPE IDropTargetImpl::QueryInterface( /* [in] */ REFIID riid,
440 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
443 if (IID_IUnknown==riid || IID_IDropTarget==riid)
446 if (*ppvObject != NULL)
448 ((LPUNKNOWN)*ppvObject)->AddRef();
451 return E_NOINTERFACE;
454 ULONG STDMETHODCALLTYPE IDropTargetImpl::Release()
456 long nTemp = --m_cRefCount;
466 bool IDropTargetImpl::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
468 DWORD dwOKEffects = *pdwEffect;
472 *pdwEffect = DROPEFFECT_NONE;
475 //CTRL+SHIFT -- DROPEFFECT_LINK
476 //CTRL -- DROPEFFECT_COPY
477 //SHIFT -- DROPEFFECT_MOVE
478 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
479 *pdwEffect = (grfKeyState & MK_CONTROL) ?
480 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ):
481 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : DROPEFFECT_NONE );
484 // No modifier keys used by user while dragging.
485 if (DROPEFFECT_COPY & dwOKEffects)
486 *pdwEffect = DROPEFFECT_COPY;
487 else if (DROPEFFECT_MOVE & dwOKEffects)
488 *pdwEffect = DROPEFFECT_MOVE;
489 else if (DROPEFFECT_LINK & dwOKEffects)
490 *pdwEffect = DROPEFFECT_LINK;
493 *pdwEffect = DROPEFFECT_NONE;
498 // Check if the drag source application allows the drop effect desired by user.
499 // The drag source specifies this in DoDragDrop
500 if (!(*pdwEffect & dwOKEffects))
501 *pdwEffect = DROPEFFECT_NONE;
504 return (DROPEFFECT_NONE == *pdwEffect)?false:true;
507 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragEnter(
508 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
509 /* [in] */ DWORD grfKeyState,
510 /* [in] */ POINTL pt,
511 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
513 if (pDataObj == NULL)
516 if (m_pDropTargetHelper)
517 m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);
518 //IEnumFORMATETC* pEnum;
519 //pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum);
522 //pEnum->Next(1,&ftm,0);
524 m_pSupportedFrmt = NULL;
526 for(FormatArray::iterator it=m_formatetc.begin(); it!=m_formatetc.end(); ++it)
528 m_bAllowDrop = (pDataObj->QueryGetData(&*it) == S_OK)? true: false;
532 m_pSupportedFrmt = &*it;
537 QueryDrop(grfKeyState, pdwEffect);
541 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragOver(
542 /* [in] */ DWORD grfKeyState,
543 /* [in] */ POINTL pt,
544 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
546 if (m_pDropTargetHelper)
547 m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
548 QueryDrop(grfKeyState, pdwEffect);
552 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragLeave()
554 if (m_pDropTargetHelper)
555 m_pDropTargetHelper->DragLeave();
557 m_bAllowDrop = false;
558 m_pSupportedFrmt = NULL;
562 HRESULT STDMETHODCALLTYPE IDropTargetImpl::Drop(
563 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
564 /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt,
565 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
567 if (pDataObj == NULL)
570 if (m_pDropTargetHelper)
571 m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);
573 if (QueryDrop(grfKeyState, pdwEffect))
575 if (m_bAllowDrop && m_pSupportedFrmt != NULL)
579 if (pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK)
581 if (OnDrop(m_pSupportedFrmt, medium, pdwEffect)) //does derive class wants us to free medium?
582 ReleaseStgMedium(&medium);
587 m_bAllowDrop = false;
588 *pdwEffect = DROPEFFECT_NONE;
589 m_pSupportedFrmt = NULL;