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