No longer directly accessing debuggee memory.
[wine] / dlls / ole32 / clipboard.c
1 /*
2  *  OLE 2 clipboard support
3  *
4  *      Copyright 1999  Noel Borthwick <noel@macadamian.com>
5  *
6  * NOTES:
7  *    This file contains the implementation for the OLE Clipboard and its
8  *    internal interfaces. The OLE clipboard interacts with an IDataObject
9  *    interface via the OleSetClipboard, OleGetClipboard and
10  *    OleIsCurrentClipboard API's. An internal IDataObject delegates
11  *    to a client supplied IDataObject or the WIN32 clipboard API depending
12  *    on whether OleSetClipboard has been invoked.
13  *    Here are some operating scenarios:
14  *
15  *    1. OleSetClipboard called: In this case the internal IDataObject
16  *       delegates to the client supplied IDataObject. Additionally OLE takes
17  *       ownership of the Windows clipboard and any HGLOCBAL IDataObject
18  *       items are placed on the Windows clipboard. This allows non OLE aware
19  *       applications to access these. A local WinProc fields WM_RENDERFORMAT
20  *       and WM_RENDERALLFORMATS messages in this case.
21  *
22  *    2. OleGetClipboard called without previous OleSetClipboard. Here the internal
23  *       IDataObject functionality wraps around the WIN32 clipboard API.
24  *
25  *    3. OleGetClipboard called after previous OleSetClipboard. Here the internal
26  *       IDataObject delegates to the source IDataObjects functionality directly,
27  *       thereby bypassing the Windows clipboard.
28  *
29  *    Implementation references : Inside OLE 2'nd  edition by Kraig Brockschmidt
30  *
31  * TODO:
32  *    - Support for pasting between different processes. OLE clipboard support
33  *      currently works only for in process copy and paste. Since we internally
34  *      store a pointer to the source's IDataObject and delegate to that, this
35  *      will fail if the IDataObject client belongs to a different process.
36  *    - IDataObject::GetDataHere is not implemented
37  *    - OleFlushClipboard needs to additionally handle TYMED_IStorage media
38  *      by copying the storage into global memory. Subsequently the default
39  *      data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
40  *      back to TYMED_IStorage.
41  *    - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
42  *      clipboard in OleSetClipboard.
43  *
44  */
45
46 #include <assert.h>
47 #include "windef.h"
48 #include "wingdi.h"
49 #include "winuser.h"
50 #include "winbase.h"
51 #include "winerror.h"
52 #include "ole2.h"
53 #include "debugtools.h"
54
55
56 #define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%lx)\n", (HRESULT)err); goto CLEANUP; }
57
58 /* For CoGetMalloc (MEMCTX_TASK is currently ignored) */
59 #ifndef MEMCTX_TASK
60   #define MEMCTX_TASK -1
61 #endif
62
63 DEFAULT_DEBUG_CHANNEL(ole)
64
65 /****************************************************************************
66  * OLEClipbrd
67  * DO NOT add any members before the VTables declaration!
68  */
69 struct OLEClipbrd
70 {
71   /*
72    * List all interface VTables here
73    */
74   ICOM_VTABLE(IDataObject)*  lpvtbl1;  /* IDataObject VTable */
75
76   /*
77    * The hidden OLE clipboard window. This window is used as the bridge between the 
78    * the OLE and windows clipboard API. (Windows creates one such window per process)
79    */
80   HWND                       hWndClipboard;
81
82   /*
83    * Pointer to the source data object (via OleSetClipboard)
84    */
85   IDataObject*               pIDataObjectSrc;
86
87   /*
88    * The registered DataObject clipboard format
89    */
90   UINT                       cfDataObj;
91
92   /*
93    * The handle to our ourself
94    */
95   UINT                       hSelf;
96
97   /*
98    * Reference count of this object
99    */
100   ULONG                      ref;
101 };
102
103 typedef struct OLEClipbrd OLEClipbrd;
104
105
106 /****************************************************************************
107 *   IEnumFORMATETC implementation
108 *   DO NOT add any members before the VTables declaration!
109 */
110 typedef struct 
111 {
112   /* IEnumFORMATETC VTable */
113   ICOM_VFIELD(IEnumFORMATETC);
114   
115   /* IEnumFORMATETC fields */
116   UINT                         posFmt;    /* current enumerator position */
117   UINT                         countFmt;  /* number of EnumFORMATETC's in array */
118   LPFORMATETC                  pFmt;      /* array of EnumFORMATETC's */
119
120   /*
121    * Reference count of this object
122    */
123   DWORD                        ref;
124
125   /*
126    * IUnknown implementation of the parent data object.
127    */
128   IUnknown*                    pUnkDataObj;
129   
130 } IEnumFORMATETCImpl;
131
132
133 /*
134  * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize()
135  */
136 static HGLOBAL hTheOleClipboard = 0;
137 static OLEClipbrd* theOleClipboard = NULL;
138
139
140 /*
141  * Prototypes for the methods of the OLEClipboard class.
142  */
143 extern void OLEClipbrd_Initialize();
144 extern void OLEClipbrd_UnInitialize();
145 static OLEClipbrd* OLEClipbrd_Construct();
146 static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy);
147 static HWND OLEClipbrd_CreateWindow();
148 static void OLEClipbrd_DestroyWindow(HWND hwnd);
149 LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
150 static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc );
151 static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc );
152
153 /*
154  * Prototypes for the methods of the OLEClipboard class
155  * that implement IDataObject methods.
156  */
157 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
158             IDataObject*     iface,
159             REFIID           riid,
160             void**           ppvObject);
161 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( 
162             IDataObject*     iface);
163 static ULONG WINAPI OLEClipbrd_IDataObject_Release( 
164             IDataObject*     iface);
165 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
166             IDataObject*     iface,
167             LPFORMATETC      pformatetcIn, 
168             STGMEDIUM*       pmedium);
169 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
170             IDataObject*     iface, 
171             LPFORMATETC      pformatetc,
172             STGMEDIUM*       pmedium);
173 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
174             IDataObject*     iface,
175             LPFORMATETC      pformatetc);
176 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
177             IDataObject*     iface, 
178             LPFORMATETC      pformatectIn, 
179             LPFORMATETC      pformatetcOut);
180 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
181             IDataObject*     iface,
182             LPFORMATETC      pformatetc, 
183             STGMEDIUM*       pmedium, 
184             BOOL             fRelease);
185 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
186             IDataObject*     iface,       
187             DWORD            dwDirection,
188             IEnumFORMATETC** ppenumFormatEtc);
189 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
190             IDataObject*     iface, 
191             FORMATETC*       pformatetc, 
192             DWORD            advf, 
193             IAdviseSink*     pAdvSink, 
194             DWORD*           pdwConnection);
195 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
196             IDataObject*     iface,
197             DWORD            dwConnection);
198 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
199             IDataObject*     iface,
200             IEnumSTATDATA**  ppenumAdvise);
201
202 /*
203  * Prototypes for the IEnumFORMATETC methods.
204  */
205 static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
206                                                            LPUNKNOWN pUnkDataObj);
207 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid,
208                                                                LPVOID* ppvObj);
209 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface);
210 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface);
211 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt,
212                                                      FORMATETC* rgelt, ULONG* pceltFethed);
213 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt);
214 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface);
215 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);
216
217
218 /*
219  * Virtual function table for the OLEClipbrd's exposed IDataObject interface
220  */
221 static ICOM_VTABLE(IDataObject) OLEClipbrd_IDataObject_VTable =
222 {
223   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
224   OLEClipbrd_IDataObject_QueryInterface,
225   OLEClipbrd_IDataObject_AddRef,
226   OLEClipbrd_IDataObject_Release,
227   OLEClipbrd_IDataObject_GetData,
228   OLEClipbrd_IDataObject_GetDataHere,
229   OLEClipbrd_IDataObject_QueryGetData,
230   OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
231   OLEClipbrd_IDataObject_SetData,
232   OLEClipbrd_IDataObject_EnumFormatEtc,
233   OLEClipbrd_IDataObject_DAdvise,
234   OLEClipbrd_IDataObject_DUnadvise,
235   OLEClipbrd_IDataObject_EnumDAdvise
236 };
237
238 /*
239  * Virtual function table for IEnumFORMATETC interface
240  */
241 static struct ICOM_VTABLE(IEnumFORMATETC) efvt =
242 {
243   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
244   OLEClipbrd_IEnumFORMATETC_QueryInterface,
245   OLEClipbrd_IEnumFORMATETC_AddRef,
246   OLEClipbrd_IEnumFORMATETC_Release,
247   OLEClipbrd_IEnumFORMATETC_Next,
248   OLEClipbrd_IEnumFORMATETC_Skip,
249   OLEClipbrd_IEnumFORMATETC_Reset,
250   OLEClipbrd_IEnumFORMATETC_Clone
251 };
252
253 /*
254  * Name of our registered OLE clipboard window class 
255  */
256 CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
257
258 /*
259  *  If we need to store state info we can store it here.
260  *  For now we dont need this functionality.
261  *
262 typedef struct tagClipboardWindowInfo
263 {
264 } ClipboardWindowInfo;
265  */
266
267 /*---------------------------------------------------------------------*
268  *           Win32 OLE clipboard API 
269  *---------------------------------------------------------------------*/
270
271 /***********************************************************************
272  *           OleSetClipboard     [OLE32.127]
273  *  Places a pointer to the specified data object onto the clipboard,
274  *  making the data object accessible to the OleGetClipboard function.
275  *
276  * RETURNS:
277  *
278  *    S_OK                  IDataObject pointer placed on the clipboard
279  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed 
280  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed 
281  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
282  *    CLIPBRD_E_CANT_SET    SetClipboard failed
283  */
284
285 HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)
286 {
287   HRESULT hr = S_OK;
288   IEnumFORMATETC* penumFormatetc = NULL;
289   FORMATETC rgelt;
290   BOOL bClipboardOpen = FALSE;
291 /*
292   HGLOBAL hDataObject = 0;
293   OLEClipbrd **ppDataObject;
294 */
295   
296   TRACE("(%p)\n", pDataObj);
297   
298   /*
299    * Make sure we have a clipboard object
300    */
301   OLEClipbrd_Initialize();
302
303   /*
304    * If the Ole clipboard window hasn't been created yet, create it now.
305    */
306   if ( !theOleClipboard->hWndClipboard )
307     theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
308
309   if ( !theOleClipboard->hWndClipboard ) /* sanity check */
310     HANDLE_ERROR( E_FAIL );
311
312   /*
313    * Open the Windows clipboard, associating it with our hidden window
314    */
315   if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
316     HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
317
318   /*
319    * Empty the current clipboard and make our window the clipboard owner
320    * NOTE: This will trigger a WM_DESTROYCLIPBOARD message 
321    */
322   if ( !EmptyClipboard() )
323     HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
324
325   /*
326    * If we are already holding on to an IDataObject first release that.
327    */
328   if ( theOleClipboard->pIDataObjectSrc )
329   {
330     IDataObject_Release(theOleClipboard->pIDataObjectSrc);
331     theOleClipboard->pIDataObjectSrc = NULL;
332   }
333
334   /*
335    * AddRef the data object passed in and save its pointer.
336    * A NULL value indicates that the clipboard should be emptied.
337    */
338   theOleClipboard->pIDataObjectSrc = pDataObj;
339   if ( pDataObj )
340   {
341     IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
342   }
343
344   /*
345    * Enumerate all HGLOBAL formats supported by the source and make 
346    * those formats available using delayed rendering using SetClipboardData.
347    * Only global memory based data items may be made available to non-OLE 
348    * applications via the standard Windows clipboard API. Data based on other 
349    * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API.
350    *
351    * TODO: Do we need to additionally handle TYMED_IStorage media by copying
352    * the storage into global memory?
353    */
354   if ( pDataObj )
355   {
356     if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj,
357                                                 DATADIR_GET,
358                                                 &penumFormatetc )))
359     {
360       HANDLE_ERROR( hr );
361     }
362       
363     while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
364     {
365       if ( rgelt.tymed == TYMED_HGLOBAL )
366       {
367         CHAR szFmtName[80];
368         TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
369               GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
370                 ? szFmtName : "");
371   
372         SetClipboardData( rgelt.cfFormat, (HANDLE)NULL);
373       }
374     }
375     IEnumFORMATETC_Release(penumFormatetc);
376   }
377
378   /*
379    * Windows additionally creates a new "DataObject" clipboard format
380    * and stores in on the clipboard. We could possibly store a pointer 
381    * to our internal IDataObject interface on the clipboard. I'm not
382    * sure what the use of this is though.
383    * Enable the code below for this functionality.
384    */
385 /*
386    theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject");
387    hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
388                              sizeof(OLEClipbrd *));
389    if (hDataObject==0)
390      HANDLE_ERROR( E_OUTOFMEMORY );
391    
392    ppDataObject = (OLEClipbrd**)GlobalLock(hDataObject);
393    *ppDataObject = theOleClipboard;
394    GlobalUnlock(hDataObject);
395
396    if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) )
397      HANDLE_ERROR( CLIPBRD_E_CANT_SET );
398 */
399   
400   hr = S_OK;
401
402 CLEANUP:
403
404   /*
405    * Close Windows clipboard (It remains associated with our window)
406    */
407   if ( bClipboardOpen && !CloseClipboard() )
408     hr = CLIPBRD_E_CANT_CLOSE;
409
410   /*
411    * Release the source IDataObject if something failed
412    */
413   if ( FAILED(hr) )
414   {
415     if (theOleClipboard->pIDataObjectSrc)
416     {
417       IDataObject_Release(theOleClipboard->pIDataObjectSrc);
418       theOleClipboard->pIDataObjectSrc = NULL;
419     }
420   }
421
422   return hr;
423 }
424
425
426 /***********************************************************************
427  * OleGetClipboard32 [OLE32.105]
428  * Returns a pointer to our internal IDataObject which represents the conceptual 
429  * state of the Windows clipboard. If the current clipboard already contains 
430  * an IDataObject, our internal IDataObject will delegate to this object.
431  */
432 HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
433 {
434   HRESULT hr = S_OK;
435   TRACE("()\n");
436     
437   /*
438    * Make sure we have a clipboard object
439    */
440   OLEClipbrd_Initialize();
441
442   if (!theOleClipboard)
443     return E_OUTOFMEMORY;
444
445   /* Return a reference counted IDataObject */
446   hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1),
447                                    &IID_IDataObject,  (void**)ppDataObj);
448   return hr;
449 }
450
451 /***********************************************************************
452  *           OleFlushClipboard   [OLE2.76]
453  */
454
455 HRESULT WINAPI OleFlushClipboard16(void)
456
457 {
458   return OleFlushClipboard();
459 }
460
461
462 /******************************************************************************
463  *              OleFlushClipboard        [OLE32.103]
464  *  Renders the data from the source IDataObject into the windows clipboard
465  *
466  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
467  *  by copying the storage into global memory. Subsequently the default
468  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
469  *  back to TYMED_IStorage.
470  */
471 HRESULT WINAPI OleFlushClipboard()
472 {
473   IEnumFORMATETC* penumFormatetc = NULL;
474   FORMATETC rgelt;
475   HRESULT hr = S_OK;
476   BOOL bClipboardOpen = FALSE;
477   IDataObject* pIDataObjectSrc = NULL;
478   
479   TRACE("()\n");
480
481   /*
482    * Make sure we have a clipboard object
483    */
484   OLEClipbrd_Initialize();
485
486   /*
487    * Already flushed or no source DataObject? Nothing to do.
488    */
489   if (!theOleClipboard->pIDataObjectSrc)
490     return S_OK;
491
492   /*
493    * Addref and save the source data object we are holding on to temporarily,
494    * since it will be released when we empty the clipboard.
495    */
496   pIDataObjectSrc = theOleClipboard->pIDataObjectSrc;
497   IDataObject_AddRef(pIDataObjectSrc);
498   
499   /*
500    * Open the Windows clipboard
501    */
502   if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
503     HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
504
505   /*
506    * Empty the current clipboard
507    */
508   if ( !EmptyClipboard() )
509     HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
510
511   /*
512    * Render all HGLOBAL formats supported by the source into
513    * the windows clipboard.
514    */
515   if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc,
516                                                DATADIR_GET,
517                                                &penumFormatetc) ))
518   {
519     HANDLE_ERROR( hr );
520   }
521
522   while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
523   {
524     if ( rgelt.tymed == TYMED_HGLOBAL )
525     {
526       CHAR szFmtName[80];
527       TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
528             GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
529               ? szFmtName : "");
530
531       /*
532        * Render the clipboard data
533        */
534       if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) )
535         continue;
536     }
537   }
538   
539   IEnumFORMATETC_Release(penumFormatetc);
540   
541   /*
542    * Release the source data object we are holding on to
543    */
544   IDataObject_Release(pIDataObjectSrc);
545
546 CLEANUP:
547
548   /*
549    * Close Windows clipboard (It remains associated with our window)
550    */
551   if ( bClipboardOpen && !CloseClipboard() )
552     hr = CLIPBRD_E_CANT_CLOSE;
553
554   return hr;
555 }
556
557
558 /***********************************************************************
559  *           OleIsCurrentClipboard32 [OLE32.110]
560  */
561 HRESULT WINAPI OleIsCurrentClipboard (  IDataObject *pDataObject) 
562 {
563   TRACE("()\n");
564   /*
565    * Make sure we have a clipboard object
566    */
567   OLEClipbrd_Initialize();
568
569   if (!theOleClipboard)
570     return E_OUTOFMEMORY;
571
572   return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;
573 }
574
575
576 /*---------------------------------------------------------------------*
577  *           Internal implementation methods for the OLE clipboard 
578  *---------------------------------------------------------------------*/
579
580 /***********************************************************************
581  * OLEClipbrd_Initialize()
582  * Initializes the OLE clipboard. 
583  */
584 void OLEClipbrd_Initialize()
585 {
586   /*
587    * Create the clipboard if necesary 
588    */
589   if ( !theOleClipboard )
590   {
591     TRACE("()\n");
592     theOleClipboard = OLEClipbrd_Construct();
593   }
594 }
595
596
597 /***********************************************************************
598  * OLEClipbrd_UnInitialize()
599  * Un-Initializes the OLE clipboard 
600  */
601 void OLEClipbrd_UnInitialize()
602 {
603   TRACE("()\n");
604   /*
605    * Destroy the clipboard if no one holds a reference to us.
606    * Note that the clipboard was created with a reference count of 1.
607    */
608   if ( theOleClipboard && (theOleClipboard->ref <= 1) )
609   {
610     OLEClipbrd_Destroy( theOleClipboard );
611   }
612   else
613   {
614     WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");
615   }
616 }
617
618
619 /*********************************************************
620  * Construct the OLEClipbrd class.
621  */
622 static OLEClipbrd* OLEClipbrd_Construct()
623 {
624   OLEClipbrd* newObject = NULL;
625   HGLOBAL hNewObject = 0;
626   
627   /*
628    * Allocate space for the object. We use GlobalAlloc since we need
629    * an HGLOBAL to expose our DataObject as a registered clipboard type.
630    */
631   hNewObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
632                            sizeof(OLEClipbrd));
633   if (hNewObject==0)
634     return NULL;
635
636   /*
637    * Lock the handle for the entire lifetime of the clipboard.
638    */
639   newObject = GlobalLock(hNewObject);
640   
641   /*
642    * Initialize the virtual function table.
643    */
644   newObject->lpvtbl1 = &OLEClipbrd_IDataObject_VTable;
645
646   /*
647    * Start with one reference count. The caller of this function 
648    * must release the interface pointer when it is done.
649    */
650   newObject->ref = 1;
651
652   newObject->hSelf = hNewObject;
653   
654   /*
655    * The Ole clipboard is a singleton - save the global handle and pointer
656    */
657   theOleClipboard = newObject;
658   hTheOleClipboard = hNewObject;
659
660   return theOleClipboard;
661 }
662
663 static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy)
664 {
665   TRACE("()\n");
666     
667   if ( !ptrToDestroy )
668     return;
669
670   /*
671    * Destroy the Ole clipboard window 
672    */
673   if ( ptrToDestroy->hWndClipboard )
674     OLEClipbrd_DestroyWindow(ptrToDestroy->hWndClipboard);
675
676   /*
677    * Free the actual OLE Clipboard structure.
678    */
679   TRACE("() - Destroying clipboard data object.\n");
680   GlobalUnlock(ptrToDestroy->hSelf);
681   GlobalFree(ptrToDestroy->hSelf);
682
683   /*
684    * The Ole clipboard is a singleton (ptrToDestroy == theOleClipboard)
685    */
686   theOleClipboard = NULL;
687   hTheOleClipboard = 0;
688 }
689
690
691 /***********************************************************************
692  * OLEClipbrd_CreateWindow()
693  * Create the clipboard window 
694  */
695 static HWND OLEClipbrd_CreateWindow()
696 {
697   HWND hwnd = 0;
698   WNDCLASSEXA wcex;
699
700   /* 
701    * Register the clipboard window class if necessary 
702    */
703     ZeroMemory( &wcex, sizeof(WNDCLASSEXA));
704
705     wcex.cbSize         = sizeof(WNDCLASSEXA);
706     /* Windows creates this class with a style mask of 0
707      * We dont bother doing this since the FindClassByAtom code
708      * would have to be changed to deal with this idiosyncracy. */
709     wcex.style          = CS_GLOBALCLASS;
710     wcex.lpfnWndProc    = (WNDPROC)OLEClipbrd_WndProc;
711     wcex.hInstance      = 0;
712     wcex.lpszClassName  = OLEClipbrd_WNDCLASS;
713
714     RegisterClassExA(&wcex);
715
716   /*
717    * Create a hidden window to receive OLE clipboard messages 
718    */
719
720 /*
721  *  If we need to store state info we can store it here.
722  *  For now we dont need this functionality.
723  *   ClipboardWindowInfo clipboardInfo;
724  *   ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo));
725  */
726
727   hwnd = CreateWindowA(OLEClipbrd_WNDCLASS, 
728                                     "ClipboardWindow",
729                                     WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
730                                     CW_USEDEFAULT, CW_USEDEFAULT,
731                                     CW_USEDEFAULT, CW_USEDEFAULT,
732                                     0,
733                                     0,
734                                     0,
735                                     0 /*(LPVOID)&clipboardInfo */);
736
737   return hwnd;
738 }
739
740 /***********************************************************************
741  * OLEClipbrd_DestroyWindow(HWND)
742  * Destroy the clipboard window and unregister its class
743  */
744 static void OLEClipbrd_DestroyWindow(HWND hwnd)
745 {
746   /* 
747    * Destroy clipboard window and unregister its WNDCLASS 
748    */
749   DestroyWindow(hwnd);
750   UnregisterClassA( OLEClipbrd_WNDCLASS, 0 );
751 }
752
753 /***********************************************************************
754  * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG)
755  * Processes messages sent to the OLE clipboard window. 
756  * Note that we will intercept messages in our WndProc only when data 
757  * has been placed in the clipboard via OleSetClipboard(). 
758  * i.e. Only when OLE owns the windows clipboard.
759  */
760 LRESULT CALLBACK OLEClipbrd_WndProc
761   (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
762 {
763   switch (message) 
764   {
765     /*
766      * WM_RENDERFORMAT 
767      * We receive this message to allow us to handle delayed rendering of
768      * a specific clipboard format when an application requests data in 
769      * that format by calling GetClipboardData.
770      * (Recall that in OleSetClipboard, we used SetClipboardData to 
771      * make all HGLOBAL formats supported by the source IDataObject
772      * available using delayed rendering)
773      * On receiving this mesage we must actually render the data in the 
774      * specified format and place it on the clipboard by calling the 
775      * SetClipboardData function. 
776      */
777     case WM_RENDERFORMAT:
778     {
779       FORMATETC rgelt;
780         
781       ZeroMemory( &rgelt, sizeof(FORMATETC));
782
783       /*
784        * Initialize FORMATETC to a Windows clipboard friendly format
785        */
786       rgelt.cfFormat = (UINT) wParam;
787       rgelt.dwAspect = DVASPECT_CONTENT;
788       rgelt.lindex = -1;
789       rgelt.tymed = TYMED_HGLOBAL;
790
791       TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat);
792       
793       /*
794        * Render the clipboard data.
795        * (We must have a source data object or we wouldn't be in this WndProc)
796        */
797       OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt );
798
799       break;
800     }
801
802     /*
803      * WM_RENDERALLFORMATS
804      * Sent before the clipboard owner window is destroyed.
805      * We should receive this message only when OleUninitialize is called
806      * while we have an IDataObject in the clipboard.
807      * For the content of the clipboard to remain available to other
808      * applications, we must render data in all the formats the source IDataObject
809      * is capable of generating, and place the data on the clipboard by calling
810      * SetClipboardData.
811      */
812     case WM_RENDERALLFORMATS:
813     {
814       IEnumFORMATETC* penumFormatetc = NULL;
815       FORMATETC rgelt;
816       
817       TRACE("(): WM_RENDERALLFORMATS\n");
818       
819       /*
820        * Render all HGLOBAL formats supported by the source into
821        * the windows clipboard.
822        */
823       if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1),
824                                  DATADIR_GET, &penumFormatetc) ) )
825       {
826         WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n");
827         return 0;
828       }
829
830       while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
831       {
832         if ( rgelt.tymed == TYMED_HGLOBAL )
833         {
834           /*
835            * Render the clipboard data. 
836            */
837           if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) )
838             continue;
839         
840           TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat);
841         }
842       }
843       
844       IEnumFORMATETC_Release(penumFormatetc);
845
846       break;
847     }
848
849     /*
850      * WM_DESTROYCLIPBOARD
851      * This is sent by EmptyClipboard before the clipboard is emptied.
852      * We should release any IDataObject we are holding onto when we receive
853      * this message, since it indicates that the OLE clipboard should be empty
854      * from this point on.
855      */
856     case WM_DESTROYCLIPBOARD:
857     {
858       TRACE("(): WM_DESTROYCLIPBOARD\n");
859       /*
860        * Release the data object we are holding on to
861        */
862       if ( theOleClipboard->pIDataObjectSrc )
863       {
864         IDataObject_Release(theOleClipboard->pIDataObjectSrc);
865         theOleClipboard->pIDataObjectSrc = NULL;
866       }
867       break;
868     }
869
870 /*
871     case WM_ASKCBFORMATNAME:
872     case WM_CHANGECBCHAIN:
873     case WM_DRAWCLIPBOARD:
874     case WM_SIZECLIPBOARD:
875     case WM_HSCROLLCLIPBOARD:
876     case WM_VSCROLLCLIPBOARD:
877     case WM_PAINTCLIPBOARD:
878 */
879     default:
880       return DefWindowProcA(hWnd, message, wParam, lParam);
881   }
882
883   return 0;
884 }
885
886
887 /***********************************************************************
888  * OLEClipbrd_RenderFormat(LPFORMATETC)
889  * Render the clipboard data. Note that this call will delegate to the
890  * source data object.
891  * Note: This function assumes it is passed an HGLOBAL format to render.
892  */
893 static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc)
894 {
895   STGMEDIUM medium;
896   HGLOBAL hDup;
897   HRESULT hr = S_OK;
898   
899   if ( FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &medium)) )
900   {
901     WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr);
902     return hr;
903   }
904
905   /*
906    *  Put a copy of the rendered data back on the clipboard
907    */
908   
909   if ( !(hDup = OLEClipbrd_GlobalDupMem(medium.u.hGlobal)) )
910     HANDLE_ERROR( E_OUTOFMEMORY );
911        
912   if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) )
913   {
914     GlobalFree(hDup);
915     WARN("() : Failed to set rendered clipboard data into clipboard!\n");
916   }
917
918 CLEANUP:
919   
920   ReleaseStgMedium(&medium);
921   
922   return hr;
923 }
924
925
926 /***********************************************************************
927  * OLEClipbrd_GlobalDupMem( HGLOBAL )
928  * Helper method to duplicate an HGLOBAL chunk of memory
929  */
930 static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc )
931 {
932     HGLOBAL hGlobalDest;
933     PVOID pGlobalSrc, pGlobalDest;
934     DWORD cBytes;
935     
936     if ( !hGlobalSrc )
937       return 0;
938
939     cBytes = GlobalSize(hGlobalSrc);
940     if ( 0 == cBytes )
941       return 0;
942         
943     hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE,
944                                cBytes );
945     if ( !hGlobalDest )
946       return 0;
947     
948     pGlobalSrc = GlobalLock(hGlobalSrc);
949     pGlobalDest = GlobalLock(hGlobalDest);
950     if ( !pGlobalSrc || !pGlobalDest )
951       return 0;
952
953     memcpy(pGlobalDest, pGlobalSrc, cBytes);
954         
955     GlobalUnlock(hGlobalSrc);
956     GlobalUnlock(hGlobalDest);
957
958     return hGlobalDest;
959 }
960
961
962 /*---------------------------------------------------------------------*
963  *  Implementation of the internal IDataObject interface exposed by 
964  *  the OLE clipboard.
965  *---------------------------------------------------------------------*/
966
967
968 /************************************************************************
969  * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
970  *
971  * See Windows documentation for more details on IUnknown methods.
972  */
973 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
974             IDataObject*     iface,
975             REFIID           riid,
976             void**           ppvObject)
977 {
978   /* 
979    * Declare "This" pointer 
980    */
981   ICOM_THIS(OLEClipbrd, iface);
982   TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObject);
983   
984   /*
985    * Perform a sanity check on the parameters.
986    */
987   if ( (This==0) || (ppvObject==0) )
988     return E_INVALIDARG;
989   
990   /*
991    * Initialize the return parameter.
992    */
993   *ppvObject = 0;
994
995   /*
996    * Compare the riid with the interface IDs implemented by this object.
997    */
998   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
999   {
1000     *ppvObject = iface;
1001   }
1002   else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) 
1003   {
1004     *ppvObject = (IDataObject*)&(This->lpvtbl1);
1005   }
1006   else  /* We only support IUnknown and IDataObject */
1007   {
1008     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1009     return E_NOINTERFACE;
1010   }
1011   
1012   /*
1013    * Query Interface always increases the reference count by one when it is
1014    * successful. 
1015    */
1016   IUnknown_AddRef((IUnknown*)*ppvObject);
1017
1018   return S_OK;
1019 }
1020
1021 /************************************************************************
1022  * OLEClipbrd_IDataObject_AddRef (IUnknown)
1023  *
1024  * See Windows documentation for more details on IUnknown methods.
1025  */
1026 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( 
1027             IDataObject*     iface)
1028 {
1029   /* 
1030    * Declare "This" pointer 
1031    */
1032   ICOM_THIS(OLEClipbrd, iface);
1033
1034   TRACE("(%p)->(count=%lu)\n",This, This->ref);
1035   
1036   This->ref++;
1037
1038   return This->ref;
1039 }
1040
1041 /************************************************************************
1042  * OLEClipbrd_IDataObject_Release (IUnknown)
1043  *
1044  * See Windows documentation for more details on IUnknown methods.
1045  */
1046 static ULONG WINAPI OLEClipbrd_IDataObject_Release( 
1047             IDataObject*     iface)
1048 {
1049   /* 
1050    * Declare "This" pointer 
1051    */
1052   ICOM_THIS(OLEClipbrd, iface);
1053
1054   TRACE("(%p)->(count=%lu)\n",This, This->ref);
1055   
1056   /*
1057    * Decrease the reference count on this object.
1058    */
1059   This->ref--;
1060
1061   /*
1062    * If the reference count goes down to 0, perform suicide.
1063    */
1064   if (This->ref==0)
1065   {
1066     OLEClipbrd_Destroy(This);
1067   }
1068   
1069   return This->ref;
1070 }
1071
1072  
1073 /************************************************************************
1074  * OLEClipbrd_IDataObject_GetData (IDataObject)
1075  *
1076  * The OLE Clipboard's implementation of this method delegates to 
1077  * a data source if there is one or wraps around the windows clipboard
1078  *
1079  * See Windows documentation for more details on IDataObject methods.
1080  */
1081 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
1082             IDataObject*     iface,
1083             LPFORMATETC      pformatetcIn, 
1084             STGMEDIUM*       pmedium)
1085 {
1086   HANDLE      hData = 0;
1087   BOOL bClipboardOpen = FALSE;
1088   HRESULT hr = S_OK;
1089
1090   /*
1091    * Declare "This" pointer 
1092    */
1093   ICOM_THIS(OLEClipbrd, iface);
1094  
1095   TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
1096
1097   if ( !pformatetcIn || !pmedium )
1098     return E_INVALIDARG;
1099
1100   /*
1101    * If we have a data source placed on the clipboard (via OleSetClipboard)
1102    * simply delegate to the source object's QueryGetData
1103    * NOTE: This code assumes that the IDataObject is in the same address space!
1104    * We will need to add marshalling support when Wine handles multiple processes.
1105    */
1106   if ( This->pIDataObjectSrc )
1107   {
1108     return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
1109   }
1110
1111   if ( pformatetcIn->lindex != -1 )
1112     return DV_E_LINDEX;
1113   if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
1114     return DV_E_TYMED;
1115 /*
1116    if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
1117      return DV_E_DVASPECT;
1118 */
1119
1120   /* 
1121    * Otherwise, get the data from the windows clipboard using GetClipboardData
1122    */
1123   if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
1124     HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
1125
1126   hData = GetClipboardData(pformatetcIn->cfFormat);
1127
1128   /* 
1129    * Return the clipboard data in the storage medium structure
1130    */
1131   pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
1132   pmedium->u.hGlobal = (HGLOBAL)hData;
1133   pmedium->pUnkForRelease = NULL;
1134   
1135   hr = S_OK;
1136   
1137 CLEANUP:
1138   /*
1139    * Close Windows clipboard
1140    */
1141   if ( bClipboardOpen && !CloseClipboard() )
1142      hr = CLIPBRD_E_CANT_CLOSE;
1143
1144   if ( FAILED(hr) )
1145       return hr;
1146   return (hData == 0) ? DV_E_FORMATETC : S_OK;
1147 }
1148
1149 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
1150             IDataObject*     iface, 
1151             LPFORMATETC      pformatetc,
1152             STGMEDIUM*       pmedium)
1153 {
1154   FIXME(": Stub\n");
1155   return E_NOTIMPL;
1156 }
1157
1158 /************************************************************************
1159  * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
1160  *
1161  * The OLE Clipboard's implementation of this method delegates to 
1162  * a data source if there is one or wraps around the windows clipboard
1163  * function IsClipboardFormatAvailable() otherwise.
1164  *
1165  * See Windows documentation for more details on IDataObject methods.
1166  */
1167 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
1168             IDataObject*     iface,
1169             LPFORMATETC      pformatetc)
1170 {
1171   /* 
1172    * Declare "This" pointer 
1173    */
1174   ICOM_THIS(OLEClipbrd, iface);
1175
1176   TRACE("(%p, %p)\n", iface, pformatetc);
1177
1178   /*
1179    * If we have a data source placed on the clipboard (via OleSetClipboard)
1180    * simply delegate to the source object's QueryGetData
1181    */
1182   if ( This->pIDataObjectSrc )
1183   {
1184     return IDataObject_QueryGetData(This->pIDataObjectSrc, pformatetc);
1185   }
1186
1187   if (!pformatetc)
1188     return E_INVALIDARG;
1189 /*
1190    if ( pformatetc->dwAspect != DVASPECT_CONTENT )
1191      return DV_E_DVASPECT;
1192 */
1193   if ( pformatetc->lindex != -1 )
1194     return DV_E_LINDEX;
1195
1196   /* TODO: Handle TYMED_IStorage media which were put on the clipboard
1197    * by copying the storage into global memory. We must convert this
1198    * TYMED_HGLOBAL back to TYMED_IStorage.
1199    */
1200   if ( pformatetc->tymed != TYMED_HGLOBAL )
1201     return DV_E_TYMED;
1202           
1203   /*
1204    * Delegate to the Windows clipboard function IsClipboardFormatAvailable
1205    */
1206   return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_FORMATETC;
1207 }
1208
1209 /************************************************************************
1210  * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
1211  *
1212  * See Windows documentation for more details on IDataObject methods.
1213  */
1214 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
1215             IDataObject*     iface, 
1216             LPFORMATETC      pformatectIn, 
1217             LPFORMATETC      pformatetcOut)
1218 {
1219   TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
1220
1221   if ( !pformatectIn || !pformatetcOut )
1222     return E_INVALIDARG;
1223
1224   memcpy(pformatetcOut, pformatectIn, sizeof(FORMATETC));
1225   return DATA_S_SAMEFORMATETC;
1226 }
1227
1228 /************************************************************************
1229  * OLEClipbrd_IDataObject_SetData (IDataObject)
1230  *
1231  * The OLE Clipboard's does not implement this method 
1232  *
1233  * See Windows documentation for more details on IDataObject methods.
1234  */
1235 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
1236             IDataObject*     iface,
1237             LPFORMATETC      pformatetc, 
1238             STGMEDIUM*       pmedium, 
1239             BOOL             fRelease)
1240 {
1241   TRACE("\n");
1242   return E_NOTIMPL;
1243 }
1244
1245 /************************************************************************
1246  * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
1247  *
1248  * See Windows documentation for more details on IDataObject methods.
1249  */
1250 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
1251             IDataObject*     iface,
1252             DWORD            dwDirection,
1253             IEnumFORMATETC** ppenumFormatEtc)
1254 {
1255   HRESULT hr = S_OK;
1256   FORMATETC *afmt = NULL;
1257   int cfmt, i;
1258   UINT format;
1259   BOOL bClipboardOpen;
1260   
1261   /* 
1262    * Declare "This" pointer 
1263    */
1264   ICOM_THIS(OLEClipbrd, iface);
1265
1266   TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc);
1267
1268   /*
1269    * If we have a data source placed on the clipboard (via OleSetClipboard)
1270    * simply delegate to the source object's EnumFormatEtc
1271    */
1272   if ( This->pIDataObjectSrc )
1273   {
1274     return IDataObject_EnumFormatEtc(This->pIDataObjectSrc,
1275                                      dwDirection, ppenumFormatEtc);
1276   }
1277
1278   /*
1279    * Otherwise we must provide our own enumerator which wraps around the
1280    * Windows clipboard function EnumClipboardFormats
1281    */
1282   if ( !ppenumFormatEtc )
1283     return E_INVALIDARG;
1284
1285   if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */
1286     return E_NOTIMPL;
1287
1288   /*
1289    * Store all current clipboard formats in an array of FORMATETC's,
1290    * and create an IEnumFORMATETC enumerator from this list.
1291    */
1292   cfmt = CountClipboardFormats();
1293   afmt = (FORMATETC *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1294                                 sizeof(FORMATETC) * cfmt);
1295   /*
1296    * Open the Windows clipboard, associating it with our hidden window
1297    */
1298   if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) )
1299     HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
1300
1301   /*
1302    * Store all current clipboard formats in an array of FORMATETC's
1303    * TODO: Handle TYMED_IStorage media which were put on the clipboard
1304    * by copying the storage into global memory. We must convert this
1305    * TYMED_HGLOBAL back to TYMED_IStorage.
1306    */
1307   for (i = 0, format = 0; i < cfmt; i++)
1308   {
1309     format = EnumClipboardFormats(format);
1310     if (!format)  /* Failed! */
1311     {
1312       ERR("EnumClipboardFormats failed to return format!\n");
1313       HANDLE_ERROR( E_FAIL );
1314     }
1315     
1316     /* Init the FORMATETC struct */
1317     afmt[i].cfFormat = format;
1318     afmt[i].ptd = NULL;
1319     afmt[i].dwAspect = DVASPECT_CONTENT;
1320     afmt[i].lindex = -1;
1321     afmt[i].tymed = TYMED_HGLOBAL;
1322   }
1323
1324   /*
1325    * Create an EnumFORMATETC enumerator and return an
1326    * EnumFORMATETC after bumping up its ref count
1327    */
1328   *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface);
1329   if (!(*ppenumFormatEtc))
1330     HANDLE_ERROR( E_OUTOFMEMORY );
1331
1332   if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc)))
1333     HANDLE_ERROR( hr );
1334       
1335   hr = S_OK;
1336   
1337 CLEANUP:
1338   /*
1339    * Free the array of FORMATETC's
1340    */
1341   if (afmt)
1342     HeapFree(GetProcessHeap(), 0, afmt);
1343   
1344   /*
1345    * Close Windows clipboard
1346    */
1347   if ( bClipboardOpen && !CloseClipboard() )
1348     hr = CLIPBRD_E_CANT_CLOSE;
1349
1350   return hr;
1351 }
1352
1353 /************************************************************************
1354  * OLEClipbrd_IDataObject_DAdvise (IDataObject)
1355  *
1356  * The OLE Clipboard's does not implement this method 
1357  *
1358  * See Windows documentation for more details on IDataObject methods.
1359  */
1360 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
1361             IDataObject*     iface, 
1362             FORMATETC*       pformatetc, 
1363             DWORD            advf, 
1364             IAdviseSink*     pAdvSink, 
1365             DWORD*           pdwConnection)
1366 {
1367   TRACE("\n");
1368   return E_NOTIMPL;
1369 }
1370
1371 /************************************************************************
1372  * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
1373  *
1374  * The OLE Clipboard's does not implement this method 
1375  *
1376  * See Windows documentation for more details on IDataObject methods.
1377  */
1378 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
1379             IDataObject*     iface,
1380             DWORD            dwConnection)
1381 {
1382   TRACE("\n");
1383   return E_NOTIMPL;
1384 }
1385
1386 /************************************************************************
1387  * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
1388  *
1389  * The OLE Clipboard does not implement this method
1390  *
1391  * See Windows documentation for more details on IDataObject methods.
1392  */
1393 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
1394             IDataObject*     iface,
1395             IEnumSTATDATA**  ppenumAdvise)
1396 {
1397   TRACE("\n");
1398   return E_NOTIMPL;
1399 }
1400
1401
1402 /*---------------------------------------------------------------------*
1403  *  Implementation of the internal IEnumFORMATETC interface returned by
1404  *  the OLE clipboard's IDataObject.
1405  *---------------------------------------------------------------------*/
1406
1407 /************************************************************************
1408  * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN)
1409  *
1410  * Creates an IEnumFORMATETC enumerator from an array of FORMATETC
1411  * Structures. pUnkOuter is the outer unknown for reference counting only.
1412  * NOTE: this does not AddRef the interface.
1413  */
1414
1415 LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
1416                                                     LPUNKNOWN pUnkDataObj)
1417 {
1418   IEnumFORMATETCImpl* ef;
1419   DWORD size=cfmt * sizeof(FORMATETC);
1420   LPMALLOC pIMalloc;
1421   
1422   ef = (IEnumFORMATETCImpl*)HeapAlloc(GetProcessHeap(),
1423                                       HEAP_ZERO_MEMORY,
1424                                       sizeof(IEnumFORMATETCImpl));
1425   if (!ef)
1426     return NULL;
1427   
1428   ef->ref = 0;
1429   ICOM_VTBL(ef) = &efvt;
1430   ef->pUnkDataObj = pUnkDataObj;
1431   
1432   ef->posFmt = 0;
1433   ef->countFmt = cfmt;
1434   if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
1435     return NULL;
1436   ef->pFmt = (LPFORMATETC)IMalloc_Alloc(pIMalloc, size);
1437   IMalloc_Release(pIMalloc);
1438   
1439   if (ef->pFmt)
1440     memcpy(ef->pFmt, afmt, size);
1441   
1442   TRACE("(%p)->()\n",ef);
1443   return (LPENUMFORMATETC)ef;
1444 }
1445
1446
1447 /************************************************************************
1448  * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
1449  *
1450  * See Windows documentation for more details on IUnknown methods.
1451  */
1452 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
1453   (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
1454 {
1455   ICOM_THIS(IEnumFORMATETCImpl,iface);
1456
1457   TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
1458
1459   /*
1460    * Since enumerators are seperate objects from the parent data object
1461    * we only need to support the IUnknown and IEnumFORMATETC interfaces
1462    */
1463   
1464   *ppvObj = NULL;
1465   
1466   if(IsEqualIID(riid, &IID_IUnknown))
1467   {
1468     *ppvObj = This;
1469   }
1470   else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
1471   {
1472     *ppvObj = (IDataObject*)This;
1473   }   
1474   
1475   if(*ppvObj)
1476   {
1477     IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
1478     TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
1479     return S_OK;
1480   }
1481   
1482   TRACE("-- Interface: E_NOINTERFACE\n");
1483   return E_NOINTERFACE;
1484 }
1485
1486 /************************************************************************
1487  * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
1488  *
1489  * Since enumerating formats only makes sense when our data object is around,
1490  * we insure that it stays as long as we stay by calling our parents IUnknown
1491  * for AddRef and Release. But since we are not controlled by the lifetime of
1492  * the outer object, we still keep our own reference count in order to
1493  * free ourselves.
1494  */
1495 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
1496 {
1497   ICOM_THIS(IEnumFORMATETCImpl,iface);
1498   TRACE("(%p)->(count=%lu)\n",This, This->ref);
1499
1500   if (This->pUnkDataObj)
1501     IUnknown_AddRef(This->pUnkDataObj);
1502   
1503   return ++(This->ref);
1504 }
1505
1506 /************************************************************************
1507  * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
1508  *
1509  * See Windows documentation for more details on IUnknown methods.
1510  */
1511 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
1512 {
1513   ICOM_THIS(IEnumFORMATETCImpl,iface);
1514   LPMALLOC pIMalloc;
1515
1516   TRACE("(%p)->(count=%lu)\n",This, This->ref);
1517
1518   if (This->pUnkDataObj)
1519     IUnknown_Release(This->pUnkDataObj);  /* Release parent data object */
1520   
1521   if (!--(This->ref)) 
1522   {
1523     TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
1524     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
1525     {
1526       IMalloc_Free(pIMalloc, This->pFmt);
1527       IMalloc_Release(pIMalloc);
1528     }
1529       
1530     HeapFree(GetProcessHeap(),0,This);
1531     return 0;
1532   }
1533
1534   return This->ref;
1535 }
1536
1537 /************************************************************************
1538  * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
1539  *
1540  * Standard enumerator members for IEnumFORMATETC
1541  */
1542 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
1543   (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
1544 {
1545   ICOM_THIS(IEnumFORMATETCImpl,iface);
1546   UINT cfetch;
1547   HRESULT hres = S_FALSE;
1548   
1549   TRACE("(%p)->(pos=%u)\n", This, This->posFmt);
1550   
1551   if (This->posFmt < This->countFmt)
1552   {
1553     cfetch = This->countFmt - This->posFmt;
1554     if (cfetch >= celt)
1555     {
1556       cfetch = celt;
1557       hres = S_OK;
1558     }
1559     
1560     memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));
1561     This->posFmt += cfetch;
1562   }
1563   else
1564   {
1565     cfetch = 0;
1566   }
1567   
1568   if (pceltFethed)
1569   {
1570     *pceltFethed = cfetch;
1571   }
1572   
1573   return hres;
1574 }
1575
1576 /************************************************************************
1577  * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
1578  *
1579  * Standard enumerator members for IEnumFORMATETC
1580  */
1581 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
1582 {
1583   ICOM_THIS(IEnumFORMATETCImpl,iface);
1584   TRACE("(%p)->(num=%lu)\n", This, celt);
1585   
1586   This->posFmt += celt;
1587   if (This->posFmt > This->countFmt)
1588   {
1589     This->posFmt = This->countFmt;
1590     return S_FALSE;
1591   }
1592   return S_OK;
1593 }
1594
1595 /************************************************************************
1596  * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
1597  *
1598  * Standard enumerator members for IEnumFORMATETC
1599  */
1600 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
1601 {
1602   ICOM_THIS(IEnumFORMATETCImpl,iface);
1603   TRACE("(%p)->()\n", This);
1604   
1605   This->posFmt = 0;
1606   return S_OK;
1607 }
1608
1609 /************************************************************************
1610  * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
1611  *
1612  * Standard enumerator members for IEnumFORMATETC
1613  */
1614 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
1615   (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
1616 {
1617   ICOM_THIS(IEnumFORMATETCImpl,iface);
1618   HRESULT hr = S_OK;
1619   
1620   TRACE("(%p)->(ppenum=%p)\n", This, ppenum);
1621
1622   if ( !ppenum )
1623     return E_INVALIDARG;
1624
1625   *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt,
1626                                                 This->pFmt,
1627                                                 This->pUnkDataObj);
1628
1629   if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum)))
1630     return ( hr );
1631   
1632   return (*ppenum) ? S_OK : E_OUTOFMEMORY;
1633 }
1634