ole32/tests: Show that it's the loword of the separate flag parameter that determines...
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <stdarg.h>
63 #include <string.h>
64 #include <stdio.h>
65
66 #define COBJMACROS
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
69
70 #include "windef.h"
71 #include "winbase.h"
72 #include "wingdi.h"
73 #include "winuser.h"
74 #include "winerror.h"
75 #include "winnls.h"
76 #include "ole2.h"
77 #include "wine/debug.h"
78 #include "olestd.h"
79
80 #include "storage32.h"
81
82 #include "compobj_private.h"
83
84 WINE_DEFAULT_DEBUG_CHANNEL(ole);
85
86 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
87
88 /* Structure of 'Ole Private Data' clipboard format */
89 typedef struct
90 {
91     FORMATETC fmtetc;
92     DWORD first_use;  /* Has this cf been added to the list already */
93     DWORD unk[2];
94 } ole_priv_data_entry;
95
96 typedef struct
97 {
98     DWORD unk1;
99     DWORD size; /* in bytes of the entire structure */
100     DWORD unk2;
101     DWORD count; /* no. of format entries */
102     DWORD unk3[2];
103     ole_priv_data_entry entries[1]; /* array of size count */
104     /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
105 } ole_priv_data;
106
107 /*****************************************************************************
108  *           td_offs_to_ptr
109  *
110  * Returns a ptr to a target device at a given offset from the
111  * start of the ole_priv_data.
112  *
113  * Used when unpacking ole private data from the clipboard.
114  */
115 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
116 {
117     if(off == 0) return NULL;
118     return (DVTARGETDEVICE*)((char*)data + off);
119 }
120
121 /*****************************************************************************
122  *           td_get_offs
123  *
124  * Get the offset from the start of the ole_priv_data of the idx'th
125  * target device.
126  *
127  * Used when packing ole private data to the clipboard.
128  */
129 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
130 {
131     if(data->entries[idx].fmtetc.ptd == NULL) return 0;
132     return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
133 }
134
135 /****************************************************************************
136  * Consumer snapshot.  Represents the state of the ole clipboard
137  * returned by OleGetClipboard().
138  */
139 typedef struct snapshot
140 {
141     const IDataObjectVtbl* lpVtbl;
142     LONG ref;
143
144     DWORD seq_no;                   /* Clipboard sequence number corresponding to this snapshot */
145
146     IDataObject *data;              /* If we unmarshal a remote data object we hold a ref here */
147 } snapshot;
148
149 /****************************************************************************
150  * ole_clipbrd
151  */
152 typedef struct ole_clipbrd
153 {
154     snapshot *latest_snapshot;       /* Latest consumer snapshot */
155
156     HWND window;                     /* Hidden clipboard window */
157     IDataObject *src_data;           /* Source object passed to OleSetClipboard */
158     ole_priv_data *cached_enum;      /* Cached result from the enumeration of src data object */
159     IStream *marshal_data;           /* Stream onto which to marshal src_data */
160 } ole_clipbrd;
161
162 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
163 {
164     return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
165 }
166
167 typedef struct PresentationDataHeader
168 {
169   BYTE unknown1[28];
170   DWORD dwObjectExtentX;
171   DWORD dwObjectExtentY;
172   DWORD dwSize;
173 } PresentationDataHeader;
174
175 /*
176  * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
177  */
178 static ole_clipbrd* theOleClipboard;
179
180 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
181 {
182     struct oletls *info = COM_CurrentInfo();
183     *clipbrd = NULL;
184
185     if(!info->ole_inits)
186         return CO_E_NOTINITIALIZED;
187     *clipbrd = theOleClipboard;
188
189     return S_OK;
190 }
191
192 /*
193  * Name of our registered OLE clipboard window class
194  */
195 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
196
197 static const WCHAR wine_marshal_dataobject[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0};
198
199 UINT ownerlink_clipboard_format = 0;
200 UINT filename_clipboard_format = 0;
201 UINT filenameW_clipboard_format = 0;
202 UINT dataobject_clipboard_format = 0;
203 UINT embedded_object_clipboard_format = 0;
204 UINT embed_source_clipboard_format = 0;
205 UINT custom_link_source_clipboard_format = 0;
206 UINT link_source_clipboard_format = 0;
207 UINT object_descriptor_clipboard_format = 0;
208 UINT link_source_descriptor_clipboard_format = 0;
209 UINT ole_private_data_clipboard_format = 0;
210
211 static UINT wine_marshal_clipboard_format;
212
213 static inline char *dump_fmtetc(FORMATETC *fmt)
214 {
215     static char buf[100];
216
217     snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
218              fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
219     return buf;
220 }
221
222 /*---------------------------------------------------------------------*
223  *  Implementation of the internal IEnumFORMATETC interface returned by
224  *  the OLE clipboard's IDataObject.
225  *---------------------------------------------------------------------*/
226
227 typedef struct enum_fmtetc
228 {
229     const IEnumFORMATETCVtbl *lpVtbl;
230     LONG ref;
231
232     UINT pos;    /* current enumerator position */
233     ole_priv_data *data;
234 } enum_fmtetc;
235
236 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
237 {
238     return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
239 }
240
241 /************************************************************************
242  * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
243  *
244  * See Windows documentation for more details on IUnknown methods.
245  */
246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
247   (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
248 {
249   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
250
251   TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
252
253   *ppvObj = NULL;
254
255   if(IsEqualIID(riid, &IID_IUnknown) ||
256      IsEqualIID(riid, &IID_IEnumFORMATETC))
257   {
258     *ppvObj = iface;
259   }
260
261   if(*ppvObj)
262   {
263     IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
264     TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
265     return S_OK;
266   }
267
268   TRACE("-- Interface: E_NOINTERFACE\n");
269   return E_NOINTERFACE;
270 }
271
272 /************************************************************************
273  * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
274  *
275  */
276 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
277 {
278   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
279   TRACE("(%p)->(count=%u)\n",This, This->ref);
280
281   return InterlockedIncrement(&This->ref);
282 }
283
284 /************************************************************************
285  * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
286  *
287  * See Windows documentation for more details on IUnknown methods.
288  */
289 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
290 {
291   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
292   ULONG ref;
293
294   TRACE("(%p)->(count=%u)\n",This, This->ref);
295
296   ref = InterlockedDecrement(&This->ref);
297   if (!ref)
298   {
299     TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
300     HeapFree(GetProcessHeap(), 0, This->data);
301     HeapFree(GetProcessHeap(), 0, This);
302   }
303   return ref;
304 }
305
306 /************************************************************************
307  * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
308  *
309  * Standard enumerator members for IEnumFORMATETC
310  */
311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
312   (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
313 {
314   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
315   UINT cfetch, i;
316   HRESULT hres = S_FALSE;
317
318   TRACE("(%p)->(pos=%u)\n", This, This->pos);
319
320   if (This->pos < This->data->count)
321   {
322     cfetch = This->data->count - This->pos;
323     if (cfetch >= celt)
324     {
325       cfetch = celt;
326       hres = S_OK;
327     }
328
329     for(i = 0; i < cfetch; i++)
330     {
331       rgelt[i] = This->data->entries[This->pos++].fmtetc;
332       if(rgelt[i].ptd)
333       {
334         DVTARGETDEVICE *target = rgelt[i].ptd;
335         rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
336         if(!rgelt[i].ptd) return E_OUTOFMEMORY;
337         memcpy(rgelt[i].ptd, target, target->tdSize);
338       }
339     }
340   }
341   else
342   {
343     cfetch = 0;
344   }
345
346   if (pceltFethed)
347   {
348     *pceltFethed = cfetch;
349   }
350
351   return hres;
352 }
353
354 /************************************************************************
355  * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
356  *
357  * Standard enumerator members for IEnumFORMATETC
358  */
359 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
360 {
361   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
362   TRACE("(%p)->(num=%u)\n", This, celt);
363
364   This->pos += celt;
365   if (This->pos > This->data->count)
366   {
367     This->pos = This->data->count;
368     return S_FALSE;
369   }
370   return S_OK;
371 }
372
373 /************************************************************************
374  * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
375  *
376  * Standard enumerator members for IEnumFORMATETC
377  */
378 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
379 {
380   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
381   TRACE("(%p)->()\n", This);
382
383   This->pos = 0;
384   return S_OK;
385 }
386
387 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
388
389 /************************************************************************
390  * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
391  *
392  * Standard enumerator members for IEnumFORMATETC
393  */
394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
395   (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
396 {
397   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
398   ole_priv_data *new_data;
399   DWORD i;
400
401   TRACE("(%p)->(%p)\n", This, obj);
402
403   if ( !obj ) return E_INVALIDARG;
404   *obj = NULL;
405
406   new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
407   if(!new_data) return E_OUTOFMEMORY;
408   memcpy(new_data, This->data, This->data->size);
409
410   /* Fixup any target device ptrs */
411   for(i = 0; i < This->data->count; i++)
412       new_data->entries[i].fmtetc.ptd =
413           td_offs_to_ptr(new_data, td_get_offs(This->data, i));
414
415   return enum_fmtetc_construct(new_data, This->pos, obj);
416 }
417
418 static const IEnumFORMATETCVtbl efvt =
419 {
420   OLEClipbrd_IEnumFORMATETC_QueryInterface,
421   OLEClipbrd_IEnumFORMATETC_AddRef,
422   OLEClipbrd_IEnumFORMATETC_Release,
423   OLEClipbrd_IEnumFORMATETC_Next,
424   OLEClipbrd_IEnumFORMATETC_Skip,
425   OLEClipbrd_IEnumFORMATETC_Reset,
426   OLEClipbrd_IEnumFORMATETC_Clone
427 };
428
429 /************************************************************************
430  * enum_fmtetc_construct
431  *
432  * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
433  */
434 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
435 {
436   enum_fmtetc* ef;
437
438   *obj = NULL;
439   ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
440   if (!ef) return E_OUTOFMEMORY;
441
442   ef->ref = 1;
443   ef->lpVtbl = &efvt;
444   ef->data = data;
445   ef->pos = pos;
446
447   TRACE("(%p)->()\n", ef);
448   *obj = (IEnumFORMATETC *)ef;
449   return S_OK;
450 }
451
452 /***********************************************************************
453  *                    dup_global_mem
454  *
455  * Helper method to duplicate an HGLOBAL chunk of memory
456  */
457 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
458 {
459     void *src_ptr, *dst_ptr;
460     DWORD size;
461
462     *dst = NULL;
463     if ( !src ) return S_FALSE;
464
465     size = GlobalSize(src);
466
467     *dst = GlobalAlloc( flags, size );
468     if ( !*dst ) return E_OUTOFMEMORY;
469
470     src_ptr = GlobalLock(src);
471     dst_ptr = GlobalLock(*dst);
472
473     memcpy(dst_ptr, src_ptr, size);
474
475     GlobalUnlock(*dst);
476     GlobalUnlock(src);
477
478     return S_OK;
479 }
480
481 /************************************************************
482  *              render_embed_source_hack
483  *
484  * This is clearly a hack and has no place in the clipboard code.
485  *
486  */
487 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
488 {
489     STGMEDIUM std;
490     HGLOBAL hStorage = 0;
491     HRESULT hr = S_OK;
492     ILockBytes *ptrILockBytes;
493
494     memset(&std, 0, sizeof(STGMEDIUM));
495     std.tymed = fmt->tymed = TYMED_ISTORAGE;
496
497     hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
498     if (hStorage == NULL) return E_OUTOFMEMORY;
499     hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
500     hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
501     ILockBytes_Release(ptrILockBytes);
502
503     if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
504     {
505         WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
506         GlobalFree(hStorage);
507         return hr;
508     }
509
510     if (1) /* check whether the presentation data is already -not- present */
511     {
512         FORMATETC fmt2;
513         STGMEDIUM std2;
514         METAFILEPICT *mfp = 0;
515
516         fmt2.cfFormat = CF_METAFILEPICT;
517         fmt2.ptd = 0;
518         fmt2.dwAspect = DVASPECT_CONTENT;
519         fmt2.lindex = -1;
520         fmt2.tymed = TYMED_MFPICT;
521
522         memset(&std2, 0, sizeof(STGMEDIUM));
523         std2.tymed = TYMED_MFPICT;
524
525         /* Get the metafile picture out of it */
526
527         if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
528         {
529             mfp = GlobalLock(std2.u.hGlobal);
530         }
531
532         if (mfp)
533         {
534             OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
535             IStream *pStream = 0;
536             void *mfBits;
537             PresentationDataHeader pdh;
538             INT nSize;
539             CLSID clsID;
540             LPOLESTR strProgID;
541             CHAR strOleTypeName[51];
542             BYTE OlePresStreamHeader [] =
543             {
544                 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
545                 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
546                 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
547                 0x00, 0x00, 0x00, 0x00
548             };
549
550             nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
551
552             memset(&pdh, 0, sizeof(PresentationDataHeader));
553             memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
554
555             pdh.dwObjectExtentX = mfp->xExt;
556             pdh.dwObjectExtentY = mfp->yExt;
557             pdh.dwSize = nSize;
558
559             hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
560
561             hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
562
563             mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
564             nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
565
566             hr = IStream_Write(pStream, mfBits, nSize, NULL);
567
568             IStream_Release(pStream);
569
570             HeapFree(GetProcessHeap(), 0, mfBits);
571
572             GlobalUnlock(std2.u.hGlobal);
573             ReleaseStgMedium(&std2);
574
575             ReadClassStg(std.u.pstg, &clsID);
576             ProgIDFromCLSID(&clsID, &strProgID);
577
578             WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
579             OLECONVERT_CreateOleStream(std.u.pstg);
580             OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
581         }
582     }
583
584     if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
585     {
586         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
587         GlobalFree(hStorage);
588         hr = CLIPBRD_E_CANT_SET;
589     }
590
591     ReleaseStgMedium(&std);
592     return hr;
593 }
594
595 /************************************************************************
596  *           find_format_in_list
597  *
598  * Returns the first entry that matches the provided clipboard format.
599  */
600 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
601 {
602     DWORD i;
603     for(i = 0; i < num; i++)
604         if(entries[i].fmtetc.cfFormat == cf)
605             return &entries[i];
606
607     return NULL;
608 }
609
610 /***************************************************************************
611  *         get_data_from_storage
612  *
613  * Returns storage data in an HGLOBAL.
614  */
615 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
616 {
617     HGLOBAL h;
618     IStorage *stg;
619     HRESULT hr;
620     FORMATETC stg_fmt;
621     STGMEDIUM med;
622     ILockBytes *lbs;
623
624     *mem = NULL;
625
626     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
627     if(!h) return E_OUTOFMEMORY;
628
629     hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
630     if(SUCCEEDED(hr))
631     {
632         hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
633         ILockBytes_Release(lbs);
634     }
635     if(FAILED(hr))
636     {
637         GlobalFree(h);
638         return hr;
639     }
640
641     stg_fmt = *fmt;
642     med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
643     med.u.pstg = stg;
644     med.pUnkForRelease = NULL;
645
646     hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
647     if(FAILED(hr))
648     {
649         med.u.pstg = NULL;
650         hr = IDataObject_GetData(data, &stg_fmt, &med);
651         if(FAILED(hr)) goto end;
652
653         hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
654         ReleaseStgMedium(&med);
655         if(FAILED(hr)) goto end;
656     }
657     *mem = h;
658
659 end:
660     IStorage_Release(stg);
661     if(FAILED(hr)) GlobalFree(h);
662     return hr;
663 }
664
665 /***************************************************************************
666  *         get_data_from_stream
667  *
668  * Returns stream data in an HGLOBAL.
669  */
670 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
671 {
672     HGLOBAL h;
673     IStream *stm = NULL;
674     HRESULT hr;
675     FORMATETC stm_fmt;
676     STGMEDIUM med;
677
678     *mem = NULL;
679
680     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
681     if(!h) return E_OUTOFMEMORY;
682
683     hr = CreateStreamOnHGlobal(h, FALSE, &stm);
684     if(FAILED(hr)) goto error;
685
686     stm_fmt = *fmt;
687     med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
688     med.u.pstm = stm;
689     med.pUnkForRelease = NULL;
690
691     hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
692     if(FAILED(hr))
693     {
694         LARGE_INTEGER offs;
695         ULARGE_INTEGER pos;
696
697         med.u.pstm = NULL;
698         hr = IDataObject_GetData(data, &stm_fmt, &med);
699         if(FAILED(hr)) goto error;
700
701         offs.QuadPart = 0;
702         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
703         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
704         hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
705         ReleaseStgMedium(&med);
706         if(FAILED(hr)) goto error;
707     }
708     *mem = h;
709     IStream_Release(stm);
710     return S_OK;
711
712 error:
713     if(stm) IStream_Release(stm);
714     GlobalFree(h);
715     return hr;
716 }
717
718 /***************************************************************************
719  *         get_data_from_global
720  *
721  * Returns global data in an HGLOBAL.
722  */
723 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
724 {
725     HGLOBAL h;
726     HRESULT hr;
727     FORMATETC mem_fmt;
728     STGMEDIUM med;
729
730     *mem = NULL;
731
732     mem_fmt = *fmt;
733     mem_fmt.tymed = TYMED_HGLOBAL;
734
735     hr = IDataObject_GetData(data, &mem_fmt, &med);
736     if(FAILED(hr)) return hr;
737
738     hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
739
740     if(SUCCEEDED(hr)) *mem = h;
741
742     ReleaseStgMedium(&med);
743
744     return hr;
745 }
746
747 /***********************************************************************
748  *                render_format
749  *
750  * Render the clipboard data. Note that this call will delegate to the
751  * source data object.
752  */
753 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
754 {
755     HGLOBAL clip_data = NULL;
756     HRESULT hr;
757
758     /* Embed source hack */
759     if(fmt->cfFormat == embed_source_clipboard_format)
760     {
761         return render_embed_source_hack(data, fmt);
762     }
763
764     if(fmt->tymed & TYMED_ISTORAGE)
765     {
766         hr = get_data_from_storage(data, fmt, &clip_data);
767     }
768     else if(fmt->tymed & TYMED_ISTREAM)
769     {
770         hr = get_data_from_stream(data, fmt, &clip_data);
771     }
772     else if(fmt->tymed & TYMED_HGLOBAL)
773     {
774         hr = get_data_from_global(data, fmt, &clip_data);
775     }
776     else
777     {
778         FIXME("Unhandled tymed %x\n", fmt->tymed);
779         hr = DV_E_FORMATETC;
780     }
781
782     if(SUCCEEDED(hr))
783     {
784         if ( !SetClipboardData(fmt->cfFormat, clip_data) )
785         {
786             WARN("() : Failed to set rendered clipboard data into clipboard!\n");
787             GlobalFree(clip_data);
788             hr = CLIPBRD_E_CANT_SET;
789         }
790     }
791
792     return hr;
793 }
794
795 /*---------------------------------------------------------------------*
796  *  Implementation of the internal IDataObject interface exposed by
797  *  the OLE clipboard.
798  *---------------------------------------------------------------------*/
799
800
801 /************************************************************************
802  *           snapshot_QueryInterface
803  */
804 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
805                                               REFIID riid, void **ppvObject)
806 {
807   snapshot *This = impl_from_IDataObject(iface);
808   TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
809
810   if ( (This==0) || (ppvObject==0) )
811     return E_INVALIDARG;
812
813   *ppvObject = 0;
814
815   if (IsEqualIID(&IID_IUnknown, riid) ||
816       IsEqualIID(&IID_IDataObject, riid))
817   {
818     *ppvObject = iface;
819   }
820   else
821   {
822     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
823     return E_NOINTERFACE;
824   }
825
826   IUnknown_AddRef((IUnknown*)*ppvObject);
827
828   return S_OK;
829 }
830
831 /************************************************************************
832  *              snapshot_AddRef
833  */
834 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
835 {
836     snapshot *This = impl_from_IDataObject(iface);
837
838     TRACE("(%p)->(count=%u)\n", This, This->ref);
839
840     return InterlockedIncrement(&This->ref);
841 }
842
843 /************************************************************************
844  *      snapshot_Release
845  */
846 static ULONG WINAPI snapshot_Release(IDataObject *iface)
847 {
848     snapshot *This = impl_from_IDataObject(iface);
849     ULONG ref;
850
851     TRACE("(%p)->(count=%u)\n", This, This->ref);
852
853     ref = InterlockedDecrement(&This->ref);
854
855     if (ref == 0)
856     {
857         ole_clipbrd *clipbrd;
858         HRESULT hr = get_ole_clipbrd(&clipbrd);
859
860         if(This->data) IDataObject_Release(This->data);
861
862         if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
863             clipbrd->latest_snapshot = NULL;
864         HeapFree(GetProcessHeap(), 0, This);
865     }
866
867     return ref;
868 }
869
870 /************************************************************
871  *              get_current_ole_clip_window
872  *
873  * Return the window that owns the ole clipboard.
874  *
875  * If the clipboard is flushed or not owned by ole this will
876  * return NULL.
877  */
878 static HWND get_current_ole_clip_window(void)
879 {
880     HGLOBAL h;
881     HWND *ptr, wnd;
882
883     h = GetClipboardData(dataobject_clipboard_format);
884     if(!h) return NULL;
885     ptr = GlobalLock(h);
886     if(!ptr) return NULL;
887     wnd = *ptr;
888     GlobalUnlock(h);
889     return wnd;
890 }
891
892 /************************************************************
893  *              get_current_dataobject
894  *
895  * Return an unmarshalled IDataObject if there is a current
896  * (ie non-flushed) object on the ole clipboard.
897  */
898 static HRESULT get_current_dataobject(IDataObject **data)
899 {
900     HRESULT hr = S_FALSE;
901     HWND wnd = get_current_ole_clip_window();
902     HGLOBAL h;
903     void *ptr;
904     IStream *stm;
905     LARGE_INTEGER pos;
906
907     *data = NULL;
908     if(!wnd) return S_FALSE;
909
910     h = GetClipboardData(wine_marshal_clipboard_format);
911     if(!h) return S_FALSE;
912     if(GlobalSize(h) == 0) return S_FALSE;
913     ptr = GlobalLock(h);
914     if(!ptr) return S_FALSE;
915
916     hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
917     if(FAILED(hr)) goto end;
918
919     hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
920     if(SUCCEEDED(hr))
921     {
922         pos.QuadPart = 0;
923         IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
924         hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
925     }
926     IStream_Release(stm);
927
928 end:
929     GlobalUnlock(h);
930     return hr;
931 }
932
933 static DWORD get_tymed_from_nonole_cf(UINT cf)
934 {
935     if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
936
937     switch(cf)
938     {
939     case CF_TEXT:
940     case CF_OEMTEXT:
941     case CF_UNICODETEXT:
942         return TYMED_ISTREAM | TYMED_HGLOBAL;
943     case CF_ENHMETAFILE:
944         return TYMED_ENHMF;
945     case CF_METAFILEPICT:
946         return TYMED_MFPICT;
947     default:
948         FIXME("returning TYMED_NULL for cf %04x\n", cf);
949         return TYMED_NULL;
950     }
951 }
952
953 /***********************************************************
954  *     get_priv_data
955  *
956  * Returns a copy of the Ole Private Data
957  */
958 static HRESULT get_priv_data(ole_priv_data **data)
959 {
960     HGLOBAL handle;
961     HRESULT hr = S_OK;
962     ole_priv_data *ret = NULL;
963
964     *data = NULL;
965
966     handle = GetClipboardData( ole_private_data_clipboard_format );
967     if(handle)
968     {
969         ole_priv_data *src = GlobalLock(handle);
970         if(src)
971         {
972             DWORD i;
973
974             /* FIXME: sanity check on size */
975             ret = HeapAlloc(GetProcessHeap(), 0, src->size);
976             if(!ret)
977             {
978                 GlobalUnlock(handle);
979                 return E_OUTOFMEMORY;
980             }
981             memcpy(ret, src, src->size);
982             GlobalUnlock(handle);
983
984             /* Fixup any target device offsets to ptrs */
985             for(i = 0; i < ret->count; i++)
986                 ret->entries[i].fmtetc.ptd =
987                     td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
988         }
989     }
990
991     if(!ret) /* Non-ole data */
992     {
993         UINT cf;
994         DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
995
996         for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
997         {
998             char buf[100];
999             GetClipboardFormatNameA(cf, buf, sizeof(buf));
1000             TRACE("\tcf %04x %s\n", cf, buf);
1001             ;
1002         }
1003         TRACE("count %d\n", count);
1004         size += count * sizeof(ret->entries[0]);
1005
1006         /* There are holes in fmtetc so zero init */
1007         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1008         if(!ret) return E_OUTOFMEMORY;
1009         ret->size = size;
1010         ret->count = count;
1011
1012         for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1013         {
1014             ret->entries[idx].fmtetc.cfFormat = cf;
1015             ret->entries[idx].fmtetc.ptd = NULL;
1016             ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1017             ret->entries[idx].fmtetc.lindex = -1;
1018             ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1019             ret->entries[idx].first_use = 1;
1020         }
1021     }
1022
1023     *data = ret;
1024     return hr;
1025 }
1026
1027 /************************************************************************
1028  *                    get_stgmed_for_global
1029  *
1030  * Returns a stg medium with a copy of the global handle
1031  */
1032 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1033 {
1034     HRESULT hr;
1035
1036     med->pUnkForRelease = NULL;
1037     med->tymed = TYMED_NULL;
1038
1039     hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1040
1041     if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1042
1043     return hr;
1044 }
1045
1046 /************************************************************************
1047  *                    get_stgmed_for_stream
1048  *
1049  * Returns a stg medium with a stream based on the handle
1050  */
1051 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1052 {
1053     HRESULT hr;
1054     HGLOBAL dst;
1055
1056     med->pUnkForRelease = NULL;
1057     med->tymed = TYMED_NULL;
1058
1059     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1060     if(FAILED(hr)) return hr;
1061
1062     hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1063     if(FAILED(hr))
1064     {
1065         GlobalFree(dst);
1066         return hr;
1067     }
1068
1069     med->tymed = TYMED_ISTREAM;
1070     return hr;
1071 }
1072
1073 /************************************************************************
1074  *                    get_stgmed_for_storage
1075  *
1076  * Returns a stg medium with a storage based on the handle
1077  */
1078 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1079 {
1080     HRESULT hr;
1081     HGLOBAL dst;
1082     ILockBytes *lbs;
1083
1084     med->pUnkForRelease = NULL;
1085     med->tymed = TYMED_NULL;
1086
1087     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1088     if(FAILED(hr)) return hr;
1089
1090     hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1091     if(FAILED(hr))
1092     {
1093         GlobalFree(dst);
1094         return hr;
1095     }
1096
1097     hr = StgOpenStorageOnILockBytes(lbs, NULL,  STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1098     ILockBytes_Release(lbs);
1099     if(FAILED(hr))
1100     {
1101         GlobalFree(dst);
1102         return hr;
1103     }
1104
1105     med->tymed = TYMED_ISTORAGE;
1106     return hr;
1107 }
1108
1109 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1110 {
1111     const WCHAR *str1, *str2;
1112
1113     if(off1 == 0 && off2 == 0) return TRUE;
1114     if(off1 == 0 || off2 == 0) return FALSE;
1115
1116     str1 = (const WCHAR*)((const char*)t1 + off1);
1117     str2 = (const WCHAR*)((const char*)t2 + off2);
1118
1119     return !lstrcmpW(str1, str2);
1120 }
1121
1122 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1123 {
1124     if(t1 == NULL && t2 == NULL) return TRUE;
1125     if(t1 == NULL || t2 == NULL) return FALSE;
1126
1127     if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1128         return FALSE;
1129     if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1130         return FALSE;
1131     if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1132         return FALSE;
1133
1134     /* FIXME check devmode? */
1135
1136     return TRUE;
1137 }
1138
1139 /************************************************************************
1140  *         snapshot_GetData
1141  */
1142 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1143                                        STGMEDIUM *med)
1144 {
1145     snapshot *This = impl_from_IDataObject(iface);
1146     HANDLE h;
1147     HRESULT hr;
1148     ole_priv_data *enum_data = NULL;
1149     ole_priv_data_entry *entry;
1150     DWORD mask;
1151
1152     TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1153
1154     if ( !fmt || !med ) return E_INVALIDARG;
1155
1156     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1157
1158     if(!This->data)
1159         hr = get_current_dataobject(&This->data);
1160
1161     if(This->data)
1162     {
1163         hr = IDataObject_GetData(This->data, fmt, med);
1164         CloseClipboard();
1165         return hr;
1166     }
1167
1168     h = GetClipboardData(fmt->cfFormat);
1169     if(!h)
1170     {
1171         hr = DV_E_FORMATETC;
1172         goto end;
1173     }
1174
1175     hr = get_priv_data(&enum_data);
1176     if(FAILED(hr)) goto end;
1177
1178     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1179     if(entry)
1180     {
1181         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1182         {
1183             hr = DV_E_FORMATETC;
1184             goto end;
1185         }
1186         mask = fmt->tymed & entry->fmtetc.tymed;
1187         if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1188     }
1189     else /* non-Ole format */
1190         mask = fmt->tymed & TYMED_HGLOBAL;
1191
1192     if(mask & TYMED_ISTORAGE)
1193         hr = get_stgmed_for_storage(h, med);
1194     else if(mask & TYMED_HGLOBAL)
1195         hr = get_stgmed_for_global(h, med);
1196     else if(mask & TYMED_ISTREAM)
1197         hr = get_stgmed_for_stream(h, med);
1198     else
1199     {
1200         FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1201         hr = E_FAIL;
1202         goto end;
1203     }
1204
1205 end:
1206     HeapFree(GetProcessHeap(), 0, enum_data);
1207     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1208     return hr;
1209 }
1210
1211 /************************************************************************
1212  *          snapshot_GetDataHere
1213  */
1214 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1215                                            STGMEDIUM *med)
1216 {
1217     snapshot *This = impl_from_IDataObject(iface);
1218     HANDLE h;
1219     HRESULT hr;
1220     ole_priv_data *enum_data = NULL;
1221     ole_priv_data_entry *entry;
1222     TYMED supported;
1223
1224     TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1225
1226     if ( !fmt || !med ) return E_INVALIDARG;
1227
1228     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1229
1230     if(!This->data)
1231         hr = get_current_dataobject(&This->data);
1232
1233     if(This->data)
1234     {
1235         hr = IDataObject_GetDataHere(This->data, fmt, med);
1236         if(SUCCEEDED(hr))
1237         {
1238             CloseClipboard();
1239             return hr;
1240         }
1241     }
1242
1243     h = GetClipboardData(fmt->cfFormat);
1244     if(!h)
1245     {
1246         hr = DV_E_FORMATETC;
1247         goto end;
1248     }
1249
1250     hr = get_priv_data(&enum_data);
1251     if(FAILED(hr)) goto end;
1252
1253     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1254     if(entry)
1255     {
1256         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1257         {
1258             hr = DV_E_FORMATETC;
1259             goto end;
1260         }
1261         supported = entry->fmtetc.tymed;
1262     }
1263     else /* non-Ole format */
1264         supported = TYMED_HGLOBAL;
1265
1266     switch(med->tymed)
1267     {
1268     case TYMED_HGLOBAL:
1269     {
1270         DWORD src_size = GlobalSize(h);
1271         DWORD dst_size = GlobalSize(med->u.hGlobal);
1272         hr = E_FAIL;
1273         if(dst_size >= src_size)
1274         {
1275             void *src = GlobalLock(h);
1276             void *dst = GlobalLock(med->u.hGlobal);
1277
1278             memcpy(dst, src, src_size);
1279             GlobalUnlock(med->u.hGlobal);
1280             GlobalUnlock(h);
1281             hr = S_OK;
1282         }
1283         break;
1284     }
1285     case TYMED_ISTREAM:
1286     {
1287         DWORD src_size = GlobalSize(h);
1288         void *src = GlobalLock(h);
1289         hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1290         GlobalUnlock(h);
1291         break;
1292     }
1293     case TYMED_ISTORAGE:
1294     {
1295         STGMEDIUM copy;
1296         if(!(supported & TYMED_ISTORAGE))
1297         {
1298             hr = E_FAIL;
1299             goto end;
1300         }
1301         hr = get_stgmed_for_storage(h, &copy);
1302         if(SUCCEEDED(hr))
1303         {
1304             hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1305             ReleaseStgMedium(&copy);
1306         }
1307         break;
1308     }
1309     default:
1310         FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1311         hr = E_FAIL;
1312         goto end;
1313     }
1314
1315 end:
1316     HeapFree(GetProcessHeap(), 0, enum_data);
1317     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1318     return hr;
1319 }
1320
1321 /************************************************************************
1322  *           snapshot_QueryGetData
1323  *
1324  * The OLE Clipboard's implementation of this method delegates to
1325  * a data source if there is one or wraps around the windows clipboard
1326  * function IsClipboardFormatAvailable() otherwise.
1327  *
1328  */
1329 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1330 {
1331     FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1332
1333     if (!fmt) return E_INVALIDARG;
1334
1335     if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1336
1337     if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1338
1339     return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1340 }
1341
1342 /************************************************************************
1343  *              snapshot_GetCanonicalFormatEtc
1344  */
1345 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1346                                                      FORMATETC *fmt_out)
1347 {
1348     TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1349
1350     if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1351
1352     *fmt_out = *fmt_in;
1353     return DATA_S_SAMEFORMATETC;
1354 }
1355
1356 /************************************************************************
1357  *              snapshot_SetData
1358  *
1359  * The OLE Clipboard does not implement this method
1360  */
1361 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1362                                        STGMEDIUM *med, BOOL release)
1363 {
1364     TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1365     return E_NOTIMPL;
1366 }
1367
1368 /************************************************************************
1369  *             snapshot_EnumFormatEtc
1370  *
1371  */
1372 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1373                                              IEnumFORMATETC **enum_fmt)
1374 {
1375     HRESULT hr;
1376     ole_priv_data *data = NULL;
1377
1378     TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1379
1380     *enum_fmt = NULL;
1381
1382     if ( dir != DATADIR_GET ) return E_NOTIMPL;
1383     if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1384
1385     hr = get_priv_data(&data);
1386
1387     if(FAILED(hr)) goto end;
1388
1389     hr = enum_fmtetc_construct( data, 0, enum_fmt );
1390
1391 end:
1392     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1393     return hr;
1394 }
1395
1396 /************************************************************************
1397  *               snapshot_DAdvise
1398  *
1399  * The OLE Clipboard does not implement this method
1400  */
1401 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1402                                        DWORD flags, IAdviseSink *sink,
1403                                        DWORD *conn)
1404 {
1405     TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1406     return E_NOTIMPL;
1407 }
1408
1409 /************************************************************************
1410  *              snapshot_DUnadvise
1411  *
1412  * The OLE Clipboard does not implement this method
1413  */
1414 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1415 {
1416     TRACE("(%p, %d): not implemented\n", iface, conn);
1417     return E_NOTIMPL;
1418 }
1419
1420 /************************************************************************
1421  *             snapshot_EnumDAdvise
1422  *
1423  * The OLE Clipboard does not implement this method
1424  */
1425 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1426                                            IEnumSTATDATA** enum_advise)
1427 {
1428     TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1429     return E_NOTIMPL;
1430 }
1431
1432 static const IDataObjectVtbl snapshot_vtable =
1433 {
1434     snapshot_QueryInterface,
1435     snapshot_AddRef,
1436     snapshot_Release,
1437     snapshot_GetData,
1438     snapshot_GetDataHere,
1439     snapshot_QueryGetData,
1440     snapshot_GetCanonicalFormatEtc,
1441     snapshot_SetData,
1442     snapshot_EnumFormatEtc,
1443     snapshot_DAdvise,
1444     snapshot_DUnadvise,
1445     snapshot_EnumDAdvise
1446 };
1447
1448 /*---------------------------------------------------------------------*
1449  *           Internal implementation methods for the OLE clipboard
1450  *---------------------------------------------------------------------*/
1451
1452 static snapshot *snapshot_construct(DWORD seq_no)
1453 {
1454     snapshot *This;
1455
1456     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1457     if (!This) return NULL;
1458
1459     This->lpVtbl = &snapshot_vtable;
1460     This->ref = 0;
1461     This->seq_no = seq_no;
1462     This->data = NULL;
1463
1464     return This;
1465 }
1466
1467 /*********************************************************
1468  *               register_clipboard_formats
1469  */
1470 static void register_clipboard_formats(void)
1471 {
1472     static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1473     static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1474     static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1475     static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1476     static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1477     static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1478     static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1479     static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1480     static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1481     static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1482                                                  'D','e','s','c','r','i','p','t','o','r',0};
1483     static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1484
1485     static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1486                                                      'D','a','t','a','O','b','j','e','c','t',0};
1487
1488     ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1489     filename_clipboard_format = RegisterClipboardFormatW(FileName);
1490     filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1491     dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1492     embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1493     embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1494     custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1495     link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1496     object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1497     link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1498     ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1499
1500     wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1501 }
1502
1503 /***********************************************************************
1504  * OLEClipbrd_Initialize()
1505  * Initializes the OLE clipboard.
1506  */
1507 void OLEClipbrd_Initialize(void)
1508 {
1509     register_clipboard_formats();
1510
1511     if ( !theOleClipboard )
1512     {
1513         ole_clipbrd* clipbrd;
1514         HGLOBAL h;
1515
1516         TRACE("()\n");
1517
1518         clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1519         if (!clipbrd) return;
1520
1521         clipbrd->latest_snapshot = NULL;
1522         clipbrd->window = NULL;
1523         clipbrd->src_data = NULL;
1524         clipbrd->cached_enum = NULL;
1525
1526         h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1527         if(!h)
1528         {
1529             HeapFree(GetProcessHeap(), 0, clipbrd);
1530             return;
1531         }
1532
1533         if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1534         {
1535             GlobalFree(h);
1536             HeapFree(GetProcessHeap(), 0, clipbrd);
1537             return;
1538         }
1539
1540         theOleClipboard = clipbrd;
1541     }
1542 }
1543
1544 /***********************************************************************
1545  * OLEClipbrd_UnInitialize()
1546  * Un-Initializes the OLE clipboard
1547  */
1548 void OLEClipbrd_UnInitialize(void)
1549 {
1550     ole_clipbrd *clipbrd = theOleClipboard;
1551
1552     TRACE("()\n");
1553
1554     if ( clipbrd )
1555     {
1556         static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1557         HINSTANCE hinst = GetModuleHandleW(ole32W);
1558
1559         if ( clipbrd->window )
1560         {
1561             DestroyWindow(clipbrd->window);
1562             UnregisterClassW( clipbrd_wndclass, hinst );
1563         }
1564
1565         IStream_Release(clipbrd->marshal_data);
1566         HeapFree(GetProcessHeap(), 0, clipbrd);
1567         theOleClipboard = NULL;
1568     }
1569 }
1570
1571 /*********************************************************************
1572  *          set_clipboard_formats
1573  *
1574  * Enumerate all formats supported by the source and make
1575  * those formats available using delayed rendering using SetClipboardData.
1576  * Cache the enumeration list and make that list visibile as the
1577  * 'Ole Private Data' format on the clipboard.
1578  *
1579  */
1580 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1581 {
1582     HRESULT hr;
1583     FORMATETC fmt;
1584     IEnumFORMATETC *enum_fmt;
1585     HGLOBAL priv_data_handle;
1586     DWORD_PTR target_offset;
1587     ole_priv_data *priv_data;
1588     DWORD count = 0, needed = sizeof(*priv_data), idx;
1589
1590     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1591     if(FAILED(hr)) return hr;
1592
1593     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1594     {
1595         count++;
1596         needed += sizeof(priv_data->entries[0]);
1597         if(fmt.ptd)
1598         {
1599             needed += fmt.ptd->tdSize;
1600             CoTaskMemFree(fmt.ptd);
1601         }
1602     }
1603
1604     /* Windows pads the list with two empty ole_priv_data_entries, one
1605      * after the entries array and one after the target device data.
1606      * Allocating with zero init to zero these pads. */
1607
1608     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1609     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1610     priv_data = GlobalLock(priv_data_handle);
1611
1612     priv_data->unk1 = 0;
1613     priv_data->size = needed;
1614     priv_data->unk2 = 1;
1615     priv_data->count = count;
1616     priv_data->unk3[0] = 0;
1617     priv_data->unk3[1] = 0;
1618
1619     IEnumFORMATETC_Reset(enum_fmt);
1620
1621     idx = 0;
1622     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1623
1624     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1625     {
1626         TRACE("%s\n", dump_fmtetc(&fmt));
1627
1628         priv_data->entries[idx].fmtetc = fmt;
1629         if(fmt.ptd)
1630         {
1631             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1632             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1633             target_offset += fmt.ptd->tdSize;
1634             CoTaskMemFree(fmt.ptd);
1635         }
1636
1637         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1638         priv_data->entries[idx].unk[0] = 0;
1639         priv_data->entries[idx].unk[1] = 0;
1640
1641         if (priv_data->entries[idx].first_use)
1642             SetClipboardData(fmt.cfFormat, NULL);
1643
1644         idx++;
1645     }
1646
1647     IEnumFORMATETC_Release(enum_fmt);
1648
1649     /* Cache the list and fixup any target device offsets to ptrs */
1650     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1651     memcpy(clipbrd->cached_enum, priv_data, needed);
1652     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1653         clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1654             td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1655
1656     GlobalUnlock(priv_data_handle);
1657     SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1658
1659     return S_OK;
1660 }
1661
1662 static HWND create_clipbrd_window(void);
1663
1664 /***********************************************************************
1665  *                 get_clipbrd_window
1666  */
1667 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1668 {
1669     if ( !clipbrd->window )
1670         clipbrd->window = create_clipbrd_window();
1671
1672     *wnd = clipbrd->window;
1673     return *wnd ? S_OK : E_FAIL;
1674 }
1675
1676
1677 /**********************************************************************
1678  *                  release_marshal_data
1679  *
1680  * Releases the data and sets the stream back to zero size.
1681  */
1682 static inline void release_marshal_data(IStream *stm)
1683 {
1684     LARGE_INTEGER pos;
1685     ULARGE_INTEGER size;
1686     pos.QuadPart = size.QuadPart = 0;
1687
1688     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1689     CoReleaseMarshalData(stm);
1690     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1691     IStream_SetSize(stm, size);
1692 }
1693
1694 /***********************************************************************
1695  *   expose_marshalled_dataobject
1696  *
1697  * Sets the marshalled dataobject to the clipboard.  In the flushed case
1698  * we set a zero sized HGLOBAL to clear the old marshalled data.
1699  */
1700 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1701 {
1702     HGLOBAL h;
1703
1704     if(data)
1705     {
1706         HGLOBAL h_stm;
1707         GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1708         dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1709     }
1710     else /* flushed */
1711         h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1712
1713     if(!h) return E_OUTOFMEMORY;
1714
1715     SetClipboardData(wine_marshal_clipboard_format, h);
1716     return S_OK;
1717 }
1718
1719 /***********************************************************************
1720  *                   set_src_dataobject
1721  *
1722  * Clears and sets the clipboard's src IDataObject.
1723  *
1724  * To marshal the source dataobject we do something rather different from Windows.
1725  * We set a clipboard format which contains the marshalled data.
1726  * Windows sets two window props one of which is an IID, the other is an endpoint number.
1727  */
1728 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1729 {
1730     HRESULT hr;
1731     HWND wnd;
1732
1733     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1734
1735     if(clipbrd->src_data)
1736     {
1737         release_marshal_data(clipbrd->marshal_data);
1738
1739         IDataObject_Release(clipbrd->src_data);
1740         clipbrd->src_data = NULL;
1741         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1742         clipbrd->cached_enum = NULL;
1743     }
1744
1745     if(data)
1746     {
1747         IUnknown *unk;
1748
1749         IDataObject_AddRef(data);
1750         clipbrd->src_data = data;
1751
1752         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1753         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1754                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1755         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1756         if(FAILED(hr)) return hr;
1757         hr = set_clipboard_formats(clipbrd, data);
1758     }
1759     return hr;
1760 }
1761
1762 /***********************************************************************
1763  *                   clipbrd_wndproc
1764  */
1765 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1766 {
1767     ole_clipbrd *clipbrd;
1768
1769     get_ole_clipbrd(&clipbrd);
1770
1771     switch (message)
1772     {
1773     case WM_RENDERFORMAT:
1774     {
1775         UINT cf = wparam;
1776         ole_priv_data_entry *entry;
1777
1778         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1779         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1780
1781         if(entry)
1782             render_format(clipbrd->src_data, &entry->fmtetc);
1783
1784         break;
1785     }
1786
1787     case WM_RENDERALLFORMATS:
1788     {
1789         DWORD i;
1790         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1791
1792         TRACE("(): WM_RENDERALLFORMATS\n");
1793
1794         for(i = 0; i < clipbrd->cached_enum->count; i++)
1795         {
1796             if(entries[i].first_use)
1797                 render_format(clipbrd->src_data, &entries[i].fmtetc);
1798         }
1799         break;
1800     }
1801
1802     case WM_DESTROYCLIPBOARD:
1803     {
1804         TRACE("(): WM_DESTROYCLIPBOARD\n");
1805
1806         set_src_dataobject(clipbrd, NULL);
1807         break;
1808     }
1809
1810     default:
1811         return DefWindowProcW(hwnd, message, wparam, lparam);
1812     }
1813
1814     return 0;
1815 }
1816
1817
1818 /***********************************************************************
1819  *                 create_clipbrd_window
1820  */
1821 static HWND create_clipbrd_window(void)
1822 {
1823     WNDCLASSEXW class;
1824     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1825     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1826     HINSTANCE hinst = GetModuleHandleW(ole32W);
1827
1828     class.cbSize         = sizeof(class);
1829     class.style          = 0;
1830     class.lpfnWndProc    = clipbrd_wndproc;
1831     class.cbClsExtra     = 0;
1832     class.cbWndExtra     = 0;
1833     class.hInstance      = hinst;
1834     class.hIcon          = 0;
1835     class.hCursor        = 0;
1836     class.hbrBackground  = 0;
1837     class.lpszMenuName   = NULL;
1838     class.lpszClassName  = clipbrd_wndclass;
1839     class.hIconSm        = NULL;
1840
1841     RegisterClassExW(&class);
1842
1843     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1844                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1845                          NULL, NULL, hinst, 0);
1846 }
1847
1848 /*********************************************************************
1849  *          set_dataobject_format
1850  *
1851  * Windows creates a 'DataObject' clipboard format that contains the
1852  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1853  */
1854 static HRESULT set_dataobject_format(HWND hwnd)
1855 {
1856     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1857     HWND *data;
1858
1859     if(!h) return E_OUTOFMEMORY;
1860
1861     data = GlobalLock(h);
1862     *data = hwnd;
1863     GlobalUnlock(h);
1864
1865     if(!SetClipboardData(dataobject_clipboard_format, h))
1866     {
1867         GlobalFree(h);
1868         return CLIPBRD_E_CANT_SET;
1869     }
1870
1871     return S_OK;
1872 }
1873
1874 /*---------------------------------------------------------------------*
1875  *           Win32 OLE clipboard API
1876  *---------------------------------------------------------------------*/
1877
1878 /***********************************************************************
1879  *           OleSetClipboard     [OLE32.@]
1880  *  Places a pointer to the specified data object onto the clipboard,
1881  *  making the data object accessible to the OleGetClipboard function.
1882  *
1883  * RETURNS
1884  *
1885  *    S_OK                  IDataObject pointer placed on the clipboard
1886  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
1887  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
1888  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
1889  *    CLIPBRD_E_CANT_SET    SetClipboard failed
1890  */
1891
1892 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1893 {
1894   HRESULT hr;
1895   ole_clipbrd *clipbrd;
1896   HWND wnd;
1897
1898   TRACE("(%p)\n", data);
1899
1900   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1901
1902   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1903
1904   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1905
1906   if ( !EmptyClipboard() )
1907   {
1908     hr = CLIPBRD_E_CANT_EMPTY;
1909     goto end;
1910   }
1911
1912   hr = set_src_dataobject(clipbrd, data);
1913   if(FAILED(hr)) goto end;
1914
1915   if(data)
1916   {
1917     hr = expose_marshalled_dataobject(clipbrd, data);
1918     if(FAILED(hr)) goto end;
1919     hr = set_dataobject_format(wnd);
1920   }
1921
1922 end:
1923
1924   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1925
1926   if ( FAILED(hr) )
1927   {
1928     expose_marshalled_dataobject(clipbrd, NULL);
1929     set_src_dataobject(clipbrd, NULL);
1930   }
1931
1932   return hr;
1933 }
1934
1935
1936 /***********************************************************************
1937  * OleGetClipboard [OLE32.@]
1938  * Returns a pointer to our internal IDataObject which represents the conceptual
1939  * state of the Windows clipboard. If the current clipboard already contains
1940  * an IDataObject, our internal IDataObject will delegate to this object.
1941  */
1942 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1943 {
1944     HRESULT hr;
1945     ole_clipbrd *clipbrd;
1946     DWORD seq_no;
1947
1948     TRACE("(%p)\n", obj);
1949
1950     if(!obj) return E_INVALIDARG;
1951
1952     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1953
1954     seq_no = GetClipboardSequenceNumber();
1955     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1956         clipbrd->latest_snapshot = NULL;
1957
1958     if(!clipbrd->latest_snapshot)
1959     {
1960         clipbrd->latest_snapshot = snapshot_construct(seq_no);
1961         if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1962     }
1963
1964     *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1965     IDataObject_AddRef(*obj);
1966
1967     return S_OK;
1968 }
1969
1970 /******************************************************************************
1971  *              OleFlushClipboard        [OLE32.@]
1972  *  Renders the data from the source IDataObject into the windows clipboard
1973  *
1974  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1975  *  by copying the storage into global memory. Subsequently the default
1976  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1977  *  back to TYMED_IStorage.
1978  */
1979 HRESULT WINAPI OleFlushClipboard(void)
1980 {
1981   HRESULT hr;
1982   ole_clipbrd *clipbrd;
1983   HWND wnd;
1984
1985   TRACE("()\n");
1986
1987   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1988
1989   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1990
1991   /*
1992    * Already flushed or no source DataObject? Nothing to do.
1993    */
1994   if (!clipbrd->src_data) return S_OK;
1995
1996   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1997
1998   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1999
2000   hr = set_dataobject_format(NULL);
2001
2002   expose_marshalled_dataobject(clipbrd, NULL);
2003   set_src_dataobject(clipbrd, NULL);
2004
2005   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2006
2007   return hr;
2008 }
2009
2010
2011 /***********************************************************************
2012  *           OleIsCurrentClipboard [OLE32.@]
2013  */
2014 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2015 {
2016     HRESULT hr;
2017     ole_clipbrd *clipbrd;
2018     TRACE("()\n");
2019
2020     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2021
2022     if (data == NULL) return S_FALSE;
2023
2024     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
2025 }