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