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