1 #include <precomp.h>
2 
3 /**************************************************************************
4    THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
5    ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
6    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
7    PARTICULAR PURPOSE.
8    Author: Leon Finker	11/2000
9    Modifications: replaced ATL by STL, Martin Fuchs 7/2003
10 **************************************************************************/
11 
12 // dragdropimp.cpp: implementation of the IDataObjectImpl class.
13 //////////////////////////////////////////////////////////////////////
14 
15 //#include <shlobj.h>
16 //#include <assert.h>
17 
18 //#include "dragdropimpl.h"
19 
20 //////////////////////////////////////////////////////////////////////
21 // IDataObjectImpl Class
22 //////////////////////////////////////////////////////////////////////
23 
IDataObjectImpl(IDropSourceImpl * pDropSource)24 IDataObjectImpl::IDataObjectImpl(IDropSourceImpl* pDropSource)
25  :	super(IID_IDataObject),
26 	m_pDropSource(pDropSource),
27 	m_cRefCount(0)
28 {
29 }
30 
~IDataObjectImpl()31 IDataObjectImpl::~IDataObjectImpl()
32 {
33 	for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it)
34 		ReleaseStgMedium(it->_medium);
35 }
36 
GetData(FORMATETC __RPC_FAR * pformatetcIn,STGMEDIUM __RPC_FAR * pmedium)37 STDMETHODIMP IDataObjectImpl::GetData(
38 	/* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,
39 	/* [out] */ STGMEDIUM __RPC_FAR *pmedium)
40 {
41 	if (pformatetcIn == NULL || pmedium == NULL)
42 		return E_INVALIDARG;
43 
44 	pmedium->hGlobal = NULL;
45 
46 	for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it)
47 	{
48 		if (pformatetcIn->tymed & it->_format->tymed &&
49 		   pformatetcIn->dwAspect == it->_format->dwAspect &&
50 		   pformatetcIn->cfFormat == it->_format->cfFormat)
51 		{
52 			CopyMedium(pmedium, it->_medium, it->_format);
53 			return S_OK;
54 		}
55 	}
56 
57 	return DV_E_FORMATETC;
58 }
59 
GetDataHere(FORMATETC __RPC_FAR * pformatetc,STGMEDIUM __RPC_FAR * pmedium)60 STDMETHODIMP IDataObjectImpl::GetDataHere(
61 	/* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,
62 	/* [out][in] */ STGMEDIUM __RPC_FAR *pmedium)
63 {
64 	return E_NOTIMPL;
65 }
66 
QueryGetData(FORMATETC __RPC_FAR * pformatetc)67 STDMETHODIMP IDataObjectImpl::QueryGetData(
68    /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc)
69 {
70 	if (pformatetc == NULL)
71 		return E_INVALIDARG;
72 
73 	//support others if needed DVASPECT_THUMBNAIL  //DVASPECT_ICON	 //DVASPECT_DOCPRINT
74 	if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
75 		return (DV_E_DVASPECT);
76 
77 	HRESULT  hr = DV_E_TYMED;
78 
79 	for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it)
80 	{
81 	   if (pformatetc->tymed & it->_format->tymed)
82 	   {
83 		  if (pformatetc->cfFormat == it->_format->cfFormat)
84 			 return S_OK;
85 		  else
86 			 hr = DV_E_CLIPFORMAT;
87 	   }
88 	   else
89 		  hr = DV_E_TYMED;
90 	}
91 
92 	return hr;
93 }
94 
GetCanonicalFormatEtc(FORMATETC __RPC_FAR * pformatectIn,FORMATETC __RPC_FAR * pformatetcOut)95 STDMETHODIMP IDataObjectImpl::GetCanonicalFormatEtc(
96 	/* [unique][in] */ FORMATETC __RPC_FAR *pformatectIn,
97 	/* [out] */ FORMATETC __RPC_FAR *pformatetcOut)
98 {
99 	if (pformatetcOut == NULL)
100 		return E_INVALIDARG;
101 
102 	return DATA_S_SAMEFORMATETC;
103 }
104 
SetData(FORMATETC __RPC_FAR * pformatetc,STGMEDIUM __RPC_FAR * pmedium,BOOL fRelease)105 STDMETHODIMP IDataObjectImpl::SetData(
106 	/* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,
107 	/* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium,
108 	/* [in] */ BOOL fRelease)
109 {
110 	if (pformatetc == NULL || pmedium == NULL)
111 	  return E_INVALIDARG;
112 
113 	assert(pformatetc->tymed == pmedium->tymed);
114 	FORMATETC* fetc=new FORMATETC;
115 	STGMEDIUM* pStgMed = new STGMEDIUM;
116 
117 	if (fetc == NULL || pStgMed == NULL)
118 		return E_OUTOFMEMORY;
119 
120 	ZeroMemory(fetc, sizeof(FORMATETC));
121 	ZeroMemory(pStgMed, sizeof(STGMEDIUM));
122 
123 	*fetc = *pformatetc;
124 
125 	if (fRelease)
126 	  *pStgMed = *pmedium;
127 	else
128 		CopyMedium(pStgMed, pmedium, pformatetc);
129 
130 	DataStorage storage;
131 
132 	storage._format = fetc;
133 	storage._medium = pStgMed;
134 
135 	_storage.push_back(storage);
136 
137 	return S_OK;
138 }
139 
CopyMedium(STGMEDIUM * pMedDest,STGMEDIUM * pMedSrc,FORMATETC * pFmtSrc)140 void IDataObjectImpl::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
141 {
142 	switch(pMedSrc->tymed)
143 	{
144 	case TYMED_HGLOBAL:
145 		pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0);
146 		break;
147 	case TYMED_GDI:
148 		pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, 0);
149 		break;
150 	case TYMED_MFPICT:
151 		pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0);
152 		break;
153 	case TYMED_ENHMF:
154 		pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0);
155 		break;
156 	case TYMED_FILE:
157 		pMedDest->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0);
158 		break;
159 	case TYMED_ISTREAM:
160 		pMedDest->pstm = pMedSrc->pstm;
161 		pMedSrc->pstm->AddRef();
162 		break;
163 	case TYMED_ISTORAGE:
164 		pMedDest->pstg = pMedSrc->pstg;
165 		pMedSrc->pstg->AddRef();
166 		break;
167 	case TYMED_NULL:
168 	default:
169 		break;
170 	}
171 	pMedDest->tymed = pMedSrc->tymed;
172 	pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
173 }
174 
EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC __RPC_FAR * __RPC_FAR * ppenumFormatEtc)175 STDMETHODIMP IDataObjectImpl::EnumFormatEtc(
176    /* [in] */ DWORD dwDirection,
177    /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc)
178 {
179 	if (ppenumFormatEtc == NULL)
180 	  return E_POINTER;
181 
182 	*ppenumFormatEtc=NULL;
183 	switch (dwDirection)
184 	{
185 	  case DATADIR_GET:
186 		 *ppenumFormatEtc = new EnumFormatEtcImpl(_storage);
187 
188 		 if (!*ppenumFormatEtc)
189 			 return E_OUTOFMEMORY;
190 
191 		 (*ppenumFormatEtc)->AddRef();
192 		 break;
193 
194 	  case DATADIR_SET:
195 	  default:
196 		 return E_NOTIMPL;
197 		 break;
198 	}
199 
200    return S_OK;
201 }
202 
DAdvise(FORMATETC __RPC_FAR * pformatetc,DWORD advf,IAdviseSink __RPC_FAR * pAdvSink,DWORD __RPC_FAR * pdwConnection)203 STDMETHODIMP IDataObjectImpl::DAdvise(
204    /* [in] */ FORMATETC __RPC_FAR *pformatetc,
205    /* [in] */ DWORD advf,
206    /* [unique][in] */ IAdviseSink __RPC_FAR *pAdvSink,
207    /* [out] */ DWORD __RPC_FAR *pdwConnection)
208 {
209 	return OLE_E_ADVISENOTSUPPORTED;
210 }
211 
DUnadvise(DWORD dwConnection)212 STDMETHODIMP IDataObjectImpl::DUnadvise(
213    /* [in] */ DWORD dwConnection)
214 {
215 	return E_NOTIMPL;
216 }
217 
EnumDAdvise(IEnumSTATDATA __RPC_FAR * __RPC_FAR * ppenumAdvise)218 HRESULT STDMETHODCALLTYPE IDataObjectImpl::EnumDAdvise(
219    /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR *ppenumAdvise)
220 {
221 	return OLE_E_ADVISENOTSUPPORTED;
222 }
223 
224 //////////////////////////////////////////////////////////////////////
225 // IDropSourceImpl Class
226 //////////////////////////////////////////////////////////////////////
227 
QueryContinueDrag(BOOL fEscapePressed,DWORD grfKeyState)228 STDMETHODIMP IDropSourceImpl::QueryContinueDrag(
229 	/* [in] */ BOOL fEscapePressed,
230 	/* [in] */ DWORD grfKeyState)
231 {
232    if (fEscapePressed)
233 	  return DRAGDROP_S_CANCEL;
234    if (!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))
235    {
236 	  m_bDropped = true;
237 	  return DRAGDROP_S_DROP;
238    }
239 
240    return S_OK;
241 
242 }
243 
GiveFeedback(DWORD dwEffect)244 STDMETHODIMP IDropSourceImpl::GiveFeedback(
245 	/* [in] */ DWORD dwEffect)
246 {
247 	return DRAGDROP_S_USEDEFAULTCURSORS;
248 }
249 
250 //////////////////////////////////////////////////////////////////////
251 // EnumFormatEtcImpl Class
252 //////////////////////////////////////////////////////////////////////
253 
EnumFormatEtcImpl(const FormatArray & ArrFE)254 EnumFormatEtcImpl::EnumFormatEtcImpl(const FormatArray& ArrFE)
255  :	super(IID_IEnumFORMATETC),
256 	m_cRefCount(0),
257 	m_iCur(0)
258 {
259    for(FormatArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it)
260 		m_pFmtEtc.push_back(*it);
261 }
262 
EnumFormatEtcImpl(const StorageArray & ArrFE)263 EnumFormatEtcImpl::EnumFormatEtcImpl(const StorageArray& ArrFE)
264  :	super(IID_IEnumFORMATETC),
265 	m_cRefCount(0),
266 	m_iCur(0)
267 {
268    for(StorageArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it)
269 		m_pFmtEtc.push_back(*it->_format);
270 }
271 
Next(ULONG celt,LPFORMATETC lpFormatEtc,ULONG * pceltFetched)272 STDMETHODIMP EnumFormatEtcImpl::Next(ULONG celt,LPFORMATETC lpFormatEtc, ULONG* pceltFetched)
273 {
274    if (pceltFetched != NULL)
275 	   *pceltFetched=0;
276 
277    ULONG cReturn = celt;
278 
279    if (celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.size())
280 	  return S_FALSE;
281 
282    if (pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request
283 	  return S_FALSE;
284 
285 	while (m_iCur < m_pFmtEtc.size() && cReturn > 0)
286 	{
287 		*lpFormatEtc++ = m_pFmtEtc[m_iCur++];
288 		--cReturn;
289 	}
290 	if (pceltFetched != NULL)
291 		*pceltFetched = celt - cReturn;
292 
293 	return (cReturn == 0) ? S_OK : S_FALSE;
294 }
295 
Skip(ULONG celt)296 STDMETHODIMP EnumFormatEtcImpl::Skip(ULONG celt)
297 {
298 	if ((m_iCur + int(celt)) >= m_pFmtEtc.size())
299 		return S_FALSE;
300 
301 	m_iCur += celt;
302 	return S_OK;
303 }
304 
Reset(void)305 STDMETHODIMP EnumFormatEtcImpl::Reset(void)
306 {
307    m_iCur = 0;
308    return S_OK;
309 }
310 
Clone(IEnumFORMATETC ** ppCloneEnumFormatEtc)311 STDMETHODIMP EnumFormatEtcImpl::Clone(IEnumFORMATETC** ppCloneEnumFormatEtc)
312 {
313   if (ppCloneEnumFormatEtc == NULL)
314 	return E_POINTER;
315 
316   EnumFormatEtcImpl* newEnum = new EnumFormatEtcImpl(m_pFmtEtc);
317 
318   if (!newEnum)
319 	return E_OUTOFMEMORY;
320 
321   newEnum->AddRef();
322   newEnum->m_iCur = m_iCur;
323   *ppCloneEnumFormatEtc = newEnum;
324 
325   return S_OK;
326 }
327 
328 //////////////////////////////////////////////////////////////////////
329 // IDropTargetImpl Class
330 //////////////////////////////////////////////////////////////////////
IDropTargetImpl(HWND hTargetWnd)331 IDropTargetImpl::IDropTargetImpl(HWND hTargetWnd)
332  :	m_cRefCount(0),
333 	m_bAllowDrop(false),
334 	m_pDropTargetHelper(NULL),
335 	m_pSupportedFrmt(NULL),
336 	m_hTargetWnd(hTargetWnd)
337 {
338 	assert(m_hTargetWnd != NULL);
339 
340 	if (FAILED(CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,
341 					 IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper)))
342 		m_pDropTargetHelper = NULL;
343 }
344 
~IDropTargetImpl()345 IDropTargetImpl::~IDropTargetImpl()
346 {
347 	if (m_pDropTargetHelper != NULL)
348 	{
349 		m_pDropTargetHelper->Release();
350 		m_pDropTargetHelper = NULL;
351 	}
352 }
353 
QueryInterface(REFIID riid,void __RPC_FAR * __RPC_FAR * ppvObject)354 HRESULT STDMETHODCALLTYPE IDropTargetImpl::QueryInterface( /* [in] */ REFIID riid,
355 						/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
356 {
357 	*ppvObject = NULL;
358 	if (IID_IUnknown==riid || IID_IDropTarget==riid)
359 		*ppvObject=this;
360 
361 	if (*ppvObject != NULL)
362 	{
363 		((LPUNKNOWN)*ppvObject)->AddRef();
364 		return S_OK;
365 	}
366 
367 	return E_NOINTERFACE;
368 }
369 
Release()370 ULONG STDMETHODCALLTYPE IDropTargetImpl::Release()
371 {
372    long nTemp = --m_cRefCount;
373 
374    assert(nTemp >= 0);
375 
376    if (nTemp == 0)
377 	  delete this;
378 
379    return nTemp;
380 }
381 
QueryDrop(DWORD grfKeyState,LPDWORD pdwEffect)382 bool IDropTargetImpl::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
383 {
384 	DWORD dwOKEffects = *pdwEffect;
385 
386 	if (!m_bAllowDrop)
387 	{
388 	   *pdwEffect = DROPEFFECT_NONE;
389 	   return false;
390 	}
391 
392 	//CTRL+SHIFT  -- DROPEFFECT_LINK
393 	//CTRL		  -- DROPEFFECT_COPY
394 	//SHIFT 	  -- DROPEFFECT_MOVE
395 	//no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
396 	*pdwEffect = (grfKeyState & MK_CONTROL) ?
397 				 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ):
398 				 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : DROPEFFECT_NONE );
399 	if (*pdwEffect == 0)
400 	{
401 	   // No modifier keys used by user while dragging.
402 	   if (DROPEFFECT_COPY & dwOKEffects)
403 		  *pdwEffect = DROPEFFECT_COPY;
404 	   else if (DROPEFFECT_MOVE & dwOKEffects)
405 		  *pdwEffect = DROPEFFECT_MOVE;
406 	   else if (DROPEFFECT_LINK & dwOKEffects)
407 		  *pdwEffect = DROPEFFECT_LINK;
408 	   else
409 	   {
410 		  *pdwEffect = DROPEFFECT_NONE;
411 	   }
412 	}
413 	else
414 	{
415 	   // Check if the drag source application allows the drop effect desired by user.
416 	   // The drag source specifies this in DoDragDrop
417 	   if (!(*pdwEffect & dwOKEffects))
418 		  *pdwEffect = DROPEFFECT_NONE;
419 	}
420 
421 	return (DROPEFFECT_NONE == *pdwEffect)?false:true;
422 }
423 
DragEnter(IDataObject __RPC_FAR * pDataObj,DWORD grfKeyState,POINTL pt,DWORD __RPC_FAR * pdwEffect)424 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragEnter(
425 	/* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
426 	/* [in] */ DWORD grfKeyState,
427 	/* [in] */ POINTL pt,
428 	/* [out][in] */ DWORD __RPC_FAR *pdwEffect)
429 {
430 	if (pDataObj == NULL)
431 		return E_INVALIDARG;
432 
433 	if (m_pDropTargetHelper)
434 		m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);
435 
436 	//IEnumFORMATETC* pEnum;
437 	//pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum);
438 	//FORMATETC ftm;
439 	//for()
440 	//pEnum->Next(1,&ftm,0);
441 	//pEnum->Release();
442 	m_pSupportedFrmt = NULL;
443 
444 	for(FormatArray::iterator it=m_formatetc.begin(); it!=m_formatetc.end(); ++it)
445 	{
446 		m_bAllowDrop = (pDataObj->QueryGetData(&*it) == S_OK)? true: false;
447 
448 		if (m_bAllowDrop)
449 		{
450 			m_pSupportedFrmt = &*it;
451 			break;
452 		}
453 	}
454 
455 	QueryDrop(grfKeyState, pdwEffect);
456 
457 	return S_OK;
458 }
459 
DragOver(DWORD grfKeyState,POINTL pt,DWORD __RPC_FAR * pdwEffect)460 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragOver(
461 		/* [in] */ DWORD grfKeyState,
462 		/* [in] */ POINTL pt,
463 		/* [out][in] */ DWORD __RPC_FAR *pdwEffect)
464 {
465 	if (m_pDropTargetHelper)
466 		m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
467 
468 	QueryDrop(grfKeyState, pdwEffect);
469 
470 	return S_OK;
471 }
472 
DragLeave()473 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragLeave()
474 {
475 	if (m_pDropTargetHelper)
476 		m_pDropTargetHelper->DragLeave();
477 
478 	m_bAllowDrop = false;
479 	m_pSupportedFrmt = NULL;
480 
481 	return S_OK;
482 }
483 
Drop(IDataObject __RPC_FAR * pDataObj,DWORD grfKeyState,POINTL pt,DWORD __RPC_FAR * pdwEffect)484 HRESULT STDMETHODCALLTYPE IDropTargetImpl::Drop(
485 	/* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
486 	/* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt,
487 	/* [out][in] */ DWORD __RPC_FAR *pdwEffect)
488 {
489 	if (pDataObj == NULL)
490 		return E_INVALIDARG;
491 
492 	if (m_pDropTargetHelper)
493 		m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);
494 
495 	if (QueryDrop(grfKeyState, pdwEffect))
496 	{
497 		if (m_bAllowDrop && m_pSupportedFrmt != NULL)
498 		{
499 			STGMEDIUM medium;
500 
501 			if (pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK)
502 			{
503 				if (OnDrop(m_pSupportedFrmt, medium, pdwEffect)) //does derive class wants us to free medium?
504 					ReleaseStgMedium(&medium);
505 			}
506 		}
507 	}
508 
509 	m_bAllowDrop = false;
510 	*pdwEffect = DROPEFFECT_NONE;
511 	m_pSupportedFrmt = NULL;
512 
513 	return S_OK;
514 }
515