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