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 1/2001
7 **************************************************************************/
8 // IDataObjectImpl.cpp: implementation of the CIDataObjectImpl class.
9 //////////////////////////////////////////////////////////////////////
13 #include "DragDropImpl.h"
17 //////////////////////////////////////////////////////////////////////
19 //////////////////////////////////////////////////////////////////////
21 CIDataObject::CIDataObject(CIDropSource
* pDropSource
):
22 m_cRefCount(0), m_pDropSource(pDropSource
)
26 CIDataObject::~CIDataObject()
28 for(int i
= 0; i
< m_StgMedium
.GetSize(); ++i
)
30 ReleaseStgMedium(m_StgMedium
[i
]);
31 delete m_StgMedium
[i
];
33 for(int j
= 0; j
< m_ArrFormatEtc
.GetSize(); ++j
)
34 delete m_ArrFormatEtc
[j
];
37 STDMETHODIMP
CIDataObject::QueryInterface(/* [in] */ REFIID riid
,
38 /* [iid_is][out] */ void __RPC_FAR
*__RPC_FAR
*ppvObject
)
43 if (IsEqualIID(IID_IUnknown
, riid
) || IsEqualIID(IID_IDataObject
, riid
))
44 *ppvObject
=static_cast<IDataObject
*>(this);
45 /*else if(riid == IID_IAsyncOperation)
46 *ppvObject=(IAsyncOperation*)this;*/
53 STDMETHODIMP_(ULONG
) CIDataObject::AddRef( void)
58 STDMETHODIMP_(ULONG
) CIDataObject::Release( void)
60 long nTemp
= --m_cRefCount
;
66 STDMETHODIMP
CIDataObject::GetData(
67 /* [unique][in] */ FORMATETC __RPC_FAR
*pformatetcIn
,
68 /* [out] */ STGMEDIUM __RPC_FAR
*pmedium
)
74 pmedium
->hGlobal
= nullptr;
76 ATLASSERT(m_StgMedium
.GetSize() == m_ArrFormatEtc
.GetSize());
77 for(int i
=0; i
< m_ArrFormatEtc
.GetSize(); ++i
)
79 if(pformatetcIn
->tymed
& m_ArrFormatEtc
[i
]->tymed
&&
80 pformatetcIn
->dwAspect
== m_ArrFormatEtc
[i
]->dwAspect
&&
81 pformatetcIn
->cfFormat
== m_ArrFormatEtc
[i
]->cfFormat
)
83 CopyMedium(pmedium
, m_StgMedium
[i
], m_ArrFormatEtc
[i
]);
87 return DV_E_FORMATETC
;
90 STDMETHODIMP
CIDataObject::GetDataHere(
91 /* [unique][in] */ FORMATETC __RPC_FAR
* /*pformatetc*/,
92 /* [out][in] */ STGMEDIUM __RPC_FAR
* /*pmedium*/)
97 STDMETHODIMP
CIDataObject::QueryGetData(
98 /* [unique][in] */ FORMATETC __RPC_FAR
*pformatetc
)
103 //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT
104 if (!(DVASPECT_CONTENT
& pformatetc
->dwAspect
))
105 return (DV_E_DVASPECT
);
106 HRESULT hr
= DV_E_TYMED
;
107 for(int i
= 0; i
< m_ArrFormatEtc
.GetSize(); ++i
)
109 if(pformatetc
->tymed
& m_ArrFormatEtc
[i
]->tymed
)
111 if(pformatetc
->cfFormat
== m_ArrFormatEtc
[i
]->cfFormat
)
114 hr
= DV_E_CLIPFORMAT
;
122 STDMETHODIMP
CIDataObject::GetCanonicalFormatEtc(
123 /* [unique][in] */ FORMATETC __RPC_FAR
* /*pformatectIn*/,
124 /* [out] */ FORMATETC __RPC_FAR
*pformatetcOut
)
128 return DATA_S_SAMEFORMATETC
;
131 STDMETHODIMP
CIDataObject::SetData(
132 /* [unique][in] */ FORMATETC __RPC_FAR
*pformatetc
,
133 /* [unique][in] */ STGMEDIUM __RPC_FAR
*pmedium
,
134 /* [in] */ BOOL fRelease
)
136 if (!pformatetc
|| !pmedium
)
139 ATLASSERT(pformatetc
->tymed
== pmedium
->tymed
);
140 FORMATETC
* fetc
= new (std::nothrow
) FORMATETC
;
141 STGMEDIUM
* pStgMed
= new (std::nothrow
) STGMEDIUM
;
143 if (!fetc
|| !pStgMed
)
147 return E_OUTOFMEMORY
;
150 SecureZeroMemory(fetc
,sizeof(FORMATETC
));
151 SecureZeroMemory(pStgMed
,sizeof(STGMEDIUM
));
153 // do we already store this format?
154 for (int i
=0; i
<m_ArrFormatEtc
.GetSize(); ++i
)
156 if ((pformatetc
->tymed
== m_ArrFormatEtc
[i
]->tymed
) &&
157 (pformatetc
->dwAspect
== m_ArrFormatEtc
[i
]->dwAspect
) &&
158 (pformatetc
->cfFormat
== m_ArrFormatEtc
[i
]->cfFormat
))
160 // yes, this format is already in our object:
161 // we have to replace the existing format. To do that, we
162 // remove the format we already have
163 delete m_ArrFormatEtc
[i
];
164 m_ArrFormatEtc
.RemoveAt(i
);
165 ReleaseStgMedium(m_StgMedium
[i
]);
166 delete m_StgMedium
[i
];
167 m_StgMedium
.RemoveAt(i
);
173 m_ArrFormatEtc
.Add(fetc
);
179 CopyMedium(pStgMed
, pmedium
, pformatetc
);
181 m_StgMedium
.Add(pStgMed
);
186 void CIDataObject::CopyMedium(STGMEDIUM
* pMedDest
, STGMEDIUM
* pMedSrc
, FORMATETC
* pFmtSrc
)
188 switch(pMedSrc
->tymed
)
191 pMedDest
->hGlobal
= (HGLOBAL
)OleDuplicateData(pMedSrc
->hGlobal
,pFmtSrc
->cfFormat
, NULL
);
194 pMedDest
->hBitmap
= (HBITMAP
)OleDuplicateData(pMedSrc
->hBitmap
,pFmtSrc
->cfFormat
, NULL
);
197 pMedDest
->hMetaFilePict
= (HMETAFILEPICT
)OleDuplicateData(pMedSrc
->hMetaFilePict
,pFmtSrc
->cfFormat
, NULL
);
200 pMedDest
->hEnhMetaFile
= (HENHMETAFILE
)OleDuplicateData(pMedSrc
->hEnhMetaFile
,pFmtSrc
->cfFormat
, NULL
);
203 pMedSrc
->lpszFileName
= (LPOLESTR
)OleDuplicateData(pMedSrc
->lpszFileName
,pFmtSrc
->cfFormat
, NULL
);
206 pMedDest
->pstm
= pMedSrc
->pstm
;
207 pMedSrc
->pstm
->AddRef();
210 pMedDest
->pstg
= pMedSrc
->pstg
;
211 pMedSrc
->pstg
->AddRef();
217 pMedDest
->tymed
= pMedSrc
->tymed
;
218 pMedDest
->pUnkForRelease
= nullptr;
219 if (pMedSrc
->pUnkForRelease
)
221 pMedDest
->pUnkForRelease
= pMedSrc
->pUnkForRelease
;
222 pMedSrc
->pUnkForRelease
->AddRef();
226 STDMETHODIMP
CIDataObject::EnumFormatEtc(
227 /* [in] */ DWORD dwDirection
,
228 /* [out] */ IEnumFORMATETC __RPC_FAR
*__RPC_FAR
*ppenumFormatEtc
)
230 if (!ppenumFormatEtc
)
233 *ppenumFormatEtc
= nullptr;
237 *ppenumFormatEtc
= new (std::nothrow
) CEnumFormatEtc(m_ArrFormatEtc
);
238 if (!*ppenumFormatEtc
)
239 return E_OUTOFMEMORY
;
240 (*ppenumFormatEtc
)->AddRef();
250 STDMETHODIMP
CIDataObject::DAdvise(
251 /* [in] */ FORMATETC __RPC_FAR
* /*pformatetc*/,
252 /* [in] */ DWORD
/*advf*/,
253 /* [unique][in] */ IAdviseSink __RPC_FAR
* /*pAdvSink*/,
254 /* [out] */ DWORD __RPC_FAR
* /*pdwConnection*/)
256 return OLE_E_ADVISENOTSUPPORTED
;
259 STDMETHODIMP
CIDataObject::DUnadvise(
260 /* [in] */ DWORD
/*dwConnection*/)
265 HRESULT STDMETHODCALLTYPE
CIDataObject::EnumDAdvise(
266 /* [out] */ IEnumSTATDATA __RPC_FAR
*__RPC_FAR
* /*ppenumAdvise*/)
268 return OLE_E_ADVISENOTSUPPORTED
;
272 HRESULT
CIDataObject::SetDropDescription(DROPIMAGETYPE image
, LPCTSTR format
, LPCTSTR insert
)
274 if (!format
|| !insert
)
277 FORMATETC fetc
= {0};
278 fetc
.cfFormat
= (CLIPFORMAT
)RegisterClipboardFormat(CFSTR_DROPDESCRIPTION
);
279 fetc
.dwAspect
= DVASPECT_CONTENT
;
281 fetc
.tymed
= TYMED_HGLOBAL
;
283 STGMEDIUM medium
= {0};
284 medium
.hGlobal
= GlobalAlloc(GHND
, sizeof(DROPDESCRIPTION
));
286 return E_OUTOFMEMORY
;
288 DROPDESCRIPTION
* pDropDescription
= (DROPDESCRIPTION
*)GlobalLock(medium
.hGlobal
);
289 if (pDropDescription
== nullptr)
290 return E_OUTOFMEMORY
;
291 StringCchCopy(pDropDescription
->szInsert
, _countof(pDropDescription
->szInsert
), insert
);
292 StringCchCopy(pDropDescription
->szMessage
, _countof(pDropDescription
->szMessage
), format
);
293 pDropDescription
->type
= image
;
294 GlobalUnlock(medium
.hGlobal
);
295 return SetData(&fetc
, &medium
, TRUE
);
298 //////////////////////////////////////////////////////////////////////
299 // CIDropSource Class
300 //////////////////////////////////////////////////////////////////////
302 STDMETHODIMP
CIDropSource::QueryInterface(/* [in] */ REFIID riid
,
303 /* [iid_is][out] */ void __RPC_FAR
*__RPC_FAR
*ppvObject
)
310 if (IsEqualIID(riid
, IID_IUnknown
))
312 *ppvObject
= static_cast<IDropSource
*>(this);
314 else if (IsEqualIID(riid
, IID_IDropSource
))
316 *ppvObject
= static_cast<IDropSource
*>(this);
318 else if (IsEqualIID(riid
, IID_IDropSourceNotify
) && pDragSourceNotify
)
320 return pDragSourceNotify
->QueryInterface(riid
, ppvObject
);
324 *ppvObject
= nullptr;
325 return E_NOINTERFACE
;
332 STDMETHODIMP_(ULONG
) CIDropSource::AddRef( void)
334 return ++m_cRefCount
;
337 STDMETHODIMP_(ULONG
) CIDropSource::Release( void)
340 nTemp
= --m_cRefCount
;
341 ATLASSERT(nTemp
>= 0);
347 STDMETHODIMP
CIDropSource::QueryContinueDrag(
348 /* [in] */ BOOL fEscapePressed
,
349 /* [in] */ DWORD grfKeyState
)
352 return DRAGDROP_S_CANCEL
;
353 if(!(grfKeyState
& (MK_LBUTTON
|MK_RBUTTON
)))
356 return DRAGDROP_S_DROP
;
362 STDMETHODIMP
CIDropSource::GiveFeedback(
363 /* [in] */ DWORD
/*dwEffect*/)
367 FORMATETC fetc
= {0};
368 fetc
.cfFormat
= (CLIPFORMAT
)RegisterClipboardFormat(L
"DragWindow");
369 fetc
.dwAspect
= DVASPECT_CONTENT
;
371 fetc
.tymed
= TYMED_HGLOBAL
;
372 if (m_pIDataObj
->QueryGetData(&fetc
) == S_OK
)
375 if (m_pIDataObj
->GetData(&fetc
, &medium
) == S_OK
)
377 HWND hWndDragWindow
= *((HWND
*) GlobalLock(medium
.hGlobal
));
378 GlobalUnlock(medium
.hGlobal
);
379 #define WM_INVALIDATEDRAGIMAGE (WM_USER + 3)
380 SendMessage(hWndDragWindow
, WM_INVALIDATEDRAGIMAGE
, NULL
, NULL
);
381 ReleaseStgMedium(&medium
);
385 return DRAGDROP_S_USEDEFAULTCURSORS
;
388 //////////////////////////////////////////////////////////////////////
389 // CEnumFormatEtc Class
390 //////////////////////////////////////////////////////////////////////
392 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray
<FORMATETC
>& ArrFE
):
393 m_cRefCount(0),m_iCur(0)
395 ATLTRACE("CEnumFormatEtc::CEnumFormatEtc()\n");
396 for(int i
= 0; i
< ArrFE
.GetSize(); ++i
)
397 m_pFmtEtc
.Add(ArrFE
[i
]);
400 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray
<FORMATETC
*>& ArrFE
):
401 m_cRefCount(0),m_iCur(0)
403 for(int i
= 0; i
< ArrFE
.GetSize(); ++i
)
404 m_pFmtEtc
.Add(*ArrFE
[i
]);
407 STDMETHODIMP
CEnumFormatEtc::QueryInterface(REFIID refiid
, void FAR
* FAR
* ppv
)
412 if (IID_IUnknown
== refiid
|| IID_IEnumFORMATETC
== refiid
)
413 *ppv
= static_cast<IEnumFORMATETC
*>(this);
415 return E_NOINTERFACE
;
421 STDMETHODIMP_(ULONG
) CEnumFormatEtc::AddRef(void)
423 return ++m_cRefCount
;
426 STDMETHODIMP_(ULONG
) CEnumFormatEtc::Release(void)
428 long nTemp
= --m_cRefCount
;
429 ATLASSERT(nTemp
>= 0);
436 STDMETHODIMP
CEnumFormatEtc::Next( ULONG celt
,LPFORMATETC lpFormatEtc
, ULONG FAR
*pceltFetched
)
440 if (!pceltFetched
&& celt
!= 1) // pceltFetched can be nullptr only for 1 item request
447 if (m_iCur
>= m_pFmtEtc
.GetSize())
450 ULONG cReturn
= celt
;
451 while (m_iCur
< m_pFmtEtc
.GetSize() && cReturn
> 0)
453 *lpFormatEtc
++ = m_pFmtEtc
[m_iCur
++];
457 *pceltFetched
= celt
- cReturn
;
459 return (cReturn
== 0) ? S_OK
: S_FALSE
;
462 STDMETHODIMP
CEnumFormatEtc::Skip(ULONG celt
)
464 if((m_iCur
+ int(celt
)) >= m_pFmtEtc
.GetSize())
470 STDMETHODIMP
CEnumFormatEtc::Reset(void)
476 STDMETHODIMP
CEnumFormatEtc::Clone(IEnumFORMATETC FAR
* FAR
*ppCloneEnumFormatEtc
)
478 if (!ppCloneEnumFormatEtc
)
481 CEnumFormatEtc
*newEnum
= new (std::nothrow
) CEnumFormatEtc(m_pFmtEtc
);
483 return E_OUTOFMEMORY
;
485 newEnum
->m_iCur
= m_iCur
;
486 *ppCloneEnumFormatEtc
= newEnum
;
490 //////////////////////////////////////////////////////////////////////
491 // CIDropTarget Class
492 //////////////////////////////////////////////////////////////////////
493 CIDropTarget::CIDropTarget(HWND hTargetWnd
):
494 m_hTargetWnd(hTargetWnd
),
495 m_cRefCount(0), m_bAllowDrop(false),
496 m_pDropTargetHelper(nullptr),
497 m_pSupportedFrmt(nullptr),
498 m_pIDataObject(nullptr)
500 if (FAILED(CoCreateInstance(CLSID_DragDropHelper
, nullptr, CLSCTX_INPROC_SERVER
, IID_IDropTargetHelper
, (LPVOID
*)&m_pDropTargetHelper
)))
501 m_pDropTargetHelper
= nullptr;
504 CIDropTarget::~CIDropTarget()
506 if (m_pDropTargetHelper
)
508 m_pDropTargetHelper
->Release();
509 m_pDropTargetHelper
= nullptr;
513 HRESULT STDMETHODCALLTYPE
CIDropTarget::QueryInterface( /* [in] */ REFIID riid
,
514 /* [iid_is][out] */ void __RPC_FAR
*__RPC_FAR
*ppvObject
)
518 *ppvObject
= nullptr;
519 if (IID_IUnknown
== riid
|| IID_IDropTarget
== riid
)
520 *ppvObject
= static_cast<IDropTarget
*>(this);
522 return E_NOINTERFACE
;
528 ULONG STDMETHODCALLTYPE
CIDropTarget::Release( void)
531 nTemp
= --m_cRefCount
;
532 ATLASSERT(nTemp
>= 0);
538 bool CIDropTarget::QueryDrop(DWORD grfKeyState
, LPDWORD pdwEffect
)
540 DWORD dwOKEffects
= *pdwEffect
;
544 *pdwEffect
= DROPEFFECT_NONE
;
547 //CTRL+SHIFT -- DROPEFFECT_LINK
548 //CTRL -- DROPEFFECT_COPY
549 //SHIFT -- DROPEFFECT_MOVE
550 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
551 *pdwEffect
= (grfKeyState
& MK_CONTROL
) ?
552 ( (grfKeyState
& MK_SHIFT
) ? DROPEFFECT_LINK
: DROPEFFECT_COPY
):
553 ( (grfKeyState
& MK_SHIFT
) ? DROPEFFECT_MOVE
: 0 );
556 // No modifier keys used by user while dragging.
557 if (DROPEFFECT_MOVE
& dwOKEffects
)
558 *pdwEffect
= DROPEFFECT_MOVE
;
559 else if (DROPEFFECT_COPY
& dwOKEffects
)
560 *pdwEffect
= DROPEFFECT_COPY
;
561 else if (DROPEFFECT_LINK
& dwOKEffects
)
562 *pdwEffect
= DROPEFFECT_LINK
;
565 *pdwEffect
= DROPEFFECT_NONE
;
570 // Check if the drag source application allows the drop effect desired by user.
571 // The drag source specifies this in DoDragDrop
572 if(!(*pdwEffect
& dwOKEffects
))
573 *pdwEffect
= DROPEFFECT_NONE
;
576 return (DROPEFFECT_NONE
== *pdwEffect
)?false:true;
579 HRESULT STDMETHODCALLTYPE
CIDropTarget::DragEnter(
580 /* [unique][in] */ IDataObject __RPC_FAR
*pDataObj
,
581 /* [in] */ DWORD grfKeyState
,
582 /* [in] */ POINTL pt
,
583 /* [out][in] */ DWORD __RPC_FAR
*pdwEffect
)
591 m_pIDataObject
= pDataObj
;
593 if(m_pDropTargetHelper
)
594 m_pDropTargetHelper
->DragEnter(m_hTargetWnd
, pDataObj
, (LPPOINT
)&pt
, *pdwEffect
);
596 m_pSupportedFrmt
= nullptr;
597 for(int i
=0; i
<m_formatetc
.GetSize(); ++i
)
599 m_bAllowDrop
= (pDataObj
->QueryGetData(&m_formatetc
[i
]) == S_OK
);
602 m_pSupportedFrmt
= &m_formatetc
[i
];
607 QueryDrop(grfKeyState
, pdwEffect
);
611 HRESULT STDMETHODCALLTYPE
CIDropTarget::DragOver(
612 /* [in] */ DWORD grfKeyState
,
613 /* [in] */ POINTL pt
,
614 /* [out][in] */ DWORD __RPC_FAR
*pdwEffect
)
618 if(m_pDropTargetHelper
)
619 m_pDropTargetHelper
->DragOver((LPPOINT
)&pt
, *pdwEffect
);
620 QueryDrop(grfKeyState
, pdwEffect
);
624 HRESULT STDMETHODCALLTYPE
CIDropTarget::DragLeave( void)
626 if(m_pDropTargetHelper
)
627 m_pDropTargetHelper
->DragLeave();
629 m_bAllowDrop
= false;
630 m_pSupportedFrmt
= nullptr;
631 m_pIDataObject
->Release();
632 m_pIDataObject
= nullptr;
636 HRESULT STDMETHODCALLTYPE
CIDropTarget::Drop(
637 /* [unique][in] */ IDataObject __RPC_FAR
*pDataObj
,
638 /* [in] */ DWORD grfKeyState
, /* [in] */ POINTL pt
,
639 /* [out][in] */ DWORD __RPC_FAR
*pdwEffect
)
646 if(m_pDropTargetHelper
)
647 m_pDropTargetHelper
->Drop(pDataObj
, (LPPOINT
)&pt
, *pdwEffect
);
649 if(QueryDrop(grfKeyState
, pdwEffect
))
651 if (m_bAllowDrop
&& m_pSupportedFrmt
)
654 if(pDataObj
->GetData(m_pSupportedFrmt
, &medium
) == S_OK
)
656 if(OnDrop(m_pSupportedFrmt
, medium
, pdwEffect
, pt
)) //does derive class wants us to free medium?
657 ReleaseStgMedium(&medium
);
662 *pdwEffect
= DROPEFFECT_NONE
;
663 m_pSupportedFrmt
= nullptr;
664 if (m_pIDataObject
) // just in case we get a drop without first receiving DragEnter()
665 m_pIDataObject
->Release();
666 m_pIDataObject
= nullptr;
670 HRESULT
CIDropTarget::SetDropDescription(DROPIMAGETYPE image
, LPCTSTR format
, LPCTSTR insert
)
672 HRESULT hr
= E_OUTOFMEMORY
;
674 FORMATETC fetc
= {0};
675 fetc
.cfFormat
= (CLIPFORMAT
)RegisterClipboardFormat(CFSTR_DROPDESCRIPTION
);
676 fetc
.dwAspect
= DVASPECT_CONTENT
;
678 fetc
.tymed
= TYMED_HGLOBAL
;
680 STGMEDIUM medium
= {0};
681 medium
.tymed
= TYMED_HGLOBAL
;
682 medium
.hGlobal
= GlobalAlloc(GHND
, sizeof(DROPDESCRIPTION
));
685 DROPDESCRIPTION
* pDropDescription
= (DROPDESCRIPTION
*)GlobalLock(medium
.hGlobal
);
686 if (pDropDescription
== nullptr)
690 StringCchCopy(pDropDescription
->szInsert
, _countof(pDropDescription
->szInsert
), insert
);
692 pDropDescription
->szInsert
[0] = 0;
694 StringCchCopy(pDropDescription
->szMessage
, _countof(pDropDescription
->szMessage
), format
);
696 pDropDescription
->szMessage
[0] = 0;
697 pDropDescription
->type
= image
;
698 GlobalUnlock(medium
.hGlobal
);
700 hr
= m_pIDataObject
->SetData(&fetc
, &medium
, TRUE
);
703 GlobalFree(medium
.hGlobal
);
711 //////////////////////////////////////////////////////////////////////
712 // CIDragSourceHelper Class
713 //////////////////////////////////////////////////////////////////////