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 = static_cast<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
= static_cast<HGLOBAL
>(OleDuplicateData(pMedSrc
->hGlobal
, pFmtSrc
->cfFormat
, 0));
194 pMedDest
->hBitmap
= static_cast<HBITMAP
>(OleDuplicateData(pMedSrc
->hBitmap
,pFmtSrc
->cfFormat
, 0));
197 pMedDest
->hMetaFilePict
= static_cast<HMETAFILEPICT
>(OleDuplicateData(pMedSrc
->hMetaFilePict
, pFmtSrc
->cfFormat
, 0));
200 pMedDest
->hEnhMetaFile
= static_cast<HENHMETAFILE
>(OleDuplicateData(pMedSrc
->hEnhMetaFile
, pFmtSrc
->cfFormat
, 0));
203 pMedSrc
->lpszFileName
= static_cast<LPOLESTR
>(OleDuplicateData(pMedSrc
->lpszFileName
, pFmtSrc
->cfFormat
, 0));
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
, LPCWSTR format
, LPCWSTR insert
)
274 if (!format
|| !insert
)
277 FORMATETC fetc
= {0};
278 fetc
.cfFormat
= static_cast<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 auto pDropDescription
= static_cast<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)
339 long nTemp
= --m_cRefCount
;
340 ATLASSERT(nTemp
>= 0);
346 STDMETHODIMP
CIDropSource::QueryContinueDrag(
347 /* [in] */ BOOL fEscapePressed
,
348 /* [in] */ DWORD grfKeyState
)
351 return DRAGDROP_S_CANCEL
;
352 if(!(grfKeyState
& (MK_LBUTTON
|MK_RBUTTON
)))
355 return DRAGDROP_S_DROP
;
361 STDMETHODIMP
CIDropSource::GiveFeedback(
362 /* [in] */ DWORD
/*dwEffect*/)
366 FORMATETC fetc
= {0};
367 fetc
.cfFormat
= static_cast<CLIPFORMAT
>(RegisterClipboardFormat(L
"DragWindow"));
368 fetc
.dwAspect
= DVASPECT_CONTENT
;
370 fetc
.tymed
= TYMED_HGLOBAL
;
371 if (m_pIDataObj
->QueryGetData(&fetc
) == S_OK
)
374 if (m_pIDataObj
->GetData(&fetc
, &medium
) == S_OK
)
376 auto hWndDragWindow
= *static_cast<HWND
*>(GlobalLock(medium
.hGlobal
));
377 GlobalUnlock(medium
.hGlobal
);
378 #define WM_INVALIDATEDRAGIMAGE (WM_USER + 3)
379 SendMessage(hWndDragWindow
, WM_INVALIDATEDRAGIMAGE
, 0, 0);
380 ReleaseStgMedium(&medium
);
384 return DRAGDROP_S_USEDEFAULTCURSORS
;
387 //////////////////////////////////////////////////////////////////////
388 // CEnumFormatEtc Class
389 //////////////////////////////////////////////////////////////////////
391 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray
<FORMATETC
>& ArrFE
):
392 m_cRefCount(0),m_iCur(0)
394 ATLTRACE("CEnumFormatEtc::CEnumFormatEtc()\n");
395 for(int i
= 0; i
< ArrFE
.GetSize(); ++i
)
396 m_pFmtEtc
.Add(ArrFE
[i
]);
399 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray
<FORMATETC
*>& ArrFE
):
400 m_cRefCount(0),m_iCur(0)
402 for(int i
= 0; i
< ArrFE
.GetSize(); ++i
)
403 m_pFmtEtc
.Add(*ArrFE
[i
]);
406 STDMETHODIMP
CEnumFormatEtc::QueryInterface(REFIID refiid
, void FAR
* FAR
* ppv
)
411 if (IID_IUnknown
== refiid
|| IID_IEnumFORMATETC
== refiid
)
412 *ppv
= static_cast<IEnumFORMATETC
*>(this);
414 return E_NOINTERFACE
;
420 STDMETHODIMP_(ULONG
) CEnumFormatEtc::AddRef()
422 return ++m_cRefCount
;
425 STDMETHODIMP_(ULONG
) CEnumFormatEtc::Release()
427 long nTemp
= --m_cRefCount
;
428 ATLASSERT(nTemp
>= 0);
435 STDMETHODIMP
CEnumFormatEtc::Next( ULONG celt
,LPFORMATETC lpFormatEtc
, ULONG FAR
*pceltFetched
)
439 if (!pceltFetched
&& celt
!= 1) // pceltFetched can be nullptr only for 1 item request
446 if (m_iCur
>= m_pFmtEtc
.GetSize())
449 ULONG cReturn
= celt
;
450 while (m_iCur
< m_pFmtEtc
.GetSize() && cReturn
> 0)
452 *lpFormatEtc
++ = m_pFmtEtc
[m_iCur
++];
456 *pceltFetched
= celt
- cReturn
;
458 return (cReturn
== 0) ? S_OK
: S_FALSE
;
461 STDMETHODIMP
CEnumFormatEtc::Skip(ULONG celt
)
463 if((m_iCur
+ int(celt
)) >= m_pFmtEtc
.GetSize())
469 STDMETHODIMP
CEnumFormatEtc::Reset()
475 STDMETHODIMP
CEnumFormatEtc::Clone(IEnumFORMATETC FAR
* FAR
*ppCloneEnumFormatEtc
)
477 if (!ppCloneEnumFormatEtc
)
480 CEnumFormatEtc
*newEnum
= new (std::nothrow
) CEnumFormatEtc(m_pFmtEtc
);
482 return E_OUTOFMEMORY
;
484 newEnum
->m_iCur
= m_iCur
;
485 *ppCloneEnumFormatEtc
= newEnum
;
489 //////////////////////////////////////////////////////////////////////
490 // CIDropTarget Class
491 //////////////////////////////////////////////////////////////////////
492 CIDropTarget::CIDropTarget(HWND hTargetWnd
):
493 m_hTargetWnd(hTargetWnd
),
494 m_cRefCount(0), m_bAllowDrop(false),
495 m_pDropTargetHelper(nullptr),
496 m_pSupportedFrmt(nullptr),
497 m_pIDataObject(nullptr)
499 if (FAILED(CoCreateInstance(CLSID_DragDropHelper
, nullptr, CLSCTX_INPROC_SERVER
, IID_IDropTargetHelper
, reinterpret_cast<LPVOID
*>(&m_pDropTargetHelper
))))
500 m_pDropTargetHelper
= nullptr;
503 CIDropTarget::~CIDropTarget()
505 if (m_pDropTargetHelper
)
507 m_pDropTargetHelper
->Release();
508 m_pDropTargetHelper
= nullptr;
512 HRESULT STDMETHODCALLTYPE
CIDropTarget::QueryInterface( /* [in] */ REFIID riid
,
513 /* [iid_is][out] */ void __RPC_FAR
*__RPC_FAR
*ppvObject
)
517 *ppvObject
= nullptr;
518 if (IID_IUnknown
== riid
|| IID_IDropTarget
== riid
)
519 *ppvObject
= static_cast<IDropTarget
*>(this);
521 return E_NOINTERFACE
;
527 ULONG STDMETHODCALLTYPE
CIDropTarget::Release( void)
529 long nTemp
= --m_cRefCount
;
530 ATLASSERT(nTemp
>= 0);
536 bool CIDropTarget::QueryDrop(DWORD grfKeyState
, LPDWORD pdwEffect
)
538 DWORD dwOKEffects
= *pdwEffect
;
542 *pdwEffect
= DROPEFFECT_NONE
;
545 //CTRL+SHIFT -- DROPEFFECT_LINK
546 //CTRL -- DROPEFFECT_COPY
547 //SHIFT -- DROPEFFECT_MOVE
548 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
549 *pdwEffect
= (grfKeyState
& MK_CONTROL
) ?
550 ( (grfKeyState
& MK_SHIFT
) ? DROPEFFECT_LINK
: DROPEFFECT_COPY
):
551 ( (grfKeyState
& MK_SHIFT
) ? DROPEFFECT_MOVE
: 0 );
554 // No modifier keys used by user while dragging.
555 if (DROPEFFECT_MOVE
& dwOKEffects
)
556 *pdwEffect
= DROPEFFECT_MOVE
;
557 else if (DROPEFFECT_COPY
& dwOKEffects
)
558 *pdwEffect
= DROPEFFECT_COPY
;
559 else if (DROPEFFECT_LINK
& dwOKEffects
)
560 *pdwEffect
= DROPEFFECT_LINK
;
563 *pdwEffect
= DROPEFFECT_NONE
;
568 // Check if the drag source application allows the drop effect desired by user.
569 // The drag source specifies this in DoDragDrop
570 if(!(*pdwEffect
& dwOKEffects
))
571 *pdwEffect
= DROPEFFECT_NONE
;
574 return (DROPEFFECT_NONE
== *pdwEffect
)?false:true;
577 HRESULT STDMETHODCALLTYPE
CIDropTarget::DragEnter(
578 /* [unique][in] */ IDataObject __RPC_FAR
*pDataObj
,
579 /* [in] */ DWORD grfKeyState
,
580 /* [in] */ POINTL pt
,
581 /* [out][in] */ DWORD __RPC_FAR
*pdwEffect
)
589 m_pIDataObject
= pDataObj
;
591 if(m_pDropTargetHelper
)
592 m_pDropTargetHelper
->DragEnter(m_hTargetWnd
, pDataObj
, reinterpret_cast<LPPOINT
>(&pt
), *pdwEffect
);
594 m_pSupportedFrmt
= nullptr;
595 for(int i
=0; i
<m_formatetc
.GetSize(); ++i
)
597 m_bAllowDrop
= (pDataObj
->QueryGetData(&m_formatetc
[i
]) == S_OK
);
600 m_pSupportedFrmt
= &m_formatetc
[i
];
605 QueryDrop(grfKeyState
, pdwEffect
);
609 HRESULT STDMETHODCALLTYPE
CIDropTarget::DragOver(
610 /* [in] */ DWORD grfKeyState
,
611 /* [in] */ POINTL pt
,
612 /* [out][in] */ DWORD __RPC_FAR
*pdwEffect
)
616 if(m_pDropTargetHelper
)
617 m_pDropTargetHelper
->DragOver(reinterpret_cast<LPPOINT
>(&pt
), *pdwEffect
);
618 QueryDrop(grfKeyState
, pdwEffect
);
622 HRESULT STDMETHODCALLTYPE
CIDropTarget::DragLeave( void)
624 if(m_pDropTargetHelper
)
625 m_pDropTargetHelper
->DragLeave();
627 m_bAllowDrop
= false;
628 m_pSupportedFrmt
= nullptr;
629 m_pIDataObject
->Release();
630 m_pIDataObject
= nullptr;
634 HRESULT STDMETHODCALLTYPE
CIDropTarget::Drop(
635 /* [unique][in] */ IDataObject __RPC_FAR
*pDataObj
,
636 /* [in] */ DWORD grfKeyState
, /* [in] */ POINTL pt
,
637 /* [out][in] */ DWORD __RPC_FAR
*pdwEffect
)
644 if(m_pDropTargetHelper
)
645 m_pDropTargetHelper
->Drop(pDataObj
, reinterpret_cast<LPPOINT
>(&pt
), *pdwEffect
);
647 if(QueryDrop(grfKeyState
, pdwEffect
))
649 if (m_bAllowDrop
&& m_pSupportedFrmt
)
652 if(pDataObj
->GetData(m_pSupportedFrmt
, &medium
) == S_OK
)
654 if(OnDrop(m_pSupportedFrmt
, medium
, pdwEffect
, pt
)) //does derive class wants us to free medium?
655 ReleaseStgMedium(&medium
);
660 *pdwEffect
= DROPEFFECT_NONE
;
661 m_pSupportedFrmt
= nullptr;
662 if (m_pIDataObject
) // just in case we get a drop without first receiving DragEnter()
663 m_pIDataObject
->Release();
664 m_pIDataObject
= nullptr;
668 HRESULT
CIDropTarget::SetDropDescription(DROPIMAGETYPE image
, LPCWSTR format
, LPCWSTR insert
)
670 HRESULT hr
= E_OUTOFMEMORY
;
672 FORMATETC fetc
= {0};
673 fetc
.cfFormat
= static_cast<CLIPFORMAT
>(RegisterClipboardFormat(CFSTR_DROPDESCRIPTION
));
674 fetc
.dwAspect
= DVASPECT_CONTENT
;
676 fetc
.tymed
= TYMED_HGLOBAL
;
678 STGMEDIUM medium
= {0};
679 medium
.tymed
= TYMED_HGLOBAL
;
680 medium
.hGlobal
= GlobalAlloc(GHND
, sizeof(DROPDESCRIPTION
));
683 auto pDropDescription
= static_cast<DROPDESCRIPTION
*>(GlobalLock(medium
.hGlobal
));
684 if (pDropDescription
== nullptr)
688 StringCchCopy(pDropDescription
->szInsert
, _countof(pDropDescription
->szInsert
), insert
);
690 pDropDescription
->szInsert
[0] = 0;
692 StringCchCopy(pDropDescription
->szMessage
, _countof(pDropDescription
->szMessage
), format
);
694 pDropDescription
->szMessage
[0] = 0;
695 pDropDescription
->type
= image
;
696 GlobalUnlock(medium
.hGlobal
);
698 hr
= m_pIDataObject
->SetData(&fetc
, &medium
, TRUE
);
701 GlobalFree(medium
.hGlobal
);
709 //////////////////////////////////////////////////////////////////////
710 // CIDragSourceHelper Class
711 //////////////////////////////////////////////////////////////////////