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.
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
77 #include "wine/debug.h"
80 #include "storage32.h"
82 #include "compobj_private.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
86 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
88 /* Structure of 'Ole Private Data' clipboard format */
92 DWORD first_use
; /* Has this cf been added to the list already */
94 } ole_priv_data_entry
;
99 DWORD size
; /* in bytes of the entire structure */
101 DWORD count
; /* no. of format entries */
103 ole_priv_data_entry entries
[1]; /* array of size count */
104 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
107 /*****************************************************************************
110 * Returns a ptr to a target device at a given offset from the
111 * start of the ole_priv_data.
113 * Used when unpacking ole private data from the clipboard.
115 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
117 if(off
== 0) return NULL
;
118 return (DVTARGETDEVICE
*)((char*)data
+ off
);
121 /*****************************************************************************
124 * Get the offset from the start of the ole_priv_data of the idx'th
127 * Used when packing ole private data to the clipboard.
129 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
131 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
132 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
135 /****************************************************************************
136 * Consumer snapshot. Represents the state of the ole clipboard
137 * returned by OleGetClipboard().
139 typedef struct snapshot
141 IDataObject IDataObject_iface
;
144 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
146 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
149 /****************************************************************************
152 typedef struct ole_clipbrd
154 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
156 HWND window
; /* Hidden clipboard window */
157 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
158 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
159 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
162 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
164 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
167 typedef struct PresentationDataHeader
170 DWORD dwObjectExtentX
;
171 DWORD dwObjectExtentY
;
173 } PresentationDataHeader
;
176 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
178 static ole_clipbrd
* theOleClipboard
;
180 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
182 struct oletls
*info
= COM_CurrentInfo();
186 return CO_E_NOTINITIALIZED
;
187 *clipbrd
= theOleClipboard
;
193 * Name of our registered OLE clipboard window class
195 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
197 static const WCHAR wine_marshal_dataobject
[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0};
199 UINT ownerlink_clipboard_format
= 0;
200 UINT filename_clipboard_format
= 0;
201 UINT filenameW_clipboard_format
= 0;
202 UINT dataobject_clipboard_format
= 0;
203 UINT embedded_object_clipboard_format
= 0;
204 UINT embed_source_clipboard_format
= 0;
205 UINT custom_link_source_clipboard_format
= 0;
206 UINT link_source_clipboard_format
= 0;
207 UINT object_descriptor_clipboard_format
= 0;
208 UINT link_source_descriptor_clipboard_format
= 0;
209 UINT ole_private_data_clipboard_format
= 0;
211 static UINT wine_marshal_clipboard_format
;
213 static inline char *dump_fmtetc(FORMATETC
*fmt
)
215 static char buf
[100];
217 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
218 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
222 /*---------------------------------------------------------------------*
223 * Implementation of the internal IEnumFORMATETC interface returned by
224 * the OLE clipboard's IDataObject.
225 *---------------------------------------------------------------------*/
227 typedef struct enum_fmtetc
229 IEnumFORMATETC IEnumFORMATETC_iface
;
232 UINT pos
; /* current enumerator position */
236 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
238 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
241 /************************************************************************
242 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
244 * See Windows documentation for more details on IUnknown methods.
246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
247 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
249 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
251 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
255 if(IsEqualIID(riid
, &IID_IUnknown
) ||
256 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
263 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
264 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
268 TRACE("-- Interface: E_NOINTERFACE\n");
269 return E_NOINTERFACE
;
272 /************************************************************************
273 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
276 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
278 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
279 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
281 return InterlockedIncrement(&This
->ref
);
284 /************************************************************************
285 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
287 * See Windows documentation for more details on IUnknown methods.
289 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
291 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
294 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
296 ref
= InterlockedDecrement(&This
->ref
);
299 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
300 HeapFree(GetProcessHeap(), 0, This
->data
);
301 HeapFree(GetProcessHeap(), 0, This
);
306 /************************************************************************
307 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
309 * Standard enumerator members for IEnumFORMATETC
311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
312 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
314 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
316 HRESULT hres
= S_FALSE
;
318 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
320 if (This
->pos
< This
->data
->count
)
322 cfetch
= This
->data
->count
- This
->pos
;
329 for(i
= 0; i
< cfetch
; i
++)
331 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
334 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
335 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
336 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
337 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
348 *pceltFethed
= cfetch
;
354 /************************************************************************
355 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
357 * Standard enumerator members for IEnumFORMATETC
359 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
361 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
362 TRACE("(%p)->(num=%u)\n", This
, celt
);
365 if (This
->pos
> This
->data
->count
)
367 This
->pos
= This
->data
->count
;
373 /************************************************************************
374 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
376 * Standard enumerator members for IEnumFORMATETC
378 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
380 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
381 TRACE("(%p)->()\n", This
);
387 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
389 /************************************************************************
390 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
392 * Standard enumerator members for IEnumFORMATETC
394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
395 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
397 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
398 ole_priv_data
*new_data
;
401 TRACE("(%p)->(%p)\n", This
, obj
);
403 if ( !obj
) return E_INVALIDARG
;
406 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
407 if(!new_data
) return E_OUTOFMEMORY
;
408 memcpy(new_data
, This
->data
, This
->data
->size
);
410 /* Fixup any target device ptrs */
411 for(i
= 0; i
< This
->data
->count
; i
++)
412 new_data
->entries
[i
].fmtetc
.ptd
=
413 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
415 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
418 static const IEnumFORMATETCVtbl efvt
=
420 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
421 OLEClipbrd_IEnumFORMATETC_AddRef
,
422 OLEClipbrd_IEnumFORMATETC_Release
,
423 OLEClipbrd_IEnumFORMATETC_Next
,
424 OLEClipbrd_IEnumFORMATETC_Skip
,
425 OLEClipbrd_IEnumFORMATETC_Reset
,
426 OLEClipbrd_IEnumFORMATETC_Clone
429 /************************************************************************
430 * enum_fmtetc_construct
432 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
434 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
439 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
440 if (!ef
) return E_OUTOFMEMORY
;
443 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
447 TRACE("(%p)->()\n", ef
);
448 *obj
= &ef
->IEnumFORMATETC_iface
;
452 /***********************************************************************
455 * Helper method to duplicate an HGLOBAL chunk of memory
457 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
459 void *src_ptr
, *dst_ptr
;
463 if ( !src
) return S_FALSE
;
465 size
= GlobalSize(src
);
467 *dst
= GlobalAlloc( flags
, size
);
468 if ( !*dst
) return E_OUTOFMEMORY
;
470 src_ptr
= GlobalLock(src
);
471 dst_ptr
= GlobalLock(*dst
);
473 memcpy(dst_ptr
, src_ptr
, size
);
481 /***********************************************************************
484 * Helper function to duplicate a handle to a METAFILEPICT, and the
485 * contained HMETAFILE.
487 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
491 METAFILEPICT
*dest_ptr
;
495 /* Copy the METAFILEPICT structure. */
496 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
497 if (FAILED(hr
)) return hr
;
499 dest_ptr
= GlobalLock(dest
);
500 if (!dest_ptr
) return E_FAIL
;
502 /* Give the new METAFILEPICT a separate HMETAFILE. */
503 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
518 /***********************************************************************
521 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
522 * free the contained HMETAFILE.
524 static void free_metafilepict(HGLOBAL src
)
526 METAFILEPICT
*src_ptr
;
528 src_ptr
= GlobalLock(src
);
531 DeleteMetaFile(src_ptr
->hMF
);
537 /***********************************************************************
540 * Helper function to duplicate an HBITMAP.
542 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
545 HGDIOBJ orig_src_bitmap
;
549 src_dc
= CreateCompatibleDC(NULL
);
550 orig_src_bitmap
= SelectObject(src_dc
, src
);
551 GetObjectW(src
, sizeof bm
, &bm
);
552 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
555 HDC dest_dc
= CreateCompatibleDC(NULL
);
556 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
557 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
558 SelectObject(dest_dc
, orig_dest_bitmap
);
561 SelectObject(src_dc
, orig_src_bitmap
);
564 return dest
? S_OK
: E_FAIL
;
567 /************************************************************
568 * render_embed_source_hack
570 * This is clearly a hack and has no place in the clipboard code.
573 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
576 HGLOBAL hStorage
= 0;
578 ILockBytes
*ptrILockBytes
;
580 memset(&std
, 0, sizeof(STGMEDIUM
));
581 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
583 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
584 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
585 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
586 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
587 ILockBytes_Release(ptrILockBytes
);
589 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
591 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
592 GlobalFree(hStorage
);
596 if (1) /* check whether the presentation data is already -not- present */
600 METAFILEPICT
*mfp
= 0;
602 fmt2
.cfFormat
= CF_METAFILEPICT
;
604 fmt2
.dwAspect
= DVASPECT_CONTENT
;
606 fmt2
.tymed
= TYMED_MFPICT
;
608 memset(&std2
, 0, sizeof(STGMEDIUM
));
609 std2
.tymed
= TYMED_MFPICT
;
611 /* Get the metafile picture out of it */
613 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
615 mfp
= GlobalLock(std2
.u
.hGlobal
);
620 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
621 IStream
*pStream
= 0;
623 PresentationDataHeader pdh
;
627 CHAR strOleTypeName
[51];
628 BYTE OlePresStreamHeader
[] =
630 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
631 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
632 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
633 0x00, 0x00, 0x00, 0x00
636 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
638 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
639 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
641 pdh
.dwObjectExtentX
= mfp
->xExt
;
642 pdh
.dwObjectExtentY
= mfp
->yExt
;
645 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
647 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
649 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
650 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
652 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
654 IStream_Release(pStream
);
656 HeapFree(GetProcessHeap(), 0, mfBits
);
658 GlobalUnlock(std2
.u
.hGlobal
);
659 ReleaseStgMedium(&std2
);
661 ReadClassStg(std
.u
.pstg
, &clsID
);
662 ProgIDFromCLSID(&clsID
, &strProgID
);
664 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
665 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
666 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
667 CoTaskMemFree(strProgID
);
671 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
673 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
674 GlobalFree(hStorage
);
675 hr
= CLIPBRD_E_CANT_SET
;
678 ReleaseStgMedium(&std
);
682 /************************************************************************
683 * find_format_in_list
685 * Returns the first entry that matches the provided clipboard format.
687 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
690 for(i
= 0; i
< num
; i
++)
691 if(entries
[i
].fmtetc
.cfFormat
== cf
)
697 /***************************************************************************
698 * get_data_from_storage
700 * Returns storage data in an HGLOBAL.
702 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
713 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
714 if(!h
) return E_OUTOFMEMORY
;
716 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
719 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
720 ILockBytes_Release(lbs
);
729 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
731 med
.pUnkForRelease
= NULL
;
733 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
737 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
738 if(FAILED(hr
)) goto end
;
740 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
741 ReleaseStgMedium(&med
);
742 if(FAILED(hr
)) goto end
;
747 IStorage_Release(stg
);
748 if(FAILED(hr
)) GlobalFree(h
);
752 /***************************************************************************
753 * get_data_from_stream
755 * Returns stream data in an HGLOBAL.
757 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
767 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
768 if(!h
) return E_OUTOFMEMORY
;
770 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
771 if(FAILED(hr
)) goto error
;
774 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
776 med
.pUnkForRelease
= NULL
;
778 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
785 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
786 if(FAILED(hr
)) goto error
;
789 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
790 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
791 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
792 ReleaseStgMedium(&med
);
793 if(FAILED(hr
)) goto error
;
796 IStream_Release(stm
);
800 if(stm
) IStream_Release(stm
);
805 /***************************************************************************
806 * get_data_from_global
808 * Returns global data in an HGLOBAL.
810 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
820 mem_fmt
.tymed
= TYMED_HGLOBAL
;
822 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
823 if(FAILED(hr
)) return hr
;
825 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
827 if(SUCCEEDED(hr
)) *mem
= h
;
829 ReleaseStgMedium(&med
);
834 /***************************************************************************
835 * get_data_from_enhmetafile
837 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
847 mem_fmt
.tymed
= TYMED_ENHMF
;
849 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
850 if(FAILED(hr
)) return hr
;
852 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
853 if(copy
) *mem
= (HGLOBAL
)copy
;
856 ReleaseStgMedium(&med
);
861 /***************************************************************************
862 * get_data_from_metafilepict
864 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
874 mem_fmt
.tymed
= TYMED_MFPICT
;
876 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
877 if(FAILED(hr
)) return hr
;
879 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
881 if(SUCCEEDED(hr
)) *mem
= copy
;
883 ReleaseStgMedium(&med
);
888 /***************************************************************************
889 * get_data_from_bitmap
891 * Returns bitmap in an HBITMAP.
893 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
903 mem_fmt
.tymed
= TYMED_GDI
;
905 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
906 if(FAILED(hr
)) return hr
;
908 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
910 if(SUCCEEDED(hr
)) *hbm
= copy
;
912 ReleaseStgMedium(&med
);
917 /***********************************************************************
920 * Render the clipboard data. Note that this call will delegate to the
921 * source data object.
923 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
925 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
928 /* Embed source hack */
929 if(fmt
->cfFormat
== embed_source_clipboard_format
)
931 return render_embed_source_hack(data
, fmt
);
934 if(fmt
->tymed
& TYMED_ISTORAGE
)
936 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
938 else if(fmt
->tymed
& TYMED_ISTREAM
)
940 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
942 else if(fmt
->tymed
& TYMED_HGLOBAL
)
944 hr
= get_data_from_global(data
, fmt
, &clip_data
);
946 else if(fmt
->tymed
& TYMED_ENHMF
)
948 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
950 else if(fmt
->tymed
& TYMED_MFPICT
)
952 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
953 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
955 else if(fmt
->tymed
& TYMED_GDI
)
957 /* Returns HBITMAP not HGLOBAL */
958 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
962 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
968 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
970 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
971 if(fmt
->tymed
& TYMED_MFPICT
)
972 free_metafilepict(clip_data
);
973 else if(fmt
->tymed
& TYMED_GDI
)
974 DeleteObject(clip_data
);
976 GlobalFree(clip_data
);
977 hr
= CLIPBRD_E_CANT_SET
;
984 /*---------------------------------------------------------------------*
985 * Implementation of the internal IDataObject interface exposed by
987 *---------------------------------------------------------------------*/
990 /************************************************************************
991 * snapshot_QueryInterface
993 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
994 REFIID riid
, void **ppvObject
)
996 snapshot
*This
= impl_from_IDataObject(iface
);
997 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
999 if ( (This
==0) || (ppvObject
==0) )
1000 return E_INVALIDARG
;
1004 if (IsEqualIID(&IID_IUnknown
, riid
) ||
1005 IsEqualIID(&IID_IDataObject
, riid
))
1011 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1012 return E_NOINTERFACE
;
1015 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1020 /************************************************************************
1023 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1025 snapshot
*This
= impl_from_IDataObject(iface
);
1027 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1029 return InterlockedIncrement(&This
->ref
);
1032 /************************************************************************
1035 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1037 snapshot
*This
= impl_from_IDataObject(iface
);
1040 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1042 ref
= InterlockedDecrement(&This
->ref
);
1046 ole_clipbrd
*clipbrd
;
1047 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
1049 if(This
->data
) IDataObject_Release(This
->data
);
1051 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
1052 clipbrd
->latest_snapshot
= NULL
;
1053 HeapFree(GetProcessHeap(), 0, This
);
1059 /************************************************************
1060 * get_current_ole_clip_window
1062 * Return the window that owns the ole clipboard.
1064 * If the clipboard is flushed or not owned by ole this will
1067 static HWND
get_current_ole_clip_window(void)
1072 h
= GetClipboardData(dataobject_clipboard_format
);
1074 ptr
= GlobalLock(h
);
1075 if(!ptr
) return NULL
;
1081 /************************************************************
1082 * get_current_dataobject
1084 * Return an unmarshalled IDataObject if there is a current
1085 * (ie non-flushed) object on the ole clipboard.
1087 static HRESULT
get_current_dataobject(IDataObject
**data
)
1089 HRESULT hr
= S_FALSE
;
1090 HWND wnd
= get_current_ole_clip_window();
1097 if(!wnd
) return S_FALSE
;
1099 h
= GetClipboardData(wine_marshal_clipboard_format
);
1100 if(!h
) return S_FALSE
;
1101 if(GlobalSize(h
) == 0) return S_FALSE
;
1102 ptr
= GlobalLock(h
);
1103 if(!ptr
) return S_FALSE
;
1105 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1106 if(FAILED(hr
)) goto end
;
1108 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1112 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1113 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1115 IStream_Release(stm
);
1122 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1124 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1130 case CF_UNICODETEXT
:
1131 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1132 case CF_ENHMETAFILE
:
1134 case CF_METAFILEPICT
:
1135 return TYMED_MFPICT
;
1137 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1142 /***********************************************************
1145 * Returns a copy of the Ole Private Data
1147 static HRESULT
get_priv_data(ole_priv_data
**data
)
1151 ole_priv_data
*ret
= NULL
;
1155 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1158 ole_priv_data
*src
= GlobalLock(handle
);
1163 /* FIXME: sanity check on size */
1164 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1167 GlobalUnlock(handle
);
1168 return E_OUTOFMEMORY
;
1170 memcpy(ret
, src
, src
->size
);
1171 GlobalUnlock(handle
);
1173 /* Fixup any target device offsets to ptrs */
1174 for(i
= 0; i
< ret
->count
; i
++)
1175 ret
->entries
[i
].fmtetc
.ptd
=
1176 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1180 if(!ret
) /* Non-ole data */
1183 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1185 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1188 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1189 TRACE("cf %04x %s\n", cf
, buf
);
1191 TRACE("count %d\n", count
);
1192 size
+= count
* sizeof(ret
->entries
[0]);
1194 /* There are holes in fmtetc so zero init */
1195 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1196 if(!ret
) return E_OUTOFMEMORY
;
1200 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1202 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1203 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1204 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1205 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1206 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1207 ret
->entries
[idx
].first_use
= 1;
1215 /************************************************************************
1216 * get_stgmed_for_global
1218 * Returns a stg medium with a copy of the global handle
1220 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1224 med
->pUnkForRelease
= NULL
;
1225 med
->tymed
= TYMED_NULL
;
1227 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1229 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1234 /************************************************************************
1235 * get_stgmed_for_stream
1237 * Returns a stg medium with a stream based on the handle
1239 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1244 med
->pUnkForRelease
= NULL
;
1245 med
->tymed
= TYMED_NULL
;
1247 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1248 if(FAILED(hr
)) return hr
;
1250 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1257 med
->tymed
= TYMED_ISTREAM
;
1261 /************************************************************************
1262 * get_stgmed_for_storage
1264 * Returns a stg medium with a storage based on the handle
1266 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1272 med
->pUnkForRelease
= NULL
;
1273 med
->tymed
= TYMED_NULL
;
1275 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1276 if(FAILED(hr
)) return hr
;
1278 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1285 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1286 ILockBytes_Release(lbs
);
1293 med
->tymed
= TYMED_ISTORAGE
;
1297 /************************************************************************
1298 * get_stgmed_for_emf
1300 * Returns a stg medium with an enhanced metafile based on the handle
1302 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1304 med
->pUnkForRelease
= NULL
;
1305 med
->tymed
= TYMED_NULL
;
1307 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1308 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1309 med
->tymed
= TYMED_ENHMF
;
1313 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1315 const WCHAR
*str1
, *str2
;
1317 if(off1
== 0 && off2
== 0) return TRUE
;
1318 if(off1
== 0 || off2
== 0) return FALSE
;
1320 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1321 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1323 return !lstrcmpW(str1
, str2
);
1326 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1328 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1329 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1331 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1333 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1335 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1338 /* FIXME check devmode? */
1343 /************************************************************************
1346 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1349 snapshot
*This
= impl_from_IDataObject(iface
);
1352 ole_priv_data
*enum_data
= NULL
;
1353 ole_priv_data_entry
*entry
;
1356 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1358 if ( !fmt
|| !med
) return E_INVALIDARG
;
1360 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1363 hr
= get_current_dataobject(&This
->data
);
1367 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1372 h
= GetClipboardData(fmt
->cfFormat
);
1375 hr
= DV_E_FORMATETC
;
1379 hr
= get_priv_data(&enum_data
);
1380 if(FAILED(hr
)) goto end
;
1382 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1385 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1387 hr
= DV_E_FORMATETC
;
1390 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1391 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1393 else /* non-Ole format */
1394 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1396 if(mask
& TYMED_ISTORAGE
)
1397 hr
= get_stgmed_for_storage(h
, med
);
1398 else if(mask
& TYMED_HGLOBAL
)
1399 hr
= get_stgmed_for_global(h
, med
);
1400 else if(mask
& TYMED_ISTREAM
)
1401 hr
= get_stgmed_for_stream(h
, med
);
1402 else if(mask
& TYMED_ENHMF
)
1403 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1406 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1412 HeapFree(GetProcessHeap(), 0, enum_data
);
1413 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1417 /************************************************************************
1418 * snapshot_GetDataHere
1420 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1423 snapshot
*This
= impl_from_IDataObject(iface
);
1426 ole_priv_data
*enum_data
= NULL
;
1427 ole_priv_data_entry
*entry
;
1430 if ( !fmt
|| !med
) return E_INVALIDARG
;
1432 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1434 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1437 hr
= get_current_dataobject(&This
->data
);
1441 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1449 h
= GetClipboardData(fmt
->cfFormat
);
1452 hr
= DV_E_FORMATETC
;
1456 hr
= get_priv_data(&enum_data
);
1457 if(FAILED(hr
)) goto end
;
1459 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1462 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1464 hr
= DV_E_FORMATETC
;
1467 supported
= entry
->fmtetc
.tymed
;
1469 else /* non-Ole format */
1470 supported
= TYMED_HGLOBAL
;
1476 DWORD src_size
= GlobalSize(h
);
1477 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1479 if(dst_size
>= src_size
)
1481 void *src
= GlobalLock(h
);
1482 void *dst
= GlobalLock(med
->u
.hGlobal
);
1484 memcpy(dst
, src
, src_size
);
1485 GlobalUnlock(med
->u
.hGlobal
);
1493 DWORD src_size
= GlobalSize(h
);
1494 void *src
= GlobalLock(h
);
1495 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1499 case TYMED_ISTORAGE
:
1502 if(!(supported
& TYMED_ISTORAGE
))
1507 hr
= get_stgmed_for_storage(h
, ©
);
1510 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1511 ReleaseStgMedium(©
);
1516 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1522 HeapFree(GetProcessHeap(), 0, enum_data
);
1523 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1527 /************************************************************************
1528 * snapshot_QueryGetData
1530 * The OLE Clipboard's implementation of this method delegates to
1531 * a data source if there is one or wraps around the windows clipboard
1532 * function IsClipboardFormatAvailable() otherwise.
1535 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1537 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1539 if (!fmt
) return E_INVALIDARG
;
1541 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1543 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1545 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1548 /************************************************************************
1549 * snapshot_GetCanonicalFormatEtc
1551 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1554 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1556 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1559 return DATA_S_SAMEFORMATETC
;
1562 /************************************************************************
1565 * The OLE Clipboard does not implement this method
1567 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1568 STGMEDIUM
*med
, BOOL release
)
1570 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1574 /************************************************************************
1575 * snapshot_EnumFormatEtc
1578 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1579 IEnumFORMATETC
**enum_fmt
)
1582 ole_priv_data
*data
= NULL
;
1584 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1588 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1589 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1591 hr
= get_priv_data(&data
);
1593 if(FAILED(hr
)) goto end
;
1595 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1598 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1602 /************************************************************************
1605 * The OLE Clipboard does not implement this method
1607 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1608 DWORD flags
, IAdviseSink
*sink
,
1611 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1615 /************************************************************************
1616 * snapshot_DUnadvise
1618 * The OLE Clipboard does not implement this method
1620 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1622 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1626 /************************************************************************
1627 * snapshot_EnumDAdvise
1629 * The OLE Clipboard does not implement this method
1631 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1632 IEnumSTATDATA
** enum_advise
)
1634 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1638 static const IDataObjectVtbl snapshot_vtable
=
1640 snapshot_QueryInterface
,
1644 snapshot_GetDataHere
,
1645 snapshot_QueryGetData
,
1646 snapshot_GetCanonicalFormatEtc
,
1648 snapshot_EnumFormatEtc
,
1651 snapshot_EnumDAdvise
1654 /*---------------------------------------------------------------------*
1655 * Internal implementation methods for the OLE clipboard
1656 *---------------------------------------------------------------------*/
1658 static snapshot
*snapshot_construct(DWORD seq_no
)
1662 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1663 if (!This
) return NULL
;
1665 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1667 This
->seq_no
= seq_no
;
1673 /*********************************************************
1674 * register_clipboard_formats
1676 static void register_clipboard_formats(void)
1678 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1679 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1680 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1681 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1682 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1683 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1684 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1685 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1686 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1687 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1688 'D','e','s','c','r','i','p','t','o','r',0};
1689 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1691 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1692 'D','a','t','a','O','b','j','e','c','t',0};
1694 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1695 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1696 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1697 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1698 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1699 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1700 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1701 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1702 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1703 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1704 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1706 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1709 /***********************************************************************
1710 * OLEClipbrd_Initialize()
1711 * Initializes the OLE clipboard.
1713 void OLEClipbrd_Initialize(void)
1715 register_clipboard_formats();
1717 if ( !theOleClipboard
)
1719 ole_clipbrd
* clipbrd
;
1724 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1725 if (!clipbrd
) return;
1727 clipbrd
->latest_snapshot
= NULL
;
1728 clipbrd
->window
= NULL
;
1729 clipbrd
->src_data
= NULL
;
1730 clipbrd
->cached_enum
= NULL
;
1732 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1735 HeapFree(GetProcessHeap(), 0, clipbrd
);
1739 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1742 HeapFree(GetProcessHeap(), 0, clipbrd
);
1746 theOleClipboard
= clipbrd
;
1750 /***********************************************************************
1751 * OLEClipbrd_UnInitialize()
1752 * Un-Initializes the OLE clipboard
1754 void OLEClipbrd_UnInitialize(void)
1756 ole_clipbrd
*clipbrd
= theOleClipboard
;
1762 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1763 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1765 if ( clipbrd
->window
)
1767 DestroyWindow(clipbrd
->window
);
1768 UnregisterClassW( clipbrd_wndclass
, hinst
);
1771 IStream_Release(clipbrd
->marshal_data
);
1772 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1773 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1774 HeapFree(GetProcessHeap(), 0, clipbrd
);
1775 theOleClipboard
= NULL
;
1779 /*********************************************************************
1780 * set_clipboard_formats
1782 * Enumerate all formats supported by the source and make
1783 * those formats available using delayed rendering using SetClipboardData.
1784 * Cache the enumeration list and make that list visibile as the
1785 * 'Ole Private Data' format on the clipboard.
1788 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1792 IEnumFORMATETC
*enum_fmt
;
1793 HGLOBAL priv_data_handle
;
1794 DWORD_PTR target_offset
;
1795 ole_priv_data
*priv_data
;
1796 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1798 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1799 if(FAILED(hr
)) return hr
;
1801 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1804 needed
+= sizeof(priv_data
->entries
[0]);
1807 needed
+= fmt
.ptd
->tdSize
;
1808 CoTaskMemFree(fmt
.ptd
);
1812 /* Windows pads the list with two empty ole_priv_data_entries, one
1813 * after the entries array and one after the target device data.
1814 * Allocating with zero init to zero these pads. */
1816 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1817 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1818 priv_data
= GlobalLock(priv_data_handle
);
1820 priv_data
->unk1
= 0;
1821 priv_data
->size
= needed
;
1822 priv_data
->unk2
= 1;
1823 priv_data
->count
= count
;
1824 priv_data
->unk3
[0] = 0;
1825 priv_data
->unk3
[1] = 0;
1827 IEnumFORMATETC_Reset(enum_fmt
);
1830 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1832 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1834 TRACE("%s\n", dump_fmtetc(&fmt
));
1836 priv_data
->entries
[idx
].fmtetc
= fmt
;
1839 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1840 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1841 target_offset
+= fmt
.ptd
->tdSize
;
1842 CoTaskMemFree(fmt
.ptd
);
1845 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1846 priv_data
->entries
[idx
].unk
[0] = 0;
1847 priv_data
->entries
[idx
].unk
[1] = 0;
1849 if (priv_data
->entries
[idx
].first_use
)
1850 SetClipboardData(fmt
.cfFormat
, NULL
);
1855 IEnumFORMATETC_Release(enum_fmt
);
1857 /* Cache the list and fixup any target device offsets to ptrs */
1858 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1859 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1860 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1861 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1862 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1864 GlobalUnlock(priv_data_handle
);
1865 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1867 GlobalFree(priv_data_handle
);
1868 return CLIPBRD_E_CANT_SET
;
1874 static HWND
create_clipbrd_window(void);
1876 /***********************************************************************
1877 * get_clipbrd_window
1879 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1881 if ( !clipbrd
->window
)
1882 clipbrd
->window
= create_clipbrd_window();
1884 *wnd
= clipbrd
->window
;
1885 return *wnd
? S_OK
: E_FAIL
;
1889 /**********************************************************************
1890 * release_marshal_data
1892 * Releases the data and sets the stream back to zero size.
1894 static inline void release_marshal_data(IStream
*stm
)
1897 ULARGE_INTEGER size
;
1898 pos
.QuadPart
= size
.QuadPart
= 0;
1900 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1901 CoReleaseMarshalData(stm
);
1902 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1903 IStream_SetSize(stm
, size
);
1906 /***********************************************************************
1907 * expose_marshalled_dataobject
1909 * Sets the marshalled dataobject to the clipboard. In the flushed case
1910 * we set a zero sized HGLOBAL to clear the old marshalled data.
1912 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1919 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1920 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1923 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1925 if(!h
) return E_OUTOFMEMORY
;
1927 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1930 return CLIPBRD_E_CANT_SET
;
1935 /***********************************************************************
1936 * set_src_dataobject
1938 * Clears and sets the clipboard's src IDataObject.
1940 * To marshal the source dataobject we do something rather different from Windows.
1941 * We set a clipboard format which contains the marshalled data.
1942 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1944 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1949 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1951 if(clipbrd
->src_data
)
1953 release_marshal_data(clipbrd
->marshal_data
);
1955 IDataObject_Release(clipbrd
->src_data
);
1956 clipbrd
->src_data
= NULL
;
1957 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1958 clipbrd
->cached_enum
= NULL
;
1965 IDataObject_AddRef(data
);
1966 clipbrd
->src_data
= data
;
1968 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1969 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1970 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1971 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1972 if(FAILED(hr
)) return hr
;
1973 hr
= set_clipboard_formats(clipbrd
, data
);
1978 /***********************************************************************
1981 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1983 ole_clipbrd
*clipbrd
;
1985 get_ole_clipbrd(&clipbrd
);
1989 case WM_RENDERFORMAT
:
1992 ole_priv_data_entry
*entry
;
1994 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
1995 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
1998 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2003 case WM_RENDERALLFORMATS
:
2006 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
2008 TRACE("(): WM_RENDERALLFORMATS\n");
2010 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2012 if(entries
[i
].first_use
)
2013 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2018 case WM_DESTROYCLIPBOARD
:
2020 TRACE("(): WM_DESTROYCLIPBOARD\n");
2022 set_src_dataobject(clipbrd
, NULL
);
2027 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2034 /***********************************************************************
2035 * create_clipbrd_window
2037 static HWND
create_clipbrd_window(void)
2040 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2041 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2042 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2044 class.cbSize
= sizeof(class);
2046 class.lpfnWndProc
= clipbrd_wndproc
;
2047 class.cbClsExtra
= 0;
2048 class.cbWndExtra
= 0;
2049 class.hInstance
= hinst
;
2052 class.hbrBackground
= 0;
2053 class.lpszMenuName
= NULL
;
2054 class.lpszClassName
= clipbrd_wndclass
;
2055 class.hIconSm
= NULL
;
2057 RegisterClassExW(&class);
2059 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2060 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2061 NULL
, NULL
, hinst
, 0);
2064 /*********************************************************************
2065 * set_dataobject_format
2067 * Windows creates a 'DataObject' clipboard format that contains the
2068 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2070 static HRESULT
set_dataobject_format(HWND hwnd
)
2072 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2075 if(!h
) return E_OUTOFMEMORY
;
2077 data
= GlobalLock(h
);
2081 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2084 return CLIPBRD_E_CANT_SET
;
2090 /*---------------------------------------------------------------------*
2091 * Win32 OLE clipboard API
2092 *---------------------------------------------------------------------*/
2094 /***********************************************************************
2095 * OleSetClipboard [OLE32.@]
2096 * Places a pointer to the specified data object onto the clipboard,
2097 * making the data object accessible to the OleGetClipboard function.
2101 * S_OK IDataObject pointer placed on the clipboard
2102 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2103 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2104 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2105 * CLIPBRD_E_CANT_SET SetClipboard failed
2108 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2111 ole_clipbrd
*clipbrd
;
2114 TRACE("(%p)\n", data
);
2116 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2118 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2120 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2122 if ( !EmptyClipboard() )
2124 hr
= CLIPBRD_E_CANT_EMPTY
;
2128 hr
= set_src_dataobject(clipbrd
, data
);
2129 if(FAILED(hr
)) goto end
;
2133 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2134 if(FAILED(hr
)) goto end
;
2135 hr
= set_dataobject_format(wnd
);
2140 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2144 expose_marshalled_dataobject(clipbrd
, NULL
);
2145 set_src_dataobject(clipbrd
, NULL
);
2152 /***********************************************************************
2153 * OleGetClipboard [OLE32.@]
2154 * Returns a pointer to our internal IDataObject which represents the conceptual
2155 * state of the Windows clipboard. If the current clipboard already contains
2156 * an IDataObject, our internal IDataObject will delegate to this object.
2158 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2161 ole_clipbrd
*clipbrd
;
2164 TRACE("(%p)\n", obj
);
2166 if(!obj
) return E_INVALIDARG
;
2168 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2170 seq_no
= GetClipboardSequenceNumber();
2171 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2172 clipbrd
->latest_snapshot
= NULL
;
2174 if(!clipbrd
->latest_snapshot
)
2176 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2177 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
2180 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2181 IDataObject_AddRef(*obj
);
2186 /******************************************************************************
2187 * OleFlushClipboard [OLE32.@]
2188 * Renders the data from the source IDataObject into the windows clipboard
2190 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2191 * by copying the storage into global memory. Subsequently the default
2192 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2193 * back to TYMED_IStorage.
2195 HRESULT WINAPI
OleFlushClipboard(void)
2198 ole_clipbrd
*clipbrd
;
2203 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2205 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2208 * Already flushed or no source DataObject? Nothing to do.
2210 if (!clipbrd
->src_data
) return S_OK
;
2212 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2214 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2216 hr
= set_dataobject_format(NULL
);
2218 expose_marshalled_dataobject(clipbrd
, NULL
);
2219 set_src_dataobject(clipbrd
, NULL
);
2221 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2227 /***********************************************************************
2228 * OleIsCurrentClipboard [OLE32.@]
2230 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2233 ole_clipbrd
*clipbrd
;
2236 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2238 if (data
== NULL
) return S_FALSE
;
2240 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;