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