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
11 #include <atlbase.h>
\r
12 #include "DragDropImpl.h"
\r
14 //////////////////////////////////////////////////////////////////////
\r
15 // CIDataObject Class
\r
16 //////////////////////////////////////////////////////////////////////
\r
18 CIDataObject::CIDataObject(CIDropSource* pDropSource):
\r
19 m_cRefCount(0), m_pDropSource(pDropSource)
\r
23 CIDataObject::~CIDataObject()
\r
25 for(int i = 0; i < m_StgMedium.GetSize(); ++i)
\r
27 ReleaseStgMedium(m_StgMedium[i]);
\r
28 delete m_StgMedium[i];
\r
30 for(int j = 0; j < m_ArrFormatEtc.GetSize(); ++j)
\r
31 delete m_ArrFormatEtc[j];
\r
34 STDMETHODIMP CIDataObject::QueryInterface(/* [in] */ REFIID riid,
\r
35 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
\r
38 if (IID_IUnknown==riid || IID_IDataObject==riid)
\r
40 /*if(riid == IID_IAsyncOperation)
\r
41 *ppvObject=(IAsyncOperation*)this;*/
\r
42 if (NULL!=*ppvObject)
\r
44 ((LPUNKNOWN)*ppvObject)->AddRef();
\r
47 return E_NOINTERFACE;
\r
50 STDMETHODIMP_(ULONG) CIDataObject::AddRef( void)
\r
52 return ++m_cRefCount;
\r
55 STDMETHODIMP_(ULONG) CIDataObject::Release( void)
\r
58 nTemp = --m_cRefCount;
\r
64 STDMETHODIMP CIDataObject::GetData(
\r
65 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,
\r
66 /* [out] */ STGMEDIUM __RPC_FAR *pmedium)
\r
68 if(pformatetcIn == NULL || pmedium == NULL)
\r
69 return E_INVALIDARG;
\r
70 pmedium->hGlobal = NULL;
\r
72 ATLASSERT(m_StgMedium.GetSize() == m_ArrFormatEtc.GetSize());
\r
73 for(int i=0; i < m_ArrFormatEtc.GetSize(); ++i)
\r
75 if(pformatetcIn->tymed & m_ArrFormatEtc[i]->tymed &&
\r
76 pformatetcIn->dwAspect == m_ArrFormatEtc[i]->dwAspect &&
\r
77 pformatetcIn->cfFormat == m_ArrFormatEtc[i]->cfFormat)
\r
79 CopyMedium(pmedium, m_StgMedium[i], m_ArrFormatEtc[i]);
\r
83 return DV_E_FORMATETC;
\r
86 STDMETHODIMP CIDataObject::GetDataHere(
\r
87 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatetc*/,
\r
88 /* [out][in] */ STGMEDIUM __RPC_FAR * /*pmedium*/)
\r
93 STDMETHODIMP CIDataObject::QueryGetData(
\r
94 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc)
\r
96 if(pformatetc == NULL)
\r
97 return E_INVALIDARG;
\r
99 //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT
\r
100 if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
\r
101 return (DV_E_DVASPECT);
\r
102 HRESULT hr = DV_E_TYMED;
\r
103 for(int i = 0; i < m_ArrFormatEtc.GetSize(); ++i)
\r
105 if(pformatetc->tymed & m_ArrFormatEtc[i]->tymed)
\r
107 if(pformatetc->cfFormat == m_ArrFormatEtc[i]->cfFormat)
\r
110 hr = DV_E_CLIPFORMAT;
\r
118 STDMETHODIMP CIDataObject::GetCanonicalFormatEtc(
\r
119 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatectIn*/,
\r
120 /* [out] */ FORMATETC __RPC_FAR *pformatetcOut)
\r
122 if (pformatetcOut == NULL)
\r
123 return E_INVALIDARG;
\r
124 return DATA_S_SAMEFORMATETC;
\r
127 STDMETHODIMP CIDataObject::SetData(
\r
128 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,
\r
129 /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium,
\r
130 /* [in] */ BOOL fRelease)
\r
132 if(pformatetc == NULL || pmedium == NULL)
\r
133 return E_INVALIDARG;
\r
135 ATLASSERT(pformatetc->tymed == pmedium->tymed);
\r
136 FORMATETC* fetc=new FORMATETC;
\r
137 STGMEDIUM* pStgMed = new STGMEDIUM;
\r
139 if(fetc == NULL || pStgMed == NULL)
\r
140 return E_OUTOFMEMORY;
\r
142 SecureZeroMemory(fetc,sizeof(FORMATETC));
\r
143 SecureZeroMemory(pStgMed,sizeof(STGMEDIUM));
\r
145 *fetc = *pformatetc;
\r
146 m_ArrFormatEtc.Add(fetc);
\r
149 *pStgMed = *pmedium;
\r
152 CopyMedium(pStgMed, pmedium, pformatetc);
\r
154 m_StgMedium.Add(pStgMed);
\r
158 void CIDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
\r
160 switch(pMedSrc->tymed)
\r
162 case TYMED_HGLOBAL:
\r
163 pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, NULL);
\r
166 pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, NULL);
\r
169 pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, NULL);
\r
172 pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, NULL);
\r
175 pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, NULL);
\r
177 case TYMED_ISTREAM:
\r
178 pMedDest->pstm = pMedSrc->pstm;
\r
179 pMedSrc->pstm->AddRef();
\r
181 case TYMED_ISTORAGE:
\r
182 pMedDest->pstg = pMedSrc->pstg;
\r
183 pMedSrc->pstg->AddRef();
\r
189 pMedDest->tymed = pMedSrc->tymed;
\r
190 pMedDest->pUnkForRelease = NULL;
\r
191 if(pMedSrc->pUnkForRelease != NULL)
\r
193 pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
\r
194 pMedSrc->pUnkForRelease->AddRef();
\r
197 STDMETHODIMP CIDataObject::EnumFormatEtc(
\r
198 /* [in] */ DWORD dwDirection,
\r
199 /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc)
\r
201 if(ppenumFormatEtc == NULL)
\r
204 *ppenumFormatEtc=NULL;
\r
205 switch (dwDirection)
\r
208 *ppenumFormatEtc= new CEnumFormatEtc(m_ArrFormatEtc);
\r
209 if(*ppenumFormatEtc == NULL)
\r
210 return E_OUTOFMEMORY;
\r
211 (*ppenumFormatEtc)->AddRef();
\r
223 STDMETHODIMP CIDataObject::DAdvise(
\r
224 /* [in] */ FORMATETC __RPC_FAR * /*pformatetc*/,
\r
225 /* [in] */ DWORD /*advf*/,
\r
226 /* [unique][in] */ IAdviseSink __RPC_FAR * /*pAdvSink*/,
\r
227 /* [out] */ DWORD __RPC_FAR * /*pdwConnection*/)
\r
229 return OLE_E_ADVISENOTSUPPORTED;
\r
232 STDMETHODIMP CIDataObject::DUnadvise(
\r
233 /* [in] */ DWORD /*dwConnection*/)
\r
238 HRESULT STDMETHODCALLTYPE CIDataObject::EnumDAdvise(
\r
239 /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR * /*ppenumAdvise*/)
\r
241 return OLE_E_ADVISENOTSUPPORTED;
\r
244 //////////////////////////////////////////////////////////////////////
\r
245 // CIDropSource Class
\r
246 //////////////////////////////////////////////////////////////////////
\r
248 STDMETHODIMP CIDropSource::QueryInterface(/* [in] */ REFIID riid,
\r
249 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
\r
252 if (IID_IUnknown==riid || IID_IDropSource==riid)
\r
255 if (*ppvObject != NULL)
\r
257 ((LPUNKNOWN)*ppvObject)->AddRef();
\r
260 return E_NOINTERFACE;
\r
263 STDMETHODIMP_(ULONG) CIDropSource::AddRef( void)
\r
265 return ++m_cRefCount;
\r
268 STDMETHODIMP_(ULONG) CIDropSource::Release( void)
\r
271 nTemp = --m_cRefCount;
\r
272 ATLASSERT(nTemp >= 0);
\r
278 STDMETHODIMP CIDropSource::QueryContinueDrag(
\r
279 /* [in] */ BOOL fEscapePressed,
\r
280 /* [in] */ DWORD grfKeyState)
\r
283 return DRAGDROP_S_CANCEL;
\r
284 if(!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))
\r
287 return DRAGDROP_S_DROP;
\r
294 STDMETHODIMP CIDropSource::GiveFeedback(
\r
295 /* [in] */ DWORD /*dwEffect*/)
\r
297 return DRAGDROP_S_USEDEFAULTCURSORS;
\r
300 //////////////////////////////////////////////////////////////////////
\r
301 // CEnumFormatEtc Class
\r
302 //////////////////////////////////////////////////////////////////////
\r
304 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC>& ArrFE):
\r
305 m_cRefCount(0),m_iCur(0)
\r
307 ATLTRACE("CEnumFormatEtc::CEnumFormatEtc()\n");
\r
308 for(int i = 0; i < ArrFE.GetSize(); ++i)
\r
309 m_pFmtEtc.Add(ArrFE[i]);
\r
312 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC*>& ArrFE):
\r
313 m_cRefCount(0),m_iCur(0)
\r
315 for(int i = 0; i < ArrFE.GetSize(); ++i)
\r
316 m_pFmtEtc.Add(*ArrFE[i]);
\r
319 STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID refiid, void FAR* FAR* ppv)
\r
322 if (IID_IUnknown==refiid || IID_IEnumFORMATETC==refiid)
\r
327 ((LPUNKNOWN)*ppv)->AddRef();
\r
330 return E_NOINTERFACE;
\r
333 STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void)
\r
335 return ++m_cRefCount;
\r
338 STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void)
\r
340 long nTemp = --m_cRefCount;
\r
341 ATLASSERT(nTemp >= 0);
\r
348 STDMETHODIMP CEnumFormatEtc::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG FAR *pceltFetched)
\r
350 if(pceltFetched != NULL)
\r
353 ULONG cReturn = celt;
\r
355 if(celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.GetSize())
\r
358 if(pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request
\r
361 while (m_iCur < m_pFmtEtc.GetSize() && cReturn > 0)
\r
363 *lpFormatEtc++ = m_pFmtEtc[m_iCur++];
\r
366 if (pceltFetched != NULL)
\r
367 *pceltFetched = celt - cReturn;
\r
369 return (cReturn == 0) ? S_OK : S_FALSE;
\r
372 STDMETHODIMP CEnumFormatEtc::Skip(ULONG celt)
\r
374 if((m_iCur + int(celt)) >= m_pFmtEtc.GetSize())
\r
380 STDMETHODIMP CEnumFormatEtc::Reset(void)
\r
386 STDMETHODIMP CEnumFormatEtc::Clone(IEnumFORMATETC FAR * FAR*ppCloneEnumFormatEtc)
\r
388 if(ppCloneEnumFormatEtc == NULL)
\r
391 CEnumFormatEtc *newEnum = new CEnumFormatEtc(m_pFmtEtc);
\r
393 return E_OUTOFMEMORY;
\r
395 newEnum->m_iCur = m_iCur;
\r
396 *ppCloneEnumFormatEtc = newEnum;
\r
400 //////////////////////////////////////////////////////////////////////
\r
401 // CIDropTarget Class
\r
402 //////////////////////////////////////////////////////////////////////
\r
403 CIDropTarget::CIDropTarget(HWND hTargetWnd):
\r
404 m_hTargetWnd(hTargetWnd),
\r
405 m_cRefCount(0), m_bAllowDrop(false),
\r
406 m_pDropTargetHelper(NULL), m_pSupportedFrmt(NULL)
\r
408 if(FAILED(CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER,
\r
409 IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper)))
\r
410 m_pDropTargetHelper = NULL;
\r
413 CIDropTarget::~CIDropTarget()
\r
415 if(m_pDropTargetHelper != NULL)
\r
417 m_pDropTargetHelper->Release();
\r
418 m_pDropTargetHelper = NULL;
\r
422 HRESULT STDMETHODCALLTYPE CIDropTarget::QueryInterface( /* [in] */ REFIID riid,
\r
423 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
\r
426 if (IID_IUnknown==riid || IID_IDropTarget==riid)
\r
429 if (*ppvObject != NULL)
\r
431 ((LPUNKNOWN)*ppvObject)->AddRef();
\r
434 return E_NOINTERFACE;
\r
437 ULONG STDMETHODCALLTYPE CIDropTarget::Release( void)
\r
440 nTemp = --m_cRefCount;
\r
441 ATLASSERT(nTemp >= 0);
\r
447 bool CIDropTarget::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
\r
449 DWORD dwOKEffects = *pdwEffect;
\r
453 *pdwEffect = DROPEFFECT_NONE;
\r
456 //CTRL+SHIFT -- DROPEFFECT_LINK
\r
457 //CTRL -- DROPEFFECT_COPY
\r
458 //SHIFT -- DROPEFFECT_MOVE
\r
459 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
\r
460 *pdwEffect = (grfKeyState & MK_CONTROL) ?
\r
461 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ):
\r
462 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 );
\r
463 if(*pdwEffect == 0)
\r
465 // No modifier keys used by user while dragging.
\r
466 if (DROPEFFECT_MOVE & dwOKEffects)
\r
467 *pdwEffect = DROPEFFECT_MOVE;
\r
468 else if (DROPEFFECT_COPY & dwOKEffects)
\r
469 *pdwEffect = DROPEFFECT_COPY;
\r
470 else if (DROPEFFECT_LINK & dwOKEffects)
\r
471 *pdwEffect = DROPEFFECT_LINK;
\r
474 *pdwEffect = DROPEFFECT_NONE;
\r
479 // Check if the drag source application allows the drop effect desired by user.
\r
480 // The drag source specifies this in DoDragDrop
\r
481 if(!(*pdwEffect & dwOKEffects))
\r
482 *pdwEffect = DROPEFFECT_NONE;
\r
485 return (DROPEFFECT_NONE == *pdwEffect)?false:true;
\r
488 HRESULT STDMETHODCALLTYPE CIDropTarget::DragEnter(
\r
489 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
\r
490 /* [in] */ DWORD grfKeyState,
\r
491 /* [in] */ POINTL pt,
\r
492 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
\r
494 if(pDataObj == NULL)
\r
495 return E_INVALIDARG;
\r
497 if(m_pDropTargetHelper)
\r
498 m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);
\r
499 //IEnumFORMATETC* pEnum;
\r
500 //pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum);
\r
503 //pEnum->Next(1,&ftm,0);
\r
504 //pEnum->Release();
\r
505 m_pSupportedFrmt = NULL;
\r
506 for(int i =0; i<m_formatetc.GetSize(); ++i)
\r
508 m_bAllowDrop = (pDataObj->QueryGetData(&m_formatetc[i]) == S_OK)?true:false;
\r
511 m_pSupportedFrmt = &m_formatetc[i];
\r
516 QueryDrop(grfKeyState, pdwEffect);
\r
520 HRESULT STDMETHODCALLTYPE CIDropTarget::DragOver(
\r
521 /* [in] */ DWORD grfKeyState,
\r
522 /* [in] */ POINTL pt,
\r
523 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
\r
525 if(m_pDropTargetHelper)
\r
526 m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
\r
527 QueryDrop(grfKeyState, pdwEffect);
\r
531 HRESULT STDMETHODCALLTYPE CIDropTarget::DragLeave( void)
\r
533 if(m_pDropTargetHelper)
\r
534 m_pDropTargetHelper->DragLeave();
\r
536 m_bAllowDrop = false;
\r
537 m_pSupportedFrmt = NULL;
\r
541 HRESULT STDMETHODCALLTYPE CIDropTarget::Drop(
\r
542 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
\r
543 /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt,
\r
544 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
\r
546 if (pDataObj == NULL)
\r
547 return E_INVALIDARG;
\r
549 if(m_pDropTargetHelper)
\r
550 m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);
\r
552 if(QueryDrop(grfKeyState, pdwEffect))
\r
554 if(m_bAllowDrop && m_pSupportedFrmt != NULL)
\r
557 if(pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK)
\r
559 if(OnDrop(m_pSupportedFrmt, medium, pdwEffect, pt)) //does derive class wants us to free medium?
\r
560 ReleaseStgMedium(&medium);
\r
564 m_bAllowDrop=false;
\r
565 *pdwEffect = DROPEFFECT_NONE;
\r
566 m_pSupportedFrmt = NULL;
\r
570 //////////////////////////////////////////////////////////////////////
\r
571 // CIDragSourceHelper Class
\r
572 //////////////////////////////////////////////////////////////////////
\r