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 /* Structure of 'Ole Private Data' clipboard format */
70 DWORD first_use
; /* Has this cf been added to the list already */
72 } ole_priv_data_entry
;
77 DWORD size
; /* in bytes of the entire structure */
79 DWORD count
; /* no. of format entries */
81 ole_priv_data_entry entries
[1]; /* array of size count */
82 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
85 /*****************************************************************************
88 * Returns a ptr to a target device at a given offset from the
89 * start of the ole_priv_data.
91 * Used when unpacking ole private data from the clipboard.
93 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
95 if(off
== 0) return NULL
;
96 return (DVTARGETDEVICE
*)((char*)data
+ off
);
99 /*****************************************************************************
102 * Get the offset from the start of the ole_priv_data of the idx'th
105 * Used when packing ole private data to the clipboard.
107 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
109 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
110 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
113 /****************************************************************************
114 * Consumer snapshot. Represents the state of the ole clipboard
115 * returned by OleGetClipboard().
117 typedef struct snapshot
119 IDataObject IDataObject_iface
;
122 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
124 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
127 /****************************************************************************
130 typedef struct ole_clipbrd
132 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
134 HWND window
; /* Hidden clipboard window */
135 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
136 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
137 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
140 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
142 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
145 typedef struct PresentationDataHeader
148 DWORD dwObjectExtentX
;
149 DWORD dwObjectExtentY
;
151 } PresentationDataHeader
;
154 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
156 static ole_clipbrd
* theOleClipboard
;
158 static CRITICAL_SECTION latest_snapshot_cs
;
159 static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug
=
161 0, 0, &latest_snapshot_cs
,
162 { &latest_snapshot_cs_debug
.ProcessLocksList
, &latest_snapshot_cs_debug
.ProcessLocksList
},
163 0, 0, { (DWORD_PTR
)(__FILE__
": clipboard last snapshot") }
165 static CRITICAL_SECTION latest_snapshot_cs
= { &latest_snapshot_cs_debug
, -1, 0, 0, 0, 0 };
167 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
169 struct oletls
*info
= COM_CurrentInfo();
173 return CO_E_NOTINITIALIZED
;
174 *clipbrd
= theOleClipboard
;
180 * Name of our registered OLE clipboard window class
182 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
184 UINT ownerlink_clipboard_format
= 0;
185 UINT filename_clipboard_format
= 0;
186 UINT filenameW_clipboard_format
= 0;
187 UINT dataobject_clipboard_format
= 0;
188 UINT embedded_object_clipboard_format
= 0;
189 UINT embed_source_clipboard_format
= 0;
190 UINT custom_link_source_clipboard_format
= 0;
191 UINT link_source_clipboard_format
= 0;
192 UINT object_descriptor_clipboard_format
= 0;
193 UINT link_source_descriptor_clipboard_format
= 0;
194 UINT ole_private_data_clipboard_format
= 0;
196 static UINT wine_marshal_clipboard_format
;
198 static inline const char *dump_fmtetc(FORMATETC
*fmt
)
200 if (!fmt
) return "(null)";
201 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
202 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
205 /*---------------------------------------------------------------------*
206 * Implementation of the internal IEnumFORMATETC interface returned by
207 * the OLE clipboard's IDataObject.
208 *---------------------------------------------------------------------*/
210 typedef struct enum_fmtetc
212 IEnumFORMATETC IEnumFORMATETC_iface
;
215 UINT pos
; /* current enumerator position */
219 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
221 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
224 /************************************************************************
225 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
227 * See Windows documentation for more details on IUnknown methods.
229 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
230 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
232 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
234 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
238 if(IsEqualIID(riid
, &IID_IUnknown
) ||
239 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
246 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
247 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
251 TRACE("-- Interface: E_NOINTERFACE\n");
252 return E_NOINTERFACE
;
255 /************************************************************************
256 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
259 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
261 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
262 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
264 return InterlockedIncrement(&This
->ref
);
267 /************************************************************************
268 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
270 * See Windows documentation for more details on IUnknown methods.
272 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
274 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
277 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
279 ref
= InterlockedDecrement(&This
->ref
);
282 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
283 HeapFree(GetProcessHeap(), 0, This
->data
);
284 HeapFree(GetProcessHeap(), 0, This
);
289 /************************************************************************
290 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
292 * Standard enumerator members for IEnumFORMATETC
294 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
295 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
297 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
299 HRESULT hres
= S_FALSE
;
301 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
303 if (This
->pos
< This
->data
->count
)
305 cfetch
= This
->data
->count
- This
->pos
;
312 for(i
= 0; i
< cfetch
; i
++)
314 hres
= copy_formatetc(rgelt
+ i
, &This
->data
->entries
[This
->pos
++].fmtetc
);
315 if(FAILED(hres
)) return hres
;
325 *pceltFethed
= cfetch
;
331 /************************************************************************
332 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
334 * Standard enumerator members for IEnumFORMATETC
336 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
338 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
339 TRACE("(%p)->(num=%u)\n", This
, celt
);
342 if (This
->pos
> This
->data
->count
)
344 This
->pos
= This
->data
->count
;
350 /************************************************************************
351 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
353 * Standard enumerator members for IEnumFORMATETC
355 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
357 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
358 TRACE("(%p)->()\n", This
);
364 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
366 /************************************************************************
367 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
369 * Standard enumerator members for IEnumFORMATETC
371 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
372 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
374 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
375 ole_priv_data
*new_data
;
378 TRACE("(%p)->(%p)\n", This
, obj
);
380 if ( !obj
) return E_INVALIDARG
;
383 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
384 if(!new_data
) return E_OUTOFMEMORY
;
385 memcpy(new_data
, This
->data
, This
->data
->size
);
387 /* Fixup any target device ptrs */
388 for(i
= 0; i
< This
->data
->count
; i
++)
389 new_data
->entries
[i
].fmtetc
.ptd
=
390 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
392 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
395 static const IEnumFORMATETCVtbl efvt
=
397 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
398 OLEClipbrd_IEnumFORMATETC_AddRef
,
399 OLEClipbrd_IEnumFORMATETC_Release
,
400 OLEClipbrd_IEnumFORMATETC_Next
,
401 OLEClipbrd_IEnumFORMATETC_Skip
,
402 OLEClipbrd_IEnumFORMATETC_Reset
,
403 OLEClipbrd_IEnumFORMATETC_Clone
406 /************************************************************************
407 * enum_fmtetc_construct
409 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
411 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
416 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
417 if (!ef
) return E_OUTOFMEMORY
;
420 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
424 TRACE("(%p)->()\n", ef
);
425 *obj
= &ef
->IEnumFORMATETC_iface
;
429 /***********************************************************************
432 * Helper method to duplicate an HGLOBAL chunk of memory
434 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
436 void *src_ptr
, *dst_ptr
;
440 if ( !src
) return S_FALSE
;
442 size
= GlobalSize(src
);
444 *dst
= GlobalAlloc( flags
, size
);
445 if ( !*dst
) return E_OUTOFMEMORY
;
447 src_ptr
= GlobalLock(src
);
448 dst_ptr
= GlobalLock(*dst
);
450 memcpy(dst_ptr
, src_ptr
, size
);
458 /***********************************************************************
461 * Helper function to duplicate a handle to a METAFILEPICT, and the
462 * contained HMETAFILE.
464 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
468 METAFILEPICT
*dest_ptr
;
472 /* Copy the METAFILEPICT structure. */
473 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
474 if (FAILED(hr
)) return hr
;
476 dest_ptr
= GlobalLock(dest
);
477 if (!dest_ptr
) return E_FAIL
;
479 /* Give the new METAFILEPICT a separate HMETAFILE. */
480 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
495 /***********************************************************************
498 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
499 * free the contained HMETAFILE.
501 static void free_metafilepict(HGLOBAL src
)
503 METAFILEPICT
*src_ptr
;
505 src_ptr
= GlobalLock(src
);
508 DeleteMetaFile(src_ptr
->hMF
);
514 /***********************************************************************
517 * Helper function to duplicate an HBITMAP.
519 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
522 HGDIOBJ orig_src_bitmap
;
526 src_dc
= CreateCompatibleDC(NULL
);
527 orig_src_bitmap
= SelectObject(src_dc
, src
);
528 GetObjectW(src
, sizeof bm
, &bm
);
529 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
532 HDC dest_dc
= CreateCompatibleDC(NULL
);
533 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
534 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
535 SelectObject(dest_dc
, orig_dest_bitmap
);
538 SelectObject(src_dc
, orig_src_bitmap
);
541 return dest
? S_OK
: E_FAIL
;
544 /************************************************************
545 * render_embed_source_hack
547 * This is clearly a hack and has no place in the clipboard code.
550 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
553 HGLOBAL hStorage
= 0;
555 ILockBytes
*ptrILockBytes
;
557 memset(&std
, 0, sizeof(STGMEDIUM
));
558 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
560 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
561 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
562 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
565 GlobalFree(hStorage
);
569 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
570 ILockBytes_Release(ptrILockBytes
);
572 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
574 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
575 GlobalFree(hStorage
);
579 if (1) /* check whether the presentation data is already -not- present */
583 METAFILEPICT
*mfp
= 0;
585 fmt2
.cfFormat
= CF_METAFILEPICT
;
587 fmt2
.dwAspect
= DVASPECT_CONTENT
;
589 fmt2
.tymed
= TYMED_MFPICT
;
591 memset(&std2
, 0, sizeof(STGMEDIUM
));
592 std2
.tymed
= TYMED_MFPICT
;
594 /* Get the metafile picture out of it */
596 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
598 mfp
= GlobalLock(std2
.u
.hGlobal
);
603 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
604 IStream
*pStream
= 0;
606 PresentationDataHeader pdh
;
610 CHAR strOleTypeName
[51];
611 BYTE OlePresStreamHeader
[] =
613 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
614 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
615 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00
619 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
621 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
622 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
624 pdh
.dwObjectExtentX
= mfp
->xExt
;
625 pdh
.dwObjectExtentY
= mfp
->yExt
;
628 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
630 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
632 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
633 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
635 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
637 IStream_Release(pStream
);
639 HeapFree(GetProcessHeap(), 0, mfBits
);
641 GlobalUnlock(std2
.u
.hGlobal
);
642 ReleaseStgMedium(&std2
);
644 ReadClassStg(std
.u
.pstg
, &clsID
);
645 ProgIDFromCLSID(&clsID
, &strProgID
);
647 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
648 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
649 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
650 CoTaskMemFree(strProgID
);
654 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
656 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
657 GlobalFree(hStorage
);
658 hr
= CLIPBRD_E_CANT_SET
;
661 ReleaseStgMedium(&std
);
665 /************************************************************************
666 * find_format_in_list
668 * Returns the first entry that matches the provided clipboard format.
670 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
673 for(i
= 0; i
< num
; i
++)
674 if(entries
[i
].fmtetc
.cfFormat
== cf
)
680 /***************************************************************************
681 * get_data_from_storage
683 * Returns storage data in an HGLOBAL.
685 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
696 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
697 if(!h
) return E_OUTOFMEMORY
;
699 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
702 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
703 ILockBytes_Release(lbs
);
712 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
714 med
.pUnkForRelease
= NULL
;
716 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
719 memset(&med
, 0, sizeof(med
));
720 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
721 if(FAILED(hr
)) goto end
;
723 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
724 ReleaseStgMedium(&med
);
725 if(FAILED(hr
)) goto end
;
730 IStorage_Release(stg
);
731 if(FAILED(hr
)) GlobalFree(h
);
735 /***************************************************************************
736 * get_data_from_stream
738 * Returns stream data in an HGLOBAL.
740 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
750 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
751 if(!h
) return E_OUTOFMEMORY
;
753 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
754 if(FAILED(hr
)) goto error
;
757 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
759 med
.pUnkForRelease
= NULL
;
761 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
767 memset(&med
, 0, sizeof(med
));
768 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
769 if(FAILED(hr
)) goto error
;
772 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
773 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
774 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
775 ReleaseStgMedium(&med
);
776 if(FAILED(hr
)) goto error
;
779 IStream_Release(stm
);
783 if(stm
) IStream_Release(stm
);
788 /***************************************************************************
789 * get_data_from_global
791 * Returns global data in an HGLOBAL.
793 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
803 mem_fmt
.tymed
= TYMED_HGLOBAL
;
804 memset(&med
, 0, sizeof(med
));
806 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
807 if(FAILED(hr
)) return hr
;
809 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
811 if(SUCCEEDED(hr
)) *mem
= h
;
813 ReleaseStgMedium(&med
);
818 /***************************************************************************
819 * get_data_from_enhmetafile
821 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
831 mem_fmt
.tymed
= TYMED_ENHMF
;
832 memset(&med
, 0, sizeof(med
));
834 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
835 if(FAILED(hr
)) return hr
;
837 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
838 if(copy
) *mem
= (HGLOBAL
)copy
;
841 ReleaseStgMedium(&med
);
846 /***************************************************************************
847 * get_data_from_metafilepict
849 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
859 mem_fmt
.tymed
= TYMED_MFPICT
;
860 memset(&med
, 0, sizeof(med
));
862 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
863 if(FAILED(hr
)) return hr
;
865 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
867 if(SUCCEEDED(hr
)) *mem
= copy
;
869 ReleaseStgMedium(&med
);
874 /***************************************************************************
875 * get_data_from_bitmap
877 * Returns bitmap in an HBITMAP.
879 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
889 mem_fmt
.tymed
= TYMED_GDI
;
890 memset(&med
, 0, sizeof(med
));
892 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
893 if(FAILED(hr
)) return hr
;
895 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
897 if(SUCCEEDED(hr
)) *hbm
= copy
;
899 ReleaseStgMedium(&med
);
904 /***********************************************************************
907 * Render the clipboard data. Note that this call will delegate to the
908 * source data object.
910 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
912 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
915 /* Embed source hack */
916 if(fmt
->cfFormat
== embed_source_clipboard_format
)
918 return render_embed_source_hack(data
, fmt
);
921 if(fmt
->tymed
& TYMED_ISTORAGE
)
923 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
925 else if(fmt
->tymed
& TYMED_ISTREAM
)
927 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
929 else if(fmt
->tymed
& TYMED_HGLOBAL
)
931 hr
= get_data_from_global(data
, fmt
, &clip_data
);
933 else if(fmt
->tymed
& TYMED_ENHMF
)
935 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
937 else if(fmt
->tymed
& TYMED_MFPICT
)
939 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
940 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
942 else if(fmt
->tymed
& TYMED_GDI
)
944 /* Returns HBITMAP not HGLOBAL */
945 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
949 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
955 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
957 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
958 if(fmt
->tymed
& TYMED_MFPICT
)
959 free_metafilepict(clip_data
);
960 else if(fmt
->tymed
& TYMED_GDI
)
961 DeleteObject(clip_data
);
963 GlobalFree(clip_data
);
964 hr
= CLIPBRD_E_CANT_SET
;
971 /*---------------------------------------------------------------------*
972 * Implementation of the internal IDataObject interface exposed by
974 *---------------------------------------------------------------------*/
977 /************************************************************************
978 * snapshot_QueryInterface
980 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
981 REFIID riid
, void **ppvObject
)
983 snapshot
*This
= impl_from_IDataObject(iface
);
984 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
986 if ( (This
==0) || (ppvObject
==0) )
991 if (IsEqualIID(&IID_IUnknown
, riid
) ||
992 IsEqualIID(&IID_IDataObject
, riid
))
998 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
999 return E_NOINTERFACE
;
1002 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1007 /************************************************************************
1010 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1012 snapshot
*This
= impl_from_IDataObject(iface
);
1014 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1016 return InterlockedIncrement(&This
->ref
);
1019 /************************************************************************
1022 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1024 snapshot
*This
= impl_from_IDataObject(iface
);
1027 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1029 ref
= InterlockedDecrement(&This
->ref
);
1033 EnterCriticalSection(&latest_snapshot_cs
);
1036 LeaveCriticalSection(&latest_snapshot_cs
);
1039 if (theOleClipboard
->latest_snapshot
== This
)
1040 theOleClipboard
->latest_snapshot
= NULL
;
1041 LeaveCriticalSection(&latest_snapshot_cs
);
1043 if(This
->data
) IDataObject_Release(This
->data
);
1044 HeapFree(GetProcessHeap(), 0, This
);
1050 /************************************************************
1051 * get_current_ole_clip_window
1053 * Return the window that owns the ole clipboard.
1055 * If the clipboard is flushed or not owned by ole this will
1058 static HWND
get_current_ole_clip_window(void)
1063 h
= GetClipboardData(dataobject_clipboard_format
);
1065 ptr
= GlobalLock(h
);
1066 if(!ptr
) return NULL
;
1072 /************************************************************
1073 * get_current_dataobject
1075 * Return an unmarshalled IDataObject if there is a current
1076 * (ie non-flushed) object on the ole clipboard.
1078 static HRESULT
get_current_dataobject(IDataObject
**data
)
1080 HRESULT hr
= S_FALSE
;
1081 HWND wnd
= get_current_ole_clip_window();
1088 if(!wnd
) return S_FALSE
;
1090 h
= GetClipboardData(wine_marshal_clipboard_format
);
1091 if(!h
) return S_FALSE
;
1092 if(GlobalSize(h
) <= 1) return S_FALSE
;
1093 ptr
= GlobalLock(h
);
1094 if(!ptr
) return S_FALSE
;
1096 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1097 if(FAILED(hr
)) goto end
;
1099 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1103 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1104 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1106 IStream_Release(stm
);
1113 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1115 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1121 case CF_UNICODETEXT
:
1122 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1123 case CF_ENHMETAFILE
:
1125 case CF_METAFILEPICT
:
1126 return TYMED_MFPICT
;
1130 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1135 /***********************************************************
1138 * Returns a copy of the Ole Private Data
1140 static HRESULT
get_priv_data(ole_priv_data
**data
)
1144 ole_priv_data
*ret
= NULL
;
1148 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1151 ole_priv_data
*src
= GlobalLock(handle
);
1156 /* FIXME: sanity check on size */
1157 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1160 GlobalUnlock(handle
);
1161 return E_OUTOFMEMORY
;
1163 memcpy(ret
, src
, src
->size
);
1164 GlobalUnlock(handle
);
1166 /* Fixup any target device offsets to ptrs */
1167 for(i
= 0; i
< ret
->count
; i
++)
1168 ret
->entries
[i
].fmtetc
.ptd
=
1169 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1173 if(!ret
) /* Non-ole data */
1176 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1178 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1181 if (GetClipboardFormatNameW(cf
, buf
, sizeof(buf
) / sizeof(WCHAR
)))
1182 TRACE("cf %04x %s\n", cf
, debugstr_w(buf
));
1184 TRACE("cf %04x\n", cf
);
1186 TRACE("count %d\n", count
);
1187 size
+= count
* sizeof(ret
->entries
[0]);
1189 /* There are holes in fmtetc so zero init */
1190 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1191 if(!ret
) return E_OUTOFMEMORY
;
1195 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1197 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1198 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1199 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1200 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1201 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1202 ret
->entries
[idx
].first_use
= 1;
1210 /************************************************************************
1211 * get_stgmed_for_global
1213 * Returns a stg medium with a copy of the global handle
1215 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1219 med
->pUnkForRelease
= NULL
;
1220 med
->tymed
= TYMED_NULL
;
1222 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1224 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1229 /************************************************************************
1230 * get_stgmed_for_stream
1232 * Returns a stg medium with a stream based on the handle
1234 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1239 med
->pUnkForRelease
= NULL
;
1240 med
->tymed
= TYMED_NULL
;
1242 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1243 if(FAILED(hr
)) return hr
;
1245 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1252 med
->tymed
= TYMED_ISTREAM
;
1256 /************************************************************************
1257 * get_stgmed_for_storage
1259 * Returns a stg medium with a storage based on the handle
1261 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1267 med
->pUnkForRelease
= NULL
;
1268 med
->tymed
= TYMED_NULL
;
1270 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1271 if(FAILED(hr
)) return hr
;
1273 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1280 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1281 ILockBytes_Release(lbs
);
1288 med
->tymed
= TYMED_ISTORAGE
;
1292 /************************************************************************
1293 * get_stgmed_for_emf
1295 * Returns a stg medium with an enhanced metafile based on the handle
1297 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1299 med
->pUnkForRelease
= NULL
;
1300 med
->tymed
= TYMED_NULL
;
1302 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1303 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1304 med
->tymed
= TYMED_ENHMF
;
1308 /************************************************************************
1309 * get_stgmed_for_bitmap
1311 * Returns a stg medium with a bitmap based on the handle
1313 static HRESULT
get_stgmed_for_bitmap(HBITMAP hbmp
, STGMEDIUM
*med
)
1317 med
->pUnkForRelease
= NULL
;
1318 med
->tymed
= TYMED_NULL
;
1320 hr
= dup_bitmap(hbmp
, &med
->u
.hBitmap
);
1325 med
->tymed
= TYMED_GDI
;
1329 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1331 const WCHAR
*str1
, *str2
;
1333 if(off1
== 0 && off2
== 0) return TRUE
;
1334 if(off1
== 0 || off2
== 0) return FALSE
;
1336 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1337 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1339 return !lstrcmpW(str1
, str2
);
1342 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1344 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1345 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1347 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1349 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1351 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1354 /* FIXME check devmode? */
1359 /************************************************************************
1362 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1365 snapshot
*This
= impl_from_IDataObject(iface
);
1368 ole_priv_data
*enum_data
= NULL
;
1369 ole_priv_data_entry
*entry
;
1372 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1374 if ( !fmt
|| !med
) return E_INVALIDARG
;
1376 memset(med
, 0, sizeof(*med
));
1378 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1381 hr
= get_current_dataobject(&This
->data
);
1385 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1390 h
= GetClipboardData(fmt
->cfFormat
);
1393 hr
= DV_E_FORMATETC
;
1397 hr
= get_priv_data(&enum_data
);
1398 if(FAILED(hr
)) goto end
;
1400 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1403 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1405 hr
= DV_E_FORMATETC
;
1408 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1409 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1411 else /* non-Ole format */
1412 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1414 if(mask
& TYMED_ISTORAGE
)
1415 hr
= get_stgmed_for_storage(h
, med
);
1416 else if(mask
& TYMED_HGLOBAL
)
1417 hr
= get_stgmed_for_global(h
, med
);
1418 else if(mask
& TYMED_ISTREAM
)
1419 hr
= get_stgmed_for_stream(h
, med
);
1420 else if(mask
& TYMED_ENHMF
)
1421 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1422 else if(mask
& TYMED_GDI
)
1423 hr
= get_stgmed_for_bitmap((HBITMAP
)h
, med
);
1426 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1432 HeapFree(GetProcessHeap(), 0, enum_data
);
1433 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1437 /************************************************************************
1438 * snapshot_GetDataHere
1440 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1443 snapshot
*This
= impl_from_IDataObject(iface
);
1446 ole_priv_data
*enum_data
= NULL
;
1447 ole_priv_data_entry
*entry
;
1450 if ( !fmt
|| !med
) return E_INVALIDARG
;
1452 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1454 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1457 hr
= get_current_dataobject(&This
->data
);
1461 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1469 h
= GetClipboardData(fmt
->cfFormat
);
1472 hr
= DV_E_FORMATETC
;
1476 hr
= get_priv_data(&enum_data
);
1477 if(FAILED(hr
)) goto end
;
1479 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1482 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1484 hr
= DV_E_FORMATETC
;
1487 supported
= entry
->fmtetc
.tymed
;
1489 else /* non-Ole format */
1490 supported
= TYMED_HGLOBAL
;
1496 DWORD src_size
= GlobalSize(h
);
1497 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1499 if(dst_size
>= src_size
)
1501 void *src
= GlobalLock(h
);
1502 void *dst
= GlobalLock(med
->u
.hGlobal
);
1504 memcpy(dst
, src
, src_size
);
1505 GlobalUnlock(med
->u
.hGlobal
);
1513 DWORD src_size
= GlobalSize(h
);
1514 void *src
= GlobalLock(h
);
1515 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1519 case TYMED_ISTORAGE
:
1522 if(!(supported
& TYMED_ISTORAGE
))
1527 hr
= get_stgmed_for_storage(h
, ©
);
1530 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1531 ReleaseStgMedium(©
);
1536 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1542 HeapFree(GetProcessHeap(), 0, enum_data
);
1543 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1547 /************************************************************************
1548 * snapshot_QueryGetData
1550 * The OLE Clipboard's implementation of this method delegates to
1551 * a data source if there is one or wraps around the windows clipboard
1552 * function IsClipboardFormatAvailable() otherwise.
1555 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1557 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1559 if (!fmt
) return E_INVALIDARG
;
1561 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1563 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1565 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1568 /************************************************************************
1569 * snapshot_GetCanonicalFormatEtc
1571 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1574 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1576 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1579 return DATA_S_SAMEFORMATETC
;
1582 /************************************************************************
1585 * The OLE Clipboard does not implement this method
1587 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1588 STGMEDIUM
*med
, BOOL release
)
1590 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1594 /************************************************************************
1595 * snapshot_EnumFormatEtc
1598 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1599 IEnumFORMATETC
**enum_fmt
)
1602 ole_priv_data
*data
= NULL
;
1604 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1608 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1609 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1611 hr
= get_priv_data(&data
);
1613 if(FAILED(hr
)) goto end
;
1615 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1618 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1622 /************************************************************************
1625 * The OLE Clipboard does not implement this method
1627 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1628 DWORD flags
, IAdviseSink
*sink
,
1631 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1635 /************************************************************************
1636 * snapshot_DUnadvise
1638 * The OLE Clipboard does not implement this method
1640 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1642 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1646 /************************************************************************
1647 * snapshot_EnumDAdvise
1649 * The OLE Clipboard does not implement this method
1651 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1652 IEnumSTATDATA
** enum_advise
)
1654 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1658 static const IDataObjectVtbl snapshot_vtable
=
1660 snapshot_QueryInterface
,
1664 snapshot_GetDataHere
,
1665 snapshot_QueryGetData
,
1666 snapshot_GetCanonicalFormatEtc
,
1668 snapshot_EnumFormatEtc
,
1671 snapshot_EnumDAdvise
1674 /*---------------------------------------------------------------------*
1675 * Internal implementation methods for the OLE clipboard
1676 *---------------------------------------------------------------------*/
1678 static snapshot
*snapshot_construct(DWORD seq_no
)
1682 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1683 if (!This
) return NULL
;
1685 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1687 This
->seq_no
= seq_no
;
1693 /*********************************************************
1694 * register_clipboard_formats
1696 static void register_clipboard_formats(void)
1698 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1699 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1700 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1701 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1702 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1703 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1704 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1705 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1706 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1707 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1708 'D','e','s','c','r','i','p','t','o','r',0};
1709 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1711 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1712 'D','a','t','a','O','b','j','e','c','t',0};
1714 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1715 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1716 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1717 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1718 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1719 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1720 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1721 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1722 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1723 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1724 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1726 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1729 /***********************************************************************
1730 * OLEClipbrd_Initialize()
1731 * Initializes the OLE clipboard.
1733 void OLEClipbrd_Initialize(void)
1735 register_clipboard_formats();
1737 if ( !theOleClipboard
)
1739 ole_clipbrd
* clipbrd
;
1744 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1745 if (!clipbrd
) return;
1747 clipbrd
->latest_snapshot
= NULL
;
1748 clipbrd
->window
= NULL
;
1749 clipbrd
->src_data
= NULL
;
1750 clipbrd
->cached_enum
= NULL
;
1752 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1755 HeapFree(GetProcessHeap(), 0, clipbrd
);
1759 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1762 HeapFree(GetProcessHeap(), 0, clipbrd
);
1766 theOleClipboard
= clipbrd
;
1770 /*********************************************************************
1771 * set_clipboard_formats
1773 * Enumerate all formats supported by the source and make
1774 * those formats available using delayed rendering using SetClipboardData.
1775 * Cache the enumeration list and make that list visible as the
1776 * 'Ole Private Data' format on the clipboard.
1779 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1783 IEnumFORMATETC
*enum_fmt
;
1784 HGLOBAL priv_data_handle
;
1785 DWORD_PTR target_offset
;
1786 ole_priv_data
*priv_data
;
1787 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1789 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1790 if(FAILED(hr
)) return hr
;
1792 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1795 needed
+= sizeof(priv_data
->entries
[0]);
1798 needed
+= fmt
.ptd
->tdSize
;
1799 CoTaskMemFree(fmt
.ptd
);
1803 /* Windows pads the list with two empty ole_priv_data_entries, one
1804 * after the entries array and one after the target device data.
1805 * Allocating with zero init to zero these pads. */
1807 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1808 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1809 priv_data
= GlobalLock(priv_data_handle
);
1811 priv_data
->unk1
= 0;
1812 priv_data
->size
= needed
;
1813 priv_data
->unk2
= 1;
1814 priv_data
->count
= count
;
1815 priv_data
->unk3
[0] = 0;
1816 priv_data
->unk3
[1] = 0;
1818 IEnumFORMATETC_Reset(enum_fmt
);
1821 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1823 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1825 TRACE("%s\n", dump_fmtetc(&fmt
));
1827 priv_data
->entries
[idx
].fmtetc
= fmt
;
1830 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1831 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1832 target_offset
+= fmt
.ptd
->tdSize
;
1833 CoTaskMemFree(fmt
.ptd
);
1836 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1837 priv_data
->entries
[idx
].unk
[0] = 0;
1838 priv_data
->entries
[idx
].unk
[1] = 0;
1840 if (priv_data
->entries
[idx
].first_use
)
1841 SetClipboardData(fmt
.cfFormat
, NULL
);
1846 IEnumFORMATETC_Release(enum_fmt
);
1848 /* Cache the list and fixup any target device offsets to ptrs */
1849 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1850 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1851 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1852 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1853 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1855 GlobalUnlock(priv_data_handle
);
1856 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1858 GlobalFree(priv_data_handle
);
1859 return CLIPBRD_E_CANT_SET
;
1865 static HWND
create_clipbrd_window(void);
1867 /***********************************************************************
1868 * get_clipbrd_window
1870 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1872 if ( !clipbrd
->window
)
1873 clipbrd
->window
= create_clipbrd_window();
1875 *wnd
= clipbrd
->window
;
1876 return *wnd
? S_OK
: E_FAIL
;
1880 /**********************************************************************
1881 * release_marshal_data
1883 * Releases the data and sets the stream back to zero size.
1885 static inline void release_marshal_data(IStream
*stm
)
1888 ULARGE_INTEGER size
;
1889 pos
.QuadPart
= size
.QuadPart
= 0;
1891 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1892 CoReleaseMarshalData(stm
);
1893 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1894 IStream_SetSize(stm
, size
);
1897 /***********************************************************************
1898 * expose_marshalled_dataobject
1900 * Sets the marshalled dataobject to the clipboard. In the flushed case
1901 * we set a zero sized HGLOBAL to clear the old marshalled data.
1903 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1910 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1911 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1914 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 1);
1916 if(!h
) return E_OUTOFMEMORY
;
1918 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1921 return CLIPBRD_E_CANT_SET
;
1926 /***********************************************************************
1927 * set_src_dataobject
1929 * Clears and sets the clipboard's src IDataObject.
1931 * To marshal the source dataobject we do something rather different from Windows.
1932 * We set a clipboard format which contains the marshalled data.
1933 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1935 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1940 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1942 if(clipbrd
->src_data
)
1944 release_marshal_data(clipbrd
->marshal_data
);
1946 IDataObject_Release(clipbrd
->src_data
);
1947 clipbrd
->src_data
= NULL
;
1948 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1949 clipbrd
->cached_enum
= NULL
;
1956 IDataObject_AddRef(data
);
1957 clipbrd
->src_data
= data
;
1959 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1960 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1961 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1962 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1963 if(FAILED(hr
)) return hr
;
1964 hr
= set_clipboard_formats(clipbrd
, data
);
1969 /***********************************************************************
1970 * OLEClipbrd_UnInitialize()
1971 * Un-Initializes the OLE clipboard
1973 void OLEClipbrd_UnInitialize(void)
1975 ole_clipbrd
*clipbrd
= theOleClipboard
;
1981 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1982 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1984 /* OleUninitialize() does not release the reference to the dataobject, so
1985 take an additional reference here. This reference is then leaked. */
1986 if (clipbrd
->src_data
)
1988 IDataObject_AddRef(clipbrd
->src_data
);
1989 set_src_dataobject(clipbrd
, NULL
);
1992 if ( clipbrd
->window
)
1994 DestroyWindow(clipbrd
->window
);
1995 UnregisterClassW( clipbrd_wndclass
, hinst
);
1998 IStream_Release(clipbrd
->marshal_data
);
1999 HeapFree(GetProcessHeap(), 0, clipbrd
);
2000 theOleClipboard
= NULL
;
2004 /***********************************************************************
2007 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
2009 ole_clipbrd
*clipbrd
;
2011 get_ole_clipbrd(&clipbrd
);
2014 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2019 case WM_RENDERFORMAT
:
2022 if (clipbrd
->cached_enum
)
2026 ole_priv_data_entry
*entry
;
2028 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2029 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2032 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2039 case WM_RENDERALLFORMATS
:
2042 ole_priv_data_entry
*entries
;
2044 TRACE("(): WM_RENDERALLFORMATS\n");
2046 if (!clipbrd
|| !clipbrd
->cached_enum
) break;
2047 entries
= clipbrd
->cached_enum
->entries
;
2048 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2050 if(entries
[i
].first_use
)
2051 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2056 case WM_DESTROYCLIPBOARD
:
2058 TRACE("(): WM_DESTROYCLIPBOARD\n");
2060 set_src_dataobject(clipbrd
, NULL
);
2065 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2072 /***********************************************************************
2073 * create_clipbrd_window
2075 static HWND
create_clipbrd_window(void)
2078 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2079 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2080 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2082 class.cbSize
= sizeof(class);
2084 class.lpfnWndProc
= clipbrd_wndproc
;
2085 class.cbClsExtra
= 0;
2086 class.cbWndExtra
= 0;
2087 class.hInstance
= hinst
;
2090 class.hbrBackground
= 0;
2091 class.lpszMenuName
= NULL
;
2092 class.lpszClassName
= clipbrd_wndclass
;
2093 class.hIconSm
= NULL
;
2095 RegisterClassExW(&class);
2097 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2098 0, 0, 0, 0, HWND_MESSAGE
, NULL
, hinst
, 0);
2101 /*********************************************************************
2102 * set_dataobject_format
2104 * Windows creates a 'DataObject' clipboard format that contains the
2105 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2107 static HRESULT
set_dataobject_format(HWND hwnd
)
2109 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2112 if(!h
) return E_OUTOFMEMORY
;
2114 data
= GlobalLock(h
);
2118 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2121 return CLIPBRD_E_CANT_SET
;
2127 /*---------------------------------------------------------------------*
2128 * Win32 OLE clipboard API
2129 *---------------------------------------------------------------------*/
2131 /***********************************************************************
2132 * OleSetClipboard [OLE32.@]
2133 * Places a pointer to the specified data object onto the clipboard,
2134 * making the data object accessible to the OleGetClipboard function.
2138 * S_OK IDataObject pointer placed on the clipboard
2139 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2140 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2141 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2142 * CLIPBRD_E_CANT_SET SetClipboard failed
2145 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2148 ole_clipbrd
*clipbrd
;
2151 TRACE("(%p)\n", data
);
2153 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2155 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2157 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2159 if ( !EmptyClipboard() )
2161 hr
= CLIPBRD_E_CANT_EMPTY
;
2165 hr
= set_src_dataobject(clipbrd
, data
);
2166 if(FAILED(hr
)) goto end
;
2170 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2171 if(FAILED(hr
)) goto end
;
2172 hr
= set_dataobject_format(wnd
);
2177 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2181 expose_marshalled_dataobject(clipbrd
, NULL
);
2182 set_src_dataobject(clipbrd
, NULL
);
2189 /***********************************************************************
2190 * OleGetClipboard [OLE32.@]
2191 * Returns a pointer to our internal IDataObject which represents the conceptual
2192 * state of the Windows clipboard. If the current clipboard already contains
2193 * an IDataObject, our internal IDataObject will delegate to this object.
2195 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2198 ole_clipbrd
*clipbrd
;
2201 TRACE("(%p)\n", obj
);
2203 if(!obj
) return E_INVALIDARG
;
2206 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2208 seq_no
= GetClipboardSequenceNumber();
2209 EnterCriticalSection(&latest_snapshot_cs
);
2210 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2211 clipbrd
->latest_snapshot
= NULL
;
2213 if(!clipbrd
->latest_snapshot
)
2215 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2216 if(!clipbrd
->latest_snapshot
)
2218 LeaveCriticalSection(&latest_snapshot_cs
);
2219 return E_OUTOFMEMORY
;
2223 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2224 IDataObject_AddRef(*obj
);
2225 LeaveCriticalSection(&latest_snapshot_cs
);
2230 /******************************************************************************
2231 * OleFlushClipboard [OLE32.@]
2232 * Renders the data from the source IDataObject into the windows clipboard
2234 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2235 * by copying the storage into global memory. Subsequently the default
2236 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2237 * back to TYMED_IStorage.
2239 HRESULT WINAPI
OleFlushClipboard(void)
2242 ole_clipbrd
*clipbrd
;
2247 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2249 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2252 * Already flushed or no source DataObject? Nothing to do.
2254 if (!clipbrd
->src_data
) return S_OK
;
2256 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2258 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2260 hr
= set_dataobject_format(NULL
);
2262 expose_marshalled_dataobject(clipbrd
, NULL
);
2263 set_src_dataobject(clipbrd
, NULL
);
2265 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2271 /***********************************************************************
2272 * OleIsCurrentClipboard [OLE32.@]
2274 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2277 ole_clipbrd
*clipbrd
;
2280 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2282 if (data
== NULL
) return S_FALSE
;
2284 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;