More include optimisations and fixes.
[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  <juergen.schmied@metronet.de>
7  */
8 #include <string.h>
9
10 #include "wine/obj_dataobject.h"
11 #include "pidl.h"
12 #include "winerror.h"
13 #include "shell32_main.h"
14 #include "debug.h"
15
16 UINT cfShellIDList=0;
17 UINT cfFileGroupDesc=0;
18 UINT cfFileContents=0;
19
20 /***********************************************************************
21 *   IEnumFORMATETC implementation
22 */
23 typedef struct 
24 {
25     /* IUnknown fields */
26     ICOM_VTABLE(IEnumFORMATETC)* lpvtbl;
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         IEnumFORMATETC_fnQueryInterface,
45         IEnumFORMATETC_fnAddRef,
46     IEnumFORMATETC_fnRelease,
47     IEnumFORMATETC_fnNext,
48     IEnumFORMATETC_fnSkip,
49     IEnumFORMATETC_fnReset,
50     IEnumFORMATETC_fnClone
51 };
52
53 LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[])
54 {
55         IEnumFORMATETCImpl* ef;
56         DWORD size=cfmt * sizeof(FORMATETC);
57         
58         ef=(IEnumFORMATETCImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IEnumFORMATETCImpl));
59         ef->ref=1;
60         ef->lpvtbl=&efvt;
61
62         ef->posFmt = 0;
63         ef->countFmt = cfmt;
64         ef->pFmt = SHAlloc (size);
65
66         if (ef->pFmt)
67         { memcpy(ef->pFmt, afmt, size);
68         }
69
70         TRACE(shell,"(%p)->()\n",ef);
71         shell32_ObjCount++;
72         return (LPENUMFORMATETC)ef;
73 }
74 static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
75 {
76         ICOM_THIS(IEnumFORMATETCImpl,iface);
77         char    xriid[50];
78         WINE_StringFromCLSID((LPCLSID)riid,xriid);
79         TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
80
81                         *ppvObj = NULL;
82
83         if(IsEqualIID(riid, &IID_IUnknown))
84         { *ppvObj = This; 
85         }
86         else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
87         { *ppvObj = (IDataObject*)This;
88         }   
89
90         if(*ppvObj)
91         { IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
92           TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
93           return S_OK;
94         }
95         TRACE(shell,"-- Interface: E_NOINTERFACE\n");
96         return E_NOINTERFACE;
97
98 }
99 static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface)
100 {
101         ICOM_THIS(IEnumFORMATETCImpl,iface);
102         TRACE(shell,"(%p)->(count=%lu)\n",This,(This->ref)+1);
103         shell32_ObjCount++;
104         return ++(This->ref);
105 }
106 static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface)
107 {
108         ICOM_THIS(IEnumFORMATETCImpl,iface);
109         TRACE(shell,"(%p)->()\n",This);
110
111         shell32_ObjCount--;
112
113         if (!--(This->ref)) 
114         { TRACE(shell," destroying IEnumFORMATETC(%p)\n",This);
115           if (This->pFmt)
116           { SHFree (This->pFmt);
117           }
118           HeapFree(GetProcessHeap(),0,This);
119           return 0;
120         }
121         return This->ref;
122 }
123 static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
124 {
125         ICOM_THIS(IEnumFORMATETCImpl,iface);
126         UINT cfetch;
127         HRESULT hres = S_FALSE;
128
129         TRACE (shell, "(%p)->()\n", This);
130
131         if (This->posFmt < This->countFmt)
132         { cfetch = This->countFmt - This->posFmt;
133           if (cfetch >= celt)
134           { cfetch = celt;
135             hres = S_OK;
136           }
137           memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));
138           This->posFmt += cfetch;
139         }
140         else
141         { cfetch = 0;
142         }
143
144         if (pceltFethed)
145         { *pceltFethed = cfetch;
146         }
147
148         return hres;
149 }
150 static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt)
151 {
152         ICOM_THIS(IEnumFORMATETCImpl,iface);
153         FIXME (shell, "(%p)->(num=%lu)\n", This, celt);
154
155         This->posFmt += celt;
156         if (This->posFmt > This->countFmt)
157         { This->posFmt = This->countFmt;
158           return S_FALSE;
159         }
160         return S_OK;
161 }
162 static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface)
163 {
164         ICOM_THIS(IEnumFORMATETCImpl,iface);
165         FIXME (shell, "(%p)->()\n", This);
166
167         This->posFmt = 0;
168         return S_OK;
169 }
170 static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
171 {
172         ICOM_THIS(IEnumFORMATETCImpl,iface);
173         FIXME (shell, "(%p)->(ppenum=%p)\n", This, ppenum);
174         return E_NOTIMPL;
175 }
176
177 /***********************************************************************
178 *   IDataObject implementation
179 */
180 typedef struct
181 {
182     /* IUnknown fields */
183     ICOM_VTABLE(IDataObject)* lpvtbl;
184     DWORD                     ref;
185     /* IDataObject fields */
186     LPSHELLFOLDER psf;
187     LPIDLLIST     lpill;       /* the data of the dataobject */
188     LPITEMIDLIST  pidl;     
189 } IDataObjectImpl;
190
191 static HRESULT WINAPI IDataObject_fnQueryInterface(LPDATAOBJECT iface, REFIID riid, LPVOID* ppvObj);
192 static ULONG WINAPI IDataObject_fnAddRef(LPDATAOBJECT iface);
193 static ULONG WINAPI IDataObject_fnRelease(LPDATAOBJECT iface);
194 static HRESULT WINAPI IDataObject_fnGetData(LPDATAOBJECT iface, LPFORMATETC pformatetcIn, STGMEDIUM* pmedium);
195 static HRESULT WINAPI IDataObject_fnGetDataHere(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM* pmedium);
196 static HRESULT WINAPI IDataObject_fnQueryGetData(LPDATAOBJECT iface, LPFORMATETC pformatetc);
197 static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(LPDATAOBJECT iface, LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut);
198 static HRESULT WINAPI IDataObject_fnSetData(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM* pmedium, BOOL fRelease);
199 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(LPDATAOBJECT iface, DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc);
200 static HRESULT WINAPI IDataObject_fnDAdvise(LPDATAOBJECT iface, LPFORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD* pdwConnection);
201 static HRESULT WINAPI IDataObject_fnDUnadvise(LPDATAOBJECT iface, DWORD dwConnection);
202 static HRESULT WINAPI IDataObject_fnEnumDAdvise(LPDATAOBJECT iface, IEnumSTATDATA **ppenumAdvise);
203
204 static struct ICOM_VTABLE(IDataObject) dtovt = 
205 {
206         IDataObject_fnQueryInterface,
207         IDataObject_fnAddRef,
208     IDataObject_fnRelease,
209     IDataObject_fnGetData,
210     IDataObject_fnGetDataHere,
211     IDataObject_fnQueryGetData,
212     IDataObject_fnGetCanonicalFormatEtc,
213     IDataObject_fnSetData,
214     IDataObject_fnEnumFormatEtc,
215     IDataObject_fnDAdvise,
216     IDataObject_fnDUnadvise,
217     IDataObject_fnEnumDAdvise
218 };
219
220 /**************************************************************************
221 *  IDataObject_Constructor
222 */
223 LPDATAOBJECT IDataObject_Constructor(HWND hwndOwner, LPSHELLFOLDER psf, LPITEMIDLIST * apidl, UINT cidl)
224 {
225         IDataObjectImpl* dto;
226         if (!(dto = (IDataObjectImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDataObjectImpl))))
227           return NULL;
228           
229         dto->ref=1;
230         dto->lpvtbl=&dtovt;
231         dto->psf=psf;
232         dto->pidl=ILClone(psf->mpidl); /* FIXME:add a reference and don't copy*/
233
234         /* fill the ItemID List List */
235         dto->lpill = IDLList_Constructor (8);
236         if (! dto->lpill )
237           return NULL;
238           
239         dto->lpill->lpvtbl->fnAddItems(dto->lpill, apidl, cidl); 
240         
241         TRACE(shell,"(%p)->(sf=%p apidl=%p cidl=%u)\n",dto, psf, apidl, cidl);
242         shell32_ObjCount++;
243         return (LPDATAOBJECT)dto;
244 }
245 /***************************************************************************
246 *  IDataObject_QueryInterface
247 */
248 static HRESULT WINAPI IDataObject_fnQueryInterface(LPDATAOBJECT iface, REFIID riid, LPVOID * ppvObj)
249 {
250         ICOM_THIS(IDataObjectImpl,iface);
251         char    xriid[50];
252         WINE_StringFromCLSID((LPCLSID)riid,xriid);
253         TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
254
255         *ppvObj = NULL;
256
257         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
258         { *ppvObj = This; 
259         }
260         else if(IsEqualIID(riid, &IID_IDataObject))  /*IDataObject*/
261         { *ppvObj = (IDataObject*)This;
262         }   
263
264         if(*ppvObj)
265         { IDataObject_AddRef((IDataObject*)*ppvObj);      
266           TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
267           return S_OK;
268         }
269         TRACE(shell,"-- Interface: E_NOINTERFACE\n");
270         return E_NOINTERFACE;
271 }   
272 /**************************************************************************
273 *  IDataObject_AddRef
274 */
275 static ULONG WINAPI IDataObject_fnAddRef(LPDATAOBJECT iface)
276 {
277         ICOM_THIS(IDataObjectImpl,iface);
278
279         TRACE(shell,"(%p)->(count=%lu)\n",This,(This->ref)+1);
280
281         shell32_ObjCount++;
282         return ++(This->ref);
283 }
284 /**************************************************************************
285 *  IDataObject_Release
286 */
287 static ULONG WINAPI IDataObject_fnRelease(LPDATAOBJECT iface)
288 {
289         ICOM_THIS(IDataObjectImpl,iface);
290         TRACE(shell,"(%p)->()\n",This);
291
292         shell32_ObjCount--;
293
294         if (!--(This->ref)) 
295         { TRACE(shell," destroying IDataObject(%p)\n",This);
296           IDLList_Destructor(This->lpill);
297           HeapFree(GetProcessHeap(),0,This);
298           return 0;
299         }
300         return This->ref;
301 }
302 /**************************************************************************
303 * DATAOBJECT_InitShellIDList (internal)
304 *
305 * NOTES
306 *  get or register the "Shell IDList Array" clipformat
307 */
308 static BOOL DATAOBJECT_InitShellIDList(void)
309 {       if (cfShellIDList)
310         { return(TRUE);
311         }
312
313         cfShellIDList = RegisterClipboardFormatA(CFSTR_SHELLIDLIST);
314         return(cfShellIDList != 0);
315 }
316
317 /**************************************************************************
318 * DATAOBJECT_InitFileGroupDesc (internal)
319 *
320 * NOTES
321 *  get or register the "FileGroupDescriptor" clipformat
322 */
323 /* FIXME: DATAOBJECT_InitFileGroupDesc is not used (19981226)
324 static BOOL32 DATAOBJECT_InitFileGroupDesc(void)
325 {       if (cfFileGroupDesc)
326         { return(TRUE);
327         }
328
329         cfFileGroupDesc = RegisterClipboardFormat32A(CFSTR_FILEDESCRIPTORA);
330         return(cfFileGroupDesc != 0);
331 }
332 */
333 /**************************************************************************
334 * DATAOBJECT_InitFileContents (internal)
335
336 * NOTES
337  * get or register the "FileContents" clipformat
338 */
339 /* FIXME: DATAOBJECT_InitFileContents is not used (19981226)
340 static BOOL32 DATAOBJECT_InitFileContents(void)
341 {       if (cfFileContents)
342         { return(TRUE);
343         }
344
345         cfFileContents = RegisterClipboardFormat32A(CFSTR_FILECONTENTS);
346         return(cfFileContents != 0);
347 }
348 */
349
350 /**************************************************************************
351 * interface implementation
352 */
353 static HRESULT WINAPI IDataObject_fnGetData(LPDATAOBJECT iface, LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
354 {
355         ICOM_THIS(IDataObjectImpl,iface);
356         char    temp[256];
357         UINT    cItems;
358         DWORD   size, size1, size2;
359         LPITEMIDLIST pidl;
360         LPCIDA pcida;
361         HGLOBAL hmem;
362         
363         GetClipboardFormatNameA (pformatetcIn->cfFormat, temp, 256);
364         WARN (shell, "(%p)->(%p %p format=%s)semi-stub\n", This, pformatetcIn, pmedium, temp);
365
366         if (!DATAOBJECT_InitShellIDList())      /* is the clipformat registred? */
367         { return(E_UNEXPECTED);
368         }
369         
370         if (pformatetcIn->cfFormat == cfShellIDList)
371         { if (pformatetcIn->ptd==NULL 
372                 && (pformatetcIn->dwAspect & DVASPECT_CONTENT) 
373                 && pformatetcIn->lindex==-1
374                 && (pformatetcIn->tymed&TYMED_HGLOBAL))
375           { cItems = This->lpill->lpvtbl->fnGetCount(This->lpill);
376             if (cItems < 1)
377             { return(E_UNEXPECTED);
378             }
379             pidl = This->lpill->lpvtbl->fnGetElement(This->lpill, 0);
380
381             pdump(This->pidl);
382             pdump(pidl);
383             
384             /*hack consider only the first item*/
385             cItems = 2;
386             size = sizeof(CIDA) + sizeof (UINT)*(cItems-1);
387             size1 = ILGetSize (This->pidl);
388             size2 = ILGetSize (pidl);
389             hmem = GlobalAlloc(GMEM_FIXED, size+size1+size2);
390             pcida = GlobalLock (hmem);
391             if (!pcida)
392             { return(E_OUTOFMEMORY);
393             }
394
395             pcida->cidl = 1;
396             pcida->aoffset[0] = size;
397             pcida->aoffset[1] = size+size1;
398
399             TRACE(shell,"-- %lu %lu %lu\n",size, size1, size2 );
400             TRACE(shell,"-- %p %p\n",This->pidl, pidl);
401             TRACE(shell,"-- %p %p %p\n",pcida, (LPBYTE)pcida+size,(LPBYTE)pcida+size+size1);
402             
403             memcpy ((LPBYTE)pcida+size, This->pidl, size1);
404             memcpy ((LPBYTE)pcida+size+size1, pidl, size2);
405             TRACE(shell,"-- after copy\n");
406
407             GlobalUnlock(hmem);
408             
409             pmedium->tymed = TYMED_HGLOBAL;
410             pmedium->u.hGlobal = (HGLOBAL)pcida;
411             pmedium->pUnkForRelease = NULL;
412             TRACE(shell,"-- ready\n");
413             return(NOERROR);
414           }
415         }
416         FIXME (shell, "-- clipformat not implemented\n");
417         return (E_INVALIDARG);
418 }
419 static HRESULT WINAPI IDataObject_fnGetDataHere(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium)
420 {
421         ICOM_THIS(IDataObjectImpl,iface);
422         FIXME (shell, "(%p)->()\n", This);
423         return E_NOTIMPL;
424 }
425 static HRESULT WINAPI IDataObject_fnQueryGetData(LPDATAOBJECT iface, LPFORMATETC pformatetc)
426 {
427         ICOM_THIS(IDataObjectImpl,iface);
428         FIXME (shell, "(%p)->()\n", This);
429         return E_NOTIMPL;
430 }
431 static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(LPDATAOBJECT iface, LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
432 {
433         ICOM_THIS(IDataObjectImpl,iface);
434         FIXME (shell, "(%p)->()\n", This);
435         return E_NOTIMPL;
436 }
437 static HRESULT WINAPI IDataObject_fnSetData(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
438 {
439         ICOM_THIS(IDataObjectImpl,iface);
440         FIXME (shell, "(%p)->()\n", This);
441         return E_NOTIMPL;
442 }
443 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(LPDATAOBJECT iface, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
444 {
445         ICOM_THIS(IDataObjectImpl,iface);
446         FIXME (shell, "(%p)->()\n", This);
447         return E_NOTIMPL;
448 }
449 static HRESULT WINAPI IDataObject_fnDAdvise(LPDATAOBJECT iface, LPFORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
450 {
451         ICOM_THIS(IDataObjectImpl,iface);
452         FIXME (shell, "(%p)->()\n", This);
453         return E_NOTIMPL;
454 }
455 static HRESULT WINAPI IDataObject_fnDUnadvise(LPDATAOBJECT iface, DWORD dwConnection)
456 {
457         ICOM_THIS(IDataObjectImpl,iface);
458         FIXME (shell, "(%p)->()\n", This);
459         return E_NOTIMPL;
460 }
461 static HRESULT WINAPI IDataObject_fnEnumDAdvise(LPDATAOBJECT iface, IEnumSTATDATA **ppenumAdvise)
462 {
463         ICOM_THIS(IDataObjectImpl,iface);
464         FIXME (shell, "(%p)->()\n", This);
465         return E_NOTIMPL;
466 }