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