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