crypt32: Constify some variables.
[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("cf %04x %s\n", cf, buf);
1001         }
1002         TRACE("count %d\n", count);
1003         size += count * sizeof(ret->entries[0]);
1004
1005         /* There are holes in fmtetc so zero init */
1006         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1007         if(!ret) return E_OUTOFMEMORY;
1008         ret->size = size;
1009         ret->count = count;
1010
1011         for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1012         {
1013             ret->entries[idx].fmtetc.cfFormat = cf;
1014             ret->entries[idx].fmtetc.ptd = NULL;
1015             ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1016             ret->entries[idx].fmtetc.lindex = -1;
1017             ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1018             ret->entries[idx].first_use = 1;
1019         }
1020     }
1021
1022     *data = ret;
1023     return hr;
1024 }
1025
1026 /************************************************************************
1027  *                    get_stgmed_for_global
1028  *
1029  * Returns a stg medium with a copy of the global handle
1030  */
1031 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1032 {
1033     HRESULT hr;
1034
1035     med->pUnkForRelease = NULL;
1036     med->tymed = TYMED_NULL;
1037
1038     hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1039
1040     if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1041
1042     return hr;
1043 }
1044
1045 /************************************************************************
1046  *                    get_stgmed_for_stream
1047  *
1048  * Returns a stg medium with a stream based on the handle
1049  */
1050 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1051 {
1052     HRESULT hr;
1053     HGLOBAL dst;
1054
1055     med->pUnkForRelease = NULL;
1056     med->tymed = TYMED_NULL;
1057
1058     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1059     if(FAILED(hr)) return hr;
1060
1061     hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1062     if(FAILED(hr))
1063     {
1064         GlobalFree(dst);
1065         return hr;
1066     }
1067
1068     med->tymed = TYMED_ISTREAM;
1069     return hr;
1070 }
1071
1072 /************************************************************************
1073  *                    get_stgmed_for_storage
1074  *
1075  * Returns a stg medium with a storage based on the handle
1076  */
1077 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1078 {
1079     HRESULT hr;
1080     HGLOBAL dst;
1081     ILockBytes *lbs;
1082
1083     med->pUnkForRelease = NULL;
1084     med->tymed = TYMED_NULL;
1085
1086     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1087     if(FAILED(hr)) return hr;
1088
1089     hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1090     if(FAILED(hr))
1091     {
1092         GlobalFree(dst);
1093         return hr;
1094     }
1095
1096     hr = StgOpenStorageOnILockBytes(lbs, NULL,  STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1097     ILockBytes_Release(lbs);
1098     if(FAILED(hr))
1099     {
1100         GlobalFree(dst);
1101         return hr;
1102     }
1103
1104     med->tymed = TYMED_ISTORAGE;
1105     return hr;
1106 }
1107
1108 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1109 {
1110     const WCHAR *str1, *str2;
1111
1112     if(off1 == 0 && off2 == 0) return TRUE;
1113     if(off1 == 0 || off2 == 0) return FALSE;
1114
1115     str1 = (const WCHAR*)((const char*)t1 + off1);
1116     str2 = (const WCHAR*)((const char*)t2 + off2);
1117
1118     return !lstrcmpW(str1, str2);
1119 }
1120
1121 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1122 {
1123     if(t1 == NULL && t2 == NULL) return TRUE;
1124     if(t1 == NULL || t2 == NULL) return FALSE;
1125
1126     if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1127         return FALSE;
1128     if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1129         return FALSE;
1130     if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1131         return FALSE;
1132
1133     /* FIXME check devmode? */
1134
1135     return TRUE;
1136 }
1137
1138 /************************************************************************
1139  *         snapshot_GetData
1140  */
1141 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1142                                        STGMEDIUM *med)
1143 {
1144     snapshot *This = impl_from_IDataObject(iface);
1145     HANDLE h;
1146     HRESULT hr;
1147     ole_priv_data *enum_data = NULL;
1148     ole_priv_data_entry *entry;
1149     DWORD mask;
1150
1151     TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1152
1153     if ( !fmt || !med ) return E_INVALIDARG;
1154
1155     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1156
1157     if(!This->data)
1158         hr = get_current_dataobject(&This->data);
1159
1160     if(This->data)
1161     {
1162         hr = IDataObject_GetData(This->data, fmt, med);
1163         CloseClipboard();
1164         return hr;
1165     }
1166
1167     h = GetClipboardData(fmt->cfFormat);
1168     if(!h)
1169     {
1170         hr = DV_E_FORMATETC;
1171         goto end;
1172     }
1173
1174     hr = get_priv_data(&enum_data);
1175     if(FAILED(hr)) goto end;
1176
1177     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1178     if(entry)
1179     {
1180         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1181         {
1182             hr = DV_E_FORMATETC;
1183             goto end;
1184         }
1185         mask = fmt->tymed & entry->fmtetc.tymed;
1186         if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1187     }
1188     else /* non-Ole format */
1189         mask = fmt->tymed & TYMED_HGLOBAL;
1190
1191     if(mask & TYMED_ISTORAGE)
1192         hr = get_stgmed_for_storage(h, med);
1193     else if(mask & TYMED_HGLOBAL)
1194         hr = get_stgmed_for_global(h, med);
1195     else if(mask & TYMED_ISTREAM)
1196         hr = get_stgmed_for_stream(h, med);
1197     else
1198     {
1199         FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1200         hr = E_FAIL;
1201         goto end;
1202     }
1203
1204 end:
1205     HeapFree(GetProcessHeap(), 0, enum_data);
1206     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1207     return hr;
1208 }
1209
1210 /************************************************************************
1211  *          snapshot_GetDataHere
1212  */
1213 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1214                                            STGMEDIUM *med)
1215 {
1216     snapshot *This = impl_from_IDataObject(iface);
1217     HANDLE h;
1218     HRESULT hr;
1219     ole_priv_data *enum_data = NULL;
1220     ole_priv_data_entry *entry;
1221     TYMED supported;
1222
1223     TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1224
1225     if ( !fmt || !med ) return E_INVALIDARG;
1226
1227     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1228
1229     if(!This->data)
1230         hr = get_current_dataobject(&This->data);
1231
1232     if(This->data)
1233     {
1234         hr = IDataObject_GetDataHere(This->data, fmt, med);
1235         if(SUCCEEDED(hr))
1236         {
1237             CloseClipboard();
1238             return hr;
1239         }
1240     }
1241
1242     h = GetClipboardData(fmt->cfFormat);
1243     if(!h)
1244     {
1245         hr = DV_E_FORMATETC;
1246         goto end;
1247     }
1248
1249     hr = get_priv_data(&enum_data);
1250     if(FAILED(hr)) goto end;
1251
1252     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1253     if(entry)
1254     {
1255         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1256         {
1257             hr = DV_E_FORMATETC;
1258             goto end;
1259         }
1260         supported = entry->fmtetc.tymed;
1261     }
1262     else /* non-Ole format */
1263         supported = TYMED_HGLOBAL;
1264
1265     switch(med->tymed)
1266     {
1267     case TYMED_HGLOBAL:
1268     {
1269         DWORD src_size = GlobalSize(h);
1270         DWORD dst_size = GlobalSize(med->u.hGlobal);
1271         hr = E_FAIL;
1272         if(dst_size >= src_size)
1273         {
1274             void *src = GlobalLock(h);
1275             void *dst = GlobalLock(med->u.hGlobal);
1276
1277             memcpy(dst, src, src_size);
1278             GlobalUnlock(med->u.hGlobal);
1279             GlobalUnlock(h);
1280             hr = S_OK;
1281         }
1282         break;
1283     }
1284     case TYMED_ISTREAM:
1285     {
1286         DWORD src_size = GlobalSize(h);
1287         void *src = GlobalLock(h);
1288         hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1289         GlobalUnlock(h);
1290         break;
1291     }
1292     case TYMED_ISTORAGE:
1293     {
1294         STGMEDIUM copy;
1295         if(!(supported & TYMED_ISTORAGE))
1296         {
1297             hr = E_FAIL;
1298             goto end;
1299         }
1300         hr = get_stgmed_for_storage(h, &copy);
1301         if(SUCCEEDED(hr))
1302         {
1303             hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1304             ReleaseStgMedium(&copy);
1305         }
1306         break;
1307     }
1308     default:
1309         FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1310         hr = E_FAIL;
1311         goto end;
1312     }
1313
1314 end:
1315     HeapFree(GetProcessHeap(), 0, enum_data);
1316     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1317     return hr;
1318 }
1319
1320 /************************************************************************
1321  *           snapshot_QueryGetData
1322  *
1323  * The OLE Clipboard's implementation of this method delegates to
1324  * a data source if there is one or wraps around the windows clipboard
1325  * function IsClipboardFormatAvailable() otherwise.
1326  *
1327  */
1328 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1329 {
1330     FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1331
1332     if (!fmt) return E_INVALIDARG;
1333
1334     if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1335
1336     if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1337
1338     return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1339 }
1340
1341 /************************************************************************
1342  *              snapshot_GetCanonicalFormatEtc
1343  */
1344 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1345                                                      FORMATETC *fmt_out)
1346 {
1347     TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1348
1349     if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1350
1351     *fmt_out = *fmt_in;
1352     return DATA_S_SAMEFORMATETC;
1353 }
1354
1355 /************************************************************************
1356  *              snapshot_SetData
1357  *
1358  * The OLE Clipboard does not implement this method
1359  */
1360 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1361                                        STGMEDIUM *med, BOOL release)
1362 {
1363     TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1364     return E_NOTIMPL;
1365 }
1366
1367 /************************************************************************
1368  *             snapshot_EnumFormatEtc
1369  *
1370  */
1371 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1372                                              IEnumFORMATETC **enum_fmt)
1373 {
1374     HRESULT hr;
1375     ole_priv_data *data = NULL;
1376
1377     TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1378
1379     *enum_fmt = NULL;
1380
1381     if ( dir != DATADIR_GET ) return E_NOTIMPL;
1382     if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1383
1384     hr = get_priv_data(&data);
1385
1386     if(FAILED(hr)) goto end;
1387
1388     hr = enum_fmtetc_construct( data, 0, enum_fmt );
1389
1390 end:
1391     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1392     return hr;
1393 }
1394
1395 /************************************************************************
1396  *               snapshot_DAdvise
1397  *
1398  * The OLE Clipboard does not implement this method
1399  */
1400 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1401                                        DWORD flags, IAdviseSink *sink,
1402                                        DWORD *conn)
1403 {
1404     TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1405     return E_NOTIMPL;
1406 }
1407
1408 /************************************************************************
1409  *              snapshot_DUnadvise
1410  *
1411  * The OLE Clipboard does not implement this method
1412  */
1413 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1414 {
1415     TRACE("(%p, %d): not implemented\n", iface, conn);
1416     return E_NOTIMPL;
1417 }
1418
1419 /************************************************************************
1420  *             snapshot_EnumDAdvise
1421  *
1422  * The OLE Clipboard does not implement this method
1423  */
1424 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1425                                            IEnumSTATDATA** enum_advise)
1426 {
1427     TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1428     return E_NOTIMPL;
1429 }
1430
1431 static const IDataObjectVtbl snapshot_vtable =
1432 {
1433     snapshot_QueryInterface,
1434     snapshot_AddRef,
1435     snapshot_Release,
1436     snapshot_GetData,
1437     snapshot_GetDataHere,
1438     snapshot_QueryGetData,
1439     snapshot_GetCanonicalFormatEtc,
1440     snapshot_SetData,
1441     snapshot_EnumFormatEtc,
1442     snapshot_DAdvise,
1443     snapshot_DUnadvise,
1444     snapshot_EnumDAdvise
1445 };
1446
1447 /*---------------------------------------------------------------------*
1448  *           Internal implementation methods for the OLE clipboard
1449  *---------------------------------------------------------------------*/
1450
1451 static snapshot *snapshot_construct(DWORD seq_no)
1452 {
1453     snapshot *This;
1454
1455     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1456     if (!This) return NULL;
1457
1458     This->lpVtbl = &snapshot_vtable;
1459     This->ref = 0;
1460     This->seq_no = seq_no;
1461     This->data = NULL;
1462
1463     return This;
1464 }
1465
1466 /*********************************************************
1467  *               register_clipboard_formats
1468  */
1469 static void register_clipboard_formats(void)
1470 {
1471     static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1472     static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1473     static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1474     static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1475     static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1476     static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1477     static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1478     static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1479     static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1480     static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1481                                                  'D','e','s','c','r','i','p','t','o','r',0};
1482     static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1483
1484     static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1485                                                      'D','a','t','a','O','b','j','e','c','t',0};
1486
1487     ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1488     filename_clipboard_format = RegisterClipboardFormatW(FileName);
1489     filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1490     dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1491     embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1492     embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1493     custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1494     link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1495     object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1496     link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1497     ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1498
1499     wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1500 }
1501
1502 /***********************************************************************
1503  * OLEClipbrd_Initialize()
1504  * Initializes the OLE clipboard.
1505  */
1506 void OLEClipbrd_Initialize(void)
1507 {
1508     register_clipboard_formats();
1509
1510     if ( !theOleClipboard )
1511     {
1512         ole_clipbrd* clipbrd;
1513         HGLOBAL h;
1514
1515         TRACE("()\n");
1516
1517         clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1518         if (!clipbrd) return;
1519
1520         clipbrd->latest_snapshot = NULL;
1521         clipbrd->window = NULL;
1522         clipbrd->src_data = NULL;
1523         clipbrd->cached_enum = NULL;
1524
1525         h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1526         if(!h)
1527         {
1528             HeapFree(GetProcessHeap(), 0, clipbrd);
1529             return;
1530         }
1531
1532         if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1533         {
1534             GlobalFree(h);
1535             HeapFree(GetProcessHeap(), 0, clipbrd);
1536             return;
1537         }
1538
1539         theOleClipboard = clipbrd;
1540     }
1541 }
1542
1543 /***********************************************************************
1544  * OLEClipbrd_UnInitialize()
1545  * Un-Initializes the OLE clipboard
1546  */
1547 void OLEClipbrd_UnInitialize(void)
1548 {
1549     ole_clipbrd *clipbrd = theOleClipboard;
1550
1551     TRACE("()\n");
1552
1553     if ( clipbrd )
1554     {
1555         static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1556         HINSTANCE hinst = GetModuleHandleW(ole32W);
1557
1558         if ( clipbrd->window )
1559         {
1560             DestroyWindow(clipbrd->window);
1561             UnregisterClassW( clipbrd_wndclass, hinst );
1562         }
1563
1564         IStream_Release(clipbrd->marshal_data);
1565         HeapFree(GetProcessHeap(), 0, clipbrd);
1566         theOleClipboard = NULL;
1567     }
1568 }
1569
1570 /*********************************************************************
1571  *          set_clipboard_formats
1572  *
1573  * Enumerate all formats supported by the source and make
1574  * those formats available using delayed rendering using SetClipboardData.
1575  * Cache the enumeration list and make that list visibile as the
1576  * 'Ole Private Data' format on the clipboard.
1577  *
1578  */
1579 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1580 {
1581     HRESULT hr;
1582     FORMATETC fmt;
1583     IEnumFORMATETC *enum_fmt;
1584     HGLOBAL priv_data_handle;
1585     DWORD_PTR target_offset;
1586     ole_priv_data *priv_data;
1587     DWORD count = 0, needed = sizeof(*priv_data), idx;
1588
1589     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1590     if(FAILED(hr)) return hr;
1591
1592     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1593     {
1594         count++;
1595         needed += sizeof(priv_data->entries[0]);
1596         if(fmt.ptd)
1597         {
1598             needed += fmt.ptd->tdSize;
1599             CoTaskMemFree(fmt.ptd);
1600         }
1601     }
1602
1603     /* Windows pads the list with two empty ole_priv_data_entries, one
1604      * after the entries array and one after the target device data.
1605      * Allocating with zero init to zero these pads. */
1606
1607     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1608     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1609     priv_data = GlobalLock(priv_data_handle);
1610
1611     priv_data->unk1 = 0;
1612     priv_data->size = needed;
1613     priv_data->unk2 = 1;
1614     priv_data->count = count;
1615     priv_data->unk3[0] = 0;
1616     priv_data->unk3[1] = 0;
1617
1618     IEnumFORMATETC_Reset(enum_fmt);
1619
1620     idx = 0;
1621     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1622
1623     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1624     {
1625         TRACE("%s\n", dump_fmtetc(&fmt));
1626
1627         priv_data->entries[idx].fmtetc = fmt;
1628         if(fmt.ptd)
1629         {
1630             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1631             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1632             target_offset += fmt.ptd->tdSize;
1633             CoTaskMemFree(fmt.ptd);
1634         }
1635
1636         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1637         priv_data->entries[idx].unk[0] = 0;
1638         priv_data->entries[idx].unk[1] = 0;
1639
1640         if (priv_data->entries[idx].first_use)
1641             SetClipboardData(fmt.cfFormat, NULL);
1642
1643         idx++;
1644     }
1645
1646     IEnumFORMATETC_Release(enum_fmt);
1647
1648     /* Cache the list and fixup any target device offsets to ptrs */
1649     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1650     memcpy(clipbrd->cached_enum, priv_data, needed);
1651     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1652         clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1653             td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1654
1655     GlobalUnlock(priv_data_handle);
1656     SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1657
1658     return S_OK;
1659 }
1660
1661 static HWND create_clipbrd_window(void);
1662
1663 /***********************************************************************
1664  *                 get_clipbrd_window
1665  */
1666 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1667 {
1668     if ( !clipbrd->window )
1669         clipbrd->window = create_clipbrd_window();
1670
1671     *wnd = clipbrd->window;
1672     return *wnd ? S_OK : E_FAIL;
1673 }
1674
1675
1676 /**********************************************************************
1677  *                  release_marshal_data
1678  *
1679  * Releases the data and sets the stream back to zero size.
1680  */
1681 static inline void release_marshal_data(IStream *stm)
1682 {
1683     LARGE_INTEGER pos;
1684     ULARGE_INTEGER size;
1685     pos.QuadPart = size.QuadPart = 0;
1686
1687     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1688     CoReleaseMarshalData(stm);
1689     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1690     IStream_SetSize(stm, size);
1691 }
1692
1693 /***********************************************************************
1694  *   expose_marshalled_dataobject
1695  *
1696  * Sets the marshalled dataobject to the clipboard.  In the flushed case
1697  * we set a zero sized HGLOBAL to clear the old marshalled data.
1698  */
1699 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1700 {
1701     HGLOBAL h;
1702
1703     if(data)
1704     {
1705         HGLOBAL h_stm;
1706         GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1707         dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1708     }
1709     else /* flushed */
1710         h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1711
1712     if(!h) return E_OUTOFMEMORY;
1713
1714     SetClipboardData(wine_marshal_clipboard_format, h);
1715     return S_OK;
1716 }
1717
1718 /***********************************************************************
1719  *                   set_src_dataobject
1720  *
1721  * Clears and sets the clipboard's src IDataObject.
1722  *
1723  * To marshal the source dataobject we do something rather different from Windows.
1724  * We set a clipboard format which contains the marshalled data.
1725  * Windows sets two window props one of which is an IID, the other is an endpoint number.
1726  */
1727 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1728 {
1729     HRESULT hr;
1730     HWND wnd;
1731
1732     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1733
1734     if(clipbrd->src_data)
1735     {
1736         release_marshal_data(clipbrd->marshal_data);
1737
1738         IDataObject_Release(clipbrd->src_data);
1739         clipbrd->src_data = NULL;
1740         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1741         clipbrd->cached_enum = NULL;
1742     }
1743
1744     if(data)
1745     {
1746         IUnknown *unk;
1747
1748         IDataObject_AddRef(data);
1749         clipbrd->src_data = data;
1750
1751         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1752         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1753                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1754         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1755         if(FAILED(hr)) return hr;
1756         hr = set_clipboard_formats(clipbrd, data);
1757     }
1758     return hr;
1759 }
1760
1761 /***********************************************************************
1762  *                   clipbrd_wndproc
1763  */
1764 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1765 {
1766     ole_clipbrd *clipbrd;
1767
1768     get_ole_clipbrd(&clipbrd);
1769
1770     switch (message)
1771     {
1772     case WM_RENDERFORMAT:
1773     {
1774         UINT cf = wparam;
1775         ole_priv_data_entry *entry;
1776
1777         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1778         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1779
1780         if(entry)
1781             render_format(clipbrd->src_data, &entry->fmtetc);
1782
1783         break;
1784     }
1785
1786     case WM_RENDERALLFORMATS:
1787     {
1788         DWORD i;
1789         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1790
1791         TRACE("(): WM_RENDERALLFORMATS\n");
1792
1793         for(i = 0; i < clipbrd->cached_enum->count; i++)
1794         {
1795             if(entries[i].first_use)
1796                 render_format(clipbrd->src_data, &entries[i].fmtetc);
1797         }
1798         break;
1799     }
1800
1801     case WM_DESTROYCLIPBOARD:
1802     {
1803         TRACE("(): WM_DESTROYCLIPBOARD\n");
1804
1805         set_src_dataobject(clipbrd, NULL);
1806         break;
1807     }
1808
1809     default:
1810         return DefWindowProcW(hwnd, message, wparam, lparam);
1811     }
1812
1813     return 0;
1814 }
1815
1816
1817 /***********************************************************************
1818  *                 create_clipbrd_window
1819  */
1820 static HWND create_clipbrd_window(void)
1821 {
1822     WNDCLASSEXW class;
1823     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1824     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1825     HINSTANCE hinst = GetModuleHandleW(ole32W);
1826
1827     class.cbSize         = sizeof(class);
1828     class.style          = 0;
1829     class.lpfnWndProc    = clipbrd_wndproc;
1830     class.cbClsExtra     = 0;
1831     class.cbWndExtra     = 0;
1832     class.hInstance      = hinst;
1833     class.hIcon          = 0;
1834     class.hCursor        = 0;
1835     class.hbrBackground  = 0;
1836     class.lpszMenuName   = NULL;
1837     class.lpszClassName  = clipbrd_wndclass;
1838     class.hIconSm        = NULL;
1839
1840     RegisterClassExW(&class);
1841
1842     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1843                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1844                          NULL, NULL, hinst, 0);
1845 }
1846
1847 /*********************************************************************
1848  *          set_dataobject_format
1849  *
1850  * Windows creates a 'DataObject' clipboard format that contains the
1851  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1852  */
1853 static HRESULT set_dataobject_format(HWND hwnd)
1854 {
1855     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1856     HWND *data;
1857
1858     if(!h) return E_OUTOFMEMORY;
1859
1860     data = GlobalLock(h);
1861     *data = hwnd;
1862     GlobalUnlock(h);
1863
1864     if(!SetClipboardData(dataobject_clipboard_format, h))
1865     {
1866         GlobalFree(h);
1867         return CLIPBRD_E_CANT_SET;
1868     }
1869
1870     return S_OK;
1871 }
1872
1873 /*---------------------------------------------------------------------*
1874  *           Win32 OLE clipboard API
1875  *---------------------------------------------------------------------*/
1876
1877 /***********************************************************************
1878  *           OleSetClipboard     [OLE32.@]
1879  *  Places a pointer to the specified data object onto the clipboard,
1880  *  making the data object accessible to the OleGetClipboard function.
1881  *
1882  * RETURNS
1883  *
1884  *    S_OK                  IDataObject pointer placed on the clipboard
1885  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
1886  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
1887  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
1888  *    CLIPBRD_E_CANT_SET    SetClipboard failed
1889  */
1890
1891 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1892 {
1893   HRESULT hr;
1894   ole_clipbrd *clipbrd;
1895   HWND wnd;
1896
1897   TRACE("(%p)\n", data);
1898
1899   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1900
1901   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1902
1903   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1904
1905   if ( !EmptyClipboard() )
1906   {
1907     hr = CLIPBRD_E_CANT_EMPTY;
1908     goto end;
1909   }
1910
1911   hr = set_src_dataobject(clipbrd, data);
1912   if(FAILED(hr)) goto end;
1913
1914   if(data)
1915   {
1916     hr = expose_marshalled_dataobject(clipbrd, data);
1917     if(FAILED(hr)) goto end;
1918     hr = set_dataobject_format(wnd);
1919   }
1920
1921 end:
1922
1923   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1924
1925   if ( FAILED(hr) )
1926   {
1927     expose_marshalled_dataobject(clipbrd, NULL);
1928     set_src_dataobject(clipbrd, NULL);
1929   }
1930
1931   return hr;
1932 }
1933
1934
1935 /***********************************************************************
1936  * OleGetClipboard [OLE32.@]
1937  * Returns a pointer to our internal IDataObject which represents the conceptual
1938  * state of the Windows clipboard. If the current clipboard already contains
1939  * an IDataObject, our internal IDataObject will delegate to this object.
1940  */
1941 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1942 {
1943     HRESULT hr;
1944     ole_clipbrd *clipbrd;
1945     DWORD seq_no;
1946
1947     TRACE("(%p)\n", obj);
1948
1949     if(!obj) return E_INVALIDARG;
1950
1951     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1952
1953     seq_no = GetClipboardSequenceNumber();
1954     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1955         clipbrd->latest_snapshot = NULL;
1956
1957     if(!clipbrd->latest_snapshot)
1958     {
1959         clipbrd->latest_snapshot = snapshot_construct(seq_no);
1960         if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1961     }
1962
1963     *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1964     IDataObject_AddRef(*obj);
1965
1966     return S_OK;
1967 }
1968
1969 /******************************************************************************
1970  *              OleFlushClipboard        [OLE32.@]
1971  *  Renders the data from the source IDataObject into the windows clipboard
1972  *
1973  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1974  *  by copying the storage into global memory. Subsequently the default
1975  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1976  *  back to TYMED_IStorage.
1977  */
1978 HRESULT WINAPI OleFlushClipboard(void)
1979 {
1980   HRESULT hr;
1981   ole_clipbrd *clipbrd;
1982   HWND wnd;
1983
1984   TRACE("()\n");
1985
1986   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1987
1988   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1989
1990   /*
1991    * Already flushed or no source DataObject? Nothing to do.
1992    */
1993   if (!clipbrd->src_data) return S_OK;
1994
1995   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1996
1997   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1998
1999   hr = set_dataobject_format(NULL);
2000
2001   expose_marshalled_dataobject(clipbrd, NULL);
2002   set_src_dataobject(clipbrd, NULL);
2003
2004   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2005
2006   return hr;
2007 }
2008
2009
2010 /***********************************************************************
2011  *           OleIsCurrentClipboard [OLE32.@]
2012  */
2013 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2014 {
2015     HRESULT hr;
2016     ole_clipbrd *clipbrd;
2017     TRACE("()\n");
2018
2019     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2020
2021     if (data == NULL) return S_FALSE;
2022
2023     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
2024 }