Started implementation of ShellExecuteEx32A.
[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 "debug.h"
9 #include "shlobj.h"
10 #include "pidl.h"
11 #include "winerror.h"
12 #include "shell32_main.h"
13
14 UINT32 cfShellIDList=0;
15 UINT32 cfFileGroupDesc=0;
16 UINT32 cfFileContents=0;
17
18 /***********************************************************************
19 *   IEnumFORMATETC implementation
20 */
21 static HRESULT WINAPI IEnumFORMATETC_QueryInterface (LPENUMFORMATETC this, REFIID riid, LPVOID * ppvObj);
22 static ULONG WINAPI IEnumFORMATETC_AddRef (LPENUMFORMATETC this);
23 static ULONG WINAPI IEnumFORMATETC_Release (LPENUMFORMATETC this);
24 static HRESULT WINAPI IEnumFORMATETC_Next(LPENUMFORMATETC this, ULONG celt, FORMATETC32 *rgelt, ULONG *pceltFethed);
25 static HRESULT WINAPI IEnumFORMATETC_Skip(LPENUMFORMATETC this, ULONG celt);
26 static HRESULT WINAPI IEnumFORMATETC_Reset(LPENUMFORMATETC this);
27 static HRESULT WINAPI IEnumFORMATETC_Clone(LPENUMFORMATETC this, LPENUMFORMATETC* ppenum);
28
29 static struct IEnumFORMATETC_VTable efvt = 
30 {       IEnumFORMATETC_QueryInterface,
31         IEnumFORMATETC_AddRef,
32         IEnumFORMATETC_Release,
33         IEnumFORMATETC_Next,
34         IEnumFORMATETC_Skip,
35         IEnumFORMATETC_Reset,
36         IEnumFORMATETC_Clone
37 };
38
39 extern LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT32 cfmt, const FORMATETC32 afmt[])
40 {       LPENUMFORMATETC ef;
41         DWORD size=cfmt * sizeof(FORMATETC32);
42         
43         ef=(LPENUMFORMATETC)HeapAlloc(GetProcessHeap(),0,sizeof(IEnumFORMATETC));
44         ef->ref=1;
45         ef->lpvtbl=&efvt;
46
47         ef->posFmt = 0;
48         ef->countFmt = cfmt;
49         ef->pFmt = SHAlloc (size);
50
51         if (ef->pFmt)
52         { memcpy(ef->pFmt, afmt, size);
53         }
54
55         TRACE(shell,"(%p)->()\n",ef);
56         return ef;
57 }
58 static HRESULT WINAPI IEnumFORMATETC_QueryInterface (LPENUMFORMATETC this, REFIID riid, LPVOID * ppvObj)
59 {       char    xriid[50];
60         WINE_StringFromCLSID((LPCLSID)riid,xriid);
61         TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",this,xriid,ppvObj);
62
63                         *ppvObj = NULL;
64
65         if(IsEqualIID(riid, &IID_IUnknown))
66         { *ppvObj = this; 
67         }
68         else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
69         { *ppvObj = (IDataObject*)this;
70         }   
71
72         if(*ppvObj)
73         { (*(LPENUMFORMATETC*)ppvObj)->lpvtbl->fnAddRef(this);      
74           TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
75           return S_OK;
76         }
77         TRACE(shell,"-- Interface: E_NOINTERFACE\n");
78         return E_NOINTERFACE;
79
80 }
81 static ULONG WINAPI IEnumFORMATETC_AddRef (LPENUMFORMATETC this)
82 {       TRACE(shell,"(%p)->(count=%lu)\n",this,(this->ref)+1);
83         return ++(this->ref);
84 }
85 static ULONG WINAPI IEnumFORMATETC_Release (LPENUMFORMATETC this)
86 {       TRACE(shell,"(%p)->()\n",this);
87         if (!--(this->ref)) 
88         { TRACE(shell," destroying IEnumFORMATETC(%p)\n",this);
89           if (this->pFmt)
90           { SHFree (this->pFmt);
91           }
92           HeapFree(GetProcessHeap(),0,this);
93           return 0;
94         }
95         return this->ref;
96 }
97 static HRESULT WINAPI IEnumFORMATETC_Next(LPENUMFORMATETC this, ULONG celt, FORMATETC32 *rgelt, ULONG *pceltFethed)
98 {       UINT32 cfetch;
99         HRESULT hres = S_FALSE;
100
101         TRACE (shell, "(%p)->()\n", this);
102
103         if (this->posFmt < this->countFmt)
104         { cfetch = this->countFmt - this->posFmt;
105           if (cfetch >= celt)
106           { cfetch = celt;
107             hres = S_OK;
108           }
109           memcpy(rgelt, &this->pFmt[this->posFmt], cfetch * sizeof(FORMATETC32));
110           this->posFmt += cfetch;
111         }
112         else
113         { cfetch = 0;
114         }
115
116         if (pceltFethed)
117         { *pceltFethed = cfetch;
118         }
119
120         return hres;
121 }
122 static HRESULT WINAPI IEnumFORMATETC_Skip(LPENUMFORMATETC this, ULONG celt)
123 {       FIXME (shell, "(%p)->(num=%lu)\n", this, celt);
124
125         this->posFmt += celt;
126         if (this->posFmt > this->countFmt)
127         { this->posFmt = this->countFmt;
128           return S_FALSE;
129         }
130         return S_OK;
131 }
132 static HRESULT WINAPI IEnumFORMATETC_Reset(LPENUMFORMATETC this)
133 {       FIXME (shell, "(%p)->()\n", this);
134
135         this->posFmt = 0;
136         return S_OK;
137 }
138 static HRESULT WINAPI IEnumFORMATETC_Clone(LPENUMFORMATETC this, LPENUMFORMATETC* ppenum)
139 {       FIXME (shell, "(%p)->(ppenum=%p)\n", this, ppenum);
140         return E_NOTIMPL;
141 }
142
143 /***********************************************************************
144 *   IDataObject implementation
145 */
146
147 static HRESULT WINAPI IDataObject_QueryInterface (LPDATAOBJECT, REFIID riid, LPVOID * ppvObj);
148 static ULONG WINAPI IDataObject_AddRef (LPDATAOBJECT);
149 static ULONG WINAPI IDataObject_Release (LPDATAOBJECT);
150 static HRESULT WINAPI IDataObject_GetData (LPDATAOBJECT, LPFORMATETC32 pformatetcIn, STGMEDIUM32 *pmedium);
151 static HRESULT WINAPI IDataObject_GetDataHere(LPDATAOBJECT, LPFORMATETC32 pformatetc, STGMEDIUM32 *pmedium);
152 static HRESULT WINAPI IDataObject_QueryGetData(LPDATAOBJECT, LPFORMATETC32 pformatetc);
153 static HRESULT WINAPI IDataObject_GetCanonicalFormatEtc(LPDATAOBJECT, LPFORMATETC32 pformatectIn, LPFORMATETC32 pformatetcOut);
154 static HRESULT WINAPI IDataObject_SetData(LPDATAOBJECT, LPFORMATETC32 pformatetc, STGMEDIUM32 *pmedium, BOOL32 fRelease);
155 static HRESULT WINAPI IDataObject_EnumFormatEtc(LPDATAOBJECT, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
156 static HRESULT WINAPI IDataObject_DAdvise (LPDATAOBJECT, LPFORMATETC32 *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
157 static HRESULT WINAPI IDataObject_DUnadvise(LPDATAOBJECT, DWORD dwConnection);
158 static HRESULT WINAPI IDataObject_EnumDAdvise(LPDATAOBJECT, IEnumSTATDATA **ppenumAdvise);
159
160 static struct IDataObject_VTable dtovt = 
161 {       IDataObject_QueryInterface,
162         IDataObject_AddRef,
163         IDataObject_Release,
164         IDataObject_GetData,
165         IDataObject_GetDataHere,
166         IDataObject_QueryGetData,
167         IDataObject_GetCanonicalFormatEtc,
168         IDataObject_SetData,
169         IDataObject_EnumFormatEtc,
170         IDataObject_DAdvise,
171         IDataObject_DUnadvise,
172         IDataObject_EnumDAdvise
173 };
174
175 /**************************************************************************
176 *  IDataObject_Constructor
177 */
178 LPDATAOBJECT IDataObject_Constructor(HWND32 hwndOwner, LPSHELLFOLDER psf, LPITEMIDLIST * apidl, UINT32 cidl)
179 {       LPDATAOBJECT dto;
180         if (!(dto = (LPDATAOBJECT)HeapAlloc(GetProcessHeap(),0,sizeof(IDataObject))))
181           return NULL;
182           
183         dto->ref=1;
184         dto->lpvtbl=&dtovt;
185         dto->psf=psf;
186         dto->pidl=ILClone(psf->mpidl); /* FIXME:add a reference and don't copy*/
187
188         /* fill the ItemID List List */
189         dto->lpill = IDLList_Constructor (8);
190         if (! dto->lpill )
191           return NULL;
192           
193         dto->lpill->lpvtbl->fnAddItems(dto->lpill, apidl, cidl); 
194         
195         TRACE(shell,"(%p)->(sf=%p apidl=%p cidl=%u)\n",dto, psf, apidl, cidl);
196         return dto;
197 }
198 /***************************************************************************
199 *  IDataObject_QueryInterface
200 */
201 static HRESULT WINAPI IDataObject_QueryInterface (LPDATAOBJECT this, REFIID riid, LPVOID * ppvObj)
202 {       char    xriid[50];
203         WINE_StringFromCLSID((LPCLSID)riid,xriid);
204         TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",this,xriid,ppvObj);
205
206         *ppvObj = NULL;
207
208         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
209         { *ppvObj = this; 
210         }
211         else if(IsEqualIID(riid, &IID_IDataObject))  /*IDataObject*/
212         { *ppvObj = (IDataObject*)this;
213         }   
214
215         if(*ppvObj)
216         { (*(LPDATAOBJECT*)ppvObj)->lpvtbl->fnAddRef(this);      
217           TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
218           return S_OK;
219         }
220         TRACE(shell,"-- Interface: E_NOINTERFACE\n");
221         return E_NOINTERFACE;
222 }   
223 /**************************************************************************
224 *  IDataObject_AddRef
225 */
226 static ULONG WINAPI IDataObject_AddRef(LPDATAOBJECT this)
227 {       TRACE(shell,"(%p)->(count=%lu)\n",this,(this->ref)+1);
228         return ++(this->ref);
229 }
230 /**************************************************************************
231 *  IDataObject_Release
232 */
233 static ULONG WINAPI IDataObject_Release(LPDATAOBJECT this)
234 {       TRACE(shell,"(%p)->()\n",this);
235         if (!--(this->ref)) 
236         { TRACE(shell," destroying IDataObject(%p)\n",this);
237           IDLList_Destructor(this->lpill);
238           HeapFree(GetProcessHeap(),0,this);
239           return 0;
240         }
241         return this->ref;
242 }
243 /**************************************************************************
244 * DATAOBJECT_InitShellIDList (internal)
245 *
246 * NOTES
247 *  get or register the "Shell IDList Array" clipformat
248 */
249 static BOOL32 DATAOBJECT_InitShellIDList(void)
250 {       if (cfShellIDList)
251         { return(TRUE);
252         }
253
254         cfShellIDList = RegisterClipboardFormat32A(CFSTR_SHELLIDLIST);
255         return(cfShellIDList != 0);
256 }
257
258 /**************************************************************************
259 * DATAOBJECT_InitFileGroupDesc (internal)
260 *
261 * NOTES
262 *  get or register the "FileGroupDescriptor" clipformat
263 */
264 static BOOL32 DATAOBJECT_InitFileGroupDesc(void)
265 {       if (cfFileGroupDesc)
266         { return(TRUE);
267         }
268
269         cfFileGroupDesc = RegisterClipboardFormat32A(CFSTR_FILEDESCRIPTORA);
270         return(cfFileGroupDesc != 0);
271 }
272 /**************************************************************************
273 * DATAOBJECT_InitFileContents (internal)
274
275 * NOTES
276  * get or register the "FileContents" clipformat
277 */
278 static BOOL32 DATAOBJECT_InitFileContents(void)
279 {       if (cfFileContents)
280         { return(TRUE);
281         }
282
283         cfFileContents = RegisterClipboardFormat32A(CFSTR_FILECONTENTS);
284         return(cfFileContents != 0);
285 }
286
287
288 /**************************************************************************
289 * interface implementation
290 */
291 static HRESULT WINAPI IDataObject_GetData (LPDATAOBJECT this, LPFORMATETC32 pformatetcIn, STGMEDIUM32 *pmedium)
292 {       char    temp[256];
293         UINT32  cItems;
294         DWORD   size, size1, size2;
295         LPITEMIDLIST pidl;
296         LPCIDA pcida;
297         HGLOBAL32 hmem;
298         
299         GetClipboardFormatName32A (pformatetcIn->cfFormat, temp, 256);
300         WARN (shell, "(%p)->(%p %p format=%s)semi-stub\n", this, pformatetcIn, pmedium, temp);
301
302         if (!DATAOBJECT_InitShellIDList())      /* is the clipformat registred? */
303         { return(E_UNEXPECTED);
304         }
305         
306         if (pformatetcIn->cfFormat == cfShellIDList)
307         { if (pformatetcIn->ptd==NULL 
308                 && (pformatetcIn->dwAspect & DVASPECT_CONTENT) 
309                 && pformatetcIn->lindex==-1
310                 && (pformatetcIn->tymed&TYMED_HGLOBAL))
311           { cItems = this->lpill->lpvtbl->fnGetCount(this->lpill);
312             if (cItems < 1)
313             { return(E_UNEXPECTED);
314             }
315             pidl = this->lpill->lpvtbl->fnGetElement(this->lpill, 0);
316
317             pdump(this->pidl);
318             pdump(pidl);
319             
320             /*hack consider only the first item*/
321             cItems = 2;
322             size = sizeof(CIDA) + sizeof (UINT32)*(cItems-1);
323             size1 = ILGetSize (this->pidl);
324             size2 = ILGetSize (pidl);
325             hmem = GlobalAlloc32(GMEM_FIXED, size+size1+size2);
326             pcida = GlobalLock32 (hmem);
327             if (!pcida)
328             { return(E_OUTOFMEMORY);
329             }
330
331             pcida->cidl = 1;
332             pcida->aoffset[0] = size;
333             pcida->aoffset[1] = size+size1;
334
335             TRACE(shell,"-- %lu %lu %lu\n",size, size1, size2 );
336             TRACE(shell,"-- %p %p\n",this->pidl, pidl);
337             TRACE(shell,"-- %p %p %p\n",pcida, (LPBYTE)pcida+size,(LPBYTE)pcida+size+size1);
338             
339             memcpy ((LPBYTE)pcida+size, this->pidl, size1);
340             memcpy ((LPBYTE)pcida+size+size1, pidl, size2);
341             TRACE(shell,"-- after copy\n");
342
343             GlobalUnlock32(hmem);
344             
345             pmedium->tymed = TYMED_HGLOBAL;
346             pmedium->u.hGlobal = (HGLOBAL32)pcida;
347             pmedium->pUnkForRelease = NULL;
348             TRACE(shell,"-- ready\n");
349             return(NOERROR);
350           }
351         }
352         FIXME (shell, "-- clipformat not implemented\n");
353         return (E_INVALIDARG);
354 }
355 static HRESULT WINAPI IDataObject_GetDataHere(LPDATAOBJECT this, LPFORMATETC32 pformatetc, STGMEDIUM32 *pmedium)
356 {       FIXME (shell, "(%p)->()\n", this);
357         return E_NOTIMPL;
358 }
359 static HRESULT WINAPI IDataObject_QueryGetData(LPDATAOBJECT this, LPFORMATETC32 pformatetc)
360 {       FIXME (shell, "(%p)->()\n", this);
361         return E_NOTIMPL;
362 }
363 static HRESULT WINAPI IDataObject_GetCanonicalFormatEtc(LPDATAOBJECT this, LPFORMATETC32 pformatectIn, LPFORMATETC32 pformatetcOut)
364 {       FIXME (shell, "(%p)->()\n", this);
365         return E_NOTIMPL;
366 }
367 static HRESULT WINAPI IDataObject_SetData(LPDATAOBJECT this, LPFORMATETC32 pformatetc, STGMEDIUM32 *pmedium, BOOL32 fRelease)
368 {       FIXME (shell, "(%p)->()\n", this);
369         return E_NOTIMPL;
370 }
371 static HRESULT WINAPI IDataObject_EnumFormatEtc(LPDATAOBJECT this, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
372 {       FIXME (shell, "(%p)->()\n", this);
373         return E_NOTIMPL;
374 }
375 static HRESULT WINAPI IDataObject_DAdvise (LPDATAOBJECT this, LPFORMATETC32 *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
376 {       FIXME (shell, "(%p)->()\n", this);
377         return E_NOTIMPL;
378 }
379 static HRESULT WINAPI IDataObject_DUnadvise(LPDATAOBJECT this, DWORD dwConnection)
380 {       FIXME (shell, "(%p)->()\n", this);
381         return E_NOTIMPL;
382 }
383 static HRESULT WINAPI IDataObject_EnumDAdvise(LPDATAOBJECT this, IEnumSTATDATA **ppenumAdvise)
384 {       FIXME (shell, "(%p)->()\n", this);
385         return E_NOTIMPL;
386 }