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