ole32: OleFlushClipboard should render all formats to the clipboard.
[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  *           create_empty_priv_data
109  *
110  * Create an empty data structure.  The only thing that really matters
111  * here is setting count and size members.  This is used by the enumerator as a
112  * convenience when there's an empty list.
113  */
114 static HRESULT create_empty_priv_data(ole_priv_data **data)
115 {
116     ole_priv_data *ptr;
117
118     *data = NULL;
119     ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr));
120     if(!ptr) return E_OUTOFMEMORY;
121     ptr->size = sizeof(*ptr);
122     ptr->count = 0;
123     *data = ptr;
124     return S_OK;
125 }
126
127 /****************************************************************************
128  * Consumer snapshot.  Represents the state of the ole clipboard
129  * returned by OleGetClipboard().
130  */
131 typedef struct snapshot
132 {
133     const IDataObjectVtbl* lpVtbl;
134     LONG ref;
135
136     DWORD seq_no;                   /* Clipboard sequence number corresponding to this snapshot */
137
138     IDataObject *data;              /* If we unmarshal a remote data object we hold a ref here */
139 } snapshot;
140
141 /****************************************************************************
142  * ole_clipbrd
143  */
144 typedef struct ole_clipbrd
145 {
146     snapshot *latest_snapshot;       /* Latest consumer snapshot */
147
148     HWND window;                     /* Hidden clipboard window */
149     IDataObject *src_data;           /* Source object passed to OleSetClipboard */
150     ole_priv_data *cached_enum;      /* Cached result from the enumeration of src data object */
151     IStream *marshal_data;           /* Stream onto which to marshal src_data */
152 } ole_clipbrd;
153
154 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
155 {
156     return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
157 }
158
159 typedef struct PresentationDataHeader
160 {
161   BYTE unknown1[28];
162   DWORD dwObjectExtentX;
163   DWORD dwObjectExtentY;
164   DWORD dwSize;
165 } PresentationDataHeader;
166
167 /*
168  * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
169  */
170 static ole_clipbrd* theOleClipboard;
171
172 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
173 {
174     struct oletls *info = COM_CurrentInfo();
175     *clipbrd = NULL;
176
177     if(!info->ole_inits)
178         return CO_E_NOTINITIALIZED;
179     *clipbrd = theOleClipboard;
180
181     return S_OK;
182 }
183
184 /*
185  * Name of our registered OLE clipboard window class
186  */
187 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
188
189 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};
190
191 static UINT dataobject_clipboard_format;
192 static UINT ole_priv_data_clipboard_format;
193 static UINT embed_source_clipboard_format;
194
195 static inline char *dump_fmtetc(FORMATETC *fmt)
196 {
197     static char buf[100];
198
199     snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
200              fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
201     return buf;
202 }
203
204 /*---------------------------------------------------------------------*
205  *  Implementation of the internal IEnumFORMATETC interface returned by
206  *  the OLE clipboard's IDataObject.
207  *---------------------------------------------------------------------*/
208
209 typedef struct enum_fmtetc
210 {
211     const IEnumFORMATETCVtbl *lpVtbl;
212     LONG ref;
213
214     UINT pos;    /* current enumerator position */
215     ole_priv_data *data;
216 } enum_fmtetc;
217
218 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
219 {
220     return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
221 }
222
223 /************************************************************************
224  * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
225  *
226  * See Windows documentation for more details on IUnknown methods.
227  */
228 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
229   (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
230 {
231   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
232
233   TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
234
235   *ppvObj = NULL;
236
237   if(IsEqualIID(riid, &IID_IUnknown) ||
238      IsEqualIID(riid, &IID_IEnumFORMATETC))
239   {
240     *ppvObj = iface;
241   }
242
243   if(*ppvObj)
244   {
245     IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
246     TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
247     return S_OK;
248   }
249
250   TRACE("-- Interface: E_NOINTERFACE\n");
251   return E_NOINTERFACE;
252 }
253
254 /************************************************************************
255  * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
256  *
257  */
258 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
259 {
260   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
261   TRACE("(%p)->(count=%u)\n",This, This->ref);
262
263   return InterlockedIncrement(&This->ref);
264 }
265
266 /************************************************************************
267  * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
268  *
269  * See Windows documentation for more details on IUnknown methods.
270  */
271 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
272 {
273   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
274   ULONG ref;
275
276   TRACE("(%p)->(count=%u)\n",This, This->ref);
277
278   ref = InterlockedDecrement(&This->ref);
279   if (!ref)
280   {
281     TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
282     HeapFree(GetProcessHeap(), 0, This->data);
283     HeapFree(GetProcessHeap(), 0, This);
284   }
285   return ref;
286 }
287
288 /************************************************************************
289  * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
290  *
291  * Standard enumerator members for IEnumFORMATETC
292  */
293 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
294   (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
295 {
296   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
297   UINT cfetch, i;
298   HRESULT hres = S_FALSE;
299
300   TRACE("(%p)->(pos=%u)\n", This, This->pos);
301
302   if (This->pos < This->data->count)
303   {
304     cfetch = This->data->count - This->pos;
305     if (cfetch >= celt)
306     {
307       cfetch = celt;
308       hres = S_OK;
309     }
310
311     for(i = 0; i < cfetch; i++)
312     {
313       rgelt[i] = This->data->entries[This->pos++].fmtetc;
314       if(rgelt[i].ptd)
315       {
316         DVTARGETDEVICE *target = (DVTARGETDEVICE *)((char *)This->data + (DWORD)rgelt[i].ptd);
317         rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
318         if(!rgelt[i].ptd) return E_OUTOFMEMORY;
319         memcpy(rgelt[i].ptd, target, target->tdSize);
320       }
321     }
322   }
323   else
324   {
325     cfetch = 0;
326   }
327
328   if (pceltFethed)
329   {
330     *pceltFethed = cfetch;
331   }
332
333   return hres;
334 }
335
336 /************************************************************************
337  * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
338  *
339  * Standard enumerator members for IEnumFORMATETC
340  */
341 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
342 {
343   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
344   TRACE("(%p)->(num=%u)\n", This, celt);
345
346   This->pos += celt;
347   if (This->pos > This->data->count)
348   {
349     This->pos = This->data->count;
350     return S_FALSE;
351   }
352   return S_OK;
353 }
354
355 /************************************************************************
356  * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
357  *
358  * Standard enumerator members for IEnumFORMATETC
359  */
360 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
361 {
362   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
363   TRACE("(%p)->()\n", This);
364
365   This->pos = 0;
366   return S_OK;
367 }
368
369 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
370
371 /************************************************************************
372  * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
373  *
374  * Standard enumerator members for IEnumFORMATETC
375  */
376 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
377   (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
378 {
379   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
380   ole_priv_data *new_data;
381
382   TRACE("(%p)->(%p)\n", This, obj);
383
384   if ( !obj ) return E_INVALIDARG;
385   *obj = NULL;
386
387   new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
388   if(!new_data) return E_OUTOFMEMORY;
389
390   return enum_fmtetc_construct(new_data, This->pos, obj);
391 }
392
393 static const IEnumFORMATETCVtbl efvt =
394 {
395   OLEClipbrd_IEnumFORMATETC_QueryInterface,
396   OLEClipbrd_IEnumFORMATETC_AddRef,
397   OLEClipbrd_IEnumFORMATETC_Release,
398   OLEClipbrd_IEnumFORMATETC_Next,
399   OLEClipbrd_IEnumFORMATETC_Skip,
400   OLEClipbrd_IEnumFORMATETC_Reset,
401   OLEClipbrd_IEnumFORMATETC_Clone
402 };
403
404 /************************************************************************
405  * enum_fmtetc_construct
406  *
407  * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
408  */
409 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
410 {
411   enum_fmtetc* ef;
412
413   *obj = NULL;
414   ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
415   if (!ef) return E_OUTOFMEMORY;
416
417   ef->ref = 1;
418   ef->lpVtbl = &efvt;
419   ef->data = data;
420   ef->pos = pos;
421
422   TRACE("(%p)->()\n", ef);
423   *obj = (IEnumFORMATETC *)ef;
424   return S_OK;
425 }
426
427 /***********************************************************************
428  *                    dup_global_mem
429  *
430  * Helper method to duplicate an HGLOBAL chunk of memory
431  */
432 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
433 {
434     void *src_ptr, *dst_ptr;
435     DWORD size;
436
437     *dst = NULL;
438     if ( !src ) return S_FALSE;
439
440     size = GlobalSize(src);
441
442     *dst = GlobalAlloc( flags, size );
443     if ( !*dst ) return E_OUTOFMEMORY;
444
445     src_ptr = GlobalLock(src);
446     dst_ptr = GlobalLock(*dst);
447
448     memcpy(dst_ptr, src_ptr, size);
449
450     GlobalUnlock(*dst);
451     GlobalUnlock(src);
452
453     return S_OK;
454 }
455
456 /************************************************************
457  *              render_embed_source_hack
458  *
459  * This is clearly a hack and has no place in the clipboard code.
460  *
461  */
462 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
463 {
464     STGMEDIUM std;
465     HGLOBAL hStorage = 0;
466     HRESULT hr = S_OK;
467     ILockBytes *ptrILockBytes;
468
469     memset(&std, 0, sizeof(STGMEDIUM));
470     std.tymed = fmt->tymed = TYMED_ISTORAGE;
471
472     hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
473     if (hStorage == NULL) return E_OUTOFMEMORY;
474     hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
475     hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
476     ILockBytes_Release(ptrILockBytes);
477
478     if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
479     {
480         WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
481         GlobalFree(hStorage);
482         return hr;
483     }
484
485     if (1) /* check whether the presentation data is already -not- present */
486     {
487         FORMATETC fmt2;
488         STGMEDIUM std2;
489         METAFILEPICT *mfp = 0;
490
491         fmt2.cfFormat = CF_METAFILEPICT;
492         fmt2.ptd = 0;
493         fmt2.dwAspect = DVASPECT_CONTENT;
494         fmt2.lindex = -1;
495         fmt2.tymed = TYMED_MFPICT;
496
497         memset(&std2, 0, sizeof(STGMEDIUM));
498         std2.tymed = TYMED_MFPICT;
499
500         /* Get the metafile picture out of it */
501
502         if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
503         {
504             mfp = GlobalLock(std2.u.hGlobal);
505         }
506
507         if (mfp)
508         {
509             OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
510             IStream *pStream = 0;
511             void *mfBits;
512             PresentationDataHeader pdh;
513             INT nSize;
514             CLSID clsID;
515             LPOLESTR strProgID;
516             CHAR strOleTypeName[51];
517             BYTE OlePresStreamHeader [] =
518             {
519                 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
520                 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
521                 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
522                 0x00, 0x00, 0x00, 0x00
523             };
524
525             nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
526
527             memset(&pdh, 0, sizeof(PresentationDataHeader));
528             memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
529
530             pdh.dwObjectExtentX = mfp->xExt;
531             pdh.dwObjectExtentY = mfp->yExt;
532             pdh.dwSize = nSize;
533
534             hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
535
536             hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
537
538             mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
539             nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
540
541             hr = IStream_Write(pStream, mfBits, nSize, NULL);
542
543             IStream_Release(pStream);
544
545             HeapFree(GetProcessHeap(), 0, mfBits);
546
547             GlobalUnlock(std2.u.hGlobal);
548             ReleaseStgMedium(&std2);
549
550             ReadClassStg(std.u.pstg, &clsID);
551             ProgIDFromCLSID(&clsID, &strProgID);
552
553             WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
554             OLECONVERT_CreateOleStream(std.u.pstg);
555             OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
556         }
557     }
558
559     if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
560     {
561         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
562         GlobalFree(hStorage);
563         hr = CLIPBRD_E_CANT_SET;
564     }
565
566     ReleaseStgMedium(&std);
567     return hr;
568 }
569
570 /************************************************************************
571  *           find_format_in_list
572  *
573  * Returns the first entry that matches the provided clipboard format.
574  */
575 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
576 {
577     DWORD i;
578     for(i = 0; i < num; i++)
579         if(entries[i].fmtetc.cfFormat == cf)
580             return &entries[i];
581
582     return NULL;
583 }
584
585 /***************************************************************************
586  *         get_data_from_storage
587  *
588  * Returns storage data in an HGLOBAL.
589  */
590 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
591 {
592     HGLOBAL h;
593     IStorage *stg;
594     HRESULT hr;
595     FORMATETC stg_fmt;
596     STGMEDIUM med;
597     ILockBytes *lbs;
598
599     *mem = NULL;
600
601     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
602     if(!h) return E_OUTOFMEMORY;
603
604     hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
605     if(SUCCEEDED(hr))
606     {
607         hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
608         ILockBytes_Release(lbs);
609     }
610     if(FAILED(hr))
611     {
612         GlobalFree(h);
613         return hr;
614     }
615
616     stg_fmt = *fmt;
617     med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
618     med.u.pstg = stg;
619     med.pUnkForRelease = NULL;
620
621     hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
622     if(FAILED(hr))
623     {
624         med.u.pstg = NULL;
625         hr = IDataObject_GetData(data, &stg_fmt, &med);
626         if(FAILED(hr)) goto end;
627
628         hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
629         ReleaseStgMedium(&med);
630         if(FAILED(hr)) goto end;
631     }
632     *mem = h;
633
634 end:
635     IStorage_Release(stg);
636     if(FAILED(hr)) GlobalFree(h);
637     return hr;
638 }
639
640 /***************************************************************************
641  *         get_data_from_stream
642  *
643  * Returns stream data in an HGLOBAL.
644  */
645 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
646 {
647     HGLOBAL h;
648     IStream *stm = NULL;
649     HRESULT hr;
650     FORMATETC stm_fmt;
651     STGMEDIUM med;
652
653     *mem = NULL;
654
655     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
656     if(!h) return E_OUTOFMEMORY;
657
658     hr = CreateStreamOnHGlobal(h, FALSE, &stm);
659     if(FAILED(hr)) goto error;
660
661     stm_fmt = *fmt;
662     med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
663     med.u.pstm = stm;
664     med.pUnkForRelease = NULL;
665
666     hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
667     if(FAILED(hr))
668     {
669         LARGE_INTEGER offs;
670         ULARGE_INTEGER pos;
671
672         med.u.pstm = NULL;
673         hr = IDataObject_GetData(data, &stm_fmt, &med);
674         if(FAILED(hr)) goto error;
675
676         offs.QuadPart = 0;
677         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
678         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
679         hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
680         ReleaseStgMedium(&med);
681         if(FAILED(hr)) goto error;
682     }
683     *mem = h;
684     IStream_Release(stm);
685     return S_OK;
686
687 error:
688     if(stm) IStream_Release(stm);
689     GlobalFree(h);
690     return hr;
691 }
692
693 /***************************************************************************
694  *         get_data_from_global
695  *
696  * Returns global data in an HGLOBAL.
697  */
698 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
699 {
700     HGLOBAL h;
701     HRESULT hr;
702     FORMATETC mem_fmt;
703     STGMEDIUM med;
704
705     *mem = NULL;
706
707     mem_fmt = *fmt;
708     mem_fmt.tymed = TYMED_HGLOBAL;
709
710     hr = IDataObject_GetData(data, &mem_fmt, &med);
711     if(FAILED(hr)) return hr;
712
713     hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
714
715     if(SUCCEEDED(hr)) *mem = h;
716
717     ReleaseStgMedium(&med);
718
719     return hr;
720 }
721
722 /***********************************************************************
723  *                render_format
724  *
725  * Render the clipboard data. Note that this call will delegate to the
726  * source data object.
727  */
728 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
729 {
730     HGLOBAL clip_data = NULL;
731     HRESULT hr;
732
733     /* Embed source hack */
734     if(fmt->cfFormat == embed_source_clipboard_format)
735     {
736         return render_embed_source_hack(data, fmt);
737     }
738
739     if(fmt->tymed & TYMED_ISTORAGE)
740     {
741         hr = get_data_from_storage(data, fmt, &clip_data);
742     }
743     else if(fmt->tymed & TYMED_ISTREAM)
744     {
745         hr = get_data_from_stream(data, fmt, &clip_data);
746     }
747     else if(fmt->tymed & TYMED_HGLOBAL)
748     {
749         hr = get_data_from_global(data, fmt, &clip_data);
750     }
751     else
752     {
753         FIXME("Unhandled tymed %x\n", fmt->tymed);
754         hr = DV_E_FORMATETC;
755     }
756
757     if(SUCCEEDED(hr))
758     {
759         if ( !SetClipboardData(fmt->cfFormat, clip_data) )
760         {
761             WARN("() : Failed to set rendered clipboard data into clipboard!\n");
762             GlobalFree(clip_data);
763             hr = CLIPBRD_E_CANT_SET;
764         }
765     }
766
767     return hr;
768 }
769
770 /*---------------------------------------------------------------------*
771  *  Implementation of the internal IDataObject interface exposed by
772  *  the OLE clipboard.
773  *---------------------------------------------------------------------*/
774
775
776 /************************************************************************
777  *           snapshot_QueryInterface
778  */
779 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
780                                               REFIID riid, void **ppvObject)
781 {
782   snapshot *This = impl_from_IDataObject(iface);
783   TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
784
785   if ( (This==0) || (ppvObject==0) )
786     return E_INVALIDARG;
787
788   *ppvObject = 0;
789
790   if (IsEqualIID(&IID_IUnknown, riid) ||
791       IsEqualIID(&IID_IDataObject, riid))
792   {
793     *ppvObject = iface;
794   }
795   else
796   {
797     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
798     return E_NOINTERFACE;
799   }
800
801   IUnknown_AddRef((IUnknown*)*ppvObject);
802
803   return S_OK;
804 }
805
806 /************************************************************************
807  *              snapshot_AddRef
808  */
809 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
810 {
811     snapshot *This = impl_from_IDataObject(iface);
812
813     TRACE("(%p)->(count=%u)\n", This, This->ref);
814
815     return InterlockedIncrement(&This->ref);
816 }
817
818 /************************************************************************
819  *      snapshot_Release
820  */
821 static ULONG WINAPI snapshot_Release(IDataObject *iface)
822 {
823     snapshot *This = impl_from_IDataObject(iface);
824     ULONG ref;
825
826     TRACE("(%p)->(count=%u)\n", This, This->ref);
827
828     ref = InterlockedDecrement(&This->ref);
829
830     if (ref == 0)
831     {
832         ole_clipbrd *clipbrd;
833         HRESULT hr = get_ole_clipbrd(&clipbrd);
834
835         if(This->data) IDataObject_Release(This->data);
836
837         if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
838             clipbrd->latest_snapshot = NULL;
839         HeapFree(GetProcessHeap(), 0, This);
840     }
841
842     return ref;
843 }
844
845 /************************************************************
846  *              get_current_ole_clip_window
847  *
848  * Return the window that owns the ole clipboard.
849  *
850  * If the clipboard is flushed or not owned by ole this will
851  * return NULL.
852  */
853 static HWND get_current_ole_clip_window(void)
854 {
855     HGLOBAL h;
856     HWND *ptr, wnd;
857
858     h = GetClipboardData(dataobject_clipboard_format);
859     if(!h) return NULL;
860     ptr = GlobalLock(h);
861     if(!ptr) return NULL;
862     wnd = *ptr;
863     GlobalUnlock(h);
864     return wnd;
865 }
866
867 /************************************************************
868  *              get_current_dataobject
869  *
870  * Return an unmarshalled IDataObject if there is a current
871  * (ie non-flushed) object on the ole clipboard.
872  */
873 static HRESULT get_current_dataobject(IDataObject **data)
874 {
875     HRESULT hr = S_FALSE;
876     HWND wnd = get_current_ole_clip_window();
877     HGLOBAL h;
878     void *ptr;
879     IStream *stm;
880     LARGE_INTEGER pos;
881
882     *data = NULL;
883     if(!wnd) return S_FALSE;
884
885     h = GetPropW(wnd, wine_marshal_dataobject);
886     if(!h) return S_FALSE;
887     ptr = GlobalLock(h);
888     if(!ptr) return S_FALSE;
889
890     hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
891     if(FAILED(hr)) goto end;
892
893     hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
894     if(SUCCEEDED(hr))
895     {
896         pos.QuadPart = 0;
897         IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
898         hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
899     }
900     IStream_Release(stm);
901
902 end:
903     GlobalUnlock(h);
904     return hr;
905 }
906
907 /***********************************************************
908  *     get_priv_data
909  *
910  * Returns a copy of the Ole Private Data
911  */
912 static HRESULT get_priv_data(ole_priv_data **data)
913 {
914     HGLOBAL handle;
915     HRESULT hr = S_OK;
916
917     *data = NULL;
918
919     handle = GetClipboardData( ole_priv_data_clipboard_format );
920     if(handle)
921     {
922         ole_priv_data *src = GlobalLock(handle);
923         if(src)
924         {
925             /* FIXME: sanity check on size */
926             *data = HeapAlloc(GetProcessHeap(), 0, src->size);
927             if(!*data)
928             {
929                 GlobalUnlock(handle);
930                 return E_OUTOFMEMORY;
931             }
932             memcpy(*data, src, src->size);
933             GlobalUnlock(handle);
934         }
935     }
936
937     if(!*data) hr = create_empty_priv_data(data);
938
939     return hr;
940 }
941
942 /************************************************************************
943  *                    get_stgmed_for_global
944  *
945  * Returns a stg medium with a copy of the global handle
946  */
947 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
948 {
949     HRESULT hr;
950
951     med->pUnkForRelease = NULL;
952     med->tymed = TYMED_NULL;
953
954     hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
955
956     if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
957
958     return hr;
959 }
960
961 /************************************************************************
962  *                    get_stgmed_for_stream
963  *
964  * Returns a stg medium with a stream based on the handle
965  */
966 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
967 {
968     HRESULT hr;
969     HGLOBAL dst;
970
971     med->pUnkForRelease = NULL;
972     med->tymed = TYMED_NULL;
973
974     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
975     if(FAILED(hr)) return hr;
976
977     hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
978     if(FAILED(hr))
979     {
980         GlobalFree(dst);
981         return hr;
982     }
983
984     med->tymed = TYMED_ISTREAM;
985     return hr;
986 }
987
988 /************************************************************************
989  *                    get_stgmed_for_storage
990  *
991  * Returns a stg medium with a storage based on the handle
992  */
993 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
994 {
995     HRESULT hr;
996     HGLOBAL dst;
997     ILockBytes *lbs;
998
999     med->pUnkForRelease = NULL;
1000     med->tymed = TYMED_NULL;
1001
1002     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1003     if(FAILED(hr)) return hr;
1004
1005     hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1006     if(FAILED(hr))
1007     {
1008         GlobalFree(dst);
1009         return hr;
1010     }
1011
1012     hr = StgOpenStorageOnILockBytes(lbs, NULL,  STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1013     ILockBytes_Release(lbs);
1014     if(FAILED(hr))
1015     {
1016         GlobalFree(dst);
1017         return hr;
1018     }
1019
1020     med->tymed = TYMED_ISTORAGE;
1021     return hr;
1022 }
1023
1024 /************************************************************************
1025  *         snapshot_GetData
1026  */
1027 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1028                                        STGMEDIUM *med)
1029 {
1030     snapshot *This = impl_from_IDataObject(iface);
1031     HANDLE h;
1032     HRESULT hr;
1033     ole_priv_data *enum_data = NULL;
1034     ole_priv_data_entry *entry;
1035     DWORD mask;
1036
1037     TRACE("(%p,%p,%p)\n", iface, fmt, med);
1038
1039     if ( !fmt || !med ) return E_INVALIDARG;
1040
1041     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1042
1043     if(!This->data)
1044         hr = get_current_dataobject(&This->data);
1045
1046     if(This->data)
1047     {
1048         hr = IDataObject_GetData(This->data, fmt, med);
1049         CloseClipboard();
1050         return hr;
1051     }
1052
1053     h = GetClipboardData(fmt->cfFormat);
1054     if(!h)
1055     {
1056         hr = DV_E_FORMATETC;
1057         goto end;
1058     }
1059
1060     hr = get_priv_data(&enum_data);
1061     if(FAILED(hr)) goto end;
1062
1063     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1064     if(entry)
1065         mask = fmt->tymed & entry->fmtetc.tymed;
1066     else /* non-Ole format */
1067         mask = fmt->tymed & TYMED_HGLOBAL;
1068
1069     if(mask & TYMED_ISTORAGE)
1070         hr = get_stgmed_for_storage(h, med);
1071     else if(mask & TYMED_HGLOBAL)
1072         hr = get_stgmed_for_global(h, med);
1073     else if(mask & TYMED_ISTREAM)
1074         hr = get_stgmed_for_stream(h, med);
1075     else
1076     {
1077         FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed);
1078         hr = E_FAIL;
1079         goto end;
1080     }
1081
1082 end:
1083     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1084     return hr;
1085 }
1086
1087 /************************************************************************
1088  *          snapshot_GetDataHere
1089  */
1090 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1091                                            STGMEDIUM *med)
1092 {
1093     FIXME("(%p, %p, %p): stub\n", iface, fmt, med);
1094     return E_NOTIMPL;
1095 }
1096
1097 /************************************************************************
1098  *           snapshot_QueryGetData
1099  *
1100  * The OLE Clipboard's implementation of this method delegates to
1101  * a data source if there is one or wraps around the windows clipboard
1102  * function IsClipboardFormatAvailable() otherwise.
1103  *
1104  */
1105 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1106 {
1107     FIXME("(%p, %p)\n", iface, fmt);
1108
1109     if (!fmt) return E_INVALIDARG;
1110
1111     if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1112
1113     if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1114
1115     return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1116 }
1117
1118 /************************************************************************
1119  *              snapshot_GetCanonicalFormatEtc
1120  */
1121 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1122                                                      FORMATETC *fmt_out)
1123 {
1124     TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1125
1126     if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1127
1128     *fmt_out = *fmt_in;
1129     return DATA_S_SAMEFORMATETC;
1130 }
1131
1132 /************************************************************************
1133  *              snapshot_SetData
1134  *
1135  * The OLE Clipboard does not implement this method
1136  */
1137 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1138                                        STGMEDIUM *med, BOOL release)
1139 {
1140     TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1141     return E_NOTIMPL;
1142 }
1143
1144 /************************************************************************
1145  *             snapshot_EnumFormatEtc
1146  *
1147  */
1148 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1149                                              IEnumFORMATETC **enum_fmt)
1150 {
1151     HRESULT hr;
1152     ole_priv_data *data = NULL;
1153
1154     TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1155
1156     *enum_fmt = NULL;
1157
1158     if ( dir != DATADIR_GET ) return E_NOTIMPL;
1159     if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1160
1161     hr = get_priv_data(&data);
1162
1163     if(FAILED(hr)) goto end;
1164
1165     hr = enum_fmtetc_construct( data, 0, enum_fmt );
1166
1167 end:
1168     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1169     return hr;
1170 }
1171
1172 /************************************************************************
1173  *               snapshot_DAdvise
1174  *
1175  * The OLE Clipboard does not implement this method
1176  */
1177 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1178                                        DWORD flags, IAdviseSink *sink,
1179                                        DWORD *conn)
1180 {
1181     TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1182     return E_NOTIMPL;
1183 }
1184
1185 /************************************************************************
1186  *              snapshot_DUnadvise
1187  *
1188  * The OLE Clipboard does not implement this method
1189  */
1190 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1191 {
1192     TRACE("(%p, %d): not implemented\n", iface, conn);
1193     return E_NOTIMPL;
1194 }
1195
1196 /************************************************************************
1197  *             snapshot_EnumDAdvise
1198  *
1199  * The OLE Clipboard does not implement this method
1200  */
1201 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1202                                            IEnumSTATDATA** enum_advise)
1203 {
1204     TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1205     return E_NOTIMPL;
1206 }
1207
1208 static const IDataObjectVtbl snapshot_vtable =
1209 {
1210     snapshot_QueryInterface,
1211     snapshot_AddRef,
1212     snapshot_Release,
1213     snapshot_GetData,
1214     snapshot_GetDataHere,
1215     snapshot_QueryGetData,
1216     snapshot_GetCanonicalFormatEtc,
1217     snapshot_SetData,
1218     snapshot_EnumFormatEtc,
1219     snapshot_DAdvise,
1220     snapshot_DUnadvise,
1221     snapshot_EnumDAdvise
1222 };
1223
1224 /*---------------------------------------------------------------------*
1225  *           Internal implementation methods for the OLE clipboard
1226  *---------------------------------------------------------------------*/
1227
1228 static snapshot *snapshot_construct(DWORD seq_no)
1229 {
1230     snapshot *This;
1231
1232     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1233     if (!This) return NULL;
1234
1235     This->lpVtbl = &snapshot_vtable;
1236     This->ref = 0;
1237     This->seq_no = seq_no;
1238     This->data = NULL;
1239
1240     return This;
1241 }
1242
1243 /*********************************************************
1244  *               register_clipboard_formats
1245  */
1246 static void register_clipboard_formats(void)
1247 {
1248     static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1249     static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1250     static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1251
1252     if(!dataobject_clipboard_format)
1253         dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1254     if(!ole_priv_data_clipboard_format)
1255         ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1256     if(!embed_source_clipboard_format)
1257         embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1258 }
1259
1260 /***********************************************************************
1261  * OLEClipbrd_Initialize()
1262  * Initializes the OLE clipboard.
1263  */
1264 void OLEClipbrd_Initialize(void)
1265 {
1266     register_clipboard_formats();
1267
1268     if ( !theOleClipboard )
1269     {
1270         ole_clipbrd* clipbrd;
1271         HGLOBAL h;
1272
1273         TRACE("()\n");
1274
1275         clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1276         if (!clipbrd) return;
1277
1278         clipbrd->latest_snapshot = NULL;
1279         clipbrd->window = NULL;
1280         clipbrd->src_data = NULL;
1281         clipbrd->cached_enum = NULL;
1282
1283         h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1284         if(!h)
1285         {
1286             HeapFree(GetProcessHeap(), 0, clipbrd);
1287             return;
1288         }
1289
1290         if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1291         {
1292             GlobalFree(h);
1293             HeapFree(GetProcessHeap(), 0, clipbrd);
1294             return;
1295         }
1296
1297         theOleClipboard = clipbrd;
1298     }
1299 }
1300
1301 /***********************************************************************
1302  * OLEClipbrd_UnInitialize()
1303  * Un-Initializes the OLE clipboard
1304  */
1305 void OLEClipbrd_UnInitialize(void)
1306 {
1307     ole_clipbrd *clipbrd = theOleClipboard;
1308
1309     TRACE("()\n");
1310
1311     if ( clipbrd )
1312     {
1313         static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1314         HINSTANCE hinst = GetModuleHandleW(ole32W);
1315
1316         if ( clipbrd->window )
1317         {
1318             DestroyWindow(clipbrd->window);
1319             UnregisterClassW( clipbrd_wndclass, hinst );
1320         }
1321
1322         IStream_Release(clipbrd->marshal_data);
1323         HeapFree(GetProcessHeap(), 0, clipbrd);
1324         theOleClipboard = NULL;
1325     }
1326 }
1327
1328 /*********************************************************************
1329  *          set_clipboard_formats
1330  *
1331  * Enumerate all formats supported by the source and make
1332  * those formats available using delayed rendering using SetClipboardData.
1333  * Cache the enumeration list and make that list visibile as the
1334  * 'Ole Private Data' format on the clipboard.
1335  *
1336  */
1337 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1338 {
1339     HRESULT hr;
1340     FORMATETC fmt;
1341     IEnumFORMATETC *enum_fmt;
1342     HGLOBAL priv_data_handle;
1343     DWORD target_offset;
1344     ole_priv_data *priv_data;
1345     DWORD count = 0, needed = sizeof(*priv_data), idx;
1346
1347     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1348     if(FAILED(hr)) return hr;
1349
1350     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1351     {
1352         count++;
1353         needed += sizeof(priv_data->entries[0]);
1354         if(fmt.ptd)
1355         {
1356             needed += fmt.ptd->tdSize;
1357             CoTaskMemFree(fmt.ptd);
1358         }
1359     }
1360
1361     /* Windows pads the list with two empty ole_priv_data_entries, one
1362      * after the entries array and one after the target device data.
1363      * Allocating with zero init to zero these pads. */
1364
1365     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1366     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1367     priv_data = GlobalLock(priv_data_handle);
1368
1369     priv_data->unk1 = 0;
1370     priv_data->size = needed;
1371     priv_data->unk2 = 1;
1372     priv_data->count = count;
1373     priv_data->unk3[0] = 0;
1374     priv_data->unk3[1] = 0;
1375
1376     IEnumFORMATETC_Reset(enum_fmt);
1377
1378     idx = 0;
1379     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1380
1381     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1382     {
1383         TRACE("%s\n", dump_fmtetc(&fmt));
1384
1385         priv_data->entries[idx].fmtetc = fmt;
1386         if(fmt.ptd)
1387         {
1388             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1389             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1390             target_offset += fmt.ptd->tdSize;
1391             CoTaskMemFree(fmt.ptd);
1392         }
1393
1394         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1395         priv_data->entries[idx].unk[0] = 0;
1396         priv_data->entries[idx].unk[1] = 0;
1397
1398         if (priv_data->entries[idx].first_use)
1399             SetClipboardData(fmt.cfFormat, NULL);
1400
1401         idx++;
1402     }
1403
1404     IEnumFORMATETC_Release(enum_fmt);
1405
1406     /* Cache the list and fixup any target device offsets to ptrs */
1407     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1408     memcpy(clipbrd->cached_enum, priv_data, needed);
1409     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1410         if(clipbrd->cached_enum->entries[idx].fmtetc.ptd)
1411             clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1412                 (DVTARGETDEVICE *)((char*)clipbrd->cached_enum + (DWORD)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1413
1414     GlobalUnlock(priv_data_handle);
1415     SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1416
1417     return S_OK;
1418 }
1419
1420 static HWND create_clipbrd_window(void);
1421
1422 /***********************************************************************
1423  *                 get_clipbrd_window
1424  */
1425 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1426 {
1427     if ( !clipbrd->window )
1428         clipbrd->window = create_clipbrd_window();
1429
1430     *wnd = clipbrd->window;
1431     return *wnd ? S_OK : E_FAIL;
1432 }
1433
1434
1435 /**********************************************************************
1436  *                  release_marshal_data
1437  *
1438  * Releases the data and sets the stream back to zero size.
1439  */
1440 static inline void release_marshal_data(IStream *stm)
1441 {
1442     LARGE_INTEGER pos;
1443     ULARGE_INTEGER size;
1444     pos.QuadPart = size.QuadPart = 0;
1445
1446     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1447     CoReleaseMarshalData(stm);
1448     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1449     IStream_SetSize(stm, size);
1450 }
1451
1452 /***********************************************************************
1453  *                   set_src_dataobject
1454  *
1455  * Clears and sets the clipboard's src IDataObject.
1456  *
1457  * To marshal the source dataobject we do something rather different from Windows.
1458  * We set a window prop which contains the marshalled data.
1459  * Windows set two props one of which is an IID, the other is an endpoint number.
1460  */
1461 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1462 {
1463     HRESULT hr;
1464     HWND wnd;
1465
1466     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1467
1468     if(clipbrd->src_data)
1469     {
1470         RemovePropW(wnd, wine_marshal_dataobject);
1471         release_marshal_data(clipbrd->marshal_data);
1472
1473         IDataObject_Release(clipbrd->src_data);
1474         clipbrd->src_data = NULL;
1475         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1476         clipbrd->cached_enum = NULL;
1477     }
1478
1479     if(data)
1480     {
1481         HGLOBAL h;
1482         IUnknown *unk;
1483
1484         IDataObject_AddRef(data);
1485         clipbrd->src_data = data;
1486
1487         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1488         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1489                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1490         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1491         if(FAILED(hr)) return hr;
1492         GetHGlobalFromStream(clipbrd->marshal_data, &h);
1493         SetPropW(wnd, wine_marshal_dataobject, h);
1494         hr = set_clipboard_formats(clipbrd, data);
1495     }
1496     return hr;
1497 }
1498
1499 /***********************************************************************
1500  *                   clipbrd_wndproc
1501  */
1502 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1503 {
1504     ole_clipbrd *clipbrd;
1505
1506     get_ole_clipbrd(&clipbrd);
1507
1508     switch (message)
1509     {
1510     case WM_RENDERFORMAT:
1511     {
1512         UINT cf = wparam;
1513         ole_priv_data_entry *entry;
1514
1515         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1516         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1517
1518         if(entry)
1519             render_format(clipbrd->src_data, &entry->fmtetc);
1520
1521         break;
1522     }
1523
1524     case WM_RENDERALLFORMATS:
1525     {
1526         DWORD i;
1527         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1528
1529         TRACE("(): WM_RENDERALLFORMATS\n");
1530
1531         for(i = 0; i < clipbrd->cached_enum->count; i++)
1532         {
1533             if(entries[i].first_use)
1534                 render_format(clipbrd->src_data, &entries[i].fmtetc);
1535         }
1536         break;
1537     }
1538
1539     case WM_DESTROYCLIPBOARD:
1540     {
1541         TRACE("(): WM_DESTROYCLIPBOARD\n");
1542
1543         set_src_dataobject(clipbrd, NULL);
1544         break;
1545     }
1546
1547     default:
1548         return DefWindowProcW(hwnd, message, wparam, lparam);
1549     }
1550
1551     return 0;
1552 }
1553
1554
1555 /***********************************************************************
1556  *                 create_clipbrd_window
1557  */
1558 static HWND create_clipbrd_window(void)
1559 {
1560     WNDCLASSEXW class;
1561     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1562     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1563     HINSTANCE hinst = GetModuleHandleW(ole32W);
1564
1565     class.cbSize         = sizeof(class);
1566     class.style          = 0;
1567     class.lpfnWndProc    = clipbrd_wndproc;
1568     class.cbClsExtra     = 0;
1569     class.cbWndExtra     = 0;
1570     class.hInstance      = hinst;
1571     class.hIcon          = 0;
1572     class.hCursor        = 0;
1573     class.hbrBackground  = 0;
1574     class.lpszMenuName   = NULL;
1575     class.lpszClassName  = clipbrd_wndclass;
1576     class.hIconSm        = NULL;
1577
1578     RegisterClassExW(&class);
1579
1580     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1581                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1582                          NULL, NULL, hinst, 0);
1583 }
1584
1585 /*********************************************************************
1586  *          set_dataobject_format
1587  *
1588  * Windows creates a 'DataObject' clipboard format that contains the
1589  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1590  */
1591 static HRESULT set_dataobject_format(HWND hwnd)
1592 {
1593     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1594     HWND *data;
1595
1596     if(!h) return E_OUTOFMEMORY;
1597
1598     data = GlobalLock(h);
1599     *data = hwnd;
1600     GlobalUnlock(h);
1601
1602     if(!SetClipboardData(dataobject_clipboard_format, h))
1603     {
1604         GlobalFree(h);
1605         return CLIPBRD_E_CANT_SET;
1606     }
1607
1608     return S_OK;
1609 }
1610
1611 /*---------------------------------------------------------------------*
1612  *           Win32 OLE clipboard API
1613  *---------------------------------------------------------------------*/
1614
1615 /***********************************************************************
1616  *           OleSetClipboard     [OLE32.@]
1617  *  Places a pointer to the specified data object onto the clipboard,
1618  *  making the data object accessible to the OleGetClipboard function.
1619  *
1620  * RETURNS
1621  *
1622  *    S_OK                  IDataObject pointer placed on the clipboard
1623  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
1624  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
1625  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
1626  *    CLIPBRD_E_CANT_SET    SetClipboard failed
1627  */
1628
1629 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1630 {
1631   HRESULT hr;
1632   ole_clipbrd *clipbrd;
1633   HWND wnd;
1634
1635   TRACE("(%p)\n", data);
1636
1637   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1638
1639   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1640
1641   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1642
1643   if ( !EmptyClipboard() )
1644   {
1645     hr = CLIPBRD_E_CANT_EMPTY;
1646     goto end;
1647   }
1648
1649   hr = set_src_dataobject(clipbrd, data);
1650   if(FAILED(hr)) goto end;
1651
1652   hr = set_dataobject_format(wnd);
1653
1654 end:
1655
1656   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1657
1658   if ( FAILED(hr) )
1659   {
1660     set_src_dataobject(clipbrd, NULL);
1661   }
1662
1663   return hr;
1664 }
1665
1666
1667 /***********************************************************************
1668  * OleGetClipboard [OLE32.@]
1669  * Returns a pointer to our internal IDataObject which represents the conceptual
1670  * state of the Windows clipboard. If the current clipboard already contains
1671  * an IDataObject, our internal IDataObject will delegate to this object.
1672  */
1673 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1674 {
1675     HRESULT hr;
1676     ole_clipbrd *clipbrd;
1677     DWORD seq_no;
1678
1679     TRACE("(%p)\n", obj);
1680
1681     if(!obj) return E_INVALIDARG;
1682
1683     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1684
1685     seq_no = GetClipboardSequenceNumber();
1686     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1687         clipbrd->latest_snapshot = NULL;
1688
1689     if(!clipbrd->latest_snapshot)
1690     {
1691         clipbrd->latest_snapshot = snapshot_construct(seq_no);
1692         if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1693     }
1694
1695     *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1696     IDataObject_AddRef(*obj);
1697
1698     return S_OK;
1699 }
1700
1701 /******************************************************************************
1702  *              OleFlushClipboard        [OLE32.@]
1703  *  Renders the data from the source IDataObject into the windows clipboard
1704  *
1705  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1706  *  by copying the storage into global memory. Subsequently the default
1707  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1708  *  back to TYMED_IStorage.
1709  */
1710 HRESULT WINAPI OleFlushClipboard(void)
1711 {
1712   HRESULT hr;
1713   ole_clipbrd *clipbrd;
1714   HWND wnd;
1715
1716   TRACE("()\n");
1717
1718   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1719
1720   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1721
1722   /*
1723    * Already flushed or no source DataObject? Nothing to do.
1724    */
1725   if (!clipbrd->src_data) return S_OK;
1726
1727   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1728
1729   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1730
1731   hr = set_dataobject_format(NULL);
1732
1733   set_src_dataobject(clipbrd, NULL);
1734
1735   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1736
1737   return hr;
1738 }
1739
1740
1741 /***********************************************************************
1742  *           OleIsCurrentClipboard [OLE32.@]
1743  */
1744 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1745 {
1746     HRESULT hr;
1747     ole_clipbrd *clipbrd;
1748     TRACE("()\n");
1749
1750     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1751
1752     if (data == NULL) return S_FALSE;
1753
1754     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
1755 }