Sync with trunk r63647.
[reactos.git] / dll / win32 / shell32 / dataobject.cpp
1 /*
2 * IEnumFORMATETC, IDataObject
3 *
4 * selecting and droping objects within the shell and/or common dialogs
5 *
6 * Copyright 1998, 1999 <juergen.schmied@metronet.de>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "precomp.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26
27 /***********************************************************************
28 * IEnumFORMATETC implementation
29 */
30
31 class IEnumFORMATETCImpl :
32 public CComObjectRootEx<CComMultiThreadModelNoCS>,
33 public IEnumFORMATETC
34 {
35 private:
36 UINT posFmt;
37 UINT countFmt;
38 LPFORMATETC pFmt;
39 public:
40 IEnumFORMATETCImpl();
41 ~IEnumFORMATETCImpl();
42 HRESULT WINAPI Initialize(UINT cfmt, const FORMATETC afmt[]);
43
44 // *****************
45 virtual HRESULT WINAPI Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed);
46 virtual HRESULT WINAPI Skip(ULONG celt);
47 virtual HRESULT WINAPI Reset();
48 virtual HRESULT WINAPI Clone(LPENUMFORMATETC* ppenum);
49
50 BEGIN_COM_MAP(IEnumFORMATETCImpl)
51 COM_INTERFACE_ENTRY_IID(IID_IEnumFORMATETC, IEnumFORMATETC)
52 END_COM_MAP()
53 };
54
55 IEnumFORMATETCImpl::IEnumFORMATETCImpl()
56 {
57 posFmt = 0;
58 countFmt = 0;
59 pFmt = NULL;
60 }
61
62 IEnumFORMATETCImpl::~IEnumFORMATETCImpl()
63 {
64 }
65
66 HRESULT WINAPI IEnumFORMATETCImpl::Initialize(UINT cfmt, const FORMATETC afmt[])
67 {
68 DWORD size;
69
70 size = cfmt * sizeof(FORMATETC);
71 countFmt = cfmt;
72 pFmt = (LPFORMATETC)SHAlloc(size);
73 if (pFmt == NULL)
74 return E_OUTOFMEMORY;
75
76 memcpy(pFmt, afmt, size);
77 return S_OK;
78 }
79
80 HRESULT WINAPI IEnumFORMATETCImpl::Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
81 {
82 UINT i;
83
84 TRACE("(%p)->(%u,%p)\n", this, celt, rgelt);
85
86 if(!pFmt)return S_FALSE;
87 if(!rgelt) return E_INVALIDARG;
88 if (pceltFethed) *pceltFethed = 0;
89
90 for(i = 0; posFmt < countFmt && celt > i; i++)
91 {
92 *rgelt++ = pFmt[posFmt++];
93 }
94
95 if (pceltFethed) *pceltFethed = i;
96
97 return ((i == celt) ? S_OK : S_FALSE);
98 }
99
100 HRESULT WINAPI IEnumFORMATETCImpl::Skip(ULONG celt)
101 {
102 TRACE("(%p)->(num=%u)\n", this, celt);
103
104 if (posFmt + celt >= countFmt) return S_FALSE;
105 posFmt += celt;
106 return S_OK;
107 }
108
109 HRESULT WINAPI IEnumFORMATETCImpl::Reset()
110 {
111 TRACE("(%p)->()\n", this);
112
113 posFmt = 0;
114 return S_OK;
115 }
116
117 HRESULT WINAPI IEnumFORMATETCImpl::Clone(LPENUMFORMATETC* ppenum)
118 {
119 HRESULT hResult;
120
121 TRACE("(%p)->(ppenum=%p)\n", this, ppenum);
122
123 if (!ppenum) return E_INVALIDARG;
124 hResult = IEnumFORMATETC_Constructor(countFmt, pFmt, ppenum);
125 if (FAILED (hResult))
126 return hResult;
127 return (*ppenum)->Skip(posFmt);
128 }
129
130 HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMATETC **enumerator)
131 {
132 CComObject<IEnumFORMATETCImpl> *theEnumerator;
133 CComPtr<IEnumFORMATETC> result;
134 HRESULT hResult;
135
136 if (enumerator == NULL)
137 return E_POINTER;
138 *enumerator = NULL;
139 ATLTRY (theEnumerator = new CComObject<IEnumFORMATETCImpl>);
140 if (theEnumerator == NULL)
141 return E_OUTOFMEMORY;
142 hResult = theEnumerator->QueryInterface (IID_PPV_ARG(IEnumFORMATETC, &result));
143 if (FAILED (hResult))
144 {
145 delete theEnumerator;
146 return hResult;
147 }
148 hResult = theEnumerator->Initialize (cfmt, afmt);
149 if (FAILED (hResult))
150 return hResult;
151 *enumerator = result.Detach ();
152 TRACE("(%p)->(%u,%p)\n", *enumerator, cfmt, afmt);
153 return S_OK;
154 }
155
156
157 /***********************************************************************
158 * IDataObject implementation
159 */
160
161 /* number of supported formats */
162 #define MAX_FORMATS 5
163
164 class IDataObjectImpl :
165 public CComObjectRootEx<CComMultiThreadModelNoCS>,
166 public IDataObject,
167 public IAsyncOperation
168 {
169 private:
170 LPITEMIDLIST pidl;
171 LPITEMIDLIST * apidl;
172 UINT cidl;
173 DWORD dropeffect;
174
175 FORMATETC pFormatEtc[MAX_FORMATS];
176 UINT cfShellIDList;
177 UINT cfFileNameA;
178 UINT cfFileNameW;
179 UINT cfPreferredDropEffect;
180 BOOL doasync;
181 public:
182 IDataObjectImpl();
183 ~IDataObjectImpl();
184 HRESULT WINAPI Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx);
185
186 ///////////
187 virtual HRESULT WINAPI GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium);
188 virtual HRESULT WINAPI GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium);
189 virtual HRESULT WINAPI QueryGetData(LPFORMATETC pformatetc);
190 virtual HRESULT WINAPI GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut);
191 virtual HRESULT WINAPI SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
192 virtual HRESULT WINAPI EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
193 virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
194 virtual HRESULT WINAPI DUnadvise(DWORD dwConnection);
195 virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
196 virtual HRESULT WINAPI GetAsyncMode(BOOL *pfIsOpAsync);
197 virtual HRESULT WINAPI InOperation(BOOL *pfInAsyncOp);
198 virtual HRESULT WINAPI SetAsyncMode(BOOL fDoOpAsync);
199 virtual HRESULT WINAPI StartOperation(IBindCtx *pbcReserved);
200 virtual HRESULT WINAPI EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
201
202 BEGIN_COM_MAP(IDataObjectImpl)
203 COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
204 COM_INTERFACE_ENTRY_IID(IID_IAsyncOperation, IAsyncOperation)
205 END_COM_MAP()
206 };
207
208 IDataObjectImpl::IDataObjectImpl()
209 {
210 pidl = NULL;
211 apidl = NULL;
212 cidl = 0;
213 dropeffect = 0;
214 cfShellIDList = 0;
215 cfFileNameA = 0;
216 cfFileNameW = 0;
217 cfPreferredDropEffect = 0;
218 doasync = FALSE;
219 }
220
221 IDataObjectImpl::~IDataObjectImpl()
222 {
223 TRACE(" destroying IDataObject(%p)\n",this);
224 _ILFreeaPidl(apidl, cidl);
225 ILFree(pidl);
226 }
227
228 HRESULT WINAPI IDataObjectImpl::Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx)
229 {
230 pidl = ILClone(pMyPidl);
231 apidl = _ILCopyaPidl(apidlx, cidlx);
232 if (pidl == NULL || apidl == NULL)
233 return E_OUTOFMEMORY;
234 cidl = cidlx;
235 dropeffect = DROPEFFECT_COPY;
236
237 cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
238 cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA);
239 cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW);
240 cfPreferredDropEffect = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW);
241 InitFormatEtc(pFormatEtc[0], cfShellIDList, TYMED_HGLOBAL);
242 InitFormatEtc(pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
243 InitFormatEtc(pFormatEtc[2], cfFileNameA, TYMED_HGLOBAL);
244 InitFormatEtc(pFormatEtc[3], cfFileNameW, TYMED_HGLOBAL);
245 InitFormatEtc(pFormatEtc[4], cfPreferredDropEffect, TYMED_HGLOBAL);
246 return S_OK;
247 }
248
249 /**************************************************************************
250 * IDataObject_fnGetData
251 */
252 HRESULT WINAPI IDataObjectImpl::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
253 {
254 char szTemp[256];
255
256 szTemp[0] = 0;
257 GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
258 TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
259
260 if (pformatetcIn->cfFormat == cfShellIDList)
261 {
262 if (cidl < 1) return(E_UNEXPECTED);
263 pmedium->hGlobal = RenderSHELLIDLIST(pidl, apidl, cidl);
264 }
265 else if (pformatetcIn->cfFormat == CF_HDROP)
266 {
267 if (cidl < 1) return(E_UNEXPECTED);
268 pmedium->hGlobal = RenderHDROP(pidl, apidl, cidl);
269 }
270 else if (pformatetcIn->cfFormat == cfFileNameA)
271 {
272 if (cidl < 1) return(E_UNEXPECTED);
273 pmedium->hGlobal = RenderFILENAMEA(pidl, apidl, cidl);
274 }
275 else if (pformatetcIn->cfFormat == cfFileNameW)
276 {
277 if (cidl < 1) return(E_UNEXPECTED);
278 pmedium->hGlobal = RenderFILENAMEW(pidl, apidl, cidl);
279 }
280 else if (pformatetcIn->cfFormat == cfPreferredDropEffect)
281 {
282 pmedium->hGlobal = RenderPREFEREDDROPEFFECT(dropeffect);
283 }
284 else
285 {
286 FIXME("-- expected clipformat not implemented\n");
287 return (E_INVALIDARG);
288 }
289 if (pmedium->hGlobal)
290 {
291 pmedium->tymed = TYMED_HGLOBAL;
292 pmedium->pUnkForRelease = NULL;
293 return S_OK;
294 }
295 return E_OUTOFMEMORY;
296 }
297
298 HRESULT WINAPI IDataObjectImpl::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium)
299 {
300 FIXME("(%p)->()\n", this);
301 return E_NOTIMPL;
302 }
303
304 HRESULT WINAPI IDataObjectImpl::QueryGetData(LPFORMATETC pformatetc)
305 {
306 UINT i;
307
308 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed);
309
310 if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
311 return DV_E_DVASPECT;
312
313 /* check our formats table what we have */
314 for (i=0; i<MAX_FORMATS; i++)
315 {
316 if ((pFormatEtc[i].cfFormat == pformatetc->cfFormat)
317 && (pFormatEtc[i].tymed == pformatetc->tymed))
318 {
319 return S_OK;
320 }
321 }
322
323 return DV_E_TYMED;
324 }
325
326 HRESULT WINAPI IDataObjectImpl::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
327 {
328 FIXME("(%p)->()\n", this);
329 return E_NOTIMPL;
330 }
331
332 HRESULT WINAPI IDataObjectImpl::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
333 {
334 if (pformatetc->cfFormat == cfPreferredDropEffect)
335 {
336 const DWORD *src = (const DWORD *)GlobalLock(pmedium->hGlobal);
337 if (src != 0)
338 {
339 dropeffect = *src;
340 GlobalUnlock(pmedium->hGlobal);
341 return S_OK;
342 }
343 FIXME("Error setting data");
344 return E_FAIL;
345 }
346
347 FIXME("(%p)->()\n", this);
348 return E_NOTIMPL;
349 }
350
351 HRESULT WINAPI IDataObjectImpl::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
352 {
353 TRACE("(%p)->()\n", this);
354 *ppenumFormatEtc = NULL;
355
356 /* only get data */
357 if (DATADIR_GET == dwDirection)
358 {
359 return IEnumFORMATETC_Constructor(MAX_FORMATS, pFormatEtc, ppenumFormatEtc);
360 }
361
362 return E_NOTIMPL;
363 }
364
365 HRESULT WINAPI IDataObjectImpl::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
366 {
367 FIXME("(%p)->()\n", this);
368 return E_NOTIMPL;
369 }
370
371 HRESULT WINAPI IDataObjectImpl::DUnadvise(DWORD dwConnection)
372 {
373 FIXME("(%p)->()\n", this);
374 return E_NOTIMPL;
375 }
376
377 HRESULT WINAPI IDataObjectImpl::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
378 {
379 FIXME("(%p)->()\n", this);
380 return E_NOTIMPL;
381 }
382
383 HRESULT WINAPI IDataObjectImpl::GetAsyncMode(BOOL *pfIsOpAsync)
384 {
385 TRACE("(%p)->()\n", this);
386 *pfIsOpAsync = doasync;
387 return S_OK;
388 }
389 HRESULT WINAPI IDataObjectImpl::InOperation(BOOL *pfInAsyncOp)
390 {
391 FIXME("(%p)->()\n", this);
392 return E_NOTIMPL;
393 }
394 HRESULT WINAPI IDataObjectImpl::SetAsyncMode(BOOL fDoOpAsync)
395 {
396 TRACE("(%p)->()\n", this);
397 doasync = fDoOpAsync;
398 return S_OK;
399 }
400
401 HRESULT WINAPI IDataObjectImpl::StartOperation(IBindCtx *pbcReserved)
402 {
403 FIXME("(%p)->()\n", this);
404 return E_NOTIMPL;
405 }
406 HRESULT WINAPI IDataObjectImpl::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
407 {
408 FIXME("(%p)->()\n", this);
409 return E_NOTIMPL;
410 }
411
412
413
414 /**************************************************************************
415 * IDataObject_Constructor
416 */
417 HRESULT IDataObject_Constructor(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidl, UINT cidl, IDataObject **dataObject)
418 {
419 CComObject<IDataObjectImpl> *theDataObject;
420 CComPtr<IDataObject> result;
421 HRESULT hResult;
422
423 if (dataObject == NULL)
424 return E_POINTER;
425 *dataObject = NULL;
426 ATLTRY (theDataObject = new CComObject<IDataObjectImpl>);
427 if (theDataObject == NULL)
428 return E_OUTOFMEMORY;
429 hResult = theDataObject->QueryInterface(IID_PPV_ARG(IDataObject, &result));
430 if (FAILED (hResult))
431 {
432 delete theDataObject;
433 return hResult;
434 }
435 hResult = theDataObject->Initialize (hwndOwner, pMyPidl, apidl, cidl);
436 if (FAILED (hResult))
437 return hResult;
438 *dataObject = result.Detach ();
439 TRACE("(%p)->(apidl=%p cidl=%u)\n", *dataObject, apidl, cidl);
440 return S_OK;
441 }
442
443 /*************************************************************************
444 * SHCreateDataObject [SHELL32.@]
445 *
446 */
447
448 HRESULT WINAPI SHCreateDataObject(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST* apidl, IDataObject *pdtInner, REFIID riid, void **ppv)
449 {
450 if (IsEqualIID(riid, IID_IDataObject))
451 {
452 return CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, (IDataObject **)ppv);
453 }
454 return E_FAIL;
455 }