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