b11e65af4c7d649d1342ecb6d010b115756cca5f
[reactos.git] / reactos / dll / win32 / shell32 / CIDLDataObj.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 **ppFormat)
131 {
132 return ShellObjectCreatorInit<IEnumFORMATETCImpl>(cfmt, afmt, IID_IEnumFORMATETC, ppFormat);
133 }
134
135
136 /***********************************************************************
137 * IDataObject implementation
138 */
139
140 /* number of supported formats */
141 #define MAX_FORMATS 5
142
143 class CIDLDataObj :
144 public CComObjectRootEx<CComMultiThreadModelNoCS>,
145 public IDataObject,
146 public IAsyncOperation
147 {
148 private:
149 LPITEMIDLIST pidl;
150 PIDLIST_RELATIVE *apidl;
151 UINT cidl;
152 DWORD dropeffect;
153
154 FORMATETC pFormatEtc[MAX_FORMATS];
155 UINT cfShellIDList;
156 UINT cfFileNameA;
157 UINT cfFileNameW;
158 UINT cfPreferredDropEffect;
159 BOOL doasync;
160 public:
161 CIDLDataObj();
162 ~CIDLDataObj();
163 HRESULT WINAPI Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidlx, UINT cidlx);
164
165 ///////////
166 virtual HRESULT WINAPI GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium);
167 virtual HRESULT WINAPI GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium);
168 virtual HRESULT WINAPI QueryGetData(LPFORMATETC pformatetc);
169 virtual HRESULT WINAPI GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut);
170 virtual HRESULT WINAPI SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
171 virtual HRESULT WINAPI EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
172 virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
173 virtual HRESULT WINAPI DUnadvise(DWORD dwConnection);
174 virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
175 virtual HRESULT WINAPI GetAsyncMode(BOOL *pfIsOpAsync);
176 virtual HRESULT WINAPI InOperation(BOOL *pfInAsyncOp);
177 virtual HRESULT WINAPI SetAsyncMode(BOOL fDoOpAsync);
178 virtual HRESULT WINAPI StartOperation(IBindCtx *pbcReserved);
179 virtual HRESULT WINAPI EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
180
181 BEGIN_COM_MAP(CIDLDataObj)
182 COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
183 COM_INTERFACE_ENTRY_IID(IID_IAsyncOperation, IAsyncOperation)
184 END_COM_MAP()
185 };
186
187 CIDLDataObj::CIDLDataObj()
188 {
189 pidl = NULL;
190 apidl = NULL;
191 cidl = 0;
192 dropeffect = 0;
193 cfShellIDList = 0;
194 cfFileNameA = 0;
195 cfFileNameW = 0;
196 cfPreferredDropEffect = 0;
197 doasync = FALSE;
198 }
199
200 CIDLDataObj::~CIDLDataObj()
201 {
202 TRACE(" destroying IDataObject(%p)\n",this);
203 _ILFreeaPidl(apidl, cidl);
204 ILFree(pidl);
205 }
206
207 HRESULT WINAPI CIDLDataObj::Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidlx, UINT cidlx)
208 {
209 pidl = ILClone(pMyPidl);
210 apidl = _ILCopyaPidl(apidlx, cidlx);
211 if (pidl == NULL || apidl == NULL)
212 return E_OUTOFMEMORY;
213 cidl = cidlx;
214 dropeffect = DROPEFFECT_COPY;
215
216 cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
217 cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA);
218 cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW);
219 cfPreferredDropEffect = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW);
220 InitFormatEtc(pFormatEtc[0], cfShellIDList, TYMED_HGLOBAL);
221 InitFormatEtc(pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
222 InitFormatEtc(pFormatEtc[2], cfFileNameA, TYMED_HGLOBAL);
223 InitFormatEtc(pFormatEtc[3], cfFileNameW, TYMED_HGLOBAL);
224 InitFormatEtc(pFormatEtc[4], cfPreferredDropEffect, TYMED_HGLOBAL);
225 return S_OK;
226 }
227
228 static HGLOBAL RenderPREFEREDDROPEFFECT (DWORD dwFlags)
229 {
230 DWORD * pdwFlag;
231 HGLOBAL hGlobal;
232
233 TRACE("(0x%08x)\n", dwFlags);
234
235 hGlobal = GlobalAlloc(GHND|GMEM_SHARE, sizeof(DWORD));
236 if(!hGlobal) return hGlobal;
237 pdwFlag = (DWORD*)GlobalLock(hGlobal);
238 *pdwFlag = dwFlags;
239 GlobalUnlock(hGlobal);
240 return hGlobal;
241 }
242
243 /**************************************************************************
244 * IDataObject_fnGetData
245 */
246 HRESULT WINAPI CIDLDataObj::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
247 {
248 char szTemp[256];
249
250 szTemp[0] = 0;
251 GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
252 TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
253
254 if (pformatetcIn->cfFormat == cfShellIDList)
255 {
256 if (cidl < 1) return(E_UNEXPECTED);
257 pmedium->hGlobal = RenderSHELLIDLIST(pidl, apidl, cidl);
258 }
259 else if (pformatetcIn->cfFormat == CF_HDROP)
260 {
261 if (cidl < 1) return(E_UNEXPECTED);
262 pmedium->hGlobal = RenderHDROP(pidl, apidl, cidl);
263 }
264 else if (pformatetcIn->cfFormat == cfFileNameA)
265 {
266 if (cidl < 1) return(E_UNEXPECTED);
267 pmedium->hGlobal = RenderFILENAMEA(pidl, apidl, cidl);
268 }
269 else if (pformatetcIn->cfFormat == cfFileNameW)
270 {
271 if (cidl < 1) return(E_UNEXPECTED);
272 pmedium->hGlobal = RenderFILENAMEW(pidl, apidl, cidl);
273 }
274 else if (pformatetcIn->cfFormat == cfPreferredDropEffect)
275 {
276 pmedium->hGlobal = RenderPREFEREDDROPEFFECT(dropeffect);
277 }
278 else
279 {
280 FIXME("-- expected clipformat not implemented\n");
281 return (E_INVALIDARG);
282 }
283 if (pmedium->hGlobal)
284 {
285 pmedium->tymed = TYMED_HGLOBAL;
286 pmedium->pUnkForRelease = NULL;
287 return S_OK;
288 }
289 return E_OUTOFMEMORY;
290 }
291
292 HRESULT WINAPI CIDLDataObj::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium)
293 {
294 FIXME("(%p)->()\n", this);
295 return E_NOTIMPL;
296 }
297
298 HRESULT WINAPI CIDLDataObj::QueryGetData(LPFORMATETC pformatetc)
299 {
300 UINT i;
301
302 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed);
303
304 if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
305 return DV_E_DVASPECT;
306
307 /* check our formats table what we have */
308 for (i=0; i<MAX_FORMATS; i++)
309 {
310 if ((pFormatEtc[i].cfFormat == pformatetc->cfFormat)
311 && (pFormatEtc[i].tymed == pformatetc->tymed))
312 {
313 return S_OK;
314 }
315 }
316
317 return DV_E_TYMED;
318 }
319
320 HRESULT WINAPI CIDLDataObj::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
321 {
322 FIXME("(%p)->()\n", this);
323 return E_NOTIMPL;
324 }
325
326 HRESULT WINAPI CIDLDataObj::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
327 {
328 if (pformatetc->cfFormat == cfPreferredDropEffect)
329 {
330 const DWORD *src = (const DWORD *)GlobalLock(pmedium->hGlobal);
331 if (src != 0)
332 {
333 dropeffect = *src;
334 GlobalUnlock(pmedium->hGlobal);
335 return S_OK;
336 }
337 FIXME("Error setting data");
338 return E_FAIL;
339 }
340
341 FIXME("(%p)->()\n", this);
342 return E_NOTIMPL;
343 }
344
345 HRESULT WINAPI CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
346 {
347 TRACE("(%p)->()\n", this);
348 *ppenumFormatEtc = NULL;
349
350 /* only get data */
351 if (DATADIR_GET == dwDirection)
352 {
353 return IEnumFORMATETC_Constructor(MAX_FORMATS, pFormatEtc, ppenumFormatEtc);
354 }
355
356 return E_NOTIMPL;
357 }
358
359 HRESULT WINAPI CIDLDataObj::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
360 {
361 FIXME("(%p)->()\n", this);
362 return E_NOTIMPL;
363 }
364
365 HRESULT WINAPI CIDLDataObj::DUnadvise(DWORD dwConnection)
366 {
367 FIXME("(%p)->()\n", this);
368 return E_NOTIMPL;
369 }
370
371 HRESULT WINAPI CIDLDataObj::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
372 {
373 FIXME("(%p)->()\n", this);
374 return E_NOTIMPL;
375 }
376
377 HRESULT WINAPI CIDLDataObj::GetAsyncMode(BOOL *pfIsOpAsync)
378 {
379 TRACE("(%p)->()\n", this);
380 *pfIsOpAsync = doasync;
381 return S_OK;
382 }
383 HRESULT WINAPI CIDLDataObj::InOperation(BOOL *pfInAsyncOp)
384 {
385 FIXME("(%p)->()\n", this);
386 return E_NOTIMPL;
387 }
388 HRESULT WINAPI CIDLDataObj::SetAsyncMode(BOOL fDoOpAsync)
389 {
390 TRACE("(%p)->()\n", this);
391 doasync = fDoOpAsync;
392 return S_OK;
393 }
394
395 HRESULT WINAPI CIDLDataObj::StartOperation(IBindCtx *pbcReserved)
396 {
397 FIXME("(%p)->()\n", this);
398 return E_NOTIMPL;
399 }
400 HRESULT WINAPI CIDLDataObj::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
401 {
402 FIXME("(%p)->()\n", this);
403 return E_NOTIMPL;
404 }
405
406
407
408 /**************************************************************************
409 * IDataObject_Constructor
410 */
411 HRESULT IDataObject_Constructor(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidl, UINT cidl, IDataObject **dataObject)
412 {
413 return ShellObjectCreatorInit<CIDLDataObj>(hwndOwner, pMyPidl, apidl, cidl, IID_IDataObject, dataObject);
414 }
415
416 /*************************************************************************
417 * SHCreateDataObject [SHELL32.@]
418 *
419 */
420
421 HRESULT WINAPI SHCreateDataObject(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, IDataObject *pdtInner, REFIID riid, void **ppv)
422 {
423 if (IsEqualIID(riid, IID_IDataObject))
424 {
425 return CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, (IDataObject **)ppv);
426 }
427 return E_FAIL;
428 }