1 /**************************************************************************
\r
2 THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
\r
3 ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
\r
4 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
\r
6 Author: Leon Finker 1/2001
\r
7 **************************************************************************/
\r
8 // IDataObjectImpl.cpp: implementation of the CIDataObjectImpl class.
\r
9 //////////////////////////////////////////////////////////////////////
\r
12 #include <atlbase.h>
\r
13 #include "DragDropImpl.h"
\r
15 //////////////////////////////////////////////////////////////////////
\r
16 // CIDataObject Class
\r
17 //////////////////////////////////////////////////////////////////////
\r
19 CIDataObject::CIDataObject(CIDropSource* pDropSource):
\r
20 m_cRefCount(0), m_pDropSource(pDropSource)
\r
24 CIDataObject::~CIDataObject()
\r
26 for(int i = 0; i < m_StgMedium.GetSize(); ++i)
\r
28 ReleaseStgMedium(m_StgMedium[i]);
\r
29 delete m_StgMedium[i];
\r
31 for(int j = 0; j < m_ArrFormatEtc.GetSize(); ++j)
\r
32 delete m_ArrFormatEtc[j];
\r
35 STDMETHODIMP CIDataObject::QueryInterface(/* [in] */ REFIID riid,
\r
36 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
\r
39 if (IID_IUnknown==riid || IID_IDataObject==riid)
\r
41 /*if(riid == IID_IAsyncOperation)
\r
42 *ppvObject=(IAsyncOperation*)this;*/
\r
43 if (NULL!=*ppvObject)
\r
45 ((LPUNKNOWN)*ppvObject)->AddRef();
\r
48 return E_NOINTERFACE;
\r
51 STDMETHODIMP_(ULONG) CIDataObject::AddRef( void)
\r
53 return ++m_cRefCount;
\r
56 STDMETHODIMP_(ULONG) CIDataObject::Release( void)
\r
59 nTemp = --m_cRefCount;
\r
65 STDMETHODIMP CIDataObject::GetData(
\r
66 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,
\r
67 /* [out] */ STGMEDIUM __RPC_FAR *pmedium)
\r
69 if(pformatetcIn == NULL || pmedium == NULL)
\r
70 return E_INVALIDARG;
\r
71 pmedium->hGlobal = NULL;
\r
73 ATLASSERT(m_StgMedium.GetSize() == m_ArrFormatEtc.GetSize());
\r
74 for(int i=0; i < m_ArrFormatEtc.GetSize(); ++i)
\r
76 if(pformatetcIn->tymed & m_ArrFormatEtc[i]->tymed &&
\r
77 pformatetcIn->dwAspect == m_ArrFormatEtc[i]->dwAspect &&
\r
78 pformatetcIn->cfFormat == m_ArrFormatEtc[i]->cfFormat)
\r
80 CopyMedium(pmedium, m_StgMedium[i], m_ArrFormatEtc[i]);
\r
84 return DV_E_FORMATETC;
\r
87 STDMETHODIMP CIDataObject::GetDataHere(
\r
88 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatetc*/,
\r
89 /* [out][in] */ STGMEDIUM __RPC_FAR * /*pmedium*/)
\r
94 STDMETHODIMP CIDataObject::QueryGetData(
\r
95 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc)
\r
97 if(pformatetc == NULL)
\r
98 return E_INVALIDARG;
\r
100 //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT
\r
101 if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
\r
102 return (DV_E_DVASPECT);
\r
103 HRESULT hr = DV_E_TYMED;
\r
104 for(int i = 0; i < m_ArrFormatEtc.GetSize(); ++i)
\r
106 if(pformatetc->tymed & m_ArrFormatEtc[i]->tymed)
\r
108 if(pformatetc->cfFormat == m_ArrFormatEtc[i]->cfFormat)
\r
111 hr = DV_E_CLIPFORMAT;
\r
119 STDMETHODIMP CIDataObject::GetCanonicalFormatEtc(
\r
120 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatectIn*/,
\r
121 /* [out] */ FORMATETC __RPC_FAR *pformatetcOut)
\r
123 if (pformatetcOut == NULL)
\r
124 return E_INVALIDARG;
\r
125 return DATA_S_SAMEFORMATETC;
\r
128 STDMETHODIMP CIDataObject::SetData(
\r
129 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,
\r
130 /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium,
\r
131 /* [in] */ BOOL fRelease)
\r
133 if(pformatetc == NULL || pmedium == NULL)
\r
134 return E_INVALIDARG;
\r
136 ATLASSERT(pformatetc->tymed == pmedium->tymed);
\r
137 FORMATETC* fetc=new FORMATETC;
\r
138 STGMEDIUM* pStgMed = new STGMEDIUM;
\r
140 if(fetc == NULL || pStgMed == NULL)
\r
141 return E_OUTOFMEMORY;
\r
143 SecureZeroMemory(fetc,sizeof(FORMATETC));
\r
144 SecureZeroMemory(pStgMed,sizeof(STGMEDIUM));
\r
146 *fetc = *pformatetc;
\r
147 m_ArrFormatEtc.Add(fetc);
\r
150 *pStgMed = *pmedium;
\r
153 CopyMedium(pStgMed, pmedium, pformatetc);
\r
155 m_StgMedium.Add(pStgMed);
\r
159 void CIDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
\r
161 switch(pMedSrc->tymed)
\r
163 case TYMED_HGLOBAL:
\r
164 pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, NULL);
\r
167 pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, NULL);
\r
170 pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, NULL);
\r
173 pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, NULL);
\r
176 pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, NULL);
\r
178 case TYMED_ISTREAM:
\r
179 pMedDest->pstm = pMedSrc->pstm;
\r
180 pMedSrc->pstm->AddRef();
\r
182 case TYMED_ISTORAGE:
\r
183 pMedDest->pstg = pMedSrc->pstg;
\r
184 pMedSrc->pstg->AddRef();
\r
190 pMedDest->tymed = pMedSrc->tymed;
\r
191 pMedDest->pUnkForRelease = NULL;
\r
192 if(pMedSrc->pUnkForRelease != NULL)
\r
194 pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
\r
195 pMedSrc->pUnkForRelease->AddRef();
\r
198 STDMETHODIMP CIDataObject::EnumFormatEtc(
\r
199 /* [in] */ DWORD dwDirection,
\r
200 /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc)
\r
202 if(ppenumFormatEtc == NULL)
\r
205 *ppenumFormatEtc=NULL;
\r
206 switch (dwDirection)
\r
209 *ppenumFormatEtc= new CEnumFormatEtc(m_ArrFormatEtc);
\r
210 if(*ppenumFormatEtc == NULL)
\r
211 return E_OUTOFMEMORY;
\r
212 (*ppenumFormatEtc)->AddRef();
\r
224 STDMETHODIMP CIDataObject::DAdvise(
\r
225 /* [in] */ FORMATETC __RPC_FAR * /*pformatetc*/,
\r
226 /* [in] */ DWORD /*advf*/,
\r
227 /* [unique][in] */ IAdviseSink __RPC_FAR * /*pAdvSink*/,
\r
228 /* [out] */ DWORD __RPC_FAR * /*pdwConnection*/)
\r
230 return OLE_E_ADVISENOTSUPPORTED;
\r
233 STDMETHODIMP CIDataObject::DUnadvise(
\r
234 /* [in] */ DWORD /*dwConnection*/)
\r
239 HRESULT STDMETHODCALLTYPE CIDataObject::EnumDAdvise(
\r
240 /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR * /*ppenumAdvise*/)
\r
242 return OLE_E_ADVISENOTSUPPORTED;
\r
245 //////////////////////////////////////////////////////////////////////
\r
246 // CIDropSource Class
\r
247 //////////////////////////////////////////////////////////////////////
\r
249 STDMETHODIMP CIDropSource::QueryInterface(/* [in] */ REFIID riid,
\r
250 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
\r
253 if (IID_IUnknown==riid || IID_IDropSource==riid)
\r
256 if (*ppvObject != NULL)
\r
258 ((LPUNKNOWN)*ppvObject)->AddRef();
\r
261 return E_NOINTERFACE;
\r
264 STDMETHODIMP_(ULONG) CIDropSource::AddRef( void)
\r
266 return ++m_cRefCount;
\r
269 STDMETHODIMP_(ULONG) CIDropSource::Release( void)
\r
272 nTemp = --m_cRefCount;
\r
273 ATLASSERT(nTemp >= 0);
\r
279 STDMETHODIMP CIDropSource::QueryContinueDrag(
\r
280 /* [in] */ BOOL fEscapePressed,
\r
281 /* [in] */ DWORD grfKeyState)
\r
284 return DRAGDROP_S_CANCEL;
\r
285 if(!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))
\r
288 return DRAGDROP_S_DROP;
\r
295 STDMETHODIMP CIDropSource::GiveFeedback(
\r
296 /* [in] */ DWORD /*dwEffect*/)
\r
298 return DRAGDROP_S_USEDEFAULTCURSORS;
\r
301 //////////////////////////////////////////////////////////////////////
\r
302 // CEnumFormatEtc Class
\r
303 //////////////////////////////////////////////////////////////////////
\r
305 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC>& ArrFE):
\r
306 m_cRefCount(0),m_iCur(0)
\r
308 ATLTRACE("CEnumFormatEtc::CEnumFormatEtc()\n");
\r
309 for(int i = 0; i < ArrFE.GetSize(); ++i)
\r
310 m_pFmtEtc.Add(ArrFE[i]);
\r
313 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC*>& ArrFE):
\r
314 m_cRefCount(0),m_iCur(0)
\r
316 for(int i = 0; i < ArrFE.GetSize(); ++i)
\r
317 m_pFmtEtc.Add(*ArrFE[i]);
\r
320 STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID refiid, void FAR* FAR* ppv)
\r
323 if (IID_IUnknown==refiid || IID_IEnumFORMATETC==refiid)
\r
328 ((LPUNKNOWN)*ppv)->AddRef();
\r
331 return E_NOINTERFACE;
\r
334 STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void)
\r
336 return ++m_cRefCount;
\r
339 STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void)
\r
341 long nTemp = --m_cRefCount;
\r
342 ATLASSERT(nTemp >= 0);
\r
349 STDMETHODIMP CEnumFormatEtc::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG FAR *pceltFetched)
\r
351 if(pceltFetched != NULL)
\r
354 ULONG cReturn = celt;
\r
356 if(celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.GetSize())
\r
359 if(pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request
\r
362 while (m_iCur < m_pFmtEtc.GetSize() && cReturn > 0)
\r
364 *lpFormatEtc++ = m_pFmtEtc[m_iCur++];
\r
367 if (pceltFetched != NULL)
\r
368 *pceltFetched = celt - cReturn;
\r
370 return (cReturn == 0) ? S_OK : S_FALSE;
\r
373 STDMETHODIMP CEnumFormatEtc::Skip(ULONG celt)
\r
375 if((m_iCur + int(celt)) >= m_pFmtEtc.GetSize())
\r
381 STDMETHODIMP CEnumFormatEtc::Reset(void)
\r
387 STDMETHODIMP CEnumFormatEtc::Clone(IEnumFORMATETC FAR * FAR*ppCloneEnumFormatEtc)
\r
389 if(ppCloneEnumFormatEtc == NULL)
\r
392 CEnumFormatEtc *newEnum = new CEnumFormatEtc(m_pFmtEtc);
\r
394 return E_OUTOFMEMORY;
\r
396 newEnum->m_iCur = m_iCur;
\r
397 *ppCloneEnumFormatEtc = newEnum;
\r
401 //////////////////////////////////////////////////////////////////////
\r
402 // CIDropTarget Class
\r
403 //////////////////////////////////////////////////////////////////////
\r
404 CIDropTarget::CIDropTarget(HWND hTargetWnd):
\r
405 m_hTargetWnd(hTargetWnd),
\r
406 m_cRefCount(0), m_bAllowDrop(false),
\r
407 m_pDropTargetHelper(NULL), m_pSupportedFrmt(NULL)
\r
409 if(FAILED(CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER,
\r
410 IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper)))
\r
411 m_pDropTargetHelper = NULL;
\r
414 CIDropTarget::~CIDropTarget()
\r
416 if(m_pDropTargetHelper != NULL)
\r
418 m_pDropTargetHelper->Release();
\r
419 m_pDropTargetHelper = NULL;
\r
423 HRESULT STDMETHODCALLTYPE CIDropTarget::QueryInterface( /* [in] */ REFIID riid,
\r
424 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
\r
427 if (IID_IUnknown==riid || IID_IDropTarget==riid)
\r
430 if (*ppvObject != NULL)
\r
432 ((LPUNKNOWN)*ppvObject)->AddRef();
\r
435 return E_NOINTERFACE;
\r
438 ULONG STDMETHODCALLTYPE CIDropTarget::Release( void)
\r
441 nTemp = --m_cRefCount;
\r
442 ATLASSERT(nTemp >= 0);
\r
448 bool CIDropTarget::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
\r
450 DWORD dwOKEffects = *pdwEffect;
\r
454 *pdwEffect = DROPEFFECT_NONE;
\r
457 //CTRL+SHIFT -- DROPEFFECT_LINK
\r
458 //CTRL -- DROPEFFECT_COPY
\r
459 //SHIFT -- DROPEFFECT_MOVE
\r
460 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
\r
461 *pdwEffect = (grfKeyState & MK_CONTROL) ?
\r
462 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ):
\r
463 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 );
\r
464 if(*pdwEffect == 0)
\r
466 // No modifier keys used by user while dragging.
\r
467 if (DROPEFFECT_MOVE & dwOKEffects)
\r
468 *pdwEffect = DROPEFFECT_MOVE;
\r
469 else if (DROPEFFECT_COPY & dwOKEffects)
\r
470 *pdwEffect = DROPEFFECT_COPY;
\r
471 else if (DROPEFFECT_LINK & dwOKEffects)
\r
472 *pdwEffect = DROPEFFECT_LINK;
\r
475 *pdwEffect = DROPEFFECT_NONE;
\r
480 // Check if the drag source application allows the drop effect desired by user.
\r
481 // The drag source specifies this in DoDragDrop
\r
482 if(!(*pdwEffect & dwOKEffects))
\r
483 *pdwEffect = DROPEFFECT_NONE;
\r
486 return (DROPEFFECT_NONE == *pdwEffect)?false:true;
\r
489 HRESULT STDMETHODCALLTYPE CIDropTarget::DragEnter(
\r
490 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
\r
491 /* [in] */ DWORD grfKeyState,
\r
492 /* [in] */ POINTL pt,
\r
493 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
\r
495 if(pDataObj == NULL)
\r
496 return E_INVALIDARG;
\r
498 if(m_pDropTargetHelper)
\r
499 m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);
\r
500 //IEnumFORMATETC* pEnum;
\r
501 //pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum);
\r
504 //pEnum->Next(1,&ftm,0);
\r
505 //pEnum->Release();
\r
506 m_pSupportedFrmt = NULL;
\r
507 for(int i =0; i<m_formatetc.GetSize(); ++i)
\r
509 m_bAllowDrop = (pDataObj->QueryGetData(&m_formatetc[i]) == S_OK)?true:false;
\r
512 m_pSupportedFrmt = &m_formatetc[i];
\r
517 QueryDrop(grfKeyState, pdwEffect);
\r
521 HRESULT STDMETHODCALLTYPE CIDropTarget::DragOver(
\r
522 /* [in] */ DWORD grfKeyState,
\r
523 /* [in] */ POINTL pt,
\r
524 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
\r
526 if(m_pDropTargetHelper)
\r
527 m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
\r
528 QueryDrop(grfKeyState, pdwEffect);
\r
532 HRESULT STDMETHODCALLTYPE CIDropTarget::DragLeave( void)
\r
534 if(m_pDropTargetHelper)
\r
535 m_pDropTargetHelper->DragLeave();
\r
537 m_bAllowDrop = false;
\r
538 m_pSupportedFrmt = NULL;
\r
542 HRESULT STDMETHODCALLTYPE CIDropTarget::Drop(
\r
543 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
\r
544 /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt,
\r
545 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
\r
547 if (pDataObj == NULL)
\r
548 return E_INVALIDARG;
\r
550 if(m_pDropTargetHelper)
\r
551 m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);
\r
553 if(QueryDrop(grfKeyState, pdwEffect))
\r
555 if(m_bAllowDrop && m_pSupportedFrmt != NULL)
\r
558 if(pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK)
\r
560 if(OnDrop(m_pSupportedFrmt, medium, pdwEffect, pt)) //does derive class wants us to free medium?
\r
561 ReleaseStgMedium(&medium);
\r
565 m_bAllowDrop=false;
\r
566 *pdwEffect = DROPEFFECT_NONE;
\r
567 m_pSupportedFrmt = NULL;
\r
571 //////////////////////////////////////////////////////////////////////
\r
572 // CIDragSourceHelper Class
\r
573 //////////////////////////////////////////////////////////////////////
\r