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