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