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