Update Git for Windows URLs
[TortoiseGit.git] / src / Utils / DragDropImpl.cpp
bloba7b4f65d05d8d2232d450b605d01042eabdd8fa4
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
5 PARTICULAR PURPOSE.
6 Author: Leon Finker 1/2001
7 **************************************************************************/
8 // IDataObjectImpl.cpp: implementation of the CIDataObjectImpl class.
9 //////////////////////////////////////////////////////////////////////
10 #include "stdafx.h"
11 #include <shlobj.h>
12 #include <atlbase.h>
13 #include "DragDropImpl.h"
14 #include <new>
15 #include <Strsafe.h>
17 //////////////////////////////////////////////////////////////////////
18 // CIDataObject Class
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)
40 if (!ppvObject)
41 return E_POINTER;
42 *ppvObject = nullptr;
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);*/
47 else
48 return E_NOINTERFACE;
49 AddRef();
50 return S_OK;
53 STDMETHODIMP_(ULONG) CIDataObject::AddRef( void)
55 return ++m_cRefCount;
58 STDMETHODIMP_(ULONG) CIDataObject::Release( void)
60 long nTemp = --m_cRefCount;
61 if(nTemp==0)
62 delete this;
63 return nTemp;
66 STDMETHODIMP CIDataObject::GetData(
67 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,
68 /* [out] */ STGMEDIUM __RPC_FAR *pmedium)
70 if (!pformatetcIn)
71 return E_INVALIDARG;
72 if (!pmedium)
73 return E_POINTER;
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]);
84 return S_OK;
87 return DV_E_FORMATETC;
90 STDMETHODIMP CIDataObject::GetDataHere(
91 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatetc*/,
92 /* [out][in] */ STGMEDIUM __RPC_FAR * /*pmedium*/)
94 return E_NOTIMPL;
97 STDMETHODIMP CIDataObject::QueryGetData(
98 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc)
100 if (!pformatetc)
101 return E_INVALIDARG;
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)
112 return S_OK;
113 else
114 hr = DV_E_CLIPFORMAT;
116 else
117 hr = DV_E_TYMED;
119 return hr;
122 STDMETHODIMP CIDataObject::GetCanonicalFormatEtc(
123 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatectIn*/,
124 /* [out] */ FORMATETC __RPC_FAR *pformatetcOut)
126 if (!pformatetcOut)
127 return E_INVALIDARG;
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)
137 return E_INVALIDARG;
139 ATLASSERT(pformatetc->tymed == pmedium->tymed);
140 FORMATETC* fetc = new (std::nothrow) FORMATETC;
141 STGMEDIUM* pStgMed = new (std::nothrow) STGMEDIUM;
143 if (!fetc || !pStgMed)
145 delete fetc;
146 delete 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);
168 break;
172 *fetc = *pformatetc;
173 m_ArrFormatEtc.Add(fetc);
175 if(fRelease)
176 *pStgMed = *pmedium;
177 else
179 CopyMedium(pStgMed, pmedium, pformatetc);
181 m_StgMedium.Add(pStgMed);
183 return S_OK;
186 void CIDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
188 switch(pMedSrc->tymed)
190 case TYMED_HGLOBAL:
191 pMedDest->hGlobal = static_cast<HGLOBAL>(OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0));
192 break;
193 case TYMED_GDI:
194 pMedDest->hBitmap = static_cast<HBITMAP>(OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, 0));
195 break;
196 case TYMED_MFPICT:
197 pMedDest->hMetaFilePict = static_cast<HMETAFILEPICT>(OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0));
198 break;
199 case TYMED_ENHMF:
200 pMedDest->hEnhMetaFile = static_cast<HENHMETAFILE>(OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0));
201 break;
202 case TYMED_FILE:
203 pMedSrc->lpszFileName = static_cast<LPOLESTR>(OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0));
204 break;
205 case TYMED_ISTREAM:
206 pMedDest->pstm = pMedSrc->pstm;
207 pMedSrc->pstm->AddRef();
208 break;
209 case TYMED_ISTORAGE:
210 pMedDest->pstg = pMedSrc->pstg;
211 pMedSrc->pstg->AddRef();
212 break;
213 case TYMED_NULL:
214 default:
215 break;
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)
231 return E_POINTER;
233 *ppenumFormatEtc = nullptr;
234 switch (dwDirection)
236 case DATADIR_GET:
237 *ppenumFormatEtc = new (std::nothrow) CEnumFormatEtc(m_ArrFormatEtc);
238 if (!*ppenumFormatEtc)
239 return E_OUTOFMEMORY;
240 (*ppenumFormatEtc)->AddRef();
241 break;
242 case DATADIR_SET:
243 default:
244 return E_NOTIMPL;
245 break;
247 return S_OK;
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*/)
262 return E_NOTIMPL;
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)
275 return E_INVALIDARG;
277 FORMATETC fetc = {0};
278 fetc.cfFormat = static_cast<CLIPFORMAT>(RegisterClipboardFormat(CFSTR_DROPDESCRIPTION));
279 fetc.dwAspect = DVASPECT_CONTENT;
280 fetc.lindex = -1;
281 fetc.tymed = TYMED_HGLOBAL;
283 STGMEDIUM medium = {0};
284 medium.hGlobal = GlobalAlloc(GHND, sizeof(DROPDESCRIPTION));
285 if (!medium.hGlobal)
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)
305 if (!ppvObject)
307 return E_POINTER;
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);
322 else
324 *ppvObject = nullptr;
325 return E_NOINTERFACE;
328 AddRef();
329 return S_OK;
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);
341 if(nTemp==0)
342 delete this;
343 return nTemp;
346 STDMETHODIMP CIDropSource::QueryContinueDrag(
347 /* [in] */ BOOL fEscapePressed,
348 /* [in] */ DWORD grfKeyState)
350 if(fEscapePressed)
351 return DRAGDROP_S_CANCEL;
352 if(!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))
354 m_bDropped = true;
355 return DRAGDROP_S_DROP;
358 return S_OK;
361 STDMETHODIMP CIDropSource::GiveFeedback(
362 /* [in] */ DWORD /*dwEffect*/)
364 if (m_pIDataObj)
366 FORMATETC fetc = {0};
367 fetc.cfFormat = static_cast<CLIPFORMAT>(RegisterClipboardFormat(L"DragWindow"));
368 fetc.dwAspect = DVASPECT_CONTENT;
369 fetc.lindex = -1;
370 fetc.tymed = TYMED_HGLOBAL;
371 if (m_pIDataObj->QueryGetData(&fetc) == S_OK)
373 STGMEDIUM medium;
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)
408 if (!ppv)
409 return E_POINTER;
410 *ppv = nullptr;
411 if (IID_IUnknown == refiid || IID_IEnumFORMATETC == refiid)
412 *ppv = static_cast<IEnumFORMATETC*>(this);
413 else
414 return E_NOINTERFACE;
416 AddRef();
417 return S_OK;
420 STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef()
422 return ++m_cRefCount;
425 STDMETHODIMP_(ULONG) CEnumFormatEtc::Release()
427 long nTemp = --m_cRefCount;
428 ATLASSERT(nTemp >= 0);
429 if(nTemp == 0)
430 delete this;
432 return nTemp;
435 STDMETHODIMP CEnumFormatEtc::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG FAR *pceltFetched)
437 if(celt <= 0)
438 return E_INVALIDARG;
439 if (!pceltFetched && celt != 1) // pceltFetched can be nullptr only for 1 item request
440 return E_POINTER;
441 if (!lpFormatEtc)
442 return E_POINTER;
444 if (pceltFetched)
445 *pceltFetched = 0;
446 if (m_iCur >= m_pFmtEtc.GetSize())
447 return S_FALSE;
449 ULONG cReturn = celt;
450 while (m_iCur < m_pFmtEtc.GetSize() && cReturn > 0)
452 *lpFormatEtc++ = m_pFmtEtc[m_iCur++];
453 --cReturn;
455 if (pceltFetched)
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())
464 return S_FALSE;
465 m_iCur += celt;
466 return S_OK;
469 STDMETHODIMP CEnumFormatEtc::Reset()
471 m_iCur = 0;
472 return S_OK;
475 STDMETHODIMP CEnumFormatEtc::Clone(IEnumFORMATETC FAR * FAR*ppCloneEnumFormatEtc)
477 if (!ppCloneEnumFormatEtc)
478 return E_POINTER;
480 CEnumFormatEtc *newEnum = new (std::nothrow) CEnumFormatEtc(m_pFmtEtc);
481 if (!newEnum)
482 return E_OUTOFMEMORY;
483 newEnum->AddRef();
484 newEnum->m_iCur = m_iCur;
485 *ppCloneEnumFormatEtc = newEnum;
486 return S_OK;
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)
515 if (!ppvObject)
516 return E_POINTER;
517 *ppvObject = nullptr;
518 if (IID_IUnknown == riid || IID_IDropTarget == riid)
519 *ppvObject = static_cast<IDropTarget*>(this);
520 else
521 return E_NOINTERFACE;
523 AddRef();
524 return S_OK;
527 ULONG STDMETHODCALLTYPE CIDropTarget::Release( void)
529 long nTemp = --m_cRefCount;
530 ATLASSERT(nTemp >= 0);
531 if(nTemp==0)
532 delete this;
533 return nTemp;
536 bool CIDropTarget::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
538 DWORD dwOKEffects = *pdwEffect;
540 if(!m_bAllowDrop)
542 *pdwEffect = DROPEFFECT_NONE;
543 return false;
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 );
552 if(*pdwEffect == 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;
561 else
563 *pdwEffect = DROPEFFECT_NONE;
566 else
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)
583 if (!pDataObj)
584 return E_INVALIDARG;
585 if (!pdwEffect)
586 return E_POINTER;
588 pDataObj->AddRef();
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);
598 if(m_bAllowDrop)
600 m_pSupportedFrmt = &m_formatetc[i];
601 break;
605 QueryDrop(grfKeyState, pdwEffect);
606 return S_OK;
609 HRESULT STDMETHODCALLTYPE CIDropTarget::DragOver(
610 /* [in] */ DWORD grfKeyState,
611 /* [in] */ POINTL pt,
612 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
614 if (!pdwEffect)
615 return E_POINTER;
616 if(m_pDropTargetHelper)
617 m_pDropTargetHelper->DragOver(reinterpret_cast<LPPOINT>(&pt), *pdwEffect);
618 QueryDrop(grfKeyState, pdwEffect);
619 return S_OK;
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;
631 return S_OK;
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)
639 if (!pDataObj)
640 return E_INVALIDARG;
641 if (!pdwEffect)
642 return E_POINTER;
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)
651 STGMEDIUM medium;
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);
659 m_bAllowDrop=false;
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;
665 return S_OK;
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;
675 fetc.lindex = -1;
676 fetc.tymed = TYMED_HGLOBAL;
678 STGMEDIUM medium = {0};
679 medium.tymed = TYMED_HGLOBAL;
680 medium.hGlobal = GlobalAlloc(GHND, sizeof(DROPDESCRIPTION));
681 if(medium.hGlobal)
683 auto pDropDescription = static_cast<DROPDESCRIPTION*>(GlobalLock(medium.hGlobal));
684 if (pDropDescription == nullptr)
685 return hr;
687 if (insert)
688 StringCchCopy(pDropDescription->szInsert, _countof(pDropDescription->szInsert), insert);
689 else
690 pDropDescription->szInsert[0] = 0;
691 if (format)
692 StringCchCopy(pDropDescription->szMessage, _countof(pDropDescription->szMessage), format);
693 else
694 pDropDescription->szMessage[0] = 0;
695 pDropDescription->type = image;
696 GlobalUnlock(medium.hGlobal);
698 hr = m_pIDataObject->SetData(&fetc, &medium, TRUE);
699 if (FAILED(hr))
701 GlobalFree(medium.hGlobal);
705 return hr;
709 //////////////////////////////////////////////////////////////////////
710 // CIDragSourceHelper Class
711 //////////////////////////////////////////////////////////////////////