SHGetFileInfo should tolerate null pointers.
[wine] / dlls / shell32 / dataobject.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 #include <string.h>
23
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "pidl.h"
27 #include "winerror.h"
28 #include "shell32_main.h"
29 #include "wine/debug.h"
30 #include "undocshell.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(shell);
33
34 /***********************************************************************
35 *   IEnumFORMATETC implementation
36 */
37
38 typedef struct
39 {
40     /* IUnknown fields */
41     ICOM_VFIELD(IEnumFORMATETC);
42     DWORD                        ref;
43     /* IEnumFORMATETC fields */
44     UINT        posFmt;
45     UINT        countFmt;
46     LPFORMATETC pFmt;
47 } IEnumFORMATETCImpl;
48
49 static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj);
50 static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface);
51 static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface);
52 static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC* rgelt, ULONG* pceltFethed);
53 static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt);
54 static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface);
55 static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);
56
57 static struct ICOM_VTABLE(IEnumFORMATETC) efvt =
58 {
59     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
60         IEnumFORMATETC_fnQueryInterface,
61         IEnumFORMATETC_fnAddRef,
62     IEnumFORMATETC_fnRelease,
63     IEnumFORMATETC_fnNext,
64     IEnumFORMATETC_fnSkip,
65     IEnumFORMATETC_fnReset,
66     IEnumFORMATETC_fnClone
67 };
68
69 LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[])
70 {
71         IEnumFORMATETCImpl* ef;
72         DWORD size=cfmt * sizeof(FORMATETC);
73
74         ef=(IEnumFORMATETCImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl));
75
76         if(ef)
77         {
78           ef->ref=1;
79           ef->lpVtbl=&efvt;
80
81           ef->countFmt = cfmt;
82           ef->pFmt = SHAlloc (size);
83
84           if (ef->pFmt)
85           {
86             memcpy(ef->pFmt, afmt, size);
87           }
88         }
89
90         TRACE("(%p)->(%u,%p)\n",ef, cfmt, afmt);
91         return (LPENUMFORMATETC)ef;
92 }
93
94 static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
95 {
96         ICOM_THIS(IEnumFORMATETCImpl,iface);
97         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
98
99         *ppvObj = NULL;
100
101         if(IsEqualIID(riid, &IID_IUnknown))
102         {
103           *ppvObj = This;
104         }
105         else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
106         {
107           *ppvObj = (IEnumFORMATETC*)This;
108         }
109
110         if(*ppvObj)
111         {
112           IUnknown_AddRef((IUnknown*)(*ppvObj));
113           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
114           return S_OK;
115         }
116         TRACE("-- Interface: E_NOINTERFACE\n");
117         return E_NOINTERFACE;
118
119 }
120
121 static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface)
122 {
123         ICOM_THIS(IEnumFORMATETCImpl,iface);
124         TRACE("(%p)->(count=%lu)\n",This, This->ref);
125         return ++(This->ref);
126 }
127
128 static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface)
129 {
130         ICOM_THIS(IEnumFORMATETCImpl,iface);
131         TRACE("(%p)->()\n",This);
132
133         if (!--(This->ref))
134         {
135           TRACE(" destroying IEnumFORMATETC(%p)\n",This);
136           if (This->pFmt)
137           {
138             SHFree (This->pFmt);
139           }
140           HeapFree(GetProcessHeap(),0,This);
141           return 0;
142         }
143         return This->ref;
144 }
145
146 static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
147 {
148         ICOM_THIS(IEnumFORMATETCImpl,iface);
149         UINT i;
150
151         TRACE("(%p)->(%lu,%p)\n", This, celt, rgelt);
152
153         if(!This->pFmt)return S_FALSE;
154         if(!rgelt) return E_INVALIDARG;
155         if (pceltFethed)  *pceltFethed = 0;
156
157         for(i = 0; This->posFmt < This->countFmt && celt > i; i++)
158         {
159           *rgelt++ = This->pFmt[This->posFmt++];
160         }
161
162         if (pceltFethed) *pceltFethed = i;
163
164         return ((i == celt) ? S_OK : S_FALSE);
165 }
166
167 static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt)
168 {
169         ICOM_THIS(IEnumFORMATETCImpl,iface);
170         TRACE("(%p)->(num=%lu)\n", This, celt);
171
172         if((This->posFmt + celt) >= This->countFmt) return S_FALSE;
173         This->posFmt += celt;
174         return S_OK;
175 }
176
177 static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface)
178 {
179         ICOM_THIS(IEnumFORMATETCImpl,iface);
180         TRACE("(%p)->()\n", This);
181
182         This->posFmt = 0;
183         return S_OK;
184 }
185
186 static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
187 {
188         ICOM_THIS(IEnumFORMATETCImpl,iface);
189         TRACE("(%p)->(ppenum=%p)\n", This, ppenum);
190
191         if (!ppenum) return E_INVALIDARG;
192         *ppenum = IEnumFORMATETC_Constructor(This->countFmt, This->pFmt);
193         if(*ppenum)
194            IEnumFORMATETC_fnSkip(*ppenum, This->posFmt);
195         return S_OK;
196 }
197
198
199 /***********************************************************************
200 *   IDataObject implementation
201 */
202
203 /* number of supported formats */
204 #define MAX_FORMATS 3
205
206 typedef struct
207 {
208         /* IUnknown fields */
209         ICOM_VFIELD(IDataObject);
210         DWORD           ref;
211
212         /* IDataObject fields */
213         LPITEMIDLIST    pidl;
214         LPITEMIDLIST *  apidl;
215         UINT            cidl;
216
217         FORMATETC       pFormatEtc[MAX_FORMATS];
218         UINT            cfShellIDList;
219         UINT            cfFileName;
220
221 } IDataObjectImpl;
222
223 static struct ICOM_VTABLE(IDataObject) dtovt;
224
225 /**************************************************************************
226 *  IDataObject_Constructor
227 */
228 LPDATAOBJECT IDataObject_Constructor(HWND hwndOwner, LPITEMIDLIST pMyPidl, LPITEMIDLIST * apidl, UINT cidl)
229 {
230         IDataObjectImpl* dto;
231
232         dto = (IDataObjectImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDataObjectImpl));
233
234         if (dto)
235         {
236           dto->ref = 1;
237           dto->lpVtbl = &dtovt;
238           dto->pidl = ILClone(pMyPidl);
239           dto->apidl = _ILCopyaPidl(apidl, cidl);
240           dto->cidl = cidl;
241
242           dto->cfShellIDList = RegisterClipboardFormatA(CFSTR_SHELLIDLIST);
243           dto->cfFileName = RegisterClipboardFormatA(CFSTR_FILENAMEA);
244           InitFormatEtc(dto->pFormatEtc[0], dto->cfShellIDList, TYMED_HGLOBAL);
245           InitFormatEtc(dto->pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
246           InitFormatEtc(dto->pFormatEtc[2], dto->cfFileName, TYMED_HGLOBAL);
247         }
248
249         TRACE("(%p)->(apidl=%p cidl=%u)\n",dto, apidl, cidl);
250         return (LPDATAOBJECT)dto;
251 }
252
253 /***************************************************************************
254 *  IDataObject_QueryInterface
255 */
256 static HRESULT WINAPI IDataObject_fnQueryInterface(LPDATAOBJECT iface, REFIID riid, LPVOID * ppvObj)
257 {
258         ICOM_THIS(IDataObjectImpl,iface);
259         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
260
261         *ppvObj = NULL;
262
263         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
264         {
265           *ppvObj = This;
266         }
267         else if(IsEqualIID(riid, &IID_IDataObject))  /*IDataObject*/
268         {
269           *ppvObj = (IDataObject*)This;
270         }
271
272         if(*ppvObj)
273         {
274           IUnknown_AddRef((IUnknown*)*ppvObj);
275           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
276           return S_OK;
277         }
278         TRACE("-- Interface: E_NOINTERFACE\n");
279         return E_NOINTERFACE;
280 }
281
282 /**************************************************************************
283 *  IDataObject_AddRef
284 */
285 static ULONG WINAPI IDataObject_fnAddRef(LPDATAOBJECT iface)
286 {
287         ICOM_THIS(IDataObjectImpl,iface);
288         TRACE("(%p)->(count=%lu)\n",This, This->ref);
289         return ++(This->ref);
290 }
291
292 /**************************************************************************
293 *  IDataObject_Release
294 */
295 static ULONG WINAPI IDataObject_fnRelease(LPDATAOBJECT iface)
296 {
297         ICOM_THIS(IDataObjectImpl,iface);
298         TRACE("(%p)->()\n",This);
299
300         if (!--(This->ref))
301         {
302           TRACE(" destroying IDataObject(%p)\n",This);
303           _ILFreeaPidl(This->apidl, This->cidl);
304           ILFree(This->pidl),
305           HeapFree(GetProcessHeap(),0,This);
306           return 0;
307         }
308         return This->ref;
309 }
310
311 /**************************************************************************
312 * IDataObject_fnGetData
313 */
314 static HRESULT WINAPI IDataObject_fnGetData(LPDATAOBJECT iface, LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
315 {
316         ICOM_THIS(IDataObjectImpl,iface);
317
318         char    szTemp[256];
319
320         szTemp[0]=0;
321         GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
322         TRACE("(%p)->(%p %p format=%s)\n", This, pformatetcIn, pmedium, szTemp);
323
324         if (pformatetcIn->cfFormat == This->cfShellIDList)
325         {
326           if (This->cidl < 1) return(E_UNEXPECTED);
327           pmedium->u.hGlobal = RenderSHELLIDLIST(This->pidl, This->apidl, This->cidl);
328         }
329         else if (pformatetcIn->cfFormat == CF_HDROP)
330         {
331           if (This->cidl < 1) return(E_UNEXPECTED);
332           pmedium->u.hGlobal = RenderHDROP(This->pidl, This->apidl, This->cidl);
333         }
334         else if (pformatetcIn->cfFormat == This->cfFileName)
335         {
336           if (This->cidl < 1) return(E_UNEXPECTED);
337           pmedium->u.hGlobal = RenderFILENAME(This->pidl, This->apidl, This->cidl);
338         }
339         else
340         {
341           FIXME("-- expected clipformat not implemented\n");
342           return (E_INVALIDARG);
343         }
344         if (pmedium->u.hGlobal)
345         {
346           pmedium->tymed = TYMED_HGLOBAL;
347           pmedium->pUnkForRelease = NULL;
348           return S_OK;
349         }
350         return E_OUTOFMEMORY;
351 }
352
353 static HRESULT WINAPI IDataObject_fnGetDataHere(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium)
354 {
355         ICOM_THIS(IDataObjectImpl,iface);
356         FIXME("(%p)->()\n", This);
357         return E_NOTIMPL;
358 }
359
360 static HRESULT WINAPI IDataObject_fnQueryGetData(LPDATAOBJECT iface, LPFORMATETC pformatetc)
361 {
362         ICOM_THIS(IDataObjectImpl,iface);
363         UINT i;
364
365         TRACE("(%p)->(fmt=0x%08x tym=0x%08lx)\n", This, pformatetc->cfFormat, pformatetc->tymed);
366
367         if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
368           return DV_E_DVASPECT;
369
370         /* check our formats table what we have */
371         for (i=0; i<MAX_FORMATS; i++)
372         {
373           if ((This->pFormatEtc[i].cfFormat == pformatetc->cfFormat)
374            && (This->pFormatEtc[i].tymed == pformatetc->tymed))
375           {
376             return S_OK;
377           }
378         }
379
380         return DV_E_TYMED;
381 }
382
383 static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(LPDATAOBJECT iface, LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
384 {
385         ICOM_THIS(IDataObjectImpl,iface);
386         FIXME("(%p)->()\n", This);
387         return E_NOTIMPL;
388 }
389
390 static HRESULT WINAPI IDataObject_fnSetData(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
391 {
392         ICOM_THIS(IDataObjectImpl,iface);
393         FIXME("(%p)->()\n", This);
394         return E_NOTIMPL;
395 }
396
397 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(LPDATAOBJECT iface, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
398 {
399         ICOM_THIS(IDataObjectImpl,iface);
400
401         TRACE("(%p)->()\n", This);
402         *ppenumFormatEtc=NULL;
403
404         /* only get data */
405         if (DATADIR_GET == dwDirection)
406         {
407           *ppenumFormatEtc = IEnumFORMATETC_Constructor(MAX_FORMATS, This->pFormatEtc);
408           return (*ppenumFormatEtc) ? S_OK : E_FAIL;
409         }
410
411         return E_NOTIMPL;
412 }
413
414 static HRESULT WINAPI IDataObject_fnDAdvise(LPDATAOBJECT iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
415 {
416         ICOM_THIS(IDataObjectImpl,iface);
417         FIXME("(%p)->()\n", This);
418         return E_NOTIMPL;
419 }
420 static HRESULT WINAPI IDataObject_fnDUnadvise(LPDATAOBJECT iface, DWORD dwConnection)
421 {
422         ICOM_THIS(IDataObjectImpl,iface);
423         FIXME("(%p)->()\n", This);
424         return E_NOTIMPL;
425 }
426 static HRESULT WINAPI IDataObject_fnEnumDAdvise(LPDATAOBJECT iface, IEnumSTATDATA **ppenumAdvise)
427 {
428         ICOM_THIS(IDataObjectImpl,iface);
429         FIXME("(%p)->()\n", This);
430         return E_NOTIMPL;
431 }
432
433 static struct ICOM_VTABLE(IDataObject) dtovt =
434 {
435         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
436         IDataObject_fnQueryInterface,
437         IDataObject_fnAddRef,
438         IDataObject_fnRelease,
439         IDataObject_fnGetData,
440         IDataObject_fnGetDataHere,
441         IDataObject_fnQueryGetData,
442         IDataObject_fnGetCanonicalFormatEtc,
443         IDataObject_fnSetData,
444         IDataObject_fnEnumFormatEtc,
445         IDataObject_fnDAdvise,
446         IDataObject_fnDUnadvise,
447         IDataObject_fnEnumDAdvise
448 };