Delete all Trailing spaces in code.
[reactos.git] / reactos / base / shell / explorer / utility / dragdropimpl.cpp
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
24 IDataObjectImpl::IDataObjectImpl(IDropSourceImpl* pDropSource)
25 : super(IID_IDataObject),
26 m_pDropSource(pDropSource),
27 m_cRefCount(0)
28 {
29 }
30
31 IDataObjectImpl::~IDataObjectImpl()
32 {
33 for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it)
34 ReleaseStgMedium(it->_medium);
35 }
36
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
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
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
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
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
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
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
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
212 STDMETHODIMP IDataObjectImpl::DUnadvise(
213 /* [in] */ DWORD dwConnection)
214 {
215 return E_NOTIMPL;
216 }
217
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
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
244 STDMETHODIMP IDropSourceImpl::GiveFeedback(
245 /* [in] */ DWORD dwEffect)
246 {
247 return DRAGDROP_S_USEDEFAULTCURSORS;
248 }
249
250 //////////////////////////////////////////////////////////////////////
251 // EnumFormatEtcImpl Class
252 //////////////////////////////////////////////////////////////////////
253
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
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
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
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
305 STDMETHODIMP EnumFormatEtcImpl::Reset(void)
306 {
307 m_iCur = 0;
308 return S_OK;
309 }
310
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 //////////////////////////////////////////////////////////////////////
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
345 IDropTargetImpl::~IDropTargetImpl()
346 {
347 if (m_pDropTargetHelper != NULL)
348 {
349 m_pDropTargetHelper->Release();
350 m_pDropTargetHelper = NULL;
351 }
352 }
353
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
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
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
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
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
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
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 }