QueryGetData, EnumFormatEtc implemented.
[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 #include <string.h>
9
10 #include "oleidl.h"
11 #include "pidl.h"
12 #include "winerror.h"
13 #include "shell32_main.h"
14 #include "debugtools.h"
15 #include "wine/undocshell.h"
16 #include "wine/obj_dataobject.h"
17
18 DEFAULT_DEBUG_CHANNEL(shell)
19
20 /***********************************************************************
21 *   IEnumFORMATETC implementation
22 */
23
24 typedef struct 
25 {
26     /* IUnknown fields */
27     ICOM_VTABLE(IEnumFORMATETC)* lpvtbl;
28     DWORD                        ref;
29     /* IEnumFORMATETC fields */
30     UINT        posFmt;
31     UINT        countFmt;
32     LPFORMATETC pFmt;
33 } IEnumFORMATETCImpl;
34
35 static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj);
36 static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface);
37 static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface);
38 static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC* rgelt, ULONG* pceltFethed);
39 static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt);
40 static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface);
41 static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);
42
43 static struct ICOM_VTABLE(IEnumFORMATETC) efvt = 
44 {
45     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
46         IEnumFORMATETC_fnQueryInterface,
47         IEnumFORMATETC_fnAddRef,
48     IEnumFORMATETC_fnRelease,
49     IEnumFORMATETC_fnNext,
50     IEnumFORMATETC_fnSkip,
51     IEnumFORMATETC_fnReset,
52     IEnumFORMATETC_fnClone
53 };
54
55 LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[])
56 {
57         IEnumFORMATETCImpl* ef;
58         DWORD size=cfmt * sizeof(FORMATETC);
59         
60         ef=(IEnumFORMATETCImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl));
61
62         if(ef)
63         {
64           ef->ref=1;
65           ef->lpvtbl=&efvt;
66
67           ef->countFmt = cfmt;
68           ef->pFmt = SHAlloc (size);
69
70           if (ef->pFmt)
71           {
72             memcpy(ef->pFmt, afmt, size);
73           }
74
75           shell32_ObjCount++;
76         }
77
78         TRACE("(%p)->()\n",ef);
79         return (LPENUMFORMATETC)ef;
80 }
81 static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
82 {
83         ICOM_THIS(IEnumFORMATETCImpl,iface);
84         char    xriid[50];
85         WINE_StringFromCLSID((LPCLSID)riid,xriid);
86         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
87
88                         *ppvObj = NULL;
89
90         if(IsEqualIID(riid, &IID_IUnknown))
91         { *ppvObj = This; 
92         }
93         else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
94         { *ppvObj = (IDataObject*)This;
95         }   
96
97         if(*ppvObj)
98         { IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
99           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
100           return S_OK;
101         }
102         TRACE("-- Interface: E_NOINTERFACE\n");
103         return E_NOINTERFACE;
104
105 }
106 static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface)
107 {
108         ICOM_THIS(IEnumFORMATETCImpl,iface);
109         TRACE("(%p)->(count=%lu)\n",This, This->ref);
110         shell32_ObjCount++;
111         return ++(This->ref);
112 }
113 static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface)
114 {
115         ICOM_THIS(IEnumFORMATETCImpl,iface);
116         TRACE("(%p)->()\n",This);
117
118         shell32_ObjCount--;
119
120         if (!--(This->ref)) 
121         { TRACE(" destroying IEnumFORMATETC(%p)\n",This);
122           if (This->pFmt)
123           { SHFree (This->pFmt);
124           }
125           HeapFree(GetProcessHeap(),0,This);
126           return 0;
127         }
128         return This->ref;
129 }
130 static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
131 {
132         ICOM_THIS(IEnumFORMATETCImpl,iface);
133         UINT cfetch;
134         HRESULT hres = S_FALSE;
135
136         TRACE("(%p)->()\n", This);
137
138         if (This->posFmt < This->countFmt)
139         {
140           cfetch = This->countFmt - This->posFmt;
141           if (cfetch >= celt)
142           {
143             cfetch = celt;
144             hres = S_OK;
145           }
146           memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));
147           This->posFmt += cfetch;
148         }
149         else
150         {
151           cfetch = 0;
152         }
153
154         if (pceltFethed)
155         {
156           *pceltFethed = cfetch;
157         }
158
159         return hres;
160 }
161 static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt)
162 {
163         ICOM_THIS(IEnumFORMATETCImpl,iface);
164         FIXME("(%p)->(num=%lu)\n", This, celt);
165
166         This->posFmt += celt;
167         if (This->posFmt > This->countFmt)
168         {
169           This->posFmt = This->countFmt;
170           return S_FALSE;
171         }
172         return S_OK;
173 }
174 static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface)
175 {
176         ICOM_THIS(IEnumFORMATETCImpl,iface);
177         FIXME("(%p)->()\n", This);
178
179         This->posFmt = 0;
180         return S_OK;
181 }
182 static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
183 {
184         ICOM_THIS(IEnumFORMATETCImpl,iface);
185         FIXME("(%p)->(ppenum=%p)\n", This, ppenum);
186         return E_NOTIMPL;
187 }
188
189 /**************************************************************************
190  *  IDLList "Item ID List List"
191  *
192  *  NOTES
193  *   interal data holder for IDataObject
194  */
195 #define STDMETHOD(xfn) HRESULT (CALLBACK *fn##xfn)
196 #define STDMETHOD_(type,xfn) type (CALLBACK *fn##xfn)
197 #define THIS_ THIS,
198
199 typedef struct tagLPIDLLIST *LPIDLLIST, IDLList;
200
201 #define THIS LPIDLLIST me
202 typedef enum
203 { State_UnInit=1,
204   State_Init=2,
205   State_OutOfMem=3
206 } IDLListState;
207
208 typedef struct IDLList_VTable
209 { STDMETHOD_(UINT, GetState)(THIS);
210   STDMETHOD_(LPITEMIDLIST, GetElement)(THIS_ UINT nIndex);
211   STDMETHOD_(UINT, GetCount)(THIS);
212   STDMETHOD_(BOOL, StoreItem)(THIS_ LPITEMIDLIST pidl);
213   STDMETHOD_(BOOL, AddItems)(THIS_ LPITEMIDLIST *apidl, UINT cidl);
214   STDMETHOD_(BOOL, InitList)(THIS);
215   STDMETHOD_(void, CleanList)(THIS);
216 } IDLList_VTable,*LPIDLLIST_VTABLE;
217
218 struct tagLPIDLLIST
219 { LPIDLLIST_VTABLE  lpvtbl;
220   HDPA  dpa;
221   UINT  uStep;
222 };
223
224 extern LPIDLLIST IDLList_Constructor (UINT uStep);
225 extern void IDLList_Destructor(LPIDLLIST me);
226 #undef THIS
227
228
229
230 /**************************************************************************
231  *  IDLList "Item ID List List"
232  * 
233  */
234 static UINT WINAPI IDLList_GetState(LPIDLLIST this);
235 static LPITEMIDLIST WINAPI IDLList_GetElement(LPIDLLIST this, UINT nIndex);
236 static UINT WINAPI IDLList_GetCount(LPIDLLIST this);
237 static BOOL WINAPI IDLList_StoreItem(LPIDLLIST this, LPITEMIDLIST pidl);
238 static BOOL WINAPI IDLList_AddItems(LPIDLLIST this, LPITEMIDLIST *apidl, UINT cidl);
239 static BOOL WINAPI IDLList_InitList(LPIDLLIST this);
240 static void WINAPI IDLList_CleanList(LPIDLLIST this);
241
242 static IDLList_VTable idllvt = 
243 {       IDLList_GetState,
244         IDLList_GetElement,
245         IDLList_GetCount,
246         IDLList_StoreItem,
247         IDLList_AddItems,
248         IDLList_InitList,
249         IDLList_CleanList
250 };
251
252 LPIDLLIST IDLList_Constructor (UINT uStep)
253 {
254         LPIDLLIST lpidll;
255         lpidll = (LPIDLLIST)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDLList));
256
257         if (lpidll)
258         {
259           lpidll->lpvtbl=&idllvt;
260           lpidll->uStep=uStep;
261         }
262
263         TRACE("(%p)\n",lpidll);
264         return lpidll;
265 }
266 void IDLList_Destructor(LPIDLLIST this)
267 {       TRACE("(%p)\n",this);
268         IDLList_CleanList(this);
269 }
270  
271 static UINT WINAPI IDLList_GetState(LPIDLLIST this)
272 {       TRACE("(%p)->(uStep=%u dpa=%p)\n",this, this->uStep, this->dpa);
273
274         if (this->uStep == 0)
275         {
276           if (this->dpa)
277             return(State_Init);
278
279           return(State_OutOfMem);
280         }
281         return(State_UnInit);
282 }
283 static LPITEMIDLIST WINAPI IDLList_GetElement(LPIDLLIST this, UINT nIndex)
284 {       TRACE("(%p)->(index=%u)\n",this, nIndex);
285         return((LPITEMIDLIST)pDPA_GetPtr(this->dpa, nIndex));
286 }
287 static UINT WINAPI IDLList_GetCount(LPIDLLIST this)
288 {       TRACE("(%p)\n",this);
289         return(IDLList_GetState(this)==State_Init ? DPA_GetPtrCount(this->dpa) : 0);
290 }
291 static BOOL WINAPI IDLList_StoreItem(LPIDLLIST this, LPITEMIDLIST pidl)
292 {       TRACE("(%p)->(pidl=%p)\n",this, pidl);
293         if (pidl)
294         { if (IDLList_InitList(this) && pDPA_InsertPtr(this->dpa, 0x7fff, (LPSTR)pidl)>=0)
295             return(TRUE);
296           ILFree(pidl);
297         }
298         IDLList_CleanList(this);
299         return(FALSE);
300 }
301 static BOOL WINAPI IDLList_AddItems(LPIDLLIST this, LPITEMIDLIST *apidl, UINT cidl)
302 {       INT i;
303         TRACE("(%p)->(apidl=%p cidl=%u)\n",this, apidl, cidl);
304
305         for (i=0; i<cidl; ++i)
306         { if (!IDLList_StoreItem(this, ILClone((LPCITEMIDLIST)apidl[i])))
307             return(FALSE);
308         }
309         return(TRUE);
310 }
311 static BOOL WINAPI IDLList_InitList(LPIDLLIST this)
312 {       TRACE("(%p)\n",this);
313         switch (IDLList_GetState(this))
314         { case State_Init:
315             return(TRUE);
316
317           case State_OutOfMem:
318             return(FALSE);
319
320           case State_UnInit:
321           default:
322             this->dpa = pDPA_Create(this->uStep);
323             this->uStep = 0;
324             return(IDLList_InitList(this));
325         }
326 }
327 static void WINAPI IDLList_CleanList(LPIDLLIST this)
328 {       INT i;
329         TRACE("(%p)\n",this);
330
331         if (this->uStep != 0)
332         { this->dpa = NULL;
333           this->uStep = 0;
334           return;
335         }
336
337         if (!this->dpa)
338         { return;
339         }
340
341         for (i=DPA_GetPtrCount(this->dpa)-1; i>=0; --i)
342         { ILFree(IDLList_GetElement(this,i));
343         }
344
345         pDPA_Destroy(this->dpa);
346         this->dpa=NULL;
347 }        
348
349
350 /***********************************************************************
351 *   IDataObject implementation
352 */
353 /* number of supported formats */
354 #define MAX_FORMATS 1
355
356 typedef struct
357 {
358         /* IUnknown fields */
359         ICOM_VTABLE(IDataObject)* lpvtbl;
360         DWORD           ref;
361
362         /* IDataObject fields */
363         LPIDLLIST       lpill;       /* the data of the dataobject */
364         LPITEMIDLIST    pidl;
365
366         FORMATETC       pFormatEtc[MAX_FORMATS];
367         UINT            cfShellIDList;
368         UINT            cfFileGroupDesc;
369         UINT            cfFileContents;
370
371 } IDataObjectImpl;
372
373 static struct ICOM_VTABLE(IDataObject) dtovt;
374
375 /**************************************************************************
376 *  IDataObject_Constructor
377 */
378 LPDATAOBJECT IDataObject_Constructor(HWND hwndOwner, LPITEMIDLIST pMyPidl, LPITEMIDLIST * apidl, UINT cidl)
379 {
380         IDataObjectImpl* dto;
381
382         dto = (IDataObjectImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDataObjectImpl));
383
384         if (dto)
385         {
386           dto->ref=1;
387           dto->lpvtbl=&dtovt;
388           dto->pidl=ILClone(pMyPidl);
389
390           /* fill the ItemID List List */
391           dto->lpill = IDLList_Constructor (8);
392           if (! dto->lpill )
393             return NULL;
394           
395           dto->lpill->lpvtbl->fnAddItems(dto->lpill, apidl, cidl); 
396
397           /* */
398           dto->cfShellIDList = RegisterClipboardFormatA(CFSTR_SHELLIDLIST);
399 /*        dto->cfFileGroupDesc = RegisterClipboardFormatA(CFSTR_FILEDESCRIPTORA);
400           dto->cfFileContents = RegisterClipboardFormatA(CFSTR_FILECONTENTS);
401 */
402           InitFormatEtc(dto->pFormatEtc[0], dto->cfShellIDList, TYMED_HGLOBAL);
403
404           shell32_ObjCount++;
405         }
406         
407         TRACE("(%p)->(apidl=%p cidl=%u)\n",dto, apidl, cidl);
408         return (LPDATAOBJECT)dto;
409 }
410 /***************************************************************************
411 *  IDataObject_QueryInterface
412 */
413 static HRESULT WINAPI IDataObject_fnQueryInterface(LPDATAOBJECT iface, REFIID riid, LPVOID * ppvObj)
414 {
415         ICOM_THIS(IDataObjectImpl,iface);
416         char    xriid[50];
417         WINE_StringFromCLSID((LPCLSID)riid,xriid);
418         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
419
420         *ppvObj = NULL;
421
422         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
423         { *ppvObj = This; 
424         }
425         else if(IsEqualIID(riid, &IID_IDataObject))  /*IDataObject*/
426         { *ppvObj = (IDataObject*)This;
427         }   
428
429         if(*ppvObj)
430         { IDataObject_AddRef((IDataObject*)*ppvObj);      
431           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
432           return S_OK;
433         }
434         TRACE("-- Interface: E_NOINTERFACE\n");
435         return E_NOINTERFACE;
436 }
437 /**************************************************************************
438 *  IDataObject_AddRef
439 */
440 static ULONG WINAPI IDataObject_fnAddRef(LPDATAOBJECT iface)
441 {
442         ICOM_THIS(IDataObjectImpl,iface);
443
444         TRACE("(%p)->(count=%lu)\n",This, This->ref);
445
446         shell32_ObjCount++;
447         return ++(This->ref);
448 }
449 /**************************************************************************
450 *  IDataObject_Release
451 */
452 static ULONG WINAPI IDataObject_fnRelease(LPDATAOBJECT iface)
453 {
454         ICOM_THIS(IDataObjectImpl,iface);
455         TRACE("(%p)->()\n",This);
456
457         shell32_ObjCount--;
458
459         if (!--(This->ref)) 
460         { TRACE(" destroying IDataObject(%p)\n",This);
461           IDLList_Destructor(This->lpill);
462           HeapFree(GetProcessHeap(),0,This);
463           return 0;
464         }
465         return This->ref;
466 }
467
468 /**************************************************************************
469 * IDataObject_fnGetData
470 */
471 static HRESULT WINAPI IDataObject_fnGetData(LPDATAOBJECT iface, LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
472 {
473         ICOM_THIS(IDataObjectImpl,iface);
474
475         char    szTemp[256];
476         UINT    cItems;
477         DWORD   sizeCIDA, sizePidl, nOffset, nSize;
478         LPCIDA  pcida;
479         HGLOBAL hmem;
480         int     i;
481         LPITEMIDLIST    pidl;
482         
483         GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
484         TRACE("(%p)->(%p %p format=%s)\n", This, pformatetcIn, pmedium, szTemp);
485
486         /* test expected format */
487         if (!(pformatetcIn->cfFormat == This->cfShellIDList))
488         {
489           FIXME("-- clipformat not implemented\n");
490           return (E_INVALIDARG);
491         }
492
493         if (pformatetcIn->ptd==NULL 
494                 && (pformatetcIn->dwAspect & DVASPECT_CONTENT) 
495                 && pformatetcIn->lindex==-1 
496                 && (pformatetcIn->tymed&TYMED_HGLOBAL))
497         {
498           cItems = This->lpill->lpvtbl->fnGetCount(This->lpill);
499           if (cItems < 1) return(E_UNEXPECTED);
500         
501           sizeCIDA = sizeof(CIDA) + sizeof (UINT)*(cItems);     /* without any pidl */
502           sizePidl = ILGetSize (This->pidl);                    /* add root pidl */
503
504           nSize = sizeCIDA + sizePidl;
505           hmem = GlobalAlloc(GHND|GMEM_SHARE, nSize);           
506           if (!hmem) return(E_OUTOFMEMORY);
507           pcida = GlobalLock (hmem);
508
509           nOffset = sizeCIDA;                           /* start after the CIDA */
510           pcida->cidl = cItems;
511
512           pcida->aoffset[0] = nOffset;                  /* first element */
513           memcpy(((LPBYTE)pcida)+nOffset, This->pidl, sizePidl);
514           nOffset += sizePidl;
515           pdump(This->pidl);
516
517           for (i=0; i< cItems; i++)
518           {
519             pidl = This->lpill->lpvtbl->fnGetElement(This->lpill, i);
520             sizePidl = ILGetSize (pidl);
521             nSize += sizePidl;                          /* size of the structure */
522             pdump(pidl);
523
524             GlobalUnlock(hmem);                         /* grow memory */
525             hmem = GlobalReAlloc(hmem, nSize, GHND|GMEM_SHARE);
526             if (!hmem) return(E_OUTOFMEMORY);
527             pcida = GlobalLock (hmem);
528
529             pcida->aoffset[i+1] = nOffset;              /* copy element */
530             memcpy(((LPBYTE)pcida)+nOffset, pidl, sizePidl);
531             nOffset += sizePidl;
532           }
533
534           GlobalUnlock(hmem);
535
536           pmedium->tymed = TYMED_HGLOBAL;
537           pmedium->u.hGlobal = hmem;
538           pmedium->pUnkForRelease = NULL;
539
540           TRACE("(%p)->(cida at %p)\n", This, pcida);
541           return hmem;
542         }
543
544         FIXME("-- can't serve format\n");
545         return (E_INVALIDARG);
546 }
547 static HRESULT WINAPI IDataObject_fnGetDataHere(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium)
548 {
549         ICOM_THIS(IDataObjectImpl,iface);
550         FIXME("(%p)->()\n", This);
551         return E_NOTIMPL;
552 }
553 static HRESULT WINAPI IDataObject_fnQueryGetData(LPDATAOBJECT iface, LPFORMATETC pformatetc)
554 {
555         ICOM_THIS(IDataObjectImpl,iface);
556         UINT i;
557         
558         TRACE("(%p)->(fmt=0x%08x tym=0x%08lx)\n", This, pformatetc->cfFormat, pformatetc->tymed);
559         
560         if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
561           return DV_E_DVASPECT;
562
563         /* check our formats table what we have */
564         for (i=0; i<MAX_FORMATS; i++)
565         {
566           if ((This->pFormatEtc[i].cfFormat == pformatetc->cfFormat)
567            && (This->pFormatEtc[i].tymed == pformatetc->tymed))
568           {
569             return S_OK;
570           }
571         }
572
573         return DV_E_TYMED;
574 }
575 static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(LPDATAOBJECT iface, LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
576 {
577         ICOM_THIS(IDataObjectImpl,iface);
578         FIXME("(%p)->()\n", This);
579         return E_NOTIMPL;
580 }
581 static HRESULT WINAPI IDataObject_fnSetData(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
582 {
583         ICOM_THIS(IDataObjectImpl,iface);
584         FIXME("(%p)->()\n", This);
585         return E_NOTIMPL;
586 }
587 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(LPDATAOBJECT iface, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
588 {
589         ICOM_THIS(IDataObjectImpl,iface);
590
591         TRACE("(%p)->()\n", This);
592         *ppenumFormatEtc=NULL;
593
594         /* only get data */
595         if (DATADIR_GET == dwDirection)
596         {
597           *ppenumFormatEtc = IEnumFORMATETC_Constructor(MAX_FORMATS, This->pFormatEtc);
598           return (*ppenumFormatEtc) ? S_OK : E_FAIL;
599         }
600         
601         return E_NOTIMPL;
602 }
603 static HRESULT WINAPI IDataObject_fnDAdvise(LPDATAOBJECT iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
604 {
605         ICOM_THIS(IDataObjectImpl,iface);
606         FIXME("(%p)->()\n", This);
607         return E_NOTIMPL;
608 }
609 static HRESULT WINAPI IDataObject_fnDUnadvise(LPDATAOBJECT iface, DWORD dwConnection)
610 {
611         ICOM_THIS(IDataObjectImpl,iface);
612         FIXME("(%p)->()\n", This);
613         return E_NOTIMPL;
614 }
615 static HRESULT WINAPI IDataObject_fnEnumDAdvise(LPDATAOBJECT iface, IEnumSTATDATA **ppenumAdvise)
616 {
617         ICOM_THIS(IDataObjectImpl,iface);
618         FIXME("(%p)->()\n", This);
619         return E_NOTIMPL;
620 }
621
622 static struct ICOM_VTABLE(IDataObject) dtovt = 
623 {
624         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
625         IDataObject_fnQueryInterface,
626         IDataObject_fnAddRef,
627         IDataObject_fnRelease,
628         IDataObject_fnGetData,
629         IDataObject_fnGetDataHere,
630         IDataObject_fnQueryGetData,
631         IDataObject_fnGetCanonicalFormatEtc,
632         IDataObject_fnSetData,
633         IDataObject_fnEnumFormatEtc,
634         IDataObject_fnDAdvise,
635         IDataObject_fnDUnadvise,
636         IDataObject_fnEnumDAdvise
637 };
638