CommitDlg: Update empty file list message
[TortoiseGit.git] / src / Utils / DragDropImpl.cpp
blob58246c4f96b2a21f22f3ac45a0c806a2e982dd8d
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 == 0)
41 return E_POINTER;
42 *ppvObject = NULL;
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 == NULL)
71 return E_INVALIDARG;
72 if(pmedium == NULL)
73 return E_POINTER;
74 pmedium->hGlobal = NULL;
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 == NULL)
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 == NULL)
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 == NULL || pmedium == NULL)
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 == NULL || pStgMed == NULL)
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 = NULL;
219 if(pMedSrc->pUnkForRelease != NULL)
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 == NULL)
231 return E_POINTER;
233 *ppenumFormatEtc=NULL;
234 switch (dwDirection)
236 case DATADIR_GET:
237 *ppenumFormatEtc = new (std::nothrow) CEnumFormatEtc(m_ArrFormatEtc);
238 if(*ppenumFormatEtc == NULL)
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 == NULL || insert == NULL)
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 == 0)
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 != NULL))
320 return pDragSourceNotify->QueryInterface(riid, ppvObject);
322 else
324 *ppvObject = NULL;
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(_T("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 == 0)
410 return E_POINTER;
411 *ppv = NULL;
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 == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request
441 return E_POINTER;
442 if(lpFormatEtc == NULL)
443 return E_POINTER;
445 if (pceltFetched != NULL)
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 != NULL)
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 == NULL)
479 return E_POINTER;
481 CEnumFormatEtc *newEnum = new (std::nothrow) CEnumFormatEtc(m_pFmtEtc);
482 if(newEnum ==NULL)
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(NULL), m_pSupportedFrmt(NULL),
497 m_pIDataObject(NULL)
499 if(FAILED(CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER,
500 IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper)))
502 m_pDropTargetHelper = NULL;
506 CIDropTarget::~CIDropTarget()
508 if(m_pDropTargetHelper != NULL)
510 m_pDropTargetHelper->Release();
511 m_pDropTargetHelper = NULL;
515 HRESULT STDMETHODCALLTYPE CIDropTarget::QueryInterface( /* [in] */ REFIID riid,
516 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
518 if(ppvObject == 0)
519 return E_POINTER;
520 *ppvObject = NULL;
521 if (IID_IUnknown == riid || IID_IDropTarget == riid)
522 *ppvObject = static_cast<IDropTarget*>(this);
523 else
524 return E_NOINTERFACE;
526 AddRef();
527 return S_OK;
530 ULONG STDMETHODCALLTYPE CIDropTarget::Release( void)
532 long nTemp;
533 nTemp = --m_cRefCount;
534 ATLASSERT(nTemp >= 0);
535 if(nTemp==0)
536 delete this;
537 return nTemp;
540 bool CIDropTarget::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
542 DWORD dwOKEffects = *pdwEffect;
544 if(!m_bAllowDrop)
546 *pdwEffect = DROPEFFECT_NONE;
547 return false;
549 //CTRL+SHIFT -- DROPEFFECT_LINK
550 //CTRL -- DROPEFFECT_COPY
551 //SHIFT -- DROPEFFECT_MOVE
552 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
553 *pdwEffect = (grfKeyState & MK_CONTROL) ?
554 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ):
555 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 );
556 if(*pdwEffect == 0)
558 // No modifier keys used by user while dragging.
559 if (DROPEFFECT_MOVE & dwOKEffects)
560 *pdwEffect = DROPEFFECT_MOVE;
561 else if (DROPEFFECT_COPY & dwOKEffects)
562 *pdwEffect = DROPEFFECT_COPY;
563 else if (DROPEFFECT_LINK & dwOKEffects)
564 *pdwEffect = DROPEFFECT_LINK;
565 else
567 *pdwEffect = DROPEFFECT_NONE;
570 else
572 // Check if the drag source application allows the drop effect desired by user.
573 // The drag source specifies this in DoDragDrop
574 if(!(*pdwEffect & dwOKEffects))
575 *pdwEffect = DROPEFFECT_NONE;
578 return (DROPEFFECT_NONE == *pdwEffect)?false:true;
581 HRESULT STDMETHODCALLTYPE CIDropTarget::DragEnter(
582 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
583 /* [in] */ DWORD grfKeyState,
584 /* [in] */ POINTL pt,
585 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
587 if(pDataObj == NULL)
588 return E_INVALIDARG;
589 if(pdwEffect == 0)
590 return E_POINTER;
592 pDataObj->AddRef();
593 m_pIDataObject = pDataObj;
595 if(m_pDropTargetHelper)
596 m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);
598 m_pSupportedFrmt = NULL;
599 for(int i =0; i<m_formatetc.GetSize(); ++i)
601 m_bAllowDrop = (pDataObj->QueryGetData(&m_formatetc[i]) == S_OK);
602 if(m_bAllowDrop)
604 m_pSupportedFrmt = &m_formatetc[i];
605 break;
609 QueryDrop(grfKeyState, pdwEffect);
610 return S_OK;
613 HRESULT STDMETHODCALLTYPE CIDropTarget::DragOver(
614 /* [in] */ DWORD grfKeyState,
615 /* [in] */ POINTL pt,
616 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
618 if(pdwEffect == 0)
619 return E_POINTER;
620 if(m_pDropTargetHelper)
621 m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
622 QueryDrop(grfKeyState, pdwEffect);
623 return S_OK;
626 HRESULT STDMETHODCALLTYPE CIDropTarget::DragLeave( void)
628 if(m_pDropTargetHelper)
629 m_pDropTargetHelper->DragLeave();
631 m_bAllowDrop = false;
632 m_pSupportedFrmt = NULL;
633 m_pIDataObject->Release();
634 m_pIDataObject = NULL;
635 return S_OK;
638 HRESULT STDMETHODCALLTYPE CIDropTarget::Drop(
639 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
640 /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt,
641 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
643 if (pDataObj == NULL)
644 return E_INVALIDARG;
645 if(pdwEffect == 0)
646 return E_POINTER;
648 if(m_pDropTargetHelper)
649 m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);
651 if(QueryDrop(grfKeyState, pdwEffect))
653 if(m_bAllowDrop && m_pSupportedFrmt != NULL)
655 STGMEDIUM medium;
656 if(pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK)
658 if(OnDrop(m_pSupportedFrmt, medium, pdwEffect, pt)) //does derive class wants us to free medium?
659 ReleaseStgMedium(&medium);
663 m_bAllowDrop=false;
664 *pdwEffect = DROPEFFECT_NONE;
665 m_pSupportedFrmt = NULL;
666 if (m_pIDataObject) // just in case we get a drop without first receiving DragEnter()
667 m_pIDataObject->Release();
668 m_pIDataObject = NULL;
669 return S_OK;
672 HRESULT CIDropTarget::SetDropDescription(DROPIMAGETYPE image, LPCTSTR format, LPCTSTR insert)
674 HRESULT hr = E_OUTOFMEMORY;
676 FORMATETC fetc = {0};
677 fetc.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DROPDESCRIPTION);
678 fetc.dwAspect = DVASPECT_CONTENT;
679 fetc.lindex = -1;
680 fetc.tymed = TYMED_HGLOBAL;
682 STGMEDIUM medium = {0};
683 medium.tymed = TYMED_HGLOBAL;
684 medium.hGlobal = GlobalAlloc(GHND, sizeof(DROPDESCRIPTION));
685 if(medium.hGlobal)
687 DROPDESCRIPTION* pDropDescription = (DROPDESCRIPTION*)GlobalLock(medium.hGlobal);
688 if (pDropDescription == nullptr)
689 return hr;
691 if (insert)
692 StringCchCopy(pDropDescription->szInsert, _countof(pDropDescription->szInsert), insert);
693 else
694 pDropDescription->szInsert[0] = 0;
695 if (format)
696 StringCchCopy(pDropDescription->szMessage, _countof(pDropDescription->szMessage), format);
697 else
698 pDropDescription->szMessage[0] = 0;
699 pDropDescription->type = image;
700 GlobalUnlock(medium.hGlobal);
702 hr = m_pIDataObject->SetData(&fetc, &medium, TRUE);
703 if (FAILED(hr))
705 GlobalFree(medium.hGlobal);
709 return hr;
713 //////////////////////////////////////////////////////////////////////
714 // CIDragSourceHelper Class
715 //////////////////////////////////////////////////////////////////////