xref: /reactos/dll/win32/ole32/clipboard.c (revision 0f5d91b7)
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 
69 #include "windef.h"
70 #include "winbase.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "winerror.h"
74 #include "winnls.h"
75 #include "ole2.h"
76 #include "wine/debug.h"
77 #include "olestd.h"
78 
79 #include "storage32.h"
80 
81 #include "compobj_private.h"
82 
83 WINE_DEFAULT_DEBUG_CHANNEL(ole);
84 
85 /* Structure of 'Ole Private Data' clipboard format */
86 typedef struct
87 {
88     FORMATETC fmtetc;
89     DWORD first_use;  /* Has this cf been added to the list already */
90     DWORD unk[2];
91 } ole_priv_data_entry;
92 
93 typedef struct
94 {
95     DWORD unk1;
96     DWORD size; /* in bytes of the entire structure */
97     DWORD unk2;
98     DWORD count; /* no. of format entries */
99     DWORD unk3[2];
100     ole_priv_data_entry entries[1]; /* array of size count */
101     /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
102 } ole_priv_data;
103 
104 /*****************************************************************************
105  *           td_offs_to_ptr
106  *
107  * Returns a ptr to a target device at a given offset from the
108  * start of the ole_priv_data.
109  *
110  * Used when unpacking ole private data from the clipboard.
111  */
td_offs_to_ptr(ole_priv_data * data,DWORD_PTR off)112 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
113 {
114     if(off == 0) return NULL;
115     return (DVTARGETDEVICE*)((char*)data + off);
116 }
117 
118 /*****************************************************************************
119  *           td_get_offs
120  *
121  * Get the offset from the start of the ole_priv_data of the idx'th
122  * target device.
123  *
124  * Used when packing ole private data to the clipboard.
125  */
td_get_offs(ole_priv_data * data,DWORD idx)126 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
127 {
128     if(data->entries[idx].fmtetc.ptd == NULL) return 0;
129     return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
130 }
131 
132 /****************************************************************************
133  * Consumer snapshot.  Represents the state of the ole clipboard
134  * returned by OleGetClipboard().
135  */
136 typedef struct snapshot
137 {
138     IDataObject IDataObject_iface;
139     LONG ref;
140 
141     DWORD seq_no;                   /* Clipboard sequence number corresponding to this snapshot */
142 
143     IDataObject *data;              /* If we unmarshal a remote data object we hold a ref here */
144 } snapshot;
145 
146 /****************************************************************************
147  * ole_clipbrd
148  */
149 typedef struct ole_clipbrd
150 {
151     snapshot *latest_snapshot;       /* Latest consumer snapshot */
152 
153     HWND window;                     /* Hidden clipboard window */
154     IDataObject *src_data;           /* Source object passed to OleSetClipboard */
155     ole_priv_data *cached_enum;      /* Cached result from the enumeration of src data object */
156     IStream *marshal_data;           /* Stream onto which to marshal src_data */
157 } ole_clipbrd;
158 
impl_from_IDataObject(IDataObject * iface)159 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
160 {
161     return CONTAINING_RECORD(iface, snapshot, IDataObject_iface);
162 }
163 
164 typedef struct PresentationDataHeader
165 {
166   BYTE unknown1[28];
167   DWORD dwObjectExtentX;
168   DWORD dwObjectExtentY;
169   DWORD dwSize;
170 } PresentationDataHeader;
171 
172 /*
173  * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
174  */
175 static ole_clipbrd* theOleClipboard;
176 
177 static CRITICAL_SECTION latest_snapshot_cs;
178 static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug =
179 {
180         0, 0, &latest_snapshot_cs,
181         { &latest_snapshot_cs_debug.ProcessLocksList, &latest_snapshot_cs_debug.ProcessLocksList },
182         0, 0, { (DWORD_PTR)(__FILE__ ": clipboard last snapshot") }
183 };
184 static CRITICAL_SECTION latest_snapshot_cs = { &latest_snapshot_cs_debug, -1, 0, 0, 0, 0 };
185 
get_ole_clipbrd(ole_clipbrd ** clipbrd)186 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
187 {
188     struct oletls *info = COM_CurrentInfo();
189     *clipbrd = NULL;
190 
191     if(!info->ole_inits)
192         return CO_E_NOTINITIALIZED;
193     *clipbrd = theOleClipboard;
194 
195     return S_OK;
196 }
197 
198 /*
199  * Name of our registered OLE clipboard window class
200  */
201 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
202 
203 UINT ownerlink_clipboard_format = 0;
204 UINT filename_clipboard_format = 0;
205 UINT filenameW_clipboard_format = 0;
206 UINT dataobject_clipboard_format = 0;
207 UINT embedded_object_clipboard_format = 0;
208 UINT embed_source_clipboard_format = 0;
209 UINT custom_link_source_clipboard_format = 0;
210 UINT link_source_clipboard_format = 0;
211 UINT object_descriptor_clipboard_format = 0;
212 UINT link_source_descriptor_clipboard_format = 0;
213 UINT ole_private_data_clipboard_format = 0;
214 
215 static UINT wine_marshal_clipboard_format;
216 
dump_fmtetc(FORMATETC * fmt)217 static inline const char *dump_fmtetc(FORMATETC *fmt)
218 {
219     if (!fmt) return "(null)";
220     return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
221                             fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
222 }
223 
224 /*---------------------------------------------------------------------*
225  *  Implementation of the internal IEnumFORMATETC interface returned by
226  *  the OLE clipboard's IDataObject.
227  *---------------------------------------------------------------------*/
228 
229 typedef struct enum_fmtetc
230 {
231     IEnumFORMATETC IEnumFORMATETC_iface;
232     LONG ref;
233 
234     UINT pos;    /* current enumerator position */
235     ole_priv_data *data;
236 } enum_fmtetc;
237 
impl_from_IEnumFORMATETC(IEnumFORMATETC * iface)238 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
239 {
240     return CONTAINING_RECORD(iface, enum_fmtetc, IEnumFORMATETC_iface);
241 }
242 
243 /************************************************************************
244  * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
245  *
246  * See Windows documentation for more details on IUnknown methods.
247  */
OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface,REFIID riid,LPVOID * ppvObj)248 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
249   (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
250 {
251   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
252 
253   TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
254 
255   *ppvObj = NULL;
256 
257   if(IsEqualIID(riid, &IID_IUnknown) ||
258      IsEqualIID(riid, &IID_IEnumFORMATETC))
259   {
260     *ppvObj = iface;
261   }
262 
263   if(*ppvObj)
264   {
265     IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
266     TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
267     return S_OK;
268   }
269 
270   TRACE("-- Interface: E_NOINTERFACE\n");
271   return E_NOINTERFACE;
272 }
273 
274 /************************************************************************
275  * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
276  *
277  */
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)278 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
279 {
280   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
281   TRACE("(%p)->(count=%u)\n",This, This->ref);
282 
283   return InterlockedIncrement(&This->ref);
284 }
285 
286 /************************************************************************
287  * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
288  *
289  * See Windows documentation for more details on IUnknown methods.
290  */
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)291 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
292 {
293   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
294   ULONG ref;
295 
296   TRACE("(%p)->(count=%u)\n",This, This->ref);
297 
298   ref = InterlockedDecrement(&This->ref);
299   if (!ref)
300   {
301     TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
302     HeapFree(GetProcessHeap(), 0, This->data);
303     HeapFree(GetProcessHeap(), 0, This);
304   }
305   return ref;
306 }
307 
308 /************************************************************************
309  * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
310  *
311  * Standard enumerator members for IEnumFORMATETC
312  */
OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface,ULONG celt,FORMATETC * rgelt,ULONG * pceltFethed)313 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
314   (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
315 {
316   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
317   UINT cfetch, i;
318   HRESULT hres = S_FALSE;
319 
320   TRACE("(%p)->(pos=%u)\n", This, This->pos);
321 
322   if (This->pos < This->data->count)
323   {
324     cfetch = This->data->count - This->pos;
325     if (cfetch >= celt)
326     {
327       cfetch = celt;
328       hres = S_OK;
329     }
330 
331     for(i = 0; i < cfetch; i++)
332     {
333       hres = copy_formatetc(rgelt + i, &This->data->entries[This->pos++].fmtetc);
334       if(FAILED(hres)) return hres;
335     }
336   }
337   else
338   {
339     cfetch = 0;
340   }
341 
342   if (pceltFethed)
343   {
344     *pceltFethed = cfetch;
345   }
346 
347   return hres;
348 }
349 
350 /************************************************************************
351  * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
352  *
353  * Standard enumerator members for IEnumFORMATETC
354  */
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface,ULONG celt)355 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
356 {
357   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
358   TRACE("(%p)->(num=%u)\n", This, celt);
359 
360   This->pos += celt;
361   if (This->pos > This->data->count)
362   {
363     This->pos = This->data->count;
364     return S_FALSE;
365   }
366   return S_OK;
367 }
368 
369 /************************************************************************
370  * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
371  *
372  * Standard enumerator members for IEnumFORMATETC
373  */
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)374 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
375 {
376   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
377   TRACE("(%p)->()\n", This);
378 
379   This->pos = 0;
380   return S_OK;
381 }
382 
383 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
384 
385 /************************************************************************
386  * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
387  *
388  * Standard enumerator members for IEnumFORMATETC
389  */
OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface,LPENUMFORMATETC * obj)390 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
391   (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
392 {
393   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
394   ole_priv_data *new_data;
395   DWORD i;
396 
397   TRACE("(%p)->(%p)\n", This, obj);
398 
399   if ( !obj ) return E_INVALIDARG;
400   *obj = NULL;
401 
402   new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
403   if(!new_data) return E_OUTOFMEMORY;
404   memcpy(new_data, This->data, This->data->size);
405 
406   /* Fixup any target device ptrs */
407   for(i = 0; i < This->data->count; i++)
408       new_data->entries[i].fmtetc.ptd =
409           td_offs_to_ptr(new_data, td_get_offs(This->data, i));
410 
411   return enum_fmtetc_construct(new_data, This->pos, obj);
412 }
413 
414 static const IEnumFORMATETCVtbl efvt =
415 {
416   OLEClipbrd_IEnumFORMATETC_QueryInterface,
417   OLEClipbrd_IEnumFORMATETC_AddRef,
418   OLEClipbrd_IEnumFORMATETC_Release,
419   OLEClipbrd_IEnumFORMATETC_Next,
420   OLEClipbrd_IEnumFORMATETC_Skip,
421   OLEClipbrd_IEnumFORMATETC_Reset,
422   OLEClipbrd_IEnumFORMATETC_Clone
423 };
424 
425 /************************************************************************
426  * enum_fmtetc_construct
427  *
428  * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
429  */
enum_fmtetc_construct(ole_priv_data * data,UINT pos,IEnumFORMATETC ** obj)430 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
431 {
432   enum_fmtetc* ef;
433 
434   *obj = NULL;
435   ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
436   if (!ef) return E_OUTOFMEMORY;
437 
438   ef->ref = 1;
439   ef->IEnumFORMATETC_iface.lpVtbl = &efvt;
440   ef->data = data;
441   ef->pos = pos;
442 
443   TRACE("(%p)->()\n", ef);
444   *obj = &ef->IEnumFORMATETC_iface;
445   return S_OK;
446 }
447 
448 /***********************************************************************
449  *                    dup_global_mem
450  *
451  * Helper method to duplicate an HGLOBAL chunk of memory
452  */
dup_global_mem(HGLOBAL src,DWORD flags,HGLOBAL * dst)453 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
454 {
455     void *src_ptr, *dst_ptr;
456     DWORD size;
457 
458     *dst = NULL;
459     if ( !src ) return S_FALSE;
460 
461     size = GlobalSize(src);
462 
463     *dst = GlobalAlloc( flags, size );
464     if ( !*dst ) return E_OUTOFMEMORY;
465 
466     src_ptr = GlobalLock(src);
467     dst_ptr = GlobalLock(*dst);
468 
469     memcpy(dst_ptr, src_ptr, size);
470 
471     GlobalUnlock(*dst);
472     GlobalUnlock(src);
473 
474     return S_OK;
475 }
476 
477 /***********************************************************************
478  *                    dup_metafilepict
479  *
480  * Helper function to duplicate a handle to a METAFILEPICT, and the
481  * contained HMETAFILE.
482  */
dup_metafilepict(HGLOBAL src,HGLOBAL * pdest)483 static HRESULT dup_metafilepict(HGLOBAL src, HGLOBAL *pdest)
484 {
485     HRESULT hr;
486     HGLOBAL dest;
487     METAFILEPICT *dest_ptr;
488 
489     *pdest = NULL;
490 
491     /* Copy the METAFILEPICT structure. */
492     hr = dup_global_mem(src, GMEM_DDESHARE|GMEM_MOVEABLE, &dest);
493     if (FAILED(hr)) return hr;
494 
495     dest_ptr = GlobalLock(dest);
496     if (!dest_ptr) return E_FAIL;
497 
498     /* Give the new METAFILEPICT a separate HMETAFILE. */
499     dest_ptr->hMF = CopyMetaFileW(dest_ptr->hMF, NULL);
500     if (dest_ptr->hMF)
501     {
502        GlobalUnlock(dest);
503        *pdest = dest;
504        return S_OK;
505     }
506     else
507     {
508        GlobalUnlock(dest);
509        GlobalFree(dest);
510        return E_FAIL;
511     }
512 }
513 
514 /***********************************************************************
515  *                    free_metafilepict
516  *
517  * Helper function to GlobalFree a handle to a METAFILEPICT, and also
518  * free the contained HMETAFILE.
519  */
free_metafilepict(HGLOBAL src)520 static void free_metafilepict(HGLOBAL src)
521 {
522     METAFILEPICT *src_ptr;
523 
524     src_ptr = GlobalLock(src);
525     if (src_ptr)
526     {
527         DeleteMetaFile(src_ptr->hMF);
528         GlobalUnlock(src);
529     }
530     GlobalFree(src);
531 }
532 
533 /***********************************************************************
534  *                    dup_bitmap
535  *
536  * Helper function to duplicate an HBITMAP.
537  */
dup_bitmap(HBITMAP src,HBITMAP * pdest)538 static HRESULT dup_bitmap(HBITMAP src, HBITMAP *pdest)
539 {
540     HDC src_dc;
541     HGDIOBJ orig_src_bitmap;
542     BITMAP bm;
543     HBITMAP dest;
544 
545     src_dc = CreateCompatibleDC(NULL);
546     orig_src_bitmap = SelectObject(src_dc, src);
547     GetObjectW(src, sizeof bm, &bm);
548     dest = CreateCompatibleBitmap(src_dc, bm.bmWidth, bm.bmHeight);
549     if (dest)
550     {
551         HDC dest_dc = CreateCompatibleDC(NULL);
552         HGDIOBJ orig_dest_bitmap = SelectObject(dest_dc, dest);
553         BitBlt(dest_dc, 0, 0, bm.bmWidth, bm.bmHeight, src_dc, 0, 0, SRCCOPY);
554         SelectObject(dest_dc, orig_dest_bitmap);
555         DeleteDC(dest_dc);
556     }
557     SelectObject(src_dc, orig_src_bitmap);
558     DeleteDC(src_dc);
559     *pdest = dest;
560     return dest ? S_OK : E_FAIL;
561 }
562 
563 /************************************************************
564  *              render_embed_source_hack
565  *
566  * This is clearly a hack and has no place in the clipboard code.
567  *
568  */
render_embed_source_hack(IDataObject * data,LPFORMATETC fmt)569 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
570 {
571     STGMEDIUM std;
572     HGLOBAL hStorage = 0;
573     HRESULT hr = S_OK;
574     ILockBytes *ptrILockBytes;
575 
576     memset(&std, 0, sizeof(STGMEDIUM));
577     std.tymed = fmt->tymed = TYMED_ISTORAGE;
578 
579     hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
580     if (hStorage == NULL) return E_OUTOFMEMORY;
581     hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
582     if (FAILED(hr))
583     {
584         GlobalFree(hStorage);
585         return hr;
586     }
587 
588     hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
589     ILockBytes_Release(ptrILockBytes);
590 
591     if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
592     {
593         WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
594         GlobalFree(hStorage);
595         return hr;
596     }
597 
598     if (1) /* check whether the presentation data is already -not- present */
599     {
600         FORMATETC fmt2;
601         STGMEDIUM std2;
602         METAFILEPICT *mfp = 0;
603 
604         fmt2.cfFormat = CF_METAFILEPICT;
605         fmt2.ptd = 0;
606         fmt2.dwAspect = DVASPECT_CONTENT;
607         fmt2.lindex = -1;
608         fmt2.tymed = TYMED_MFPICT;
609 
610         memset(&std2, 0, sizeof(STGMEDIUM));
611         std2.tymed = TYMED_MFPICT;
612 
613         /* Get the metafile picture out of it */
614 
615         if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
616         {
617             mfp = GlobalLock(std2.u.hGlobal);
618         }
619 
620         if (mfp)
621         {
622             OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
623             IStream *pStream = 0;
624             void *mfBits;
625             PresentationDataHeader pdh;
626             INT nSize;
627             CLSID clsID;
628             LPOLESTR strProgID;
629             CHAR strOleTypeName[51];
630             BYTE OlePresStreamHeader [] =
631             {
632                 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
633                 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
634                 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
635                 0x00, 0x00, 0x00, 0x00
636             };
637 
638             nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
639 
640             memset(&pdh, 0, sizeof(PresentationDataHeader));
641             memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
642 
643             pdh.dwObjectExtentX = mfp->xExt;
644             pdh.dwObjectExtentY = mfp->yExt;
645             pdh.dwSize = nSize;
646 
647             hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
648 
649             hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
650 
651             mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
652             nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
653 
654             hr = IStream_Write(pStream, mfBits, nSize, NULL);
655 
656             IStream_Release(pStream);
657 
658             HeapFree(GetProcessHeap(), 0, mfBits);
659 
660             GlobalUnlock(std2.u.hGlobal);
661             ReleaseStgMedium(&std2);
662 
663             ReadClassStg(std.u.pstg, &clsID);
664             ProgIDFromCLSID(&clsID, &strProgID);
665 
666             WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
667             STORAGE_CreateOleStream(std.u.pstg, 0);
668             OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
669             CoTaskMemFree(strProgID);
670         }
671     }
672 
673     if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
674     {
675         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
676         GlobalFree(hStorage);
677         hr = CLIPBRD_E_CANT_SET;
678     }
679 
680     ReleaseStgMedium(&std);
681     return hr;
682 }
683 
684 /************************************************************************
685  *           find_format_in_list
686  *
687  * Returns the first entry that matches the provided clipboard format.
688  */
find_format_in_list(ole_priv_data_entry * entries,DWORD num,UINT cf)689 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
690 {
691     DWORD i;
692     for(i = 0; i < num; i++)
693         if(entries[i].fmtetc.cfFormat == cf)
694             return &entries[i];
695 
696     return NULL;
697 }
698 
699 /***************************************************************************
700  *         get_data_from_storage
701  *
702  * Returns storage data in an HGLOBAL.
703  */
get_data_from_storage(IDataObject * data,FORMATETC * fmt,HGLOBAL * mem)704 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
705 {
706     HGLOBAL h;
707     IStorage *stg;
708     HRESULT hr;
709     FORMATETC stg_fmt;
710     STGMEDIUM med;
711     ILockBytes *lbs;
712 
713     *mem = NULL;
714 
715     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
716     if(!h) return E_OUTOFMEMORY;
717 
718     hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
719     if(SUCCEEDED(hr))
720     {
721         hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
722         ILockBytes_Release(lbs);
723     }
724     if(FAILED(hr))
725     {
726         GlobalFree(h);
727         return hr;
728     }
729 
730     stg_fmt = *fmt;
731     med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
732     med.u.pstg = stg;
733     med.pUnkForRelease = NULL;
734 
735     hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
736     if(FAILED(hr))
737     {
738         memset(&med, 0, sizeof(med));
739         hr = IDataObject_GetData(data, &stg_fmt, &med);
740         if(FAILED(hr)) goto end;
741 
742         hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
743         ReleaseStgMedium(&med);
744         if(FAILED(hr)) goto end;
745     }
746     *mem = h;
747 
748 end:
749     IStorage_Release(stg);
750     if(FAILED(hr)) GlobalFree(h);
751     return hr;
752 }
753 
754 /***************************************************************************
755  *         get_data_from_stream
756  *
757  * Returns stream data in an HGLOBAL.
758  */
get_data_from_stream(IDataObject * data,FORMATETC * fmt,HGLOBAL * mem)759 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
760 {
761     HGLOBAL h;
762     IStream *stm = NULL;
763     HRESULT hr;
764     FORMATETC stm_fmt;
765     STGMEDIUM med;
766 
767     *mem = NULL;
768 
769     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
770     if(!h) return E_OUTOFMEMORY;
771 
772     hr = CreateStreamOnHGlobal(h, FALSE, &stm);
773     if(FAILED(hr)) goto error;
774 
775     stm_fmt = *fmt;
776     med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
777     med.u.pstm = stm;
778     med.pUnkForRelease = NULL;
779 
780     hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
781     if(FAILED(hr))
782     {
783         LARGE_INTEGER offs;
784         ULARGE_INTEGER pos;
785 
786         memset(&med, 0, sizeof(med));
787         hr = IDataObject_GetData(data, &stm_fmt, &med);
788         if(FAILED(hr)) goto error;
789 
790         offs.QuadPart = 0;
791         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
792         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
793         hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
794         ReleaseStgMedium(&med);
795         if(FAILED(hr)) goto error;
796     }
797     *mem = h;
798     IStream_Release(stm);
799     return S_OK;
800 
801 error:
802     if(stm) IStream_Release(stm);
803     GlobalFree(h);
804     return hr;
805 }
806 
807 /***************************************************************************
808  *         get_data_from_global
809  *
810  * Returns global data in an HGLOBAL.
811  */
get_data_from_global(IDataObject * data,FORMATETC * fmt,HGLOBAL * mem)812 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
813 {
814     HGLOBAL h;
815     HRESULT hr;
816     FORMATETC mem_fmt;
817     STGMEDIUM med;
818 
819     *mem = NULL;
820 
821     mem_fmt = *fmt;
822     mem_fmt.tymed = TYMED_HGLOBAL;
823     memset(&med, 0, sizeof(med));
824 
825     hr = IDataObject_GetData(data, &mem_fmt, &med);
826     if(FAILED(hr)) return hr;
827 
828     hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
829 
830     if(SUCCEEDED(hr)) *mem = h;
831 
832     ReleaseStgMedium(&med);
833 
834     return hr;
835 }
836 
837 /***************************************************************************
838  *         get_data_from_enhmetafile
839  */
get_data_from_enhmetafile(IDataObject * data,FORMATETC * fmt,HGLOBAL * mem)840 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
841 {
842     HENHMETAFILE copy;
843     HRESULT hr;
844     FORMATETC mem_fmt;
845     STGMEDIUM med;
846 
847     *mem = NULL;
848 
849     mem_fmt = *fmt;
850     mem_fmt.tymed = TYMED_ENHMF;
851     memset(&med, 0, sizeof(med));
852 
853     hr = IDataObject_GetData(data, &mem_fmt, &med);
854     if(FAILED(hr)) return hr;
855 
856     copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
857     if(copy) *mem = (HGLOBAL)copy;
858     else hr = E_FAIL;
859 
860     ReleaseStgMedium(&med);
861 
862     return hr;
863 }
864 
865 /***************************************************************************
866  *         get_data_from_metafilepict
867  */
get_data_from_metafilepict(IDataObject * data,FORMATETC * fmt,HGLOBAL * mem)868 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
869 {
870     HGLOBAL copy;
871     HRESULT hr;
872     FORMATETC mem_fmt;
873     STGMEDIUM med;
874 
875     *mem = NULL;
876 
877     mem_fmt = *fmt;
878     mem_fmt.tymed = TYMED_MFPICT;
879     memset(&med, 0, sizeof(med));
880 
881     hr = IDataObject_GetData(data, &mem_fmt, &med);
882     if(FAILED(hr)) return hr;
883 
884     hr = dup_metafilepict(med.u.hMetaFilePict, &copy);
885 
886     if(SUCCEEDED(hr)) *mem = copy;
887 
888     ReleaseStgMedium(&med);
889 
890     return hr;
891 }
892 
893 /***************************************************************************
894  *         get_data_from_bitmap
895  *
896  * Returns bitmap in an HBITMAP.
897  */
get_data_from_bitmap(IDataObject * data,FORMATETC * fmt,HBITMAP * hbm)898 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm)
899 {
900     HBITMAP copy;
901     HRESULT hr;
902     FORMATETC mem_fmt;
903     STGMEDIUM med;
904 
905     *hbm = NULL;
906 
907     mem_fmt = *fmt;
908     mem_fmt.tymed = TYMED_GDI;
909     memset(&med, 0, sizeof(med));
910 
911     hr = IDataObject_GetData(data, &mem_fmt, &med);
912     if(FAILED(hr)) return hr;
913 
914     hr = dup_bitmap(med.u.hBitmap, &copy);
915 
916     if(SUCCEEDED(hr)) *hbm = copy;
917 
918     ReleaseStgMedium(&med);
919 
920     return hr;
921 }
922 
923 /***********************************************************************
924  *                render_format
925  *
926  * Render the clipboard data. Note that this call will delegate to the
927  * source data object.
928  */
render_format(IDataObject * data,LPFORMATETC fmt)929 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
930 {
931     HANDLE clip_data = NULL;  /* HGLOBAL unless otherwise specified */
932     HRESULT hr;
933 
934     /* Embed source hack */
935     if(fmt->cfFormat == embed_source_clipboard_format)
936     {
937         return render_embed_source_hack(data, fmt);
938     }
939 
940     if(fmt->tymed & TYMED_ISTORAGE)
941     {
942         hr = get_data_from_storage(data, fmt, &clip_data);
943     }
944     else if(fmt->tymed & TYMED_ISTREAM)
945     {
946         hr = get_data_from_stream(data, fmt, &clip_data);
947     }
948     else if(fmt->tymed & TYMED_HGLOBAL)
949     {
950         hr = get_data_from_global(data, fmt, &clip_data);
951     }
952     else if(fmt->tymed & TYMED_ENHMF)
953     {
954         hr = get_data_from_enhmetafile(data, fmt, &clip_data);
955     }
956     else if(fmt->tymed & TYMED_MFPICT)
957     {
958         /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
959         hr = get_data_from_metafilepict(data, fmt, &clip_data);
960     }
961     else if(fmt->tymed & TYMED_GDI)
962     {
963         /* Returns HBITMAP not HGLOBAL */
964         hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data);
965     }
966     else
967     {
968         FIXME("Unhandled tymed %x\n", fmt->tymed);
969         hr = DV_E_FORMATETC;
970     }
971 
972     if(SUCCEEDED(hr))
973     {
974         if ( !SetClipboardData(fmt->cfFormat, clip_data) )
975         {
976             WARN("() : Failed to set rendered clipboard data into clipboard!\n");
977             if(fmt->tymed & TYMED_MFPICT)
978                 free_metafilepict(clip_data);
979             else if(fmt->tymed & TYMED_GDI)
980                 DeleteObject(clip_data);
981             else
982                 GlobalFree(clip_data);
983             hr = CLIPBRD_E_CANT_SET;
984         }
985     }
986 
987     return hr;
988 }
989 
990 /*---------------------------------------------------------------------*
991  *  Implementation of the internal IDataObject interface exposed by
992  *  the OLE clipboard.
993  *---------------------------------------------------------------------*/
994 
995 
996 /************************************************************************
997  *           snapshot_QueryInterface
998  */
snapshot_QueryInterface(IDataObject * iface,REFIID riid,void ** ppvObject)999 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
1000                                               REFIID riid, void **ppvObject)
1001 {
1002   snapshot *This = impl_from_IDataObject(iface);
1003   TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1004 
1005   if ( (This==0) || (ppvObject==0) )
1006     return E_INVALIDARG;
1007 
1008   *ppvObject = 0;
1009 
1010   if (IsEqualIID(&IID_IUnknown, riid) ||
1011       IsEqualIID(&IID_IDataObject, riid))
1012   {
1013     *ppvObject = iface;
1014   }
1015   else
1016   {
1017     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1018     return E_NOINTERFACE;
1019   }
1020 
1021   IUnknown_AddRef((IUnknown*)*ppvObject);
1022 
1023   return S_OK;
1024 }
1025 
1026 /************************************************************************
1027  *              snapshot_AddRef
1028  */
snapshot_AddRef(IDataObject * iface)1029 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
1030 {
1031     snapshot *This = impl_from_IDataObject(iface);
1032 
1033     TRACE("(%p)->(count=%u)\n", This, This->ref);
1034 
1035     return InterlockedIncrement(&This->ref);
1036 }
1037 
1038 /************************************************************************
1039  *      snapshot_Release
1040  */
snapshot_Release(IDataObject * iface)1041 static ULONG WINAPI snapshot_Release(IDataObject *iface)
1042 {
1043     snapshot *This = impl_from_IDataObject(iface);
1044     ULONG ref;
1045 
1046     TRACE("(%p)->(count=%u)\n", This, This->ref);
1047 
1048     ref = InterlockedDecrement(&This->ref);
1049 
1050     if (ref == 0)
1051     {
1052         EnterCriticalSection(&latest_snapshot_cs);
1053         if (This->ref)
1054         {
1055             LeaveCriticalSection(&latest_snapshot_cs);
1056             return ref;
1057         }
1058         if (theOleClipboard->latest_snapshot == This)
1059             theOleClipboard->latest_snapshot = NULL;
1060         LeaveCriticalSection(&latest_snapshot_cs);
1061 
1062         if(This->data) IDataObject_Release(This->data);
1063         HeapFree(GetProcessHeap(), 0, This);
1064     }
1065 
1066     return ref;
1067 }
1068 
1069 /************************************************************
1070  *              get_current_ole_clip_window
1071  *
1072  * Return the window that owns the ole clipboard.
1073  *
1074  * If the clipboard is flushed or not owned by ole this will
1075  * return NULL.
1076  */
get_current_ole_clip_window(void)1077 static HWND get_current_ole_clip_window(void)
1078 {
1079     HGLOBAL h;
1080     HWND *ptr, wnd;
1081 
1082     h = GetClipboardData(dataobject_clipboard_format);
1083     if(!h) return NULL;
1084     ptr = GlobalLock(h);
1085     if(!ptr) return NULL;
1086     wnd = *ptr;
1087     GlobalUnlock(h);
1088     return wnd;
1089 }
1090 
1091 /************************************************************
1092  *              get_current_dataobject
1093  *
1094  * Return an unmarshalled IDataObject if there is a current
1095  * (ie non-flushed) object on the ole clipboard.
1096  */
get_current_dataobject(IDataObject ** data)1097 static HRESULT get_current_dataobject(IDataObject **data)
1098 {
1099     HRESULT hr = S_FALSE;
1100     HWND wnd = get_current_ole_clip_window();
1101     HGLOBAL h;
1102     void *ptr;
1103     IStream *stm;
1104     LARGE_INTEGER pos;
1105 
1106     *data = NULL;
1107     if(!wnd) return S_FALSE;
1108 
1109     h = GetClipboardData(wine_marshal_clipboard_format);
1110     if(!h) return S_FALSE;
1111     if(GlobalSize(h) <= 1) return S_FALSE;
1112     ptr = GlobalLock(h);
1113     if(!ptr) return S_FALSE;
1114 
1115     hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
1116     if(FAILED(hr)) goto end;
1117 
1118     hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
1119     if(SUCCEEDED(hr))
1120     {
1121         pos.QuadPart = 0;
1122         IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1123         hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
1124     }
1125     IStream_Release(stm);
1126 
1127 end:
1128     GlobalUnlock(h);
1129     return hr;
1130 }
1131 
get_tymed_from_nonole_cf(UINT cf)1132 static DWORD get_tymed_from_nonole_cf(UINT cf)
1133 {
1134     if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
1135 
1136     switch(cf)
1137     {
1138     case CF_TEXT:
1139     case CF_OEMTEXT:
1140     case CF_UNICODETEXT:
1141         return TYMED_ISTREAM | TYMED_HGLOBAL;
1142     case CF_ENHMETAFILE:
1143         return TYMED_ENHMF;
1144     case CF_METAFILEPICT:
1145         return TYMED_MFPICT;
1146     case CF_BITMAP:
1147         return TYMED_GDI;
1148     default:
1149         FIXME("returning TYMED_NULL for cf %04x\n", cf);
1150         return TYMED_NULL;
1151     }
1152 }
1153 
1154 /***********************************************************
1155  *     get_priv_data
1156  *
1157  * Returns a copy of the Ole Private Data
1158  */
get_priv_data(ole_priv_data ** data)1159 static HRESULT get_priv_data(ole_priv_data **data)
1160 {
1161     HGLOBAL handle;
1162     HRESULT hr = S_OK;
1163     ole_priv_data *ret = NULL;
1164 
1165     *data = NULL;
1166 
1167     handle = GetClipboardData( ole_private_data_clipboard_format );
1168     if(handle)
1169     {
1170         ole_priv_data *src = GlobalLock(handle);
1171         if(src)
1172         {
1173             DWORD i;
1174 
1175             /* FIXME: sanity check on size */
1176             ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1177             if(!ret)
1178             {
1179                 GlobalUnlock(handle);
1180                 return E_OUTOFMEMORY;
1181             }
1182             memcpy(ret, src, src->size);
1183             GlobalUnlock(handle);
1184 
1185             /* Fixup any target device offsets to ptrs */
1186             for(i = 0; i < ret->count; i++)
1187                 ret->entries[i].fmtetc.ptd =
1188                     td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1189         }
1190     }
1191 
1192     if(!ret) /* Non-ole data */
1193     {
1194         UINT cf;
1195         DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1196 
1197         for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1198         {
1199             WCHAR buf[256];
1200             if (GetClipboardFormatNameW(cf, buf, ARRAY_SIZE(buf)))
1201                 TRACE("cf %04x %s\n", cf, debugstr_w(buf));
1202             else
1203                 TRACE("cf %04x\n", cf);
1204         }
1205         TRACE("count %d\n", count);
1206         size += count * sizeof(ret->entries[0]);
1207 
1208         /* There are holes in fmtetc so zero init */
1209         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1210         if(!ret) return E_OUTOFMEMORY;
1211         ret->size = size;
1212         ret->count = count;
1213 
1214         for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1215         {
1216             ret->entries[idx].fmtetc.cfFormat = cf;
1217             ret->entries[idx].fmtetc.ptd = NULL;
1218             ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1219             ret->entries[idx].fmtetc.lindex = -1;
1220             ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1221             ret->entries[idx].first_use = 1;
1222         }
1223     }
1224 
1225     *data = ret;
1226     return hr;
1227 }
1228 
1229 /************************************************************************
1230  *                    get_stgmed_for_global
1231  *
1232  * Returns a stg medium with a copy of the global handle
1233  */
get_stgmed_for_global(HGLOBAL h,STGMEDIUM * med)1234 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1235 {
1236     HRESULT hr;
1237 
1238     med->pUnkForRelease = NULL;
1239     med->tymed = TYMED_NULL;
1240 
1241     hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1242 
1243     if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1244 
1245     return hr;
1246 }
1247 
1248 /************************************************************************
1249  *                    get_stgmed_for_stream
1250  *
1251  * Returns a stg medium with a stream based on the handle
1252  */
get_stgmed_for_stream(HGLOBAL h,STGMEDIUM * med)1253 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1254 {
1255     HRESULT hr;
1256     HGLOBAL dst;
1257 
1258     med->pUnkForRelease = NULL;
1259     med->tymed = TYMED_NULL;
1260 
1261     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1262     if(FAILED(hr)) return hr;
1263 
1264     hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1265     if(FAILED(hr))
1266     {
1267         GlobalFree(dst);
1268         return hr;
1269     }
1270 
1271     med->tymed = TYMED_ISTREAM;
1272     return hr;
1273 }
1274 
1275 /************************************************************************
1276  *                    get_stgmed_for_storage
1277  *
1278  * Returns a stg medium with a storage based on the handle
1279  */
get_stgmed_for_storage(HGLOBAL h,STGMEDIUM * med)1280 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1281 {
1282     HRESULT hr;
1283     HGLOBAL dst;
1284     ILockBytes *lbs;
1285 
1286     med->pUnkForRelease = NULL;
1287     med->tymed = TYMED_NULL;
1288 
1289     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1290     if(FAILED(hr)) return hr;
1291 
1292     hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1293     if(FAILED(hr))
1294     {
1295         GlobalFree(dst);
1296         return hr;
1297     }
1298 
1299     hr = StgIsStorageILockBytes(lbs);
1300     if(hr!=S_OK)
1301     {
1302         ILockBytes_Release(lbs);
1303         GlobalFree(dst);
1304         return SUCCEEDED(hr) ? E_FAIL : hr;
1305     }
1306 
1307     hr = StgOpenStorageOnILockBytes(lbs, NULL,  STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1308     ILockBytes_Release(lbs);
1309     if(FAILED(hr))
1310     {
1311         GlobalFree(dst);
1312         return hr;
1313     }
1314 
1315     med->tymed = TYMED_ISTORAGE;
1316     return hr;
1317 }
1318 
1319 /************************************************************************
1320  *                    get_stgmed_for_emf
1321  *
1322  * Returns a stg medium with an enhanced metafile based on the handle
1323  */
get_stgmed_for_emf(HENHMETAFILE hemf,STGMEDIUM * med)1324 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
1325 {
1326     med->pUnkForRelease = NULL;
1327     med->tymed = TYMED_NULL;
1328 
1329     med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
1330     if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
1331     med->tymed = TYMED_ENHMF;
1332     return S_OK;
1333 }
1334 
1335 /************************************************************************
1336  *                    get_stgmed_for_bitmap
1337  *
1338  * Returns a stg medium with a bitmap based on the handle
1339  */
get_stgmed_for_bitmap(HBITMAP hbmp,STGMEDIUM * med)1340 static HRESULT get_stgmed_for_bitmap(HBITMAP hbmp, STGMEDIUM *med)
1341 {
1342     HRESULT hr;
1343 
1344     med->pUnkForRelease = NULL;
1345     med->tymed = TYMED_NULL;
1346 
1347     hr = dup_bitmap(hbmp, &med->u.hBitmap);
1348 
1349     if (FAILED(hr))
1350         return hr;
1351 
1352     med->tymed = TYMED_GDI;
1353     return S_OK;
1354 }
1355 
string_off_equal(const DVTARGETDEVICE * t1,WORD off1,const DVTARGETDEVICE * t2,WORD off2)1356 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1357 {
1358     const WCHAR *str1, *str2;
1359 
1360     if(off1 == 0 && off2 == 0) return TRUE;
1361     if(off1 == 0 || off2 == 0) return FALSE;
1362 
1363     str1 = (const WCHAR*)((const char*)t1 + off1);
1364     str2 = (const WCHAR*)((const char*)t2 + off2);
1365 
1366     return !wcscmp(str1, str2);
1367 }
1368 
td_equal(const DVTARGETDEVICE * t1,const DVTARGETDEVICE * t2)1369 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1370 {
1371     if(t1 == NULL && t2 == NULL) return TRUE;
1372     if(t1 == NULL || t2 == NULL) return FALSE;
1373 
1374     if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1375         return FALSE;
1376     if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1377         return FALSE;
1378     if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1379         return FALSE;
1380 
1381     /* FIXME check devmode? */
1382 
1383     return TRUE;
1384 }
1385 
1386 /************************************************************************
1387  *         snapshot_GetData
1388  */
snapshot_GetData(IDataObject * iface,FORMATETC * fmt,STGMEDIUM * med)1389 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1390                                        STGMEDIUM *med)
1391 {
1392     snapshot *This = impl_from_IDataObject(iface);
1393     HANDLE h;
1394     HRESULT hr;
1395     ole_priv_data *enum_data = NULL;
1396     ole_priv_data_entry *entry;
1397     DWORD mask;
1398 
1399     TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1400 
1401     if ( !fmt || !med ) return E_INVALIDARG;
1402 
1403     memset(med, 0, sizeof(*med));
1404 
1405     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1406 
1407     if(!This->data)
1408         hr = get_current_dataobject(&This->data);
1409 
1410     if(This->data)
1411     {
1412         hr = IDataObject_GetData(This->data, fmt, med);
1413         if(SUCCEEDED(hr))
1414         {
1415             CloseClipboard();
1416             return hr;
1417         }
1418     }
1419     if(fmt->lindex != -1)
1420     {
1421         hr = DV_E_FORMATETC;
1422         goto end;
1423     }
1424 
1425     if(!IsClipboardFormatAvailable(fmt->cfFormat))
1426     {
1427         hr = DV_E_FORMATETC;
1428         goto end;
1429     }
1430 
1431     hr = get_priv_data(&enum_data);
1432     if(FAILED(hr)) goto end;
1433 
1434     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1435     if(entry)
1436     {
1437         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1438         {
1439             hr = DV_E_FORMATETC;
1440             goto end;
1441         }
1442         mask = fmt->tymed & entry->fmtetc.tymed;
1443         if(!mask && (entry->fmtetc.tymed & (TYMED_ISTREAM | TYMED_HGLOBAL | TYMED_ISTORAGE)))
1444             mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL | TYMED_ISTORAGE);
1445     }
1446     else /* non-Ole format */
1447         mask = fmt->tymed & get_tymed_from_nonole_cf(fmt->cfFormat);
1448 
1449     if(!mask)
1450     {
1451         hr = DV_E_TYMED;
1452         goto end;
1453     }
1454 
1455     h = GetClipboardData(fmt->cfFormat);
1456     if(!h)
1457     {
1458         hr = DV_E_FORMATETC;
1459         goto end;
1460     }
1461 
1462     if(mask & TYMED_HGLOBAL)
1463         hr = get_stgmed_for_global(h, med);
1464     else if(mask & TYMED_ISTREAM)
1465         hr = get_stgmed_for_stream(h, med);
1466     else if(mask & TYMED_ISTORAGE)
1467         hr = get_stgmed_for_storage(h, med);
1468     else if(mask & TYMED_ENHMF)
1469         hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
1470     else if(mask & TYMED_GDI)
1471         hr = get_stgmed_for_bitmap((HBITMAP)h, med);
1472     else
1473     {
1474         FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1475         hr = E_FAIL;
1476         goto end;
1477     }
1478 
1479 end:
1480     HeapFree(GetProcessHeap(), 0, enum_data);
1481     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1482     return hr;
1483 }
1484 
1485 /************************************************************************
1486  *          snapshot_GetDataHere
1487  */
snapshot_GetDataHere(IDataObject * iface,FORMATETC * fmt,STGMEDIUM * med)1488 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1489                                            STGMEDIUM *med)
1490 {
1491     snapshot *This = impl_from_IDataObject(iface);
1492     HANDLE h;
1493     HRESULT hr;
1494     ole_priv_data *enum_data = NULL;
1495     ole_priv_data_entry *entry;
1496     TYMED supported;
1497 
1498     if ( !fmt || !med ) return E_INVALIDARG;
1499 
1500     TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1501 
1502     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1503 
1504     if(!This->data)
1505         hr = get_current_dataobject(&This->data);
1506 
1507     if(This->data)
1508     {
1509         hr = IDataObject_GetDataHere(This->data, fmt, med);
1510         if(SUCCEEDED(hr))
1511         {
1512             CloseClipboard();
1513             return hr;
1514         }
1515     }
1516 
1517     h = GetClipboardData(fmt->cfFormat);
1518     if(!h)
1519     {
1520         hr = DV_E_FORMATETC;
1521         goto end;
1522     }
1523 
1524     hr = get_priv_data(&enum_data);
1525     if(FAILED(hr)) goto end;
1526 
1527     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1528     if(entry)
1529     {
1530         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1531         {
1532             hr = DV_E_FORMATETC;
1533             goto end;
1534         }
1535         supported = entry->fmtetc.tymed;
1536     }
1537     else /* non-Ole format */
1538         supported = TYMED_HGLOBAL;
1539 
1540     switch(med->tymed)
1541     {
1542     case TYMED_HGLOBAL:
1543     {
1544         DWORD src_size = GlobalSize(h);
1545         DWORD dst_size = GlobalSize(med->u.hGlobal);
1546         hr = E_FAIL;
1547         if(dst_size >= src_size)
1548         {
1549             void *src = GlobalLock(h);
1550             void *dst = GlobalLock(med->u.hGlobal);
1551 
1552             memcpy(dst, src, src_size);
1553             GlobalUnlock(med->u.hGlobal);
1554             GlobalUnlock(h);
1555             hr = S_OK;
1556         }
1557         break;
1558     }
1559     case TYMED_ISTREAM:
1560     {
1561         DWORD src_size = GlobalSize(h);
1562         void *src = GlobalLock(h);
1563         hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1564         GlobalUnlock(h);
1565         break;
1566     }
1567     case TYMED_ISTORAGE:
1568     {
1569         STGMEDIUM copy;
1570         if(!(supported & TYMED_ISTORAGE))
1571         {
1572             hr = E_FAIL;
1573             goto end;
1574         }
1575         hr = get_stgmed_for_storage(h, &copy);
1576         if(SUCCEEDED(hr))
1577         {
1578             hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1579             ReleaseStgMedium(&copy);
1580         }
1581         break;
1582     }
1583     default:
1584         FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1585         hr = E_FAIL;
1586         goto end;
1587     }
1588 
1589 end:
1590     HeapFree(GetProcessHeap(), 0, enum_data);
1591     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1592     return hr;
1593 }
1594 
1595 /************************************************************************
1596  *           snapshot_QueryGetData
1597  *
1598  * The OLE Clipboard's implementation of this method delegates to
1599  * a data source if there is one or wraps around the windows clipboard
1600  * function IsClipboardFormatAvailable() otherwise.
1601  *
1602  */
snapshot_QueryGetData(IDataObject * iface,FORMATETC * fmt)1603 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1604 {
1605     TRACE("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1606 
1607     if (!fmt) return E_INVALIDARG;
1608 
1609     if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1610 
1611     if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1612 
1613     return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1614 }
1615 
1616 /************************************************************************
1617  *              snapshot_GetCanonicalFormatEtc
1618  */
snapshot_GetCanonicalFormatEtc(IDataObject * iface,FORMATETC * fmt_in,FORMATETC * fmt_out)1619 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1620                                                      FORMATETC *fmt_out)
1621 {
1622     TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1623 
1624     if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1625 
1626     *fmt_out = *fmt_in;
1627     return DATA_S_SAMEFORMATETC;
1628 }
1629 
1630 /************************************************************************
1631  *              snapshot_SetData
1632  *
1633  * The OLE Clipboard does not implement this method
1634  */
snapshot_SetData(IDataObject * iface,FORMATETC * fmt,STGMEDIUM * med,BOOL release)1635 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1636                                        STGMEDIUM *med, BOOL release)
1637 {
1638     TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1639     return E_NOTIMPL;
1640 }
1641 
1642 /************************************************************************
1643  *             snapshot_EnumFormatEtc
1644  *
1645  */
snapshot_EnumFormatEtc(IDataObject * iface,DWORD dir,IEnumFORMATETC ** enum_fmt)1646 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1647                                              IEnumFORMATETC **enum_fmt)
1648 {
1649     HRESULT hr;
1650     ole_priv_data *data = NULL;
1651 
1652     TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1653 
1654     *enum_fmt = NULL;
1655 
1656     if ( dir != DATADIR_GET ) return E_NOTIMPL;
1657     if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1658 
1659     hr = get_priv_data(&data);
1660 
1661     if(FAILED(hr)) goto end;
1662 
1663     hr = enum_fmtetc_construct( data, 0, enum_fmt );
1664 
1665 end:
1666     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1667     return hr;
1668 }
1669 
1670 /************************************************************************
1671  *               snapshot_DAdvise
1672  *
1673  * The OLE Clipboard does not implement this method
1674  */
snapshot_DAdvise(IDataObject * iface,FORMATETC * fmt,DWORD flags,IAdviseSink * sink,DWORD * conn)1675 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1676                                        DWORD flags, IAdviseSink *sink,
1677                                        DWORD *conn)
1678 {
1679     TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1680     return E_NOTIMPL;
1681 }
1682 
1683 /************************************************************************
1684  *              snapshot_DUnadvise
1685  *
1686  * The OLE Clipboard does not implement this method
1687  */
snapshot_DUnadvise(IDataObject * iface,DWORD conn)1688 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1689 {
1690     TRACE("(%p, %d): not implemented\n", iface, conn);
1691     return E_NOTIMPL;
1692 }
1693 
1694 /************************************************************************
1695  *             snapshot_EnumDAdvise
1696  *
1697  * The OLE Clipboard does not implement this method
1698  */
snapshot_EnumDAdvise(IDataObject * iface,IEnumSTATDATA ** enum_advise)1699 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1700                                            IEnumSTATDATA** enum_advise)
1701 {
1702     TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1703     return E_NOTIMPL;
1704 }
1705 
1706 static const IDataObjectVtbl snapshot_vtable =
1707 {
1708     snapshot_QueryInterface,
1709     snapshot_AddRef,
1710     snapshot_Release,
1711     snapshot_GetData,
1712     snapshot_GetDataHere,
1713     snapshot_QueryGetData,
1714     snapshot_GetCanonicalFormatEtc,
1715     snapshot_SetData,
1716     snapshot_EnumFormatEtc,
1717     snapshot_DAdvise,
1718     snapshot_DUnadvise,
1719     snapshot_EnumDAdvise
1720 };
1721 
1722 /*---------------------------------------------------------------------*
1723  *           Internal implementation methods for the OLE clipboard
1724  *---------------------------------------------------------------------*/
1725 
snapshot_construct(DWORD seq_no)1726 static snapshot *snapshot_construct(DWORD seq_no)
1727 {
1728     snapshot *This;
1729 
1730     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1731     if (!This) return NULL;
1732 
1733     This->IDataObject_iface.lpVtbl = &snapshot_vtable;
1734     This->ref = 0;
1735     This->seq_no = seq_no;
1736     This->data = NULL;
1737 
1738     return This;
1739 }
1740 
1741 /*********************************************************
1742  *               register_clipboard_formats
1743  */
register_clipboard_formats(void)1744 static void register_clipboard_formats(void)
1745 {
1746     static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1747     static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1748     static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1749     static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1750     static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1751     static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1752     static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1753     static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1754     static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1755     static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1756                                                  'D','e','s','c','r','i','p','t','o','r',0};
1757     static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1758 
1759     static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1760                                                      'D','a','t','a','O','b','j','e','c','t',0};
1761 
1762     ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1763     filename_clipboard_format = RegisterClipboardFormatW(FileName);
1764     filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1765     dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1766     embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1767     embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1768     custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1769     link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1770     object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1771     link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1772     ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1773 
1774     wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1775 }
1776 
1777 /***********************************************************************
1778  * OLEClipbrd_Initialize()
1779  * Initializes the OLE clipboard.
1780  */
OLEClipbrd_Initialize(void)1781 void OLEClipbrd_Initialize(void)
1782 {
1783     register_clipboard_formats();
1784 
1785     if ( !theOleClipboard )
1786     {
1787         ole_clipbrd* clipbrd;
1788         HGLOBAL h;
1789 
1790         TRACE("()\n");
1791 
1792         clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1793         if (!clipbrd) return;
1794 
1795         clipbrd->latest_snapshot = NULL;
1796         clipbrd->window = NULL;
1797         clipbrd->src_data = NULL;
1798         clipbrd->cached_enum = NULL;
1799 
1800         h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1801         if(!h)
1802         {
1803             HeapFree(GetProcessHeap(), 0, clipbrd);
1804             return;
1805         }
1806 
1807         if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1808         {
1809             GlobalFree(h);
1810             HeapFree(GetProcessHeap(), 0, clipbrd);
1811             return;
1812         }
1813 
1814         theOleClipboard = clipbrd;
1815     }
1816 }
1817 
1818 /*********************************************************************
1819  *          set_clipboard_formats
1820  *
1821  * Enumerate all formats supported by the source and make
1822  * those formats available using delayed rendering using SetClipboardData.
1823  * Cache the enumeration list and make that list visible as the
1824  * 'Ole Private Data' format on the clipboard.
1825  *
1826  */
set_clipboard_formats(ole_clipbrd * clipbrd,IDataObject * data)1827 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1828 {
1829     HRESULT hr;
1830     FORMATETC fmt;
1831     IEnumFORMATETC *enum_fmt;
1832     HGLOBAL priv_data_handle;
1833     DWORD_PTR target_offset;
1834     ole_priv_data *priv_data;
1835     DWORD count = 0, needed = sizeof(*priv_data), idx;
1836 
1837     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1838     if(FAILED(hr)) return hr;
1839 
1840     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1841     {
1842         count++;
1843         needed += sizeof(priv_data->entries[0]);
1844         if(fmt.ptd)
1845         {
1846             needed += fmt.ptd->tdSize;
1847             CoTaskMemFree(fmt.ptd);
1848         }
1849     }
1850 
1851     /* Windows pads the list with two empty ole_priv_data_entries, one
1852      * after the entries array and one after the target device data.
1853      * Allocating with zero init to zero these pads. */
1854 
1855     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1856     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1857     priv_data = GlobalLock(priv_data_handle);
1858 
1859     priv_data->unk1 = 0;
1860     priv_data->size = needed;
1861     priv_data->unk2 = 1;
1862     priv_data->count = count;
1863     priv_data->unk3[0] = 0;
1864     priv_data->unk3[1] = 0;
1865 
1866     IEnumFORMATETC_Reset(enum_fmt);
1867 
1868     idx = 0;
1869     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1870 
1871     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1872     {
1873         TRACE("%s\n", dump_fmtetc(&fmt));
1874 
1875         priv_data->entries[idx].fmtetc = fmt;
1876         if(fmt.ptd)
1877         {
1878             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1879             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1880             target_offset += fmt.ptd->tdSize;
1881             CoTaskMemFree(fmt.ptd);
1882         }
1883 
1884         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1885         priv_data->entries[idx].unk[0] = 0;
1886         priv_data->entries[idx].unk[1] = 0;
1887 
1888         if (priv_data->entries[idx].first_use)
1889             SetClipboardData(fmt.cfFormat, NULL);
1890 
1891         idx++;
1892     }
1893 
1894     IEnumFORMATETC_Release(enum_fmt);
1895 
1896     /* Cache the list and fixup any target device offsets to ptrs */
1897     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1898     memcpy(clipbrd->cached_enum, priv_data, needed);
1899     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1900         clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1901             td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1902 
1903     GlobalUnlock(priv_data_handle);
1904     if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle))
1905     {
1906         GlobalFree(priv_data_handle);
1907         return CLIPBRD_E_CANT_SET;
1908     }
1909 
1910     return S_OK;
1911 }
1912 
1913 static HWND create_clipbrd_window(void);
1914 
1915 /***********************************************************************
1916  *                 get_clipbrd_window
1917  */
get_clipbrd_window(ole_clipbrd * clipbrd,HWND * wnd)1918 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1919 {
1920 #ifdef __REACTOS__
1921     /* The clipboard window can get destroyed if the  thread that created it dies so we may need to create it again */
1922     if (!IsWindow(clipbrd->window))
1923         clipbrd->window = create_clipbrd_window();
1924 #endif
1925 
1926     if ( !clipbrd->window )
1927         clipbrd->window = create_clipbrd_window();
1928 
1929     *wnd = clipbrd->window;
1930     return *wnd ? S_OK : E_FAIL;
1931 }
1932 
1933 
1934 /**********************************************************************
1935  *                  release_marshal_data
1936  *
1937  * Releases the data and sets the stream back to zero size.
1938  */
release_marshal_data(IStream * stm)1939 static inline void release_marshal_data(IStream *stm)
1940 {
1941     LARGE_INTEGER pos;
1942     ULARGE_INTEGER size;
1943     pos.QuadPart = size.QuadPart = 0;
1944 
1945     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1946     CoReleaseMarshalData(stm);
1947     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1948     IStream_SetSize(stm, size);
1949 }
1950 
1951 /***********************************************************************
1952  *   expose_marshalled_dataobject
1953  *
1954  * Sets the marshalled dataobject to the clipboard.  In the flushed case
1955  * we set a zero sized HGLOBAL to clear the old marshalled data.
1956  */
expose_marshalled_dataobject(ole_clipbrd * clipbrd,IDataObject * data)1957 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1958 {
1959     HGLOBAL h;
1960 
1961     if(data)
1962     {
1963         HGLOBAL h_stm;
1964         GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1965         dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1966     }
1967     else /* flushed */
1968         h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 1);
1969 
1970     if(!h) return E_OUTOFMEMORY;
1971 
1972     if(!SetClipboardData(wine_marshal_clipboard_format, h))
1973     {
1974         GlobalFree(h);
1975         return CLIPBRD_E_CANT_SET;
1976     }
1977     return S_OK;
1978 }
1979 
1980 /***********************************************************************
1981  *                   set_src_dataobject
1982  *
1983  * Clears and sets the clipboard's src IDataObject.
1984  *
1985  * To marshal the source dataobject we do something rather different from Windows.
1986  * We set a clipboard format which contains the marshalled data.
1987  * Windows sets two window props one of which is an IID, the other is an endpoint number.
1988  */
set_src_dataobject(ole_clipbrd * clipbrd,IDataObject * data)1989 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1990 {
1991     HRESULT hr;
1992     HWND wnd;
1993 
1994     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1995 
1996     if(clipbrd->src_data)
1997     {
1998         release_marshal_data(clipbrd->marshal_data);
1999 
2000         IDataObject_Release(clipbrd->src_data);
2001         clipbrd->src_data = NULL;
2002         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
2003         clipbrd->cached_enum = NULL;
2004     }
2005 
2006     if(data)
2007     {
2008         IUnknown *unk;
2009 
2010         IDataObject_AddRef(data);
2011         clipbrd->src_data = data;
2012 
2013         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
2014         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
2015                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
2016         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
2017         if(FAILED(hr)) return hr;
2018         hr = set_clipboard_formats(clipbrd, data);
2019     }
2020     return hr;
2021 }
2022 
2023 /***********************************************************************
2024  * OLEClipbrd_UnInitialize()
2025  * Un-Initializes the OLE clipboard
2026  */
OLEClipbrd_UnInitialize(void)2027 void OLEClipbrd_UnInitialize(void)
2028 {
2029     ole_clipbrd *clipbrd = theOleClipboard;
2030 
2031     TRACE("()\n");
2032 
2033     if ( clipbrd )
2034     {
2035         static const WCHAR ole32W[] = {'o','l','e','3','2',0};
2036         HINSTANCE hinst = GetModuleHandleW(ole32W);
2037 
2038         /* OleUninitialize() does not release the reference to the dataobject, so
2039            take an additional reference here.  This reference is then leaked. */
2040         if (clipbrd->src_data)
2041         {
2042             IDataObject_AddRef(clipbrd->src_data);
2043             set_src_dataobject(clipbrd, NULL);
2044         }
2045 
2046         if ( clipbrd->window )
2047         {
2048             DestroyWindow(clipbrd->window);
2049             UnregisterClassW( clipbrd_wndclass, hinst );
2050         }
2051 
2052         IStream_Release(clipbrd->marshal_data);
2053         HeapFree(GetProcessHeap(), 0, clipbrd);
2054         theOleClipboard = NULL;
2055     }
2056 }
2057 
2058 /***********************************************************************
2059  *                   clipbrd_wndproc
2060  */
clipbrd_wndproc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)2061 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2062 {
2063     ole_clipbrd *clipbrd;
2064 
2065     get_ole_clipbrd(&clipbrd);
2066 #ifdef __REACTOS__
2067     if(clipbrd == NULL)
2068         return DefWindowProcW(hwnd, message, wparam, lparam);
2069 #endif
2070 
2071     switch (message)
2072     {
2073     case WM_RENDERFORMAT:
2074     {
2075 #ifdef __REACTOS__
2076     if (clipbrd->cached_enum)
2077     {
2078 #endif
2079         UINT cf = wparam;
2080         ole_priv_data_entry *entry;
2081 
2082         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
2083         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
2084 
2085         if(entry)
2086             render_format(clipbrd->src_data, &entry->fmtetc);
2087 #ifdef __REACTOS__
2088     }
2089 #endif
2090         break;
2091     }
2092 
2093     case WM_RENDERALLFORMATS:
2094     {
2095         DWORD i;
2096         ole_priv_data_entry *entries;
2097 
2098         TRACE("(): WM_RENDERALLFORMATS\n");
2099 
2100         if (!clipbrd || !clipbrd->cached_enum) break;
2101         entries = clipbrd->cached_enum->entries;
2102         for(i = 0; i < clipbrd->cached_enum->count; i++)
2103         {
2104             if(entries[i].first_use)
2105                 render_format(clipbrd->src_data, &entries[i].fmtetc);
2106         }
2107         break;
2108     }
2109 
2110     case WM_DESTROYCLIPBOARD:
2111     {
2112         TRACE("(): WM_DESTROYCLIPBOARD\n");
2113 
2114         set_src_dataobject(clipbrd, NULL);
2115         break;
2116     }
2117 
2118     default:
2119         return DefWindowProcW(hwnd, message, wparam, lparam);
2120     }
2121 
2122     return 0;
2123 }
2124 
2125 
2126 /***********************************************************************
2127  *                 create_clipbrd_window
2128  */
create_clipbrd_window(void)2129 static HWND create_clipbrd_window(void)
2130 {
2131     WNDCLASSEXW class;
2132     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
2133     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2134     HINSTANCE hinst = GetModuleHandleW(ole32W);
2135 
2136     class.cbSize         = sizeof(class);
2137     class.style          = 0;
2138     class.lpfnWndProc    = clipbrd_wndproc;
2139     class.cbClsExtra     = 0;
2140     class.cbWndExtra     = 0;
2141     class.hInstance      = hinst;
2142     class.hIcon          = 0;
2143     class.hCursor        = 0;
2144     class.hbrBackground  = 0;
2145     class.lpszMenuName   = NULL;
2146     class.lpszClassName  = clipbrd_wndclass;
2147     class.hIconSm        = NULL;
2148 
2149     RegisterClassExW(&class);
2150 
2151     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
2152                          0, 0, 0, 0, HWND_MESSAGE, NULL, hinst, 0);
2153 }
2154 
2155 /*********************************************************************
2156  *          set_dataobject_format
2157  *
2158  * Windows creates a 'DataObject' clipboard format that contains the
2159  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2160  */
set_dataobject_format(HWND hwnd)2161 static HRESULT set_dataobject_format(HWND hwnd)
2162 {
2163     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
2164     HWND *data;
2165 
2166     if(!h) return E_OUTOFMEMORY;
2167 
2168     data = GlobalLock(h);
2169     *data = hwnd;
2170     GlobalUnlock(h);
2171 
2172     if(!SetClipboardData(dataobject_clipboard_format, h))
2173     {
2174         GlobalFree(h);
2175         return CLIPBRD_E_CANT_SET;
2176     }
2177 
2178     return S_OK;
2179 }
2180 
2181 /*---------------------------------------------------------------------*
2182  *           Win32 OLE clipboard API
2183  *---------------------------------------------------------------------*/
2184 
2185 /***********************************************************************
2186  *           OleSetClipboard     [OLE32.@]
2187  *  Places a pointer to the specified data object onto the clipboard,
2188  *  making the data object accessible to the OleGetClipboard function.
2189  *
2190  * RETURNS
2191  *
2192  *    S_OK                  IDataObject pointer placed on the clipboard
2193  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
2194  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
2195  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
2196  *    CLIPBRD_E_CANT_SET    SetClipboard failed
2197  */
2198 
OleSetClipboard(IDataObject * data)2199 HRESULT WINAPI OleSetClipboard(IDataObject* data)
2200 {
2201   HRESULT hr;
2202   ole_clipbrd *clipbrd;
2203   HWND wnd;
2204 
2205   TRACE("(%p)\n", data);
2206 
2207   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2208 
2209   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2210 
2211   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
2212 
2213   if ( !EmptyClipboard() )
2214   {
2215     hr = CLIPBRD_E_CANT_EMPTY;
2216     goto end;
2217   }
2218 
2219   hr = set_src_dataobject(clipbrd, data);
2220   if(FAILED(hr)) goto end;
2221 
2222   if(data)
2223   {
2224     hr = expose_marshalled_dataobject(clipbrd, data);
2225     if(FAILED(hr)) goto end;
2226     hr = set_dataobject_format(wnd);
2227   }
2228 
2229 end:
2230 
2231   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2232 
2233   if ( FAILED(hr) )
2234   {
2235     expose_marshalled_dataobject(clipbrd, NULL);
2236     set_src_dataobject(clipbrd, NULL);
2237   }
2238 
2239   return hr;
2240 }
2241 
2242 
2243 /***********************************************************************
2244  * OleGetClipboard [OLE32.@]
2245  * Returns a pointer to our internal IDataObject which represents the conceptual
2246  * state of the Windows clipboard. If the current clipboard already contains
2247  * an IDataObject, our internal IDataObject will delegate to this object.
2248  */
OleGetClipboard(IDataObject ** obj)2249 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
2250 {
2251     HRESULT hr;
2252     ole_clipbrd *clipbrd;
2253     DWORD seq_no;
2254 
2255     TRACE("(%p)\n", obj);
2256 
2257     if(!obj) return E_INVALIDARG;
2258     *obj = NULL;
2259 
2260     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2261 
2262     seq_no = GetClipboardSequenceNumber();
2263     EnterCriticalSection(&latest_snapshot_cs);
2264     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2265         clipbrd->latest_snapshot = NULL;
2266 
2267     if(!clipbrd->latest_snapshot)
2268     {
2269         clipbrd->latest_snapshot = snapshot_construct(seq_no);
2270         if(!clipbrd->latest_snapshot)
2271         {
2272             LeaveCriticalSection(&latest_snapshot_cs);
2273             return E_OUTOFMEMORY;
2274         }
2275     }
2276 
2277     *obj = &clipbrd->latest_snapshot->IDataObject_iface;
2278     IDataObject_AddRef(*obj);
2279     LeaveCriticalSection(&latest_snapshot_cs);
2280 
2281     return S_OK;
2282 }
2283 
2284 /******************************************************************************
2285  *              OleFlushClipboard        [OLE32.@]
2286  *  Renders the data from the source IDataObject into the windows clipboard
2287  *
2288  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2289  *  by copying the storage into global memory. Subsequently the default
2290  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2291  *  back to TYMED_IStorage.
2292  */
OleFlushClipboard(void)2293 HRESULT WINAPI OleFlushClipboard(void)
2294 {
2295   HRESULT hr;
2296   ole_clipbrd *clipbrd;
2297   HWND wnd;
2298 
2299   TRACE("()\n");
2300 
2301   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2302 
2303   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2304 
2305   /*
2306    * Already flushed or no source DataObject? Nothing to do.
2307    */
2308   if (!clipbrd->src_data) return S_OK;
2309 
2310   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2311 
2312   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2313 
2314   hr = set_dataobject_format(NULL);
2315 
2316   expose_marshalled_dataobject(clipbrd, NULL);
2317   set_src_dataobject(clipbrd, NULL);
2318 
2319   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2320 
2321   return hr;
2322 }
2323 
2324 
2325 /***********************************************************************
2326  *           OleIsCurrentClipboard [OLE32.@]
2327  */
OleIsCurrentClipboard(IDataObject * data)2328 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2329 {
2330     HRESULT hr;
2331     ole_clipbrd *clipbrd;
2332     TRACE("()\n");
2333 
2334     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2335 
2336     if (data == NULL) return S_FALSE;
2337 
2338     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
2339 }
2340