Adjust the background icon size for high dpi monitors
[TortoiseGit.git] / src / Utils / DragDropImpl.cpp
blobfa194c91d37816c1b4a43bbe468160684ded7645
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=(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 = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, NULL);
192 break;
193 case TYMED_GDI:
194 pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, NULL);
195 break;
196 case TYMED_MFPICT:
197 pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, NULL);
198 break;
199 case TYMED_ENHMF:
200 pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, NULL);
201 break;
202 case TYMED_FILE:
203 pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, NULL);
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, LPCTSTR format, LPCTSTR insert)
274 if (!format || !insert)
275 return E_INVALIDARG;
277 FORMATETC fetc = {0};
278 fetc.cfFormat = (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 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)
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;
340 nTemp = --m_cRefCount;
341 ATLASSERT(nTemp >= 0);
342 if(nTemp==0)
343 delete this;
344 return nTemp;
347 STDMETHODIMP CIDropSource::QueryContinueDrag(
348 /* [in] */ BOOL fEscapePressed,
349 /* [in] */ DWORD grfKeyState)
351 if(fEscapePressed)
352 return DRAGDROP_S_CANCEL;
353 if(!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))
355 m_bDropped = true;
356 return DRAGDROP_S_DROP;
359 return S_OK;
362 STDMETHODIMP CIDropSource::GiveFeedback(
363 /* [in] */ DWORD /*dwEffect*/)
365 if (m_pIDataObj)
367 FORMATETC fetc = {0};
368 fetc.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(L"DragWindow");
369 fetc.dwAspect = DVASPECT_CONTENT;
370 fetc.lindex = -1;
371 fetc.tymed = TYMED_HGLOBAL;
372 if (m_pIDataObj->QueryGetData(&fetc) == S_OK)
374 STGMEDIUM medium;
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)
409 if (!ppv)
410 return E_POINTER;
411 *ppv = nullptr;
412 if (IID_IUnknown == refiid || IID_IEnumFORMATETC == refiid)
413 *ppv = static_cast<IEnumFORMATETC*>(this);
414 else
415 return E_NOINTERFACE;
417 AddRef();
418 return S_OK;
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);
430 if(nTemp == 0)
431 delete this;
433 return nTemp;
436 STDMETHODIMP CEnumFormatEtc::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG FAR *pceltFetched)
438 if(celt <= 0)
439 return E_INVALIDARG;
440 if (!pceltFetched && celt != 1) // pceltFetched can be nullptr only for 1 item request
441 return E_POINTER;
442 if (!lpFormatEtc)
443 return E_POINTER;
445 if (pceltFetched)
446 *pceltFetched = 0;
447 if (m_iCur >= m_pFmtEtc.GetSize())
448 return S_FALSE;
450 ULONG cReturn = celt;
451 while (m_iCur < m_pFmtEtc.GetSize() && cReturn > 0)
453 *lpFormatEtc++ = m_pFmtEtc[m_iCur++];
454 --cReturn;
456 if (pceltFetched)
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())
465 return S_FALSE;
466 m_iCur += celt;
467 return S_OK;
470 STDMETHODIMP CEnumFormatEtc::Reset(void)
472 m_iCur = 0;
473 return S_OK;
476 STDMETHODIMP CEnumFormatEtc::Clone(IEnumFORMATETC FAR * FAR*ppCloneEnumFormatEtc)
478 if (!ppCloneEnumFormatEtc)
479 return E_POINTER;
481 CEnumFormatEtc *newEnum = new (std::nothrow) CEnumFormatEtc(m_pFmtEtc);
482 if (!newEnum)
483 return E_OUTOFMEMORY;
484 newEnum->AddRef();
485 newEnum->m_iCur = m_iCur;
486 *ppCloneEnumFormatEtc = newEnum;
487 return S_OK;
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)
516 if (!ppvObject)
517 return E_POINTER;
518 *ppvObject = nullptr;
519 if (IID_IUnknown == riid || IID_IDropTarget == riid)
520 *ppvObject = static_cast<IDropTarget*>(this);
521 else
522 return E_NOINTERFACE;
524 AddRef();
525 return S_OK;
528 ULONG STDMETHODCALLTYPE CIDropTarget::Release( void)
530 long nTemp;
531 nTemp = --m_cRefCount;
532 ATLASSERT(nTemp >= 0);
533 if(nTemp==0)
534 delete this;
535 return nTemp;
538 bool CIDropTarget::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
540 DWORD dwOKEffects = *pdwEffect;
542 if(!m_bAllowDrop)
544 *pdwEffect = DROPEFFECT_NONE;
545 return false;
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 );
554 if(*pdwEffect == 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;
563 else
565 *pdwEffect = DROPEFFECT_NONE;
568 else
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)
585 if (!pDataObj)
586 return E_INVALIDARG;
587 if (!pdwEffect)
588 return E_POINTER;
590 pDataObj->AddRef();
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);
600 if(m_bAllowDrop)
602 m_pSupportedFrmt = &m_formatetc[i];
603 break;
607 QueryDrop(grfKeyState, pdwEffect);
608 return S_OK;
611 HRESULT STDMETHODCALLTYPE CIDropTarget::DragOver(
612 /* [in] */ DWORD grfKeyState,
613 /* [in] */ POINTL pt,
614 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
616 if (!pdwEffect)
617 return E_POINTER;
618 if(m_pDropTargetHelper)
619 m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
620 QueryDrop(grfKeyState, pdwEffect);
621 return S_OK;
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;
633 return S_OK;
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)
641 if (!pDataObj)
642 return E_INVALIDARG;
643 if (!pdwEffect)
644 return E_POINTER;
646 if(m_pDropTargetHelper)
647 m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);
649 if(QueryDrop(grfKeyState, pdwEffect))
651 if (m_bAllowDrop && m_pSupportedFrmt)
653 STGMEDIUM medium;
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);
661 m_bAllowDrop=false;
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;
667 return S_OK;
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;
677 fetc.lindex = -1;
678 fetc.tymed = TYMED_HGLOBAL;
680 STGMEDIUM medium = {0};
681 medium.tymed = TYMED_HGLOBAL;
682 medium.hGlobal = GlobalAlloc(GHND, sizeof(DROPDESCRIPTION));
683 if(medium.hGlobal)
685 DROPDESCRIPTION* pDropDescription = (DROPDESCRIPTION*)GlobalLock(medium.hGlobal);
686 if (pDropDescription == nullptr)
687 return hr;
689 if (insert)
690 StringCchCopy(pDropDescription->szInsert, _countof(pDropDescription->szInsert), insert);
691 else
692 pDropDescription->szInsert[0] = 0;
693 if (format)
694 StringCchCopy(pDropDescription->szMessage, _countof(pDropDescription->szMessage), format);
695 else
696 pDropDescription->szMessage[0] = 0;
697 pDropDescription->type = image;
698 GlobalUnlock(medium.hGlobal);
700 hr = m_pIDataObject->SetData(&fetc, &medium, TRUE);
701 if (FAILED(hr))
703 GlobalFree(medium.hGlobal);
707 return hr;
711 //////////////////////////////////////////////////////////////////////
712 // CIDragSourceHelper Class
713 //////////////////////////////////////////////////////////////////////