2 * OLE 2 clipboard support
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
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.
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.
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
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:
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.
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
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.
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
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.
62 #include "storage32.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
66 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
68 /* Structure of 'Ole Private Data' clipboard format */
72 DWORD first_use
; /* Has this cf been added to the list already */
74 } ole_priv_data_entry
;
79 DWORD size
; /* in bytes of the entire structure */
81 DWORD count
; /* no. of format entries */
83 ole_priv_data_entry entries
[1]; /* array of size count */
84 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
87 /*****************************************************************************
90 * Returns a ptr to a target device at a given offset from the
91 * start of the ole_priv_data.
93 * Used when unpacking ole private data from the clipboard.
95 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
97 if(off
== 0) return NULL
;
98 return (DVTARGETDEVICE
*)((char*)data
+ off
);
101 /*****************************************************************************
104 * Get the offset from the start of the ole_priv_data of the idx'th
107 * Used when packing ole private data to the clipboard.
109 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
111 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
112 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
115 /****************************************************************************
116 * Consumer snapshot. Represents the state of the ole clipboard
117 * returned by OleGetClipboard().
119 typedef struct snapshot
121 IDataObject IDataObject_iface
;
124 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
126 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
129 /****************************************************************************
132 typedef struct ole_clipbrd
134 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
136 HWND window
; /* Hidden clipboard window */
137 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
138 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
139 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
142 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
144 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
147 typedef struct PresentationDataHeader
150 DWORD dwObjectExtentX
;
151 DWORD dwObjectExtentY
;
153 } PresentationDataHeader
;
156 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
158 static ole_clipbrd
* theOleClipboard
;
160 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
162 struct oletls
*info
= COM_CurrentInfo();
166 return CO_E_NOTINITIALIZED
;
167 *clipbrd
= theOleClipboard
;
173 * Name of our registered OLE clipboard window class
175 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
177 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};
179 UINT ownerlink_clipboard_format
= 0;
180 UINT filename_clipboard_format
= 0;
181 UINT filenameW_clipboard_format
= 0;
182 UINT dataobject_clipboard_format
= 0;
183 UINT embedded_object_clipboard_format
= 0;
184 UINT embed_source_clipboard_format
= 0;
185 UINT custom_link_source_clipboard_format
= 0;
186 UINT link_source_clipboard_format
= 0;
187 UINT object_descriptor_clipboard_format
= 0;
188 UINT link_source_descriptor_clipboard_format
= 0;
189 UINT ole_private_data_clipboard_format
= 0;
191 static UINT wine_marshal_clipboard_format
;
193 static inline char *dump_fmtetc(FORMATETC
*fmt
)
195 static char buf
[100];
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
);
202 /*---------------------------------------------------------------------*
203 * Implementation of the internal IEnumFORMATETC interface returned by
204 * the OLE clipboard's IDataObject.
205 *---------------------------------------------------------------------*/
207 typedef struct enum_fmtetc
209 IEnumFORMATETC IEnumFORMATETC_iface
;
212 UINT pos
; /* current enumerator position */
216 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
218 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
221 /************************************************************************
222 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
224 * See Windows documentation for more details on IUnknown methods.
226 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
227 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
229 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
231 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
235 if(IsEqualIID(riid
, &IID_IUnknown
) ||
236 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
243 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
244 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
248 TRACE("-- Interface: E_NOINTERFACE\n");
249 return E_NOINTERFACE
;
252 /************************************************************************
253 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
256 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
258 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
259 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
261 return InterlockedIncrement(&This
->ref
);
264 /************************************************************************
265 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
267 * See Windows documentation for more details on IUnknown methods.
269 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
271 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
274 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
276 ref
= InterlockedDecrement(&This
->ref
);
279 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
280 HeapFree(GetProcessHeap(), 0, This
->data
);
281 HeapFree(GetProcessHeap(), 0, This
);
286 /************************************************************************
287 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
289 * Standard enumerator members for IEnumFORMATETC
291 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
292 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
294 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
296 HRESULT hres
= S_FALSE
;
298 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
300 if (This
->pos
< This
->data
->count
)
302 cfetch
= This
->data
->count
- This
->pos
;
309 for(i
= 0; i
< cfetch
; i
++)
311 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
314 DVTARGETDEVICE
*target
= 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
);
328 *pceltFethed
= cfetch
;
334 /************************************************************************
335 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
337 * Standard enumerator members for IEnumFORMATETC
339 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
341 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
342 TRACE("(%p)->(num=%u)\n", This
, celt
);
345 if (This
->pos
> This
->data
->count
)
347 This
->pos
= This
->data
->count
;
353 /************************************************************************
354 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
356 * Standard enumerator members for IEnumFORMATETC
358 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
360 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
361 TRACE("(%p)->()\n", This
);
367 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
369 /************************************************************************
370 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
372 * Standard enumerator members for IEnumFORMATETC
374 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
375 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
377 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
378 ole_priv_data
*new_data
;
381 TRACE("(%p)->(%p)\n", This
, obj
);
383 if ( !obj
) return E_INVALIDARG
;
386 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
387 if(!new_data
) return E_OUTOFMEMORY
;
388 memcpy(new_data
, This
->data
, This
->data
->size
);
390 /* Fixup any target device ptrs */
391 for(i
= 0; i
< This
->data
->count
; i
++)
392 new_data
->entries
[i
].fmtetc
.ptd
=
393 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
395 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
398 static const IEnumFORMATETCVtbl efvt
=
400 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
401 OLEClipbrd_IEnumFORMATETC_AddRef
,
402 OLEClipbrd_IEnumFORMATETC_Release
,
403 OLEClipbrd_IEnumFORMATETC_Next
,
404 OLEClipbrd_IEnumFORMATETC_Skip
,
405 OLEClipbrd_IEnumFORMATETC_Reset
,
406 OLEClipbrd_IEnumFORMATETC_Clone
409 /************************************************************************
410 * enum_fmtetc_construct
412 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
414 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
419 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
420 if (!ef
) return E_OUTOFMEMORY
;
423 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
427 TRACE("(%p)->()\n", ef
);
428 *obj
= &ef
->IEnumFORMATETC_iface
;
432 /***********************************************************************
435 * Helper method to duplicate an HGLOBAL chunk of memory
437 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
439 void *src_ptr
, *dst_ptr
;
443 if ( !src
) return S_FALSE
;
445 size
= GlobalSize(src
);
447 *dst
= GlobalAlloc( flags
, size
);
448 if ( !*dst
) return E_OUTOFMEMORY
;
450 src_ptr
= GlobalLock(src
);
451 dst_ptr
= GlobalLock(*dst
);
453 memcpy(dst_ptr
, src_ptr
, size
);
461 /***********************************************************************
464 * Helper function to duplicate a handle to a METAFILEPICT, and the
465 * contained HMETAFILE.
467 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
471 METAFILEPICT
*dest_ptr
;
475 /* Copy the METAFILEPICT structure. */
476 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
477 if (FAILED(hr
)) return hr
;
479 dest_ptr
= GlobalLock(dest
);
480 if (!dest_ptr
) return E_FAIL
;
482 /* Give the new METAFILEPICT a separate HMETAFILE. */
483 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
498 /***********************************************************************
501 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
502 * free the contained HMETAFILE.
504 static void free_metafilepict(HGLOBAL src
)
506 METAFILEPICT
*src_ptr
;
508 src_ptr
= GlobalLock(src
);
511 DeleteMetaFile(src_ptr
->hMF
);
517 /***********************************************************************
520 * Helper function to duplicate an HBITMAP.
522 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
525 HGDIOBJ orig_src_bitmap
;
529 src_dc
= CreateCompatibleDC(NULL
);
530 orig_src_bitmap
= SelectObject(src_dc
, src
);
531 GetObjectW(src
, sizeof bm
, &bm
);
532 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
535 HDC dest_dc
= CreateCompatibleDC(NULL
);
536 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
537 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
538 SelectObject(dest_dc
, orig_dest_bitmap
);
541 SelectObject(src_dc
, orig_src_bitmap
);
544 return dest
? S_OK
: E_FAIL
;
547 /************************************************************
548 * render_embed_source_hack
550 * This is clearly a hack and has no place in the clipboard code.
553 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
556 HGLOBAL hStorage
= 0;
558 ILockBytes
*ptrILockBytes
;
560 memset(&std
, 0, sizeof(STGMEDIUM
));
561 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
563 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
564 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
565 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
566 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
567 ILockBytes_Release(ptrILockBytes
);
569 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
571 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
572 GlobalFree(hStorage
);
576 if (1) /* check whether the presentation data is already -not- present */
580 METAFILEPICT
*mfp
= 0;
582 fmt2
.cfFormat
= CF_METAFILEPICT
;
584 fmt2
.dwAspect
= DVASPECT_CONTENT
;
586 fmt2
.tymed
= TYMED_MFPICT
;
588 memset(&std2
, 0, sizeof(STGMEDIUM
));
589 std2
.tymed
= TYMED_MFPICT
;
591 /* Get the metafile picture out of it */
593 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
595 mfp
= GlobalLock(std2
.u
.hGlobal
);
600 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
601 IStream
*pStream
= 0;
603 PresentationDataHeader pdh
;
607 CHAR strOleTypeName
[51];
608 BYTE OlePresStreamHeader
[] =
610 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
611 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
612 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00
616 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
618 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
619 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
621 pdh
.dwObjectExtentX
= mfp
->xExt
;
622 pdh
.dwObjectExtentY
= mfp
->yExt
;
625 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
627 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
629 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
630 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
632 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
634 IStream_Release(pStream
);
636 HeapFree(GetProcessHeap(), 0, mfBits
);
638 GlobalUnlock(std2
.u
.hGlobal
);
639 ReleaseStgMedium(&std2
);
641 ReadClassStg(std
.u
.pstg
, &clsID
);
642 ProgIDFromCLSID(&clsID
, &strProgID
);
644 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
645 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
646 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
647 CoTaskMemFree(strProgID
);
651 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
653 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
654 GlobalFree(hStorage
);
655 hr
= CLIPBRD_E_CANT_SET
;
658 ReleaseStgMedium(&std
);
662 /************************************************************************
663 * find_format_in_list
665 * Returns the first entry that matches the provided clipboard format.
667 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
670 for(i
= 0; i
< num
; i
++)
671 if(entries
[i
].fmtetc
.cfFormat
== cf
)
677 /***************************************************************************
678 * get_data_from_storage
680 * Returns storage data in an HGLOBAL.
682 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
693 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
694 if(!h
) return E_OUTOFMEMORY
;
696 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
699 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
700 ILockBytes_Release(lbs
);
709 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
711 med
.pUnkForRelease
= NULL
;
713 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
717 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
718 if(FAILED(hr
)) goto end
;
720 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
721 ReleaseStgMedium(&med
);
722 if(FAILED(hr
)) goto end
;
727 IStorage_Release(stg
);
728 if(FAILED(hr
)) GlobalFree(h
);
732 /***************************************************************************
733 * get_data_from_stream
735 * Returns stream data in an HGLOBAL.
737 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
747 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
748 if(!h
) return E_OUTOFMEMORY
;
750 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
751 if(FAILED(hr
)) goto error
;
754 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
756 med
.pUnkForRelease
= NULL
;
758 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
765 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
766 if(FAILED(hr
)) goto error
;
769 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
770 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
771 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
772 ReleaseStgMedium(&med
);
773 if(FAILED(hr
)) goto error
;
776 IStream_Release(stm
);
780 if(stm
) IStream_Release(stm
);
785 /***************************************************************************
786 * get_data_from_global
788 * Returns global data in an HGLOBAL.
790 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
800 mem_fmt
.tymed
= TYMED_HGLOBAL
;
802 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
803 if(FAILED(hr
)) return hr
;
805 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
807 if(SUCCEEDED(hr
)) *mem
= h
;
809 ReleaseStgMedium(&med
);
814 /***************************************************************************
815 * get_data_from_enhmetafile
817 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
827 mem_fmt
.tymed
= TYMED_ENHMF
;
829 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
830 if(FAILED(hr
)) return hr
;
832 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
833 if(copy
) *mem
= (HGLOBAL
)copy
;
836 ReleaseStgMedium(&med
);
841 /***************************************************************************
842 * get_data_from_metafilepict
844 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
854 mem_fmt
.tymed
= TYMED_MFPICT
;
856 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
857 if(FAILED(hr
)) return hr
;
859 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
861 if(SUCCEEDED(hr
)) *mem
= copy
;
863 ReleaseStgMedium(&med
);
868 /***************************************************************************
869 * get_data_from_bitmap
871 * Returns bitmap in an HBITMAP.
873 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
883 mem_fmt
.tymed
= TYMED_GDI
;
885 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
886 if(FAILED(hr
)) return hr
;
888 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
890 if(SUCCEEDED(hr
)) *hbm
= copy
;
892 ReleaseStgMedium(&med
);
897 /***********************************************************************
900 * Render the clipboard data. Note that this call will delegate to the
901 * source data object.
903 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
905 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
908 /* Embed source hack */
909 if(fmt
->cfFormat
== embed_source_clipboard_format
)
911 return render_embed_source_hack(data
, fmt
);
914 if(fmt
->tymed
& TYMED_ISTORAGE
)
916 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
918 else if(fmt
->tymed
& TYMED_ISTREAM
)
920 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
922 else if(fmt
->tymed
& TYMED_HGLOBAL
)
924 hr
= get_data_from_global(data
, fmt
, &clip_data
);
926 else if(fmt
->tymed
& TYMED_ENHMF
)
928 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
930 else if(fmt
->tymed
& TYMED_MFPICT
)
932 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
933 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
935 else if(fmt
->tymed
& TYMED_GDI
)
937 /* Returns HBITMAP not HGLOBAL */
938 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
942 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
948 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
950 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
951 if(fmt
->tymed
& TYMED_MFPICT
)
952 free_metafilepict(clip_data
);
953 else if(fmt
->tymed
& TYMED_GDI
)
954 DeleteObject(clip_data
);
956 GlobalFree(clip_data
);
957 hr
= CLIPBRD_E_CANT_SET
;
964 /*---------------------------------------------------------------------*
965 * Implementation of the internal IDataObject interface exposed by
967 *---------------------------------------------------------------------*/
970 /************************************************************************
971 * snapshot_QueryInterface
973 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
974 REFIID riid
, void **ppvObject
)
976 snapshot
*This
= impl_from_IDataObject(iface
);
977 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
979 if ( (This
==0) || (ppvObject
==0) )
984 if (IsEqualIID(&IID_IUnknown
, riid
) ||
985 IsEqualIID(&IID_IDataObject
, riid
))
991 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
992 return E_NOINTERFACE
;
995 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1000 /************************************************************************
1003 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1005 snapshot
*This
= impl_from_IDataObject(iface
);
1007 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1009 return InterlockedIncrement(&This
->ref
);
1012 /************************************************************************
1015 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1017 snapshot
*This
= impl_from_IDataObject(iface
);
1020 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1022 ref
= InterlockedDecrement(&This
->ref
);
1026 ole_clipbrd
*clipbrd
;
1027 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
1029 if(This
->data
) IDataObject_Release(This
->data
);
1031 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
1032 clipbrd
->latest_snapshot
= NULL
;
1033 HeapFree(GetProcessHeap(), 0, This
);
1039 /************************************************************
1040 * get_current_ole_clip_window
1042 * Return the window that owns the ole clipboard.
1044 * If the clipboard is flushed or not owned by ole this will
1047 static HWND
get_current_ole_clip_window(void)
1052 h
= GetClipboardData(dataobject_clipboard_format
);
1054 ptr
= GlobalLock(h
);
1055 if(!ptr
) return NULL
;
1061 /************************************************************
1062 * get_current_dataobject
1064 * Return an unmarshalled IDataObject if there is a current
1065 * (ie non-flushed) object on the ole clipboard.
1067 static HRESULT
get_current_dataobject(IDataObject
**data
)
1069 HRESULT hr
= S_FALSE
;
1070 HWND wnd
= get_current_ole_clip_window();
1077 if(!wnd
) return S_FALSE
;
1079 h
= GetClipboardData(wine_marshal_clipboard_format
);
1080 if(!h
) return S_FALSE
;
1081 if(GlobalSize(h
) == 0) return S_FALSE
;
1082 ptr
= GlobalLock(h
);
1083 if(!ptr
) return S_FALSE
;
1085 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1086 if(FAILED(hr
)) goto end
;
1088 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1092 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1093 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1095 IStream_Release(stm
);
1102 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1104 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1110 case CF_UNICODETEXT
:
1111 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1112 case CF_ENHMETAFILE
:
1114 case CF_METAFILEPICT
:
1115 return TYMED_MFPICT
;
1117 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1122 /***********************************************************
1125 * Returns a copy of the Ole Private Data
1127 static HRESULT
get_priv_data(ole_priv_data
**data
)
1131 ole_priv_data
*ret
= NULL
;
1135 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1138 ole_priv_data
*src
= GlobalLock(handle
);
1143 /* FIXME: sanity check on size */
1144 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1147 GlobalUnlock(handle
);
1148 return E_OUTOFMEMORY
;
1150 memcpy(ret
, src
, src
->size
);
1151 GlobalUnlock(handle
);
1153 /* Fixup any target device offsets to ptrs */
1154 for(i
= 0; i
< ret
->count
; i
++)
1155 ret
->entries
[i
].fmtetc
.ptd
=
1156 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1160 if(!ret
) /* Non-ole data */
1163 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1165 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1168 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1169 TRACE("cf %04x %s\n", cf
, buf
);
1171 TRACE("count %d\n", count
);
1172 size
+= count
* sizeof(ret
->entries
[0]);
1174 /* There are holes in fmtetc so zero init */
1175 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1176 if(!ret
) return E_OUTOFMEMORY
;
1180 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1182 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1183 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1184 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1185 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1186 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1187 ret
->entries
[idx
].first_use
= 1;
1195 /************************************************************************
1196 * get_stgmed_for_global
1198 * Returns a stg medium with a copy of the global handle
1200 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1204 med
->pUnkForRelease
= NULL
;
1205 med
->tymed
= TYMED_NULL
;
1207 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1209 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1214 /************************************************************************
1215 * get_stgmed_for_stream
1217 * Returns a stg medium with a stream based on the handle
1219 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1224 med
->pUnkForRelease
= NULL
;
1225 med
->tymed
= TYMED_NULL
;
1227 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1228 if(FAILED(hr
)) return hr
;
1230 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1237 med
->tymed
= TYMED_ISTREAM
;
1241 /************************************************************************
1242 * get_stgmed_for_storage
1244 * Returns a stg medium with a storage based on the handle
1246 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1252 med
->pUnkForRelease
= NULL
;
1253 med
->tymed
= TYMED_NULL
;
1255 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1256 if(FAILED(hr
)) return hr
;
1258 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1265 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1266 ILockBytes_Release(lbs
);
1273 med
->tymed
= TYMED_ISTORAGE
;
1277 /************************************************************************
1278 * get_stgmed_for_emf
1280 * Returns a stg medium with an enhanced metafile based on the handle
1282 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1284 med
->pUnkForRelease
= NULL
;
1285 med
->tymed
= TYMED_NULL
;
1287 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1288 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1289 med
->tymed
= TYMED_ENHMF
;
1293 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1295 const WCHAR
*str1
, *str2
;
1297 if(off1
== 0 && off2
== 0) return TRUE
;
1298 if(off1
== 0 || off2
== 0) return FALSE
;
1300 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1301 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1303 return !lstrcmpW(str1
, str2
);
1306 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1308 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1309 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1311 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1313 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1315 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1318 /* FIXME check devmode? */
1323 /************************************************************************
1326 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1329 snapshot
*This
= impl_from_IDataObject(iface
);
1332 ole_priv_data
*enum_data
= NULL
;
1333 ole_priv_data_entry
*entry
;
1336 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1338 if ( !fmt
|| !med
) return E_INVALIDARG
;
1340 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1343 hr
= get_current_dataobject(&This
->data
);
1347 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1352 h
= GetClipboardData(fmt
->cfFormat
);
1355 hr
= DV_E_FORMATETC
;
1359 hr
= get_priv_data(&enum_data
);
1360 if(FAILED(hr
)) goto end
;
1362 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1365 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1367 hr
= DV_E_FORMATETC
;
1370 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1371 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1373 else /* non-Ole format */
1374 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1376 if(mask
& TYMED_ISTORAGE
)
1377 hr
= get_stgmed_for_storage(h
, med
);
1378 else if(mask
& TYMED_HGLOBAL
)
1379 hr
= get_stgmed_for_global(h
, med
);
1380 else if(mask
& TYMED_ISTREAM
)
1381 hr
= get_stgmed_for_stream(h
, med
);
1382 else if(mask
& TYMED_ENHMF
)
1383 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1386 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1392 HeapFree(GetProcessHeap(), 0, enum_data
);
1393 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1397 /************************************************************************
1398 * snapshot_GetDataHere
1400 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1403 snapshot
*This
= impl_from_IDataObject(iface
);
1406 ole_priv_data
*enum_data
= NULL
;
1407 ole_priv_data_entry
*entry
;
1410 if ( !fmt
|| !med
) return E_INVALIDARG
;
1412 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1414 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1417 hr
= get_current_dataobject(&This
->data
);
1421 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1429 h
= GetClipboardData(fmt
->cfFormat
);
1432 hr
= DV_E_FORMATETC
;
1436 hr
= get_priv_data(&enum_data
);
1437 if(FAILED(hr
)) goto end
;
1439 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1442 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1444 hr
= DV_E_FORMATETC
;
1447 supported
= entry
->fmtetc
.tymed
;
1449 else /* non-Ole format */
1450 supported
= TYMED_HGLOBAL
;
1456 DWORD src_size
= GlobalSize(h
);
1457 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1459 if(dst_size
>= src_size
)
1461 void *src
= GlobalLock(h
);
1462 void *dst
= GlobalLock(med
->u
.hGlobal
);
1464 memcpy(dst
, src
, src_size
);
1465 GlobalUnlock(med
->u
.hGlobal
);
1473 DWORD src_size
= GlobalSize(h
);
1474 void *src
= GlobalLock(h
);
1475 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1479 case TYMED_ISTORAGE
:
1482 if(!(supported
& TYMED_ISTORAGE
))
1487 hr
= get_stgmed_for_storage(h
, ©
);
1490 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1491 ReleaseStgMedium(©
);
1496 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1502 HeapFree(GetProcessHeap(), 0, enum_data
);
1503 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1507 /************************************************************************
1508 * snapshot_QueryGetData
1510 * The OLE Clipboard's implementation of this method delegates to
1511 * a data source if there is one or wraps around the windows clipboard
1512 * function IsClipboardFormatAvailable() otherwise.
1515 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1517 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1519 if (!fmt
) return E_INVALIDARG
;
1521 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1523 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1525 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1528 /************************************************************************
1529 * snapshot_GetCanonicalFormatEtc
1531 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1534 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1536 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1539 return DATA_S_SAMEFORMATETC
;
1542 /************************************************************************
1545 * The OLE Clipboard does not implement this method
1547 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1548 STGMEDIUM
*med
, BOOL release
)
1550 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1554 /************************************************************************
1555 * snapshot_EnumFormatEtc
1558 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1559 IEnumFORMATETC
**enum_fmt
)
1562 ole_priv_data
*data
= NULL
;
1564 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1568 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1569 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1571 hr
= get_priv_data(&data
);
1573 if(FAILED(hr
)) goto end
;
1575 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1578 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1582 /************************************************************************
1585 * The OLE Clipboard does not implement this method
1587 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1588 DWORD flags
, IAdviseSink
*sink
,
1591 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1595 /************************************************************************
1596 * snapshot_DUnadvise
1598 * The OLE Clipboard does not implement this method
1600 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1602 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1606 /************************************************************************
1607 * snapshot_EnumDAdvise
1609 * The OLE Clipboard does not implement this method
1611 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1612 IEnumSTATDATA
** enum_advise
)
1614 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1618 static const IDataObjectVtbl snapshot_vtable
=
1620 snapshot_QueryInterface
,
1624 snapshot_GetDataHere
,
1625 snapshot_QueryGetData
,
1626 snapshot_GetCanonicalFormatEtc
,
1628 snapshot_EnumFormatEtc
,
1631 snapshot_EnumDAdvise
1634 /*---------------------------------------------------------------------*
1635 * Internal implementation methods for the OLE clipboard
1636 *---------------------------------------------------------------------*/
1638 static snapshot
*snapshot_construct(DWORD seq_no
)
1642 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1643 if (!This
) return NULL
;
1645 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1647 This
->seq_no
= seq_no
;
1653 /*********************************************************
1654 * register_clipboard_formats
1656 static void register_clipboard_formats(void)
1658 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1659 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1660 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1661 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1662 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1663 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1664 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1665 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1666 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1667 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1668 'D','e','s','c','r','i','p','t','o','r',0};
1669 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1671 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1672 'D','a','t','a','O','b','j','e','c','t',0};
1674 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1675 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1676 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1677 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1678 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1679 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1680 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1681 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1682 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1683 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1684 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1686 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1689 /***********************************************************************
1690 * OLEClipbrd_Initialize()
1691 * Initializes the OLE clipboard.
1693 void OLEClipbrd_Initialize(void)
1695 register_clipboard_formats();
1697 if ( !theOleClipboard
)
1699 ole_clipbrd
* clipbrd
;
1704 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1705 if (!clipbrd
) return;
1707 clipbrd
->latest_snapshot
= NULL
;
1708 clipbrd
->window
= NULL
;
1709 clipbrd
->src_data
= NULL
;
1710 clipbrd
->cached_enum
= NULL
;
1712 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1715 HeapFree(GetProcessHeap(), 0, clipbrd
);
1719 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1722 HeapFree(GetProcessHeap(), 0, clipbrd
);
1726 theOleClipboard
= clipbrd
;
1730 /***********************************************************************
1731 * OLEClipbrd_UnInitialize()
1732 * Un-Initializes the OLE clipboard
1734 void OLEClipbrd_UnInitialize(void)
1736 ole_clipbrd
*clipbrd
= theOleClipboard
;
1742 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1743 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1745 if ( clipbrd
->window
)
1747 DestroyWindow(clipbrd
->window
);
1748 UnregisterClassW( clipbrd_wndclass
, hinst
);
1751 IStream_Release(clipbrd
->marshal_data
);
1752 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1753 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1754 HeapFree(GetProcessHeap(), 0, clipbrd
);
1755 theOleClipboard
= NULL
;
1759 /*********************************************************************
1760 * set_clipboard_formats
1762 * Enumerate all formats supported by the source and make
1763 * those formats available using delayed rendering using SetClipboardData.
1764 * Cache the enumeration list and make that list visibile as the
1765 * 'Ole Private Data' format on the clipboard.
1768 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1772 IEnumFORMATETC
*enum_fmt
;
1773 HGLOBAL priv_data_handle
;
1774 DWORD_PTR target_offset
;
1775 ole_priv_data
*priv_data
;
1776 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1778 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1779 if(FAILED(hr
)) return hr
;
1781 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1784 needed
+= sizeof(priv_data
->entries
[0]);
1787 needed
+= fmt
.ptd
->tdSize
;
1788 CoTaskMemFree(fmt
.ptd
);
1792 /* Windows pads the list with two empty ole_priv_data_entries, one
1793 * after the entries array and one after the target device data.
1794 * Allocating with zero init to zero these pads. */
1796 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1797 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1798 priv_data
= GlobalLock(priv_data_handle
);
1800 priv_data
->unk1
= 0;
1801 priv_data
->size
= needed
;
1802 priv_data
->unk2
= 1;
1803 priv_data
->count
= count
;
1804 priv_data
->unk3
[0] = 0;
1805 priv_data
->unk3
[1] = 0;
1807 IEnumFORMATETC_Reset(enum_fmt
);
1810 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1812 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1814 TRACE("%s\n", dump_fmtetc(&fmt
));
1816 priv_data
->entries
[idx
].fmtetc
= fmt
;
1819 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1820 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1821 target_offset
+= fmt
.ptd
->tdSize
;
1822 CoTaskMemFree(fmt
.ptd
);
1825 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1826 priv_data
->entries
[idx
].unk
[0] = 0;
1827 priv_data
->entries
[idx
].unk
[1] = 0;
1829 if (priv_data
->entries
[idx
].first_use
)
1830 SetClipboardData(fmt
.cfFormat
, NULL
);
1835 IEnumFORMATETC_Release(enum_fmt
);
1837 /* Cache the list and fixup any target device offsets to ptrs */
1838 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1839 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1840 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1841 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1842 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1844 GlobalUnlock(priv_data_handle
);
1845 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1847 GlobalFree(priv_data_handle
);
1848 return CLIPBRD_E_CANT_SET
;
1854 static HWND
create_clipbrd_window(void);
1856 /***********************************************************************
1857 * get_clipbrd_window
1859 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1861 if ( !clipbrd
->window
)
1862 clipbrd
->window
= create_clipbrd_window();
1864 *wnd
= clipbrd
->window
;
1865 return *wnd
? S_OK
: E_FAIL
;
1869 /**********************************************************************
1870 * release_marshal_data
1872 * Releases the data and sets the stream back to zero size.
1874 static inline void release_marshal_data(IStream
*stm
)
1877 ULARGE_INTEGER size
;
1878 pos
.QuadPart
= size
.QuadPart
= 0;
1880 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1881 CoReleaseMarshalData(stm
);
1882 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1883 IStream_SetSize(stm
, size
);
1886 /***********************************************************************
1887 * expose_marshalled_dataobject
1889 * Sets the marshalled dataobject to the clipboard. In the flushed case
1890 * we set a zero sized HGLOBAL to clear the old marshalled data.
1892 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1899 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1900 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1903 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1905 if(!h
) return E_OUTOFMEMORY
;
1907 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1910 return CLIPBRD_E_CANT_SET
;
1915 /***********************************************************************
1916 * set_src_dataobject
1918 * Clears and sets the clipboard's src IDataObject.
1920 * To marshal the source dataobject we do something rather different from Windows.
1921 * We set a clipboard format which contains the marshalled data.
1922 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1924 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1929 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1931 if(clipbrd
->src_data
)
1933 release_marshal_data(clipbrd
->marshal_data
);
1935 IDataObject_Release(clipbrd
->src_data
);
1936 clipbrd
->src_data
= NULL
;
1937 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1938 clipbrd
->cached_enum
= NULL
;
1945 IDataObject_AddRef(data
);
1946 clipbrd
->src_data
= data
;
1948 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1949 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1950 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1951 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1952 if(FAILED(hr
)) return hr
;
1953 hr
= set_clipboard_formats(clipbrd
, data
);
1958 /***********************************************************************
1961 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1963 ole_clipbrd
*clipbrd
;
1965 get_ole_clipbrd(&clipbrd
);
1969 case WM_RENDERFORMAT
:
1972 ole_priv_data_entry
*entry
;
1974 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
1975 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
1978 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
1983 case WM_RENDERALLFORMATS
:
1986 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
1988 TRACE("(): WM_RENDERALLFORMATS\n");
1990 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
1992 if(entries
[i
].first_use
)
1993 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
1998 case WM_DESTROYCLIPBOARD
:
2000 TRACE("(): WM_DESTROYCLIPBOARD\n");
2002 set_src_dataobject(clipbrd
, NULL
);
2007 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2014 /***********************************************************************
2015 * create_clipbrd_window
2017 static HWND
create_clipbrd_window(void)
2020 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2021 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2022 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2024 class.cbSize
= sizeof(class);
2026 class.lpfnWndProc
= clipbrd_wndproc
;
2027 class.cbClsExtra
= 0;
2028 class.cbWndExtra
= 0;
2029 class.hInstance
= hinst
;
2032 class.hbrBackground
= 0;
2033 class.lpszMenuName
= NULL
;
2034 class.lpszClassName
= clipbrd_wndclass
;
2035 class.hIconSm
= NULL
;
2037 RegisterClassExW(&class);
2039 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2040 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2041 NULL
, NULL
, hinst
, 0);
2044 /*********************************************************************
2045 * set_dataobject_format
2047 * Windows creates a 'DataObject' clipboard format that contains the
2048 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2050 static HRESULT
set_dataobject_format(HWND hwnd
)
2052 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2055 if(!h
) return E_OUTOFMEMORY
;
2057 data
= GlobalLock(h
);
2061 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2064 return CLIPBRD_E_CANT_SET
;
2070 /*---------------------------------------------------------------------*
2071 * Win32 OLE clipboard API
2072 *---------------------------------------------------------------------*/
2074 /***********************************************************************
2075 * OleSetClipboard [OLE32.@]
2076 * Places a pointer to the specified data object onto the clipboard,
2077 * making the data object accessible to the OleGetClipboard function.
2081 * S_OK IDataObject pointer placed on the clipboard
2082 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2083 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2084 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2085 * CLIPBRD_E_CANT_SET SetClipboard failed
2088 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2091 ole_clipbrd
*clipbrd
;
2094 TRACE("(%p)\n", data
);
2096 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2098 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2100 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2102 if ( !EmptyClipboard() )
2104 hr
= CLIPBRD_E_CANT_EMPTY
;
2108 hr
= set_src_dataobject(clipbrd
, data
);
2109 if(FAILED(hr
)) goto end
;
2113 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2114 if(FAILED(hr
)) goto end
;
2115 hr
= set_dataobject_format(wnd
);
2120 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2124 expose_marshalled_dataobject(clipbrd
, NULL
);
2125 set_src_dataobject(clipbrd
, NULL
);
2132 /***********************************************************************
2133 * OleGetClipboard [OLE32.@]
2134 * Returns a pointer to our internal IDataObject which represents the conceptual
2135 * state of the Windows clipboard. If the current clipboard already contains
2136 * an IDataObject, our internal IDataObject will delegate to this object.
2138 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2141 ole_clipbrd
*clipbrd
;
2144 TRACE("(%p)\n", obj
);
2146 if(!obj
) return E_INVALIDARG
;
2148 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2150 seq_no
= GetClipboardSequenceNumber();
2151 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2152 clipbrd
->latest_snapshot
= NULL
;
2154 if(!clipbrd
->latest_snapshot
)
2156 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2157 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
2160 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2161 IDataObject_AddRef(*obj
);
2166 /******************************************************************************
2167 * OleFlushClipboard [OLE32.@]
2168 * Renders the data from the source IDataObject into the windows clipboard
2170 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2171 * by copying the storage into global memory. Subsequently the default
2172 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2173 * back to TYMED_IStorage.
2175 HRESULT WINAPI
OleFlushClipboard(void)
2178 ole_clipbrd
*clipbrd
;
2183 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2185 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2188 * Already flushed or no source DataObject? Nothing to do.
2190 if (!clipbrd
->src_data
) return S_OK
;
2192 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2194 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2196 hr
= set_dataobject_format(NULL
);
2198 expose_marshalled_dataobject(clipbrd
, NULL
);
2199 set_src_dataobject(clipbrd
, NULL
);
2201 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2207 /***********************************************************************
2208 * OleIsCurrentClipboard [OLE32.@]
2210 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2213 ole_clipbrd
*clipbrd
;
2216 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2218 if (data
== NULL
) return S_FALSE
;
2220 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;