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