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