comctl32/comboex: Reduce variable scope.
[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     IDataObject IDataObject_iface;
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 CONTAINING_RECORD(iface, snapshot, IDataObject_iface);
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     IEnumFORMATETC IEnumFORMATETC_iface;
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 CONTAINING_RECORD(iface, enum_fmtetc, IEnumFORMATETC_iface);
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->IEnumFORMATETC_iface.lpVtbl = &efvt;
444   ef->data = data;
445   ef->pos = pos;
446
447   TRACE("(%p)->()\n", ef);
448   *obj = &ef->IEnumFORMATETC_iface;
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  *                    dup_metafilepict
483  *
484  * Helper function to duplicate a handle to a METAFILEPICT, and the
485  * contained HMETAFILE.
486  */
487 static HRESULT dup_metafilepict(HGLOBAL src, HGLOBAL *pdest)
488 {
489     HRESULT hr;
490     HGLOBAL dest;
491     METAFILEPICT *dest_ptr;
492
493     *pdest = NULL;
494
495     /* Copy the METAFILEPICT structure. */
496     hr = dup_global_mem(src, GMEM_DDESHARE|GMEM_MOVEABLE, &dest);
497     if (FAILED(hr)) return hr;
498
499     dest_ptr = GlobalLock(dest);
500     if (!dest_ptr) return E_FAIL;
501
502     /* Give the new METAFILEPICT a separate HMETAFILE. */
503     dest_ptr->hMF = CopyMetaFileW(dest_ptr->hMF, NULL);
504     if (dest_ptr->hMF)
505     {
506        GlobalUnlock(dest);
507        *pdest = dest;
508        return S_OK;
509     }
510     else
511     {
512        GlobalUnlock(dest);
513        GlobalFree(dest);
514        return E_FAIL;
515     }
516 }
517
518 /***********************************************************************
519  *                    free_metafilepict
520  *
521  * Helper function to GlobalFree a handle to a METAFILEPICT, and also
522  * free the contained HMETAFILE.
523  */
524 static void free_metafilepict(HGLOBAL src)
525 {
526     METAFILEPICT *src_ptr;
527
528     src_ptr = GlobalLock(src);
529     if (src_ptr)
530     {
531         DeleteMetaFile(src_ptr->hMF);
532         GlobalUnlock(src);
533     }
534     GlobalFree(src);
535 }
536
537 /***********************************************************************
538  *                    dup_bitmap
539  *
540  * Helper function to duplicate an HBITMAP.
541  */
542 static HRESULT dup_bitmap(HBITMAP src, HBITMAP *pdest)
543 {
544     HDC src_dc;
545     HGDIOBJ orig_src_bitmap;
546     BITMAP bm;
547     HBITMAP dest;
548
549     src_dc = CreateCompatibleDC(NULL);
550     orig_src_bitmap = SelectObject(src_dc, src);
551     GetObjectW(src, sizeof bm, &bm);
552     dest = CreateCompatibleBitmap(src_dc, bm.bmWidth, bm.bmHeight);
553     if (dest)
554     {
555         HDC dest_dc = CreateCompatibleDC(NULL);
556         HGDIOBJ orig_dest_bitmap = SelectObject(dest_dc, dest);
557         BitBlt(dest_dc, 0, 0, bm.bmWidth, bm.bmHeight, src_dc, 0, 0, SRCCOPY);
558         SelectObject(dest_dc, orig_dest_bitmap);
559         DeleteDC(dest_dc);
560     }
561     SelectObject(src_dc, orig_src_bitmap);
562     DeleteDC(src_dc);
563     *pdest = dest;
564     return dest ? S_OK : E_FAIL;
565 }
566
567 /************************************************************
568  *              render_embed_source_hack
569  *
570  * This is clearly a hack and has no place in the clipboard code.
571  *
572  */
573 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
574 {
575     STGMEDIUM std;
576     HGLOBAL hStorage = 0;
577     HRESULT hr = S_OK;
578     ILockBytes *ptrILockBytes;
579
580     memset(&std, 0, sizeof(STGMEDIUM));
581     std.tymed = fmt->tymed = TYMED_ISTORAGE;
582
583     hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
584     if (hStorage == NULL) return E_OUTOFMEMORY;
585     hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
586     hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
587     ILockBytes_Release(ptrILockBytes);
588
589     if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
590     {
591         WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
592         GlobalFree(hStorage);
593         return hr;
594     }
595
596     if (1) /* check whether the presentation data is already -not- present */
597     {
598         FORMATETC fmt2;
599         STGMEDIUM std2;
600         METAFILEPICT *mfp = 0;
601
602         fmt2.cfFormat = CF_METAFILEPICT;
603         fmt2.ptd = 0;
604         fmt2.dwAspect = DVASPECT_CONTENT;
605         fmt2.lindex = -1;
606         fmt2.tymed = TYMED_MFPICT;
607
608         memset(&std2, 0, sizeof(STGMEDIUM));
609         std2.tymed = TYMED_MFPICT;
610
611         /* Get the metafile picture out of it */
612
613         if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
614         {
615             mfp = GlobalLock(std2.u.hGlobal);
616         }
617
618         if (mfp)
619         {
620             OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
621             IStream *pStream = 0;
622             void *mfBits;
623             PresentationDataHeader pdh;
624             INT nSize;
625             CLSID clsID;
626             LPOLESTR strProgID;
627             CHAR strOleTypeName[51];
628             BYTE OlePresStreamHeader [] =
629             {
630                 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
631                 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
632                 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
633                 0x00, 0x00, 0x00, 0x00
634             };
635
636             nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
637
638             memset(&pdh, 0, sizeof(PresentationDataHeader));
639             memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
640
641             pdh.dwObjectExtentX = mfp->xExt;
642             pdh.dwObjectExtentY = mfp->yExt;
643             pdh.dwSize = nSize;
644
645             hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
646
647             hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
648
649             mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
650             nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
651
652             hr = IStream_Write(pStream, mfBits, nSize, NULL);
653
654             IStream_Release(pStream);
655
656             HeapFree(GetProcessHeap(), 0, mfBits);
657
658             GlobalUnlock(std2.u.hGlobal);
659             ReleaseStgMedium(&std2);
660
661             ReadClassStg(std.u.pstg, &clsID);
662             ProgIDFromCLSID(&clsID, &strProgID);
663
664             WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
665             OLECONVERT_CreateOleStream(std.u.pstg);
666             OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
667         }
668     }
669
670     if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
671     {
672         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
673         GlobalFree(hStorage);
674         hr = CLIPBRD_E_CANT_SET;
675     }
676
677     ReleaseStgMedium(&std);
678     return hr;
679 }
680
681 /************************************************************************
682  *           find_format_in_list
683  *
684  * Returns the first entry that matches the provided clipboard format.
685  */
686 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
687 {
688     DWORD i;
689     for(i = 0; i < num; i++)
690         if(entries[i].fmtetc.cfFormat == cf)
691             return &entries[i];
692
693     return NULL;
694 }
695
696 /***************************************************************************
697  *         get_data_from_storage
698  *
699  * Returns storage data in an HGLOBAL.
700  */
701 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
702 {
703     HGLOBAL h;
704     IStorage *stg;
705     HRESULT hr;
706     FORMATETC stg_fmt;
707     STGMEDIUM med;
708     ILockBytes *lbs;
709
710     *mem = NULL;
711
712     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
713     if(!h) return E_OUTOFMEMORY;
714
715     hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
716     if(SUCCEEDED(hr))
717     {
718         hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
719         ILockBytes_Release(lbs);
720     }
721     if(FAILED(hr))
722     {
723         GlobalFree(h);
724         return hr;
725     }
726
727     stg_fmt = *fmt;
728     med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
729     med.u.pstg = stg;
730     med.pUnkForRelease = NULL;
731
732     hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
733     if(FAILED(hr))
734     {
735         med.u.pstg = NULL;
736         hr = IDataObject_GetData(data, &stg_fmt, &med);
737         if(FAILED(hr)) goto end;
738
739         hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
740         ReleaseStgMedium(&med);
741         if(FAILED(hr)) goto end;
742     }
743     *mem = h;
744
745 end:
746     IStorage_Release(stg);
747     if(FAILED(hr)) GlobalFree(h);
748     return hr;
749 }
750
751 /***************************************************************************
752  *         get_data_from_stream
753  *
754  * Returns stream data in an HGLOBAL.
755  */
756 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
757 {
758     HGLOBAL h;
759     IStream *stm = NULL;
760     HRESULT hr;
761     FORMATETC stm_fmt;
762     STGMEDIUM med;
763
764     *mem = NULL;
765
766     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
767     if(!h) return E_OUTOFMEMORY;
768
769     hr = CreateStreamOnHGlobal(h, FALSE, &stm);
770     if(FAILED(hr)) goto error;
771
772     stm_fmt = *fmt;
773     med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
774     med.u.pstm = stm;
775     med.pUnkForRelease = NULL;
776
777     hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
778     if(FAILED(hr))
779     {
780         LARGE_INTEGER offs;
781         ULARGE_INTEGER pos;
782
783         med.u.pstm = NULL;
784         hr = IDataObject_GetData(data, &stm_fmt, &med);
785         if(FAILED(hr)) goto error;
786
787         offs.QuadPart = 0;
788         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
789         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
790         hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
791         ReleaseStgMedium(&med);
792         if(FAILED(hr)) goto error;
793     }
794     *mem = h;
795     IStream_Release(stm);
796     return S_OK;
797
798 error:
799     if(stm) IStream_Release(stm);
800     GlobalFree(h);
801     return hr;
802 }
803
804 /***************************************************************************
805  *         get_data_from_global
806  *
807  * Returns global data in an HGLOBAL.
808  */
809 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
810 {
811     HGLOBAL h;
812     HRESULT hr;
813     FORMATETC mem_fmt;
814     STGMEDIUM med;
815
816     *mem = NULL;
817
818     mem_fmt = *fmt;
819     mem_fmt.tymed = TYMED_HGLOBAL;
820
821     hr = IDataObject_GetData(data, &mem_fmt, &med);
822     if(FAILED(hr)) return hr;
823
824     hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
825
826     if(SUCCEEDED(hr)) *mem = h;
827
828     ReleaseStgMedium(&med);
829
830     return hr;
831 }
832
833 /***************************************************************************
834  *         get_data_from_enhmetafile
835  */
836 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
837 {
838     HENHMETAFILE copy;
839     HRESULT hr;
840     FORMATETC mem_fmt;
841     STGMEDIUM med;
842
843     *mem = NULL;
844
845     mem_fmt = *fmt;
846     mem_fmt.tymed = TYMED_ENHMF;
847
848     hr = IDataObject_GetData(data, &mem_fmt, &med);
849     if(FAILED(hr)) return hr;
850
851     copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
852     if(copy) *mem = (HGLOBAL)copy;
853     else hr = E_FAIL;
854
855     ReleaseStgMedium(&med);
856
857     return hr;
858 }
859
860 /***************************************************************************
861  *         get_data_from_metafilepict
862  */
863 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
864 {
865     HGLOBAL copy;
866     HRESULT hr;
867     FORMATETC mem_fmt;
868     STGMEDIUM med;
869
870     *mem = NULL;
871
872     mem_fmt = *fmt;
873     mem_fmt.tymed = TYMED_MFPICT;
874
875     hr = IDataObject_GetData(data, &mem_fmt, &med);
876     if(FAILED(hr)) return hr;
877
878     hr = dup_metafilepict(med.u.hMetaFilePict, &copy);
879
880     if(SUCCEEDED(hr)) *mem = copy;
881
882     ReleaseStgMedium(&med);
883
884     return hr;
885 }
886
887 /***************************************************************************
888  *         get_data_from_bitmap
889  *
890  * Returns bitmap in an HBITMAP.
891  */
892 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm)
893 {
894     HBITMAP copy;
895     HRESULT hr;
896     FORMATETC mem_fmt;
897     STGMEDIUM med;
898
899     *hbm = NULL;
900
901     mem_fmt = *fmt;
902     mem_fmt.tymed = TYMED_GDI;
903
904     hr = IDataObject_GetData(data, &mem_fmt, &med);
905     if(FAILED(hr)) return hr;
906
907     hr = dup_bitmap(med.u.hBitmap, &copy);
908
909     if(SUCCEEDED(hr)) *hbm = copy;
910
911     ReleaseStgMedium(&med);
912
913     return hr;
914 }
915
916 /***********************************************************************
917  *                render_format
918  *
919  * Render the clipboard data. Note that this call will delegate to the
920  * source data object.
921  */
922 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
923 {
924     HANDLE clip_data = NULL;  /* HGLOBAL unless otherwise specified */
925     HRESULT hr;
926
927     /* Embed source hack */
928     if(fmt->cfFormat == embed_source_clipboard_format)
929     {
930         return render_embed_source_hack(data, fmt);
931     }
932
933     if(fmt->tymed & TYMED_ISTORAGE)
934     {
935         hr = get_data_from_storage(data, fmt, &clip_data);
936     }
937     else if(fmt->tymed & TYMED_ISTREAM)
938     {
939         hr = get_data_from_stream(data, fmt, &clip_data);
940     }
941     else if(fmt->tymed & TYMED_HGLOBAL)
942     {
943         hr = get_data_from_global(data, fmt, &clip_data);
944     }
945     else if(fmt->tymed & TYMED_ENHMF)
946     {
947         hr = get_data_from_enhmetafile(data, fmt, &clip_data);
948     }
949     else if(fmt->tymed & TYMED_MFPICT)
950     {
951         /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
952         hr = get_data_from_metafilepict(data, fmt, &clip_data);
953     }
954     else if(fmt->tymed & TYMED_GDI)
955     {
956         /* Returns HBITMAP not HGLOBAL */
957         hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data);
958     }
959     else
960     {
961         FIXME("Unhandled tymed %x\n", fmt->tymed);
962         hr = DV_E_FORMATETC;
963     }
964
965     if(SUCCEEDED(hr))
966     {
967         if ( !SetClipboardData(fmt->cfFormat, clip_data) )
968         {
969             WARN("() : Failed to set rendered clipboard data into clipboard!\n");
970             if(fmt->tymed & TYMED_MFPICT)
971                 free_metafilepict(clip_data);
972             else if(fmt->tymed & TYMED_GDI)
973                 DeleteObject(clip_data);
974             else
975                 GlobalFree(clip_data);
976             hr = CLIPBRD_E_CANT_SET;
977         }
978     }
979
980     return hr;
981 }
982
983 /*---------------------------------------------------------------------*
984  *  Implementation of the internal IDataObject interface exposed by
985  *  the OLE clipboard.
986  *---------------------------------------------------------------------*/
987
988
989 /************************************************************************
990  *           snapshot_QueryInterface
991  */
992 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
993                                               REFIID riid, void **ppvObject)
994 {
995   snapshot *This = impl_from_IDataObject(iface);
996   TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
997
998   if ( (This==0) || (ppvObject==0) )
999     return E_INVALIDARG;
1000
1001   *ppvObject = 0;
1002
1003   if (IsEqualIID(&IID_IUnknown, riid) ||
1004       IsEqualIID(&IID_IDataObject, riid))
1005   {
1006     *ppvObject = iface;
1007   }
1008   else
1009   {
1010     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1011     return E_NOINTERFACE;
1012   }
1013
1014   IUnknown_AddRef((IUnknown*)*ppvObject);
1015
1016   return S_OK;
1017 }
1018
1019 /************************************************************************
1020  *              snapshot_AddRef
1021  */
1022 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
1023 {
1024     snapshot *This = impl_from_IDataObject(iface);
1025
1026     TRACE("(%p)->(count=%u)\n", This, This->ref);
1027
1028     return InterlockedIncrement(&This->ref);
1029 }
1030
1031 /************************************************************************
1032  *      snapshot_Release
1033  */
1034 static ULONG WINAPI snapshot_Release(IDataObject *iface)
1035 {
1036     snapshot *This = impl_from_IDataObject(iface);
1037     ULONG ref;
1038
1039     TRACE("(%p)->(count=%u)\n", This, This->ref);
1040
1041     ref = InterlockedDecrement(&This->ref);
1042
1043     if (ref == 0)
1044     {
1045         ole_clipbrd *clipbrd;
1046         HRESULT hr = get_ole_clipbrd(&clipbrd);
1047
1048         if(This->data) IDataObject_Release(This->data);
1049
1050         if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
1051             clipbrd->latest_snapshot = NULL;
1052         HeapFree(GetProcessHeap(), 0, This);
1053     }
1054
1055     return ref;
1056 }
1057
1058 /************************************************************
1059  *              get_current_ole_clip_window
1060  *
1061  * Return the window that owns the ole clipboard.
1062  *
1063  * If the clipboard is flushed or not owned by ole this will
1064  * return NULL.
1065  */
1066 static HWND get_current_ole_clip_window(void)
1067 {
1068     HGLOBAL h;
1069     HWND *ptr, wnd;
1070
1071     h = GetClipboardData(dataobject_clipboard_format);
1072     if(!h) return NULL;
1073     ptr = GlobalLock(h);
1074     if(!ptr) return NULL;
1075     wnd = *ptr;
1076     GlobalUnlock(h);
1077     return wnd;
1078 }
1079
1080 /************************************************************
1081  *              get_current_dataobject
1082  *
1083  * Return an unmarshalled IDataObject if there is a current
1084  * (ie non-flushed) object on the ole clipboard.
1085  */
1086 static HRESULT get_current_dataobject(IDataObject **data)
1087 {
1088     HRESULT hr = S_FALSE;
1089     HWND wnd = get_current_ole_clip_window();
1090     HGLOBAL h;
1091     void *ptr;
1092     IStream *stm;
1093     LARGE_INTEGER pos;
1094
1095     *data = NULL;
1096     if(!wnd) return S_FALSE;
1097
1098     h = GetClipboardData(wine_marshal_clipboard_format);
1099     if(!h) return S_FALSE;
1100     if(GlobalSize(h) == 0) return S_FALSE;
1101     ptr = GlobalLock(h);
1102     if(!ptr) return S_FALSE;
1103
1104     hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
1105     if(FAILED(hr)) goto end;
1106
1107     hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
1108     if(SUCCEEDED(hr))
1109     {
1110         pos.QuadPart = 0;
1111         IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1112         hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
1113     }
1114     IStream_Release(stm);
1115
1116 end:
1117     GlobalUnlock(h);
1118     return hr;
1119 }
1120
1121 static DWORD get_tymed_from_nonole_cf(UINT cf)
1122 {
1123     if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
1124
1125     switch(cf)
1126     {
1127     case CF_TEXT:
1128     case CF_OEMTEXT:
1129     case CF_UNICODETEXT:
1130         return TYMED_ISTREAM | TYMED_HGLOBAL;
1131     case CF_ENHMETAFILE:
1132         return TYMED_ENHMF;
1133     case CF_METAFILEPICT:
1134         return TYMED_MFPICT;
1135     default:
1136         FIXME("returning TYMED_NULL for cf %04x\n", cf);
1137         return TYMED_NULL;
1138     }
1139 }
1140
1141 /***********************************************************
1142  *     get_priv_data
1143  *
1144  * Returns a copy of the Ole Private Data
1145  */
1146 static HRESULT get_priv_data(ole_priv_data **data)
1147 {
1148     HGLOBAL handle;
1149     HRESULT hr = S_OK;
1150     ole_priv_data *ret = NULL;
1151
1152     *data = NULL;
1153
1154     handle = GetClipboardData( ole_private_data_clipboard_format );
1155     if(handle)
1156     {
1157         ole_priv_data *src = GlobalLock(handle);
1158         if(src)
1159         {
1160             DWORD i;
1161
1162             /* FIXME: sanity check on size */
1163             ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1164             if(!ret)
1165             {
1166                 GlobalUnlock(handle);
1167                 return E_OUTOFMEMORY;
1168             }
1169             memcpy(ret, src, src->size);
1170             GlobalUnlock(handle);
1171
1172             /* Fixup any target device offsets to ptrs */
1173             for(i = 0; i < ret->count; i++)
1174                 ret->entries[i].fmtetc.ptd =
1175                     td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1176         }
1177     }
1178
1179     if(!ret) /* Non-ole data */
1180     {
1181         UINT cf;
1182         DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1183
1184         for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1185         {
1186             char buf[100];
1187             GetClipboardFormatNameA(cf, buf, sizeof(buf));
1188             TRACE("cf %04x %s\n", cf, buf);
1189         }
1190         TRACE("count %d\n", count);
1191         size += count * sizeof(ret->entries[0]);
1192
1193         /* There are holes in fmtetc so zero init */
1194         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1195         if(!ret) return E_OUTOFMEMORY;
1196         ret->size = size;
1197         ret->count = count;
1198
1199         for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1200         {
1201             ret->entries[idx].fmtetc.cfFormat = cf;
1202             ret->entries[idx].fmtetc.ptd = NULL;
1203             ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1204             ret->entries[idx].fmtetc.lindex = -1;
1205             ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1206             ret->entries[idx].first_use = 1;
1207         }
1208     }
1209
1210     *data = ret;
1211     return hr;
1212 }
1213
1214 /************************************************************************
1215  *                    get_stgmed_for_global
1216  *
1217  * Returns a stg medium with a copy of the global handle
1218  */
1219 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1220 {
1221     HRESULT hr;
1222
1223     med->pUnkForRelease = NULL;
1224     med->tymed = TYMED_NULL;
1225
1226     hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1227
1228     if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1229
1230     return hr;
1231 }
1232
1233 /************************************************************************
1234  *                    get_stgmed_for_stream
1235  *
1236  * Returns a stg medium with a stream based on the handle
1237  */
1238 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1239 {
1240     HRESULT hr;
1241     HGLOBAL dst;
1242
1243     med->pUnkForRelease = NULL;
1244     med->tymed = TYMED_NULL;
1245
1246     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1247     if(FAILED(hr)) return hr;
1248
1249     hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1250     if(FAILED(hr))
1251     {
1252         GlobalFree(dst);
1253         return hr;
1254     }
1255
1256     med->tymed = TYMED_ISTREAM;
1257     return hr;
1258 }
1259
1260 /************************************************************************
1261  *                    get_stgmed_for_storage
1262  *
1263  * Returns a stg medium with a storage based on the handle
1264  */
1265 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1266 {
1267     HRESULT hr;
1268     HGLOBAL dst;
1269     ILockBytes *lbs;
1270
1271     med->pUnkForRelease = NULL;
1272     med->tymed = TYMED_NULL;
1273
1274     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1275     if(FAILED(hr)) return hr;
1276
1277     hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1278     if(FAILED(hr))
1279     {
1280         GlobalFree(dst);
1281         return hr;
1282     }
1283
1284     hr = StgOpenStorageOnILockBytes(lbs, NULL,  STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1285     ILockBytes_Release(lbs);
1286     if(FAILED(hr))
1287     {
1288         GlobalFree(dst);
1289         return hr;
1290     }
1291
1292     med->tymed = TYMED_ISTORAGE;
1293     return hr;
1294 }
1295
1296 /************************************************************************
1297  *                    get_stgmed_for_emf
1298  *
1299  * Returns a stg medium with an enhanced metafile based on the handle
1300  */
1301 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
1302 {
1303     med->pUnkForRelease = NULL;
1304     med->tymed = TYMED_NULL;
1305
1306     med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
1307     if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
1308     med->tymed = TYMED_ENHMF;
1309     return S_OK;
1310 }
1311
1312 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1313 {
1314     const WCHAR *str1, *str2;
1315
1316     if(off1 == 0 && off2 == 0) return TRUE;
1317     if(off1 == 0 || off2 == 0) return FALSE;
1318
1319     str1 = (const WCHAR*)((const char*)t1 + off1);
1320     str2 = (const WCHAR*)((const char*)t2 + off2);
1321
1322     return !lstrcmpW(str1, str2);
1323 }
1324
1325 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1326 {
1327     if(t1 == NULL && t2 == NULL) return TRUE;
1328     if(t1 == NULL || t2 == NULL) return FALSE;
1329
1330     if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1331         return FALSE;
1332     if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1333         return FALSE;
1334     if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1335         return FALSE;
1336
1337     /* FIXME check devmode? */
1338
1339     return TRUE;
1340 }
1341
1342 /************************************************************************
1343  *         snapshot_GetData
1344  */
1345 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1346                                        STGMEDIUM *med)
1347 {
1348     snapshot *This = impl_from_IDataObject(iface);
1349     HANDLE h;
1350     HRESULT hr;
1351     ole_priv_data *enum_data = NULL;
1352     ole_priv_data_entry *entry;
1353     DWORD mask;
1354
1355     TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1356
1357     if ( !fmt || !med ) return E_INVALIDARG;
1358
1359     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1360
1361     if(!This->data)
1362         hr = get_current_dataobject(&This->data);
1363
1364     if(This->data)
1365     {
1366         hr = IDataObject_GetData(This->data, fmt, med);
1367         CloseClipboard();
1368         return hr;
1369     }
1370
1371     h = GetClipboardData(fmt->cfFormat);
1372     if(!h)
1373     {
1374         hr = DV_E_FORMATETC;
1375         goto end;
1376     }
1377
1378     hr = get_priv_data(&enum_data);
1379     if(FAILED(hr)) goto end;
1380
1381     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1382     if(entry)
1383     {
1384         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1385         {
1386             hr = DV_E_FORMATETC;
1387             goto end;
1388         }
1389         mask = fmt->tymed & entry->fmtetc.tymed;
1390         if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1391     }
1392     else /* non-Ole format */
1393         mask = fmt->tymed & TYMED_HGLOBAL;
1394
1395     if(mask & TYMED_ISTORAGE)
1396         hr = get_stgmed_for_storage(h, med);
1397     else if(mask & TYMED_HGLOBAL)
1398         hr = get_stgmed_for_global(h, med);
1399     else if(mask & TYMED_ISTREAM)
1400         hr = get_stgmed_for_stream(h, med);
1401     else if(mask & TYMED_ENHMF)
1402         hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
1403     else
1404     {
1405         FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1406         hr = E_FAIL;
1407         goto end;
1408     }
1409
1410 end:
1411     HeapFree(GetProcessHeap(), 0, enum_data);
1412     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1413     return hr;
1414 }
1415
1416 /************************************************************************
1417  *          snapshot_GetDataHere
1418  */
1419 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1420                                            STGMEDIUM *med)
1421 {
1422     snapshot *This = impl_from_IDataObject(iface);
1423     HANDLE h;
1424     HRESULT hr;
1425     ole_priv_data *enum_data = NULL;
1426     ole_priv_data_entry *entry;
1427     TYMED supported;
1428
1429     if ( !fmt || !med ) return E_INVALIDARG;
1430
1431     TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1432
1433     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1434
1435     if(!This->data)
1436         hr = get_current_dataobject(&This->data);
1437
1438     if(This->data)
1439     {
1440         hr = IDataObject_GetDataHere(This->data, fmt, med);
1441         if(SUCCEEDED(hr))
1442         {
1443             CloseClipboard();
1444             return hr;
1445         }
1446     }
1447
1448     h = GetClipboardData(fmt->cfFormat);
1449     if(!h)
1450     {
1451         hr = DV_E_FORMATETC;
1452         goto end;
1453     }
1454
1455     hr = get_priv_data(&enum_data);
1456     if(FAILED(hr)) goto end;
1457
1458     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1459     if(entry)
1460     {
1461         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1462         {
1463             hr = DV_E_FORMATETC;
1464             goto end;
1465         }
1466         supported = entry->fmtetc.tymed;
1467     }
1468     else /* non-Ole format */
1469         supported = TYMED_HGLOBAL;
1470
1471     switch(med->tymed)
1472     {
1473     case TYMED_HGLOBAL:
1474     {
1475         DWORD src_size = GlobalSize(h);
1476         DWORD dst_size = GlobalSize(med->u.hGlobal);
1477         hr = E_FAIL;
1478         if(dst_size >= src_size)
1479         {
1480             void *src = GlobalLock(h);
1481             void *dst = GlobalLock(med->u.hGlobal);
1482
1483             memcpy(dst, src, src_size);
1484             GlobalUnlock(med->u.hGlobal);
1485             GlobalUnlock(h);
1486             hr = S_OK;
1487         }
1488         break;
1489     }
1490     case TYMED_ISTREAM:
1491     {
1492         DWORD src_size = GlobalSize(h);
1493         void *src = GlobalLock(h);
1494         hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1495         GlobalUnlock(h);
1496         break;
1497     }
1498     case TYMED_ISTORAGE:
1499     {
1500         STGMEDIUM copy;
1501         if(!(supported & TYMED_ISTORAGE))
1502         {
1503             hr = E_FAIL;
1504             goto end;
1505         }
1506         hr = get_stgmed_for_storage(h, &copy);
1507         if(SUCCEEDED(hr))
1508         {
1509             hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1510             ReleaseStgMedium(&copy);
1511         }
1512         break;
1513     }
1514     default:
1515         FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1516         hr = E_FAIL;
1517         goto end;
1518     }
1519
1520 end:
1521     HeapFree(GetProcessHeap(), 0, enum_data);
1522     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1523     return hr;
1524 }
1525
1526 /************************************************************************
1527  *           snapshot_QueryGetData
1528  *
1529  * The OLE Clipboard's implementation of this method delegates to
1530  * a data source if there is one or wraps around the windows clipboard
1531  * function IsClipboardFormatAvailable() otherwise.
1532  *
1533  */
1534 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1535 {
1536     FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1537
1538     if (!fmt) return E_INVALIDARG;
1539
1540     if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1541
1542     if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1543
1544     return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1545 }
1546
1547 /************************************************************************
1548  *              snapshot_GetCanonicalFormatEtc
1549  */
1550 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1551                                                      FORMATETC *fmt_out)
1552 {
1553     TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1554
1555     if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1556
1557     *fmt_out = *fmt_in;
1558     return DATA_S_SAMEFORMATETC;
1559 }
1560
1561 /************************************************************************
1562  *              snapshot_SetData
1563  *
1564  * The OLE Clipboard does not implement this method
1565  */
1566 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1567                                        STGMEDIUM *med, BOOL release)
1568 {
1569     TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1570     return E_NOTIMPL;
1571 }
1572
1573 /************************************************************************
1574  *             snapshot_EnumFormatEtc
1575  *
1576  */
1577 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1578                                              IEnumFORMATETC **enum_fmt)
1579 {
1580     HRESULT hr;
1581     ole_priv_data *data = NULL;
1582
1583     TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1584
1585     *enum_fmt = NULL;
1586
1587     if ( dir != DATADIR_GET ) return E_NOTIMPL;
1588     if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1589
1590     hr = get_priv_data(&data);
1591
1592     if(FAILED(hr)) goto end;
1593
1594     hr = enum_fmtetc_construct( data, 0, enum_fmt );
1595
1596 end:
1597     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1598     return hr;
1599 }
1600
1601 /************************************************************************
1602  *               snapshot_DAdvise
1603  *
1604  * The OLE Clipboard does not implement this method
1605  */
1606 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1607                                        DWORD flags, IAdviseSink *sink,
1608                                        DWORD *conn)
1609 {
1610     TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1611     return E_NOTIMPL;
1612 }
1613
1614 /************************************************************************
1615  *              snapshot_DUnadvise
1616  *
1617  * The OLE Clipboard does not implement this method
1618  */
1619 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1620 {
1621     TRACE("(%p, %d): not implemented\n", iface, conn);
1622     return E_NOTIMPL;
1623 }
1624
1625 /************************************************************************
1626  *             snapshot_EnumDAdvise
1627  *
1628  * The OLE Clipboard does not implement this method
1629  */
1630 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1631                                            IEnumSTATDATA** enum_advise)
1632 {
1633     TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1634     return E_NOTIMPL;
1635 }
1636
1637 static const IDataObjectVtbl snapshot_vtable =
1638 {
1639     snapshot_QueryInterface,
1640     snapshot_AddRef,
1641     snapshot_Release,
1642     snapshot_GetData,
1643     snapshot_GetDataHere,
1644     snapshot_QueryGetData,
1645     snapshot_GetCanonicalFormatEtc,
1646     snapshot_SetData,
1647     snapshot_EnumFormatEtc,
1648     snapshot_DAdvise,
1649     snapshot_DUnadvise,
1650     snapshot_EnumDAdvise
1651 };
1652
1653 /*---------------------------------------------------------------------*
1654  *           Internal implementation methods for the OLE clipboard
1655  *---------------------------------------------------------------------*/
1656
1657 static snapshot *snapshot_construct(DWORD seq_no)
1658 {
1659     snapshot *This;
1660
1661     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1662     if (!This) return NULL;
1663
1664     This->IDataObject_iface.lpVtbl = &snapshot_vtable;
1665     This->ref = 0;
1666     This->seq_no = seq_no;
1667     This->data = NULL;
1668
1669     return This;
1670 }
1671
1672 /*********************************************************
1673  *               register_clipboard_formats
1674  */
1675 static void register_clipboard_formats(void)
1676 {
1677     static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1678     static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1679     static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1680     static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1681     static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1682     static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1683     static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1684     static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1685     static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1686     static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1687                                                  'D','e','s','c','r','i','p','t','o','r',0};
1688     static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1689
1690     static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1691                                                      'D','a','t','a','O','b','j','e','c','t',0};
1692
1693     ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1694     filename_clipboard_format = RegisterClipboardFormatW(FileName);
1695     filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1696     dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1697     embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1698     embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1699     custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1700     link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1701     object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1702     link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1703     ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1704
1705     wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1706 }
1707
1708 /***********************************************************************
1709  * OLEClipbrd_Initialize()
1710  * Initializes the OLE clipboard.
1711  */
1712 void OLEClipbrd_Initialize(void)
1713 {
1714     register_clipboard_formats();
1715
1716     if ( !theOleClipboard )
1717     {
1718         ole_clipbrd* clipbrd;
1719         HGLOBAL h;
1720
1721         TRACE("()\n");
1722
1723         clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1724         if (!clipbrd) return;
1725
1726         clipbrd->latest_snapshot = NULL;
1727         clipbrd->window = NULL;
1728         clipbrd->src_data = NULL;
1729         clipbrd->cached_enum = NULL;
1730
1731         h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1732         if(!h)
1733         {
1734             HeapFree(GetProcessHeap(), 0, clipbrd);
1735             return;
1736         }
1737
1738         if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1739         {
1740             GlobalFree(h);
1741             HeapFree(GetProcessHeap(), 0, clipbrd);
1742             return;
1743         }
1744
1745         theOleClipboard = clipbrd;
1746     }
1747 }
1748
1749 /***********************************************************************
1750  * OLEClipbrd_UnInitialize()
1751  * Un-Initializes the OLE clipboard
1752  */
1753 void OLEClipbrd_UnInitialize(void)
1754 {
1755     ole_clipbrd *clipbrd = theOleClipboard;
1756
1757     TRACE("()\n");
1758
1759     if ( clipbrd )
1760     {
1761         static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1762         HINSTANCE hinst = GetModuleHandleW(ole32W);
1763
1764         if ( clipbrd->window )
1765         {
1766             DestroyWindow(clipbrd->window);
1767             UnregisterClassW( clipbrd_wndclass, hinst );
1768         }
1769
1770         IStream_Release(clipbrd->marshal_data);
1771         if (clipbrd->src_data) IDataObject_Release(clipbrd->src_data);
1772         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1773         HeapFree(GetProcessHeap(), 0, clipbrd);
1774         theOleClipboard = NULL;
1775     }
1776 }
1777
1778 /*********************************************************************
1779  *          set_clipboard_formats
1780  *
1781  * Enumerate all formats supported by the source and make
1782  * those formats available using delayed rendering using SetClipboardData.
1783  * Cache the enumeration list and make that list visibile as the
1784  * 'Ole Private Data' format on the clipboard.
1785  *
1786  */
1787 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1788 {
1789     HRESULT hr;
1790     FORMATETC fmt;
1791     IEnumFORMATETC *enum_fmt;
1792     HGLOBAL priv_data_handle;
1793     DWORD_PTR target_offset;
1794     ole_priv_data *priv_data;
1795     DWORD count = 0, needed = sizeof(*priv_data), idx;
1796
1797     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1798     if(FAILED(hr)) return hr;
1799
1800     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1801     {
1802         count++;
1803         needed += sizeof(priv_data->entries[0]);
1804         if(fmt.ptd)
1805         {
1806             needed += fmt.ptd->tdSize;
1807             CoTaskMemFree(fmt.ptd);
1808         }
1809     }
1810
1811     /* Windows pads the list with two empty ole_priv_data_entries, one
1812      * after the entries array and one after the target device data.
1813      * Allocating with zero init to zero these pads. */
1814
1815     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1816     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1817     priv_data = GlobalLock(priv_data_handle);
1818
1819     priv_data->unk1 = 0;
1820     priv_data->size = needed;
1821     priv_data->unk2 = 1;
1822     priv_data->count = count;
1823     priv_data->unk3[0] = 0;
1824     priv_data->unk3[1] = 0;
1825
1826     IEnumFORMATETC_Reset(enum_fmt);
1827
1828     idx = 0;
1829     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1830
1831     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1832     {
1833         TRACE("%s\n", dump_fmtetc(&fmt));
1834
1835         priv_data->entries[idx].fmtetc = fmt;
1836         if(fmt.ptd)
1837         {
1838             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1839             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1840             target_offset += fmt.ptd->tdSize;
1841             CoTaskMemFree(fmt.ptd);
1842         }
1843
1844         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1845         priv_data->entries[idx].unk[0] = 0;
1846         priv_data->entries[idx].unk[1] = 0;
1847
1848         if (priv_data->entries[idx].first_use)
1849             SetClipboardData(fmt.cfFormat, NULL);
1850
1851         idx++;
1852     }
1853
1854     IEnumFORMATETC_Release(enum_fmt);
1855
1856     /* Cache the list and fixup any target device offsets to ptrs */
1857     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1858     memcpy(clipbrd->cached_enum, priv_data, needed);
1859     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1860         clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1861             td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1862
1863     GlobalUnlock(priv_data_handle);
1864     if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle))
1865     {
1866         GlobalFree(priv_data_handle);
1867         return CLIPBRD_E_CANT_SET;
1868     }
1869
1870     return S_OK;
1871 }
1872
1873 static HWND create_clipbrd_window(void);
1874
1875 /***********************************************************************
1876  *                 get_clipbrd_window
1877  */
1878 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1879 {
1880     if ( !clipbrd->window )
1881         clipbrd->window = create_clipbrd_window();
1882
1883     *wnd = clipbrd->window;
1884     return *wnd ? S_OK : E_FAIL;
1885 }
1886
1887
1888 /**********************************************************************
1889  *                  release_marshal_data
1890  *
1891  * Releases the data and sets the stream back to zero size.
1892  */
1893 static inline void release_marshal_data(IStream *stm)
1894 {
1895     LARGE_INTEGER pos;
1896     ULARGE_INTEGER size;
1897     pos.QuadPart = size.QuadPart = 0;
1898
1899     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1900     CoReleaseMarshalData(stm);
1901     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1902     IStream_SetSize(stm, size);
1903 }
1904
1905 /***********************************************************************
1906  *   expose_marshalled_dataobject
1907  *
1908  * Sets the marshalled dataobject to the clipboard.  In the flushed case
1909  * we set a zero sized HGLOBAL to clear the old marshalled data.
1910  */
1911 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1912 {
1913     HGLOBAL h;
1914
1915     if(data)
1916     {
1917         HGLOBAL h_stm;
1918         GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1919         dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1920     }
1921     else /* flushed */
1922         h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1923
1924     if(!h) return E_OUTOFMEMORY;
1925
1926     if(!SetClipboardData(wine_marshal_clipboard_format, h))
1927     {
1928         GlobalFree(h);
1929         return CLIPBRD_E_CANT_SET;
1930     }
1931     return S_OK;
1932 }
1933
1934 /***********************************************************************
1935  *                   set_src_dataobject
1936  *
1937  * Clears and sets the clipboard's src IDataObject.
1938  *
1939  * To marshal the source dataobject we do something rather different from Windows.
1940  * We set a clipboard format which contains the marshalled data.
1941  * Windows sets two window props one of which is an IID, the other is an endpoint number.
1942  */
1943 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1944 {
1945     HRESULT hr;
1946     HWND wnd;
1947
1948     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1949
1950     if(clipbrd->src_data)
1951     {
1952         release_marshal_data(clipbrd->marshal_data);
1953
1954         IDataObject_Release(clipbrd->src_data);
1955         clipbrd->src_data = NULL;
1956         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1957         clipbrd->cached_enum = NULL;
1958     }
1959
1960     if(data)
1961     {
1962         IUnknown *unk;
1963
1964         IDataObject_AddRef(data);
1965         clipbrd->src_data = data;
1966
1967         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1968         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1969                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1970         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1971         if(FAILED(hr)) return hr;
1972         hr = set_clipboard_formats(clipbrd, data);
1973     }
1974     return hr;
1975 }
1976
1977 /***********************************************************************
1978  *                   clipbrd_wndproc
1979  */
1980 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1981 {
1982     ole_clipbrd *clipbrd;
1983
1984     get_ole_clipbrd(&clipbrd);
1985
1986     switch (message)
1987     {
1988     case WM_RENDERFORMAT:
1989     {
1990         UINT cf = wparam;
1991         ole_priv_data_entry *entry;
1992
1993         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1994         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1995
1996         if(entry)
1997             render_format(clipbrd->src_data, &entry->fmtetc);
1998
1999         break;
2000     }
2001
2002     case WM_RENDERALLFORMATS:
2003     {
2004         DWORD i;
2005         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
2006
2007         TRACE("(): WM_RENDERALLFORMATS\n");
2008
2009         for(i = 0; i < clipbrd->cached_enum->count; i++)
2010         {
2011             if(entries[i].first_use)
2012                 render_format(clipbrd->src_data, &entries[i].fmtetc);
2013         }
2014         break;
2015     }
2016
2017     case WM_DESTROYCLIPBOARD:
2018     {
2019         TRACE("(): WM_DESTROYCLIPBOARD\n");
2020
2021         set_src_dataobject(clipbrd, NULL);
2022         break;
2023     }
2024
2025     default:
2026         return DefWindowProcW(hwnd, message, wparam, lparam);
2027     }
2028
2029     return 0;
2030 }
2031
2032
2033 /***********************************************************************
2034  *                 create_clipbrd_window
2035  */
2036 static HWND create_clipbrd_window(void)
2037 {
2038     WNDCLASSEXW class;
2039     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
2040     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2041     HINSTANCE hinst = GetModuleHandleW(ole32W);
2042
2043     class.cbSize         = sizeof(class);
2044     class.style          = 0;
2045     class.lpfnWndProc    = clipbrd_wndproc;
2046     class.cbClsExtra     = 0;
2047     class.cbWndExtra     = 0;
2048     class.hInstance      = hinst;
2049     class.hIcon          = 0;
2050     class.hCursor        = 0;
2051     class.hbrBackground  = 0;
2052     class.lpszMenuName   = NULL;
2053     class.lpszClassName  = clipbrd_wndclass;
2054     class.hIconSm        = NULL;
2055
2056     RegisterClassExW(&class);
2057
2058     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
2059                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2060                          NULL, NULL, hinst, 0);
2061 }
2062
2063 /*********************************************************************
2064  *          set_dataobject_format
2065  *
2066  * Windows creates a 'DataObject' clipboard format that contains the
2067  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2068  */
2069 static HRESULT set_dataobject_format(HWND hwnd)
2070 {
2071     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
2072     HWND *data;
2073
2074     if(!h) return E_OUTOFMEMORY;
2075
2076     data = GlobalLock(h);
2077     *data = hwnd;
2078     GlobalUnlock(h);
2079
2080     if(!SetClipboardData(dataobject_clipboard_format, h))
2081     {
2082         GlobalFree(h);
2083         return CLIPBRD_E_CANT_SET;
2084     }
2085
2086     return S_OK;
2087 }
2088
2089 /*---------------------------------------------------------------------*
2090  *           Win32 OLE clipboard API
2091  *---------------------------------------------------------------------*/
2092
2093 /***********************************************************************
2094  *           OleSetClipboard     [OLE32.@]
2095  *  Places a pointer to the specified data object onto the clipboard,
2096  *  making the data object accessible to the OleGetClipboard function.
2097  *
2098  * RETURNS
2099  *
2100  *    S_OK                  IDataObject pointer placed on the clipboard
2101  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
2102  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
2103  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
2104  *    CLIPBRD_E_CANT_SET    SetClipboard failed
2105  */
2106
2107 HRESULT WINAPI OleSetClipboard(IDataObject* data)
2108 {
2109   HRESULT hr;
2110   ole_clipbrd *clipbrd;
2111   HWND wnd;
2112
2113   TRACE("(%p)\n", data);
2114
2115   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2116
2117   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2118
2119   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
2120
2121   if ( !EmptyClipboard() )
2122   {
2123     hr = CLIPBRD_E_CANT_EMPTY;
2124     goto end;
2125   }
2126
2127   hr = set_src_dataobject(clipbrd, data);
2128   if(FAILED(hr)) goto end;
2129
2130   if(data)
2131   {
2132     hr = expose_marshalled_dataobject(clipbrd, data);
2133     if(FAILED(hr)) goto end;
2134     hr = set_dataobject_format(wnd);
2135   }
2136
2137 end:
2138
2139   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2140
2141   if ( FAILED(hr) )
2142   {
2143     expose_marshalled_dataobject(clipbrd, NULL);
2144     set_src_dataobject(clipbrd, NULL);
2145   }
2146
2147   return hr;
2148 }
2149
2150
2151 /***********************************************************************
2152  * OleGetClipboard [OLE32.@]
2153  * Returns a pointer to our internal IDataObject which represents the conceptual
2154  * state of the Windows clipboard. If the current clipboard already contains
2155  * an IDataObject, our internal IDataObject will delegate to this object.
2156  */
2157 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
2158 {
2159     HRESULT hr;
2160     ole_clipbrd *clipbrd;
2161     DWORD seq_no;
2162
2163     TRACE("(%p)\n", obj);
2164
2165     if(!obj) return E_INVALIDARG;
2166
2167     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2168
2169     seq_no = GetClipboardSequenceNumber();
2170     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2171         clipbrd->latest_snapshot = NULL;
2172
2173     if(!clipbrd->latest_snapshot)
2174     {
2175         clipbrd->latest_snapshot = snapshot_construct(seq_no);
2176         if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
2177     }
2178
2179     *obj = &clipbrd->latest_snapshot->IDataObject_iface;
2180     IDataObject_AddRef(*obj);
2181
2182     return S_OK;
2183 }
2184
2185 /******************************************************************************
2186  *              OleFlushClipboard        [OLE32.@]
2187  *  Renders the data from the source IDataObject into the windows clipboard
2188  *
2189  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2190  *  by copying the storage into global memory. Subsequently the default
2191  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2192  *  back to TYMED_IStorage.
2193  */
2194 HRESULT WINAPI OleFlushClipboard(void)
2195 {
2196   HRESULT hr;
2197   ole_clipbrd *clipbrd;
2198   HWND wnd;
2199
2200   TRACE("()\n");
2201
2202   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2203
2204   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2205
2206   /*
2207    * Already flushed or no source DataObject? Nothing to do.
2208    */
2209   if (!clipbrd->src_data) return S_OK;
2210
2211   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2212
2213   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2214
2215   hr = set_dataobject_format(NULL);
2216
2217   expose_marshalled_dataobject(clipbrd, NULL);
2218   set_src_dataobject(clipbrd, NULL);
2219
2220   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2221
2222   return hr;
2223 }
2224
2225
2226 /***********************************************************************
2227  *           OleIsCurrentClipboard [OLE32.@]
2228  */
2229 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2230 {
2231     HRESULT hr;
2232     ole_clipbrd *clipbrd;
2233     TRACE("()\n");
2234
2235     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2236
2237     if (data == NULL) return S_FALSE;
2238
2239     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
2240 }