mshtml: Implement IHTMLWindow2::get_top.
[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     TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1270
1271     if ( !fmt || !med ) return E_INVALIDARG;
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         HeapFree(GetProcessHeap(), 0, clipbrd);
1612         theOleClipboard = NULL;
1613     }
1614 }
1615
1616 /*********************************************************************
1617  *          set_clipboard_formats
1618  *
1619  * Enumerate all formats supported by the source and make
1620  * those formats available using delayed rendering using SetClipboardData.
1621  * Cache the enumeration list and make that list visibile as the
1622  * 'Ole Private Data' format on the clipboard.
1623  *
1624  */
1625 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1626 {
1627     HRESULT hr;
1628     FORMATETC fmt;
1629     IEnumFORMATETC *enum_fmt;
1630     HGLOBAL priv_data_handle;
1631     DWORD_PTR target_offset;
1632     ole_priv_data *priv_data;
1633     DWORD count = 0, needed = sizeof(*priv_data), idx;
1634
1635     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1636     if(FAILED(hr)) return hr;
1637
1638     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1639     {
1640         count++;
1641         needed += sizeof(priv_data->entries[0]);
1642         if(fmt.ptd)
1643         {
1644             needed += fmt.ptd->tdSize;
1645             CoTaskMemFree(fmt.ptd);
1646         }
1647     }
1648
1649     /* Windows pads the list with two empty ole_priv_data_entries, one
1650      * after the entries array and one after the target device data.
1651      * Allocating with zero init to zero these pads. */
1652
1653     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1654     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1655     priv_data = GlobalLock(priv_data_handle);
1656
1657     priv_data->unk1 = 0;
1658     priv_data->size = needed;
1659     priv_data->unk2 = 1;
1660     priv_data->count = count;
1661     priv_data->unk3[0] = 0;
1662     priv_data->unk3[1] = 0;
1663
1664     IEnumFORMATETC_Reset(enum_fmt);
1665
1666     idx = 0;
1667     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1668
1669     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1670     {
1671         TRACE("%s\n", dump_fmtetc(&fmt));
1672
1673         priv_data->entries[idx].fmtetc = fmt;
1674         if(fmt.ptd)
1675         {
1676             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1677             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1678             target_offset += fmt.ptd->tdSize;
1679             CoTaskMemFree(fmt.ptd);
1680         }
1681
1682         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1683         priv_data->entries[idx].unk[0] = 0;
1684         priv_data->entries[idx].unk[1] = 0;
1685
1686         if (priv_data->entries[idx].first_use)
1687             SetClipboardData(fmt.cfFormat, NULL);
1688
1689         idx++;
1690     }
1691
1692     IEnumFORMATETC_Release(enum_fmt);
1693
1694     /* Cache the list and fixup any target device offsets to ptrs */
1695     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1696     memcpy(clipbrd->cached_enum, priv_data, needed);
1697     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1698         clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1699             td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1700
1701     GlobalUnlock(priv_data_handle);
1702     SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1703
1704     return S_OK;
1705 }
1706
1707 static HWND create_clipbrd_window(void);
1708
1709 /***********************************************************************
1710  *                 get_clipbrd_window
1711  */
1712 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1713 {
1714     if ( !clipbrd->window )
1715         clipbrd->window = create_clipbrd_window();
1716
1717     *wnd = clipbrd->window;
1718     return *wnd ? S_OK : E_FAIL;
1719 }
1720
1721
1722 /**********************************************************************
1723  *                  release_marshal_data
1724  *
1725  * Releases the data and sets the stream back to zero size.
1726  */
1727 static inline void release_marshal_data(IStream *stm)
1728 {
1729     LARGE_INTEGER pos;
1730     ULARGE_INTEGER size;
1731     pos.QuadPart = size.QuadPart = 0;
1732
1733     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1734     CoReleaseMarshalData(stm);
1735     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1736     IStream_SetSize(stm, size);
1737 }
1738
1739 /***********************************************************************
1740  *   expose_marshalled_dataobject
1741  *
1742  * Sets the marshalled dataobject to the clipboard.  In the flushed case
1743  * we set a zero sized HGLOBAL to clear the old marshalled data.
1744  */
1745 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1746 {
1747     HGLOBAL h;
1748
1749     if(data)
1750     {
1751         HGLOBAL h_stm;
1752         GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1753         dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1754     }
1755     else /* flushed */
1756         h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1757
1758     if(!h) return E_OUTOFMEMORY;
1759
1760     SetClipboardData(wine_marshal_clipboard_format, h);
1761     return S_OK;
1762 }
1763
1764 /***********************************************************************
1765  *                   set_src_dataobject
1766  *
1767  * Clears and sets the clipboard's src IDataObject.
1768  *
1769  * To marshal the source dataobject we do something rather different from Windows.
1770  * We set a clipboard format which contains the marshalled data.
1771  * Windows sets two window props one of which is an IID, the other is an endpoint number.
1772  */
1773 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1774 {
1775     HRESULT hr;
1776     HWND wnd;
1777
1778     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1779
1780     if(clipbrd->src_data)
1781     {
1782         release_marshal_data(clipbrd->marshal_data);
1783
1784         IDataObject_Release(clipbrd->src_data);
1785         clipbrd->src_data = NULL;
1786         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1787         clipbrd->cached_enum = NULL;
1788     }
1789
1790     if(data)
1791     {
1792         IUnknown *unk;
1793
1794         IDataObject_AddRef(data);
1795         clipbrd->src_data = data;
1796
1797         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1798         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1799                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1800         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1801         if(FAILED(hr)) return hr;
1802         hr = set_clipboard_formats(clipbrd, data);
1803     }
1804     return hr;
1805 }
1806
1807 /***********************************************************************
1808  *                   clipbrd_wndproc
1809  */
1810 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1811 {
1812     ole_clipbrd *clipbrd;
1813
1814     get_ole_clipbrd(&clipbrd);
1815
1816     switch (message)
1817     {
1818     case WM_RENDERFORMAT:
1819     {
1820         UINT cf = wparam;
1821         ole_priv_data_entry *entry;
1822
1823         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1824         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1825
1826         if(entry)
1827             render_format(clipbrd->src_data, &entry->fmtetc);
1828
1829         break;
1830     }
1831
1832     case WM_RENDERALLFORMATS:
1833     {
1834         DWORD i;
1835         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1836
1837         TRACE("(): WM_RENDERALLFORMATS\n");
1838
1839         for(i = 0; i < clipbrd->cached_enum->count; i++)
1840         {
1841             if(entries[i].first_use)
1842                 render_format(clipbrd->src_data, &entries[i].fmtetc);
1843         }
1844         break;
1845     }
1846
1847     case WM_DESTROYCLIPBOARD:
1848     {
1849         TRACE("(): WM_DESTROYCLIPBOARD\n");
1850
1851         set_src_dataobject(clipbrd, NULL);
1852         break;
1853     }
1854
1855     default:
1856         return DefWindowProcW(hwnd, message, wparam, lparam);
1857     }
1858
1859     return 0;
1860 }
1861
1862
1863 /***********************************************************************
1864  *                 create_clipbrd_window
1865  */
1866 static HWND create_clipbrd_window(void)
1867 {
1868     WNDCLASSEXW class;
1869     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1870     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1871     HINSTANCE hinst = GetModuleHandleW(ole32W);
1872
1873     class.cbSize         = sizeof(class);
1874     class.style          = 0;
1875     class.lpfnWndProc    = clipbrd_wndproc;
1876     class.cbClsExtra     = 0;
1877     class.cbWndExtra     = 0;
1878     class.hInstance      = hinst;
1879     class.hIcon          = 0;
1880     class.hCursor        = 0;
1881     class.hbrBackground  = 0;
1882     class.lpszMenuName   = NULL;
1883     class.lpszClassName  = clipbrd_wndclass;
1884     class.hIconSm        = NULL;
1885
1886     RegisterClassExW(&class);
1887
1888     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1889                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1890                          NULL, NULL, hinst, 0);
1891 }
1892
1893 /*********************************************************************
1894  *          set_dataobject_format
1895  *
1896  * Windows creates a 'DataObject' clipboard format that contains the
1897  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1898  */
1899 static HRESULT set_dataobject_format(HWND hwnd)
1900 {
1901     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1902     HWND *data;
1903
1904     if(!h) return E_OUTOFMEMORY;
1905
1906     data = GlobalLock(h);
1907     *data = hwnd;
1908     GlobalUnlock(h);
1909
1910     if(!SetClipboardData(dataobject_clipboard_format, h))
1911     {
1912         GlobalFree(h);
1913         return CLIPBRD_E_CANT_SET;
1914     }
1915
1916     return S_OK;
1917 }
1918
1919 /*---------------------------------------------------------------------*
1920  *           Win32 OLE clipboard API
1921  *---------------------------------------------------------------------*/
1922
1923 /***********************************************************************
1924  *           OleSetClipboard     [OLE32.@]
1925  *  Places a pointer to the specified data object onto the clipboard,
1926  *  making the data object accessible to the OleGetClipboard function.
1927  *
1928  * RETURNS
1929  *
1930  *    S_OK                  IDataObject pointer placed on the clipboard
1931  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
1932  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
1933  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
1934  *    CLIPBRD_E_CANT_SET    SetClipboard failed
1935  */
1936
1937 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1938 {
1939   HRESULT hr;
1940   ole_clipbrd *clipbrd;
1941   HWND wnd;
1942
1943   TRACE("(%p)\n", data);
1944
1945   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1946
1947   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1948
1949   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1950
1951   if ( !EmptyClipboard() )
1952   {
1953     hr = CLIPBRD_E_CANT_EMPTY;
1954     goto end;
1955   }
1956
1957   hr = set_src_dataobject(clipbrd, data);
1958   if(FAILED(hr)) goto end;
1959
1960   if(data)
1961   {
1962     hr = expose_marshalled_dataobject(clipbrd, data);
1963     if(FAILED(hr)) goto end;
1964     hr = set_dataobject_format(wnd);
1965   }
1966
1967 end:
1968
1969   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1970
1971   if ( FAILED(hr) )
1972   {
1973     expose_marshalled_dataobject(clipbrd, NULL);
1974     set_src_dataobject(clipbrd, NULL);
1975   }
1976
1977   return hr;
1978 }
1979
1980
1981 /***********************************************************************
1982  * OleGetClipboard [OLE32.@]
1983  * Returns a pointer to our internal IDataObject which represents the conceptual
1984  * state of the Windows clipboard. If the current clipboard already contains
1985  * an IDataObject, our internal IDataObject will delegate to this object.
1986  */
1987 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1988 {
1989     HRESULT hr;
1990     ole_clipbrd *clipbrd;
1991     DWORD seq_no;
1992
1993     TRACE("(%p)\n", obj);
1994
1995     if(!obj) return E_INVALIDARG;
1996
1997     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1998
1999     seq_no = GetClipboardSequenceNumber();
2000     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2001         clipbrd->latest_snapshot = NULL;
2002
2003     if(!clipbrd->latest_snapshot)
2004     {
2005         clipbrd->latest_snapshot = snapshot_construct(seq_no);
2006         if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
2007     }
2008
2009     *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
2010     IDataObject_AddRef(*obj);
2011
2012     return S_OK;
2013 }
2014
2015 /******************************************************************************
2016  *              OleFlushClipboard        [OLE32.@]
2017  *  Renders the data from the source IDataObject into the windows clipboard
2018  *
2019  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2020  *  by copying the storage into global memory. Subsequently the default
2021  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2022  *  back to TYMED_IStorage.
2023  */
2024 HRESULT WINAPI OleFlushClipboard(void)
2025 {
2026   HRESULT hr;
2027   ole_clipbrd *clipbrd;
2028   HWND wnd;
2029
2030   TRACE("()\n");
2031
2032   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2033
2034   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2035
2036   /*
2037    * Already flushed or no source DataObject? Nothing to do.
2038    */
2039   if (!clipbrd->src_data) return S_OK;
2040
2041   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2042
2043   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2044
2045   hr = set_dataobject_format(NULL);
2046
2047   expose_marshalled_dataobject(clipbrd, NULL);
2048   set_src_dataobject(clipbrd, NULL);
2049
2050   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2051
2052   return hr;
2053 }
2054
2055
2056 /***********************************************************************
2057  *           OleIsCurrentClipboard [OLE32.@]
2058  */
2059 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2060 {
2061     HRESULT hr;
2062     ole_clipbrd *clipbrd;
2063     TRACE("()\n");
2064
2065     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2066
2067     if (data == NULL) return S_FALSE;
2068
2069     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
2070 }