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
76 #include "wine/debug.h"
79 #include "storage32.h"
81 #include "compobj_private.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
85 /* Structure of 'Ole Private Data' clipboard format */
89 DWORD first_use
; /* Has this cf been added to the list already */
91 } ole_priv_data_entry
;
96 DWORD size
; /* in bytes of the entire structure */
98 DWORD count
; /* no. of format entries */
100 ole_priv_data_entry entries
[1]; /* array of size count */
101 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
104 /*****************************************************************************
107 * Returns a ptr to a target device at a given offset from the
108 * start of the ole_priv_data.
110 * Used when unpacking ole private data from the clipboard.
112 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
114 if(off
== 0) return NULL
;
115 return (DVTARGETDEVICE
*)((char*)data
+ off
);
118 /*****************************************************************************
121 * Get the offset from the start of the ole_priv_data of the idx'th
124 * Used when packing ole private data to the clipboard.
126 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
128 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
129 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
132 /****************************************************************************
133 * Consumer snapshot. Represents the state of the ole clipboard
134 * returned by OleGetClipboard().
136 typedef struct snapshot
138 IDataObject IDataObject_iface
;
141 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
143 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
146 /****************************************************************************
149 typedef struct ole_clipbrd
151 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
153 HWND window
; /* Hidden clipboard window */
154 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
155 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
156 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
159 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
161 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
164 typedef struct PresentationDataHeader
167 DWORD dwObjectExtentX
;
168 DWORD dwObjectExtentY
;
170 } PresentationDataHeader
;
173 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
175 static ole_clipbrd
* theOleClipboard
;
177 static CRITICAL_SECTION latest_snapshot_cs
;
178 static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug
=
180 0, 0, &latest_snapshot_cs
,
181 { &latest_snapshot_cs_debug
.ProcessLocksList
, &latest_snapshot_cs_debug
.ProcessLocksList
},
182 0, 0, { (DWORD_PTR
)(__FILE__
": clipboard last snapshot") }
184 static CRITICAL_SECTION latest_snapshot_cs
= { &latest_snapshot_cs_debug
, -1, 0, 0, 0, 0 };
186 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
188 struct oletls
*info
= COM_CurrentInfo();
192 return CO_E_NOTINITIALIZED
;
193 *clipbrd
= theOleClipboard
;
199 * Name of our registered OLE clipboard window class
201 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
203 UINT ownerlink_clipboard_format
= 0;
204 UINT filename_clipboard_format
= 0;
205 UINT filenameW_clipboard_format
= 0;
206 UINT dataobject_clipboard_format
= 0;
207 UINT embedded_object_clipboard_format
= 0;
208 UINT embed_source_clipboard_format
= 0;
209 UINT custom_link_source_clipboard_format
= 0;
210 UINT link_source_clipboard_format
= 0;
211 UINT object_descriptor_clipboard_format
= 0;
212 UINT link_source_descriptor_clipboard_format
= 0;
213 UINT ole_private_data_clipboard_format
= 0;
215 static UINT wine_marshal_clipboard_format
;
217 static inline const char *dump_fmtetc(FORMATETC
*fmt
)
219 if (!fmt
) return "(null)";
220 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
221 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
224 /*---------------------------------------------------------------------*
225 * Implementation of the internal IEnumFORMATETC interface returned by
226 * the OLE clipboard's IDataObject.
227 *---------------------------------------------------------------------*/
229 typedef struct enum_fmtetc
231 IEnumFORMATETC IEnumFORMATETC_iface
;
234 UINT pos
; /* current enumerator position */
238 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
240 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
243 /************************************************************************
244 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
246 * See Windows documentation for more details on IUnknown methods.
248 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
249 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
251 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
253 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
257 if(IsEqualIID(riid
, &IID_IUnknown
) ||
258 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
265 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
266 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
270 TRACE("-- Interface: E_NOINTERFACE\n");
271 return E_NOINTERFACE
;
274 /************************************************************************
275 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
278 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
280 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
281 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
283 return InterlockedIncrement(&This
->ref
);
286 /************************************************************************
287 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
289 * See Windows documentation for more details on IUnknown methods.
291 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
293 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
296 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
298 ref
= InterlockedDecrement(&This
->ref
);
301 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
302 HeapFree(GetProcessHeap(), 0, This
->data
);
303 HeapFree(GetProcessHeap(), 0, This
);
308 /************************************************************************
309 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
311 * Standard enumerator members for IEnumFORMATETC
313 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
314 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
316 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
318 HRESULT hres
= S_FALSE
;
320 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
322 if (This
->pos
< This
->data
->count
)
324 cfetch
= This
->data
->count
- This
->pos
;
331 for(i
= 0; i
< cfetch
; i
++)
333 hres
= copy_formatetc(rgelt
+ i
, &This
->data
->entries
[This
->pos
++].fmtetc
);
334 if(FAILED(hres
)) return hres
;
344 *pceltFethed
= cfetch
;
350 /************************************************************************
351 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
353 * Standard enumerator members for IEnumFORMATETC
355 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
357 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
358 TRACE("(%p)->(num=%u)\n", This
, celt
);
361 if (This
->pos
> This
->data
->count
)
363 This
->pos
= This
->data
->count
;
369 /************************************************************************
370 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
372 * Standard enumerator members for IEnumFORMATETC
374 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
376 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
377 TRACE("(%p)->()\n", This
);
383 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
385 /************************************************************************
386 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
388 * Standard enumerator members for IEnumFORMATETC
390 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
391 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
393 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
394 ole_priv_data
*new_data
;
397 TRACE("(%p)->(%p)\n", This
, obj
);
399 if ( !obj
) return E_INVALIDARG
;
402 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
403 if(!new_data
) return E_OUTOFMEMORY
;
404 memcpy(new_data
, This
->data
, This
->data
->size
);
406 /* Fixup any target device ptrs */
407 for(i
= 0; i
< This
->data
->count
; i
++)
408 new_data
->entries
[i
].fmtetc
.ptd
=
409 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
411 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
414 static const IEnumFORMATETCVtbl efvt
=
416 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
417 OLEClipbrd_IEnumFORMATETC_AddRef
,
418 OLEClipbrd_IEnumFORMATETC_Release
,
419 OLEClipbrd_IEnumFORMATETC_Next
,
420 OLEClipbrd_IEnumFORMATETC_Skip
,
421 OLEClipbrd_IEnumFORMATETC_Reset
,
422 OLEClipbrd_IEnumFORMATETC_Clone
425 /************************************************************************
426 * enum_fmtetc_construct
428 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
430 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
435 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
436 if (!ef
) return E_OUTOFMEMORY
;
439 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
443 TRACE("(%p)->()\n", ef
);
444 *obj
= &ef
->IEnumFORMATETC_iface
;
448 /***********************************************************************
451 * Helper method to duplicate an HGLOBAL chunk of memory
453 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
455 void *src_ptr
, *dst_ptr
;
459 if ( !src
) return S_FALSE
;
461 size
= GlobalSize(src
);
463 *dst
= GlobalAlloc( flags
, size
);
464 if ( !*dst
) return E_OUTOFMEMORY
;
466 src_ptr
= GlobalLock(src
);
467 dst_ptr
= GlobalLock(*dst
);
469 memcpy(dst_ptr
, src_ptr
, size
);
477 /***********************************************************************
480 * Helper function to duplicate a handle to a METAFILEPICT, and the
481 * contained HMETAFILE.
483 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
487 METAFILEPICT
*dest_ptr
;
491 /* Copy the METAFILEPICT structure. */
492 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
493 if (FAILED(hr
)) return hr
;
495 dest_ptr
= GlobalLock(dest
);
496 if (!dest_ptr
) return E_FAIL
;
498 /* Give the new METAFILEPICT a separate HMETAFILE. */
499 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
514 /***********************************************************************
517 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
518 * free the contained HMETAFILE.
520 static void free_metafilepict(HGLOBAL src
)
522 METAFILEPICT
*src_ptr
;
524 src_ptr
= GlobalLock(src
);
527 DeleteMetaFile(src_ptr
->hMF
);
533 /***********************************************************************
536 * Helper function to duplicate an HBITMAP.
538 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
541 HGDIOBJ orig_src_bitmap
;
545 src_dc
= CreateCompatibleDC(NULL
);
546 orig_src_bitmap
= SelectObject(src_dc
, src
);
547 GetObjectW(src
, sizeof bm
, &bm
);
548 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
551 HDC dest_dc
= CreateCompatibleDC(NULL
);
552 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
553 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
554 SelectObject(dest_dc
, orig_dest_bitmap
);
557 SelectObject(src_dc
, orig_src_bitmap
);
560 return dest
? S_OK
: E_FAIL
;
563 /************************************************************
564 * render_embed_source_hack
566 * This is clearly a hack and has no place in the clipboard code.
569 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
572 HGLOBAL hStorage
= 0;
574 ILockBytes
*ptrILockBytes
;
576 memset(&std
, 0, sizeof(STGMEDIUM
));
577 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
579 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
580 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
581 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
584 GlobalFree(hStorage
);
588 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
589 ILockBytes_Release(ptrILockBytes
);
591 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
593 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
594 GlobalFree(hStorage
);
598 if (1) /* check whether the presentation data is already -not- present */
602 METAFILEPICT
*mfp
= 0;
604 fmt2
.cfFormat
= CF_METAFILEPICT
;
606 fmt2
.dwAspect
= DVASPECT_CONTENT
;
608 fmt2
.tymed
= TYMED_MFPICT
;
610 memset(&std2
, 0, sizeof(STGMEDIUM
));
611 std2
.tymed
= TYMED_MFPICT
;
613 /* Get the metafile picture out of it */
615 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
617 mfp
= GlobalLock(std2
.u
.hGlobal
);
622 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
623 IStream
*pStream
= 0;
625 PresentationDataHeader pdh
;
629 CHAR strOleTypeName
[51];
630 BYTE OlePresStreamHeader
[] =
632 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
633 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
634 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
635 0x00, 0x00, 0x00, 0x00
638 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
640 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
641 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
643 pdh
.dwObjectExtentX
= mfp
->xExt
;
644 pdh
.dwObjectExtentY
= mfp
->yExt
;
647 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
649 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
651 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
652 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
654 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
656 IStream_Release(pStream
);
658 HeapFree(GetProcessHeap(), 0, mfBits
);
660 GlobalUnlock(std2
.u
.hGlobal
);
661 ReleaseStgMedium(&std2
);
663 ReadClassStg(std
.u
.pstg
, &clsID
);
664 ProgIDFromCLSID(&clsID
, &strProgID
);
666 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
667 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
668 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
669 CoTaskMemFree(strProgID
);
673 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
675 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
676 GlobalFree(hStorage
);
677 hr
= CLIPBRD_E_CANT_SET
;
680 ReleaseStgMedium(&std
);
684 /************************************************************************
685 * find_format_in_list
687 * Returns the first entry that matches the provided clipboard format.
689 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
692 for(i
= 0; i
< num
; i
++)
693 if(entries
[i
].fmtetc
.cfFormat
== cf
)
699 /***************************************************************************
700 * get_data_from_storage
702 * Returns storage data in an HGLOBAL.
704 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
715 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
716 if(!h
) return E_OUTOFMEMORY
;
718 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
721 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
722 ILockBytes_Release(lbs
);
731 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
733 med
.pUnkForRelease
= NULL
;
735 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
738 memset(&med
, 0, sizeof(med
));
739 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
740 if(FAILED(hr
)) goto end
;
742 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
743 ReleaseStgMedium(&med
);
744 if(FAILED(hr
)) goto end
;
749 IStorage_Release(stg
);
750 if(FAILED(hr
)) GlobalFree(h
);
754 /***************************************************************************
755 * get_data_from_stream
757 * Returns stream data in an HGLOBAL.
759 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
769 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
770 if(!h
) return E_OUTOFMEMORY
;
772 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
773 if(FAILED(hr
)) goto error
;
776 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
778 med
.pUnkForRelease
= NULL
;
780 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
786 memset(&med
, 0, sizeof(med
));
787 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
788 if(FAILED(hr
)) goto error
;
791 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
792 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
793 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
794 ReleaseStgMedium(&med
);
795 if(FAILED(hr
)) goto error
;
798 IStream_Release(stm
);
802 if(stm
) IStream_Release(stm
);
807 /***************************************************************************
808 * get_data_from_global
810 * Returns global data in an HGLOBAL.
812 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
822 mem_fmt
.tymed
= TYMED_HGLOBAL
;
823 memset(&med
, 0, sizeof(med
));
825 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
826 if(FAILED(hr
)) return hr
;
828 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
830 if(SUCCEEDED(hr
)) *mem
= h
;
832 ReleaseStgMedium(&med
);
837 /***************************************************************************
838 * get_data_from_enhmetafile
840 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
850 mem_fmt
.tymed
= TYMED_ENHMF
;
851 memset(&med
, 0, sizeof(med
));
853 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
854 if(FAILED(hr
)) return hr
;
856 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
857 if(copy
) *mem
= (HGLOBAL
)copy
;
860 ReleaseStgMedium(&med
);
865 /***************************************************************************
866 * get_data_from_metafilepict
868 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
878 mem_fmt
.tymed
= TYMED_MFPICT
;
879 memset(&med
, 0, sizeof(med
));
881 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
882 if(FAILED(hr
)) return hr
;
884 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
886 if(SUCCEEDED(hr
)) *mem
= copy
;
888 ReleaseStgMedium(&med
);
893 /***************************************************************************
894 * get_data_from_bitmap
896 * Returns bitmap in an HBITMAP.
898 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
908 mem_fmt
.tymed
= TYMED_GDI
;
909 memset(&med
, 0, sizeof(med
));
911 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
912 if(FAILED(hr
)) return hr
;
914 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
916 if(SUCCEEDED(hr
)) *hbm
= copy
;
918 ReleaseStgMedium(&med
);
923 /***********************************************************************
926 * Render the clipboard data. Note that this call will delegate to the
927 * source data object.
929 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
931 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
934 /* Embed source hack */
935 if(fmt
->cfFormat
== embed_source_clipboard_format
)
937 return render_embed_source_hack(data
, fmt
);
940 if(fmt
->tymed
& TYMED_ISTORAGE
)
942 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
944 else if(fmt
->tymed
& TYMED_ISTREAM
)
946 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
948 else if(fmt
->tymed
& TYMED_HGLOBAL
)
950 hr
= get_data_from_global(data
, fmt
, &clip_data
);
952 else if(fmt
->tymed
& TYMED_ENHMF
)
954 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
956 else if(fmt
->tymed
& TYMED_MFPICT
)
958 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
959 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
961 else if(fmt
->tymed
& TYMED_GDI
)
963 /* Returns HBITMAP not HGLOBAL */
964 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
968 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
974 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
976 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
977 if(fmt
->tymed
& TYMED_MFPICT
)
978 free_metafilepict(clip_data
);
979 else if(fmt
->tymed
& TYMED_GDI
)
980 DeleteObject(clip_data
);
982 GlobalFree(clip_data
);
983 hr
= CLIPBRD_E_CANT_SET
;
990 /*---------------------------------------------------------------------*
991 * Implementation of the internal IDataObject interface exposed by
993 *---------------------------------------------------------------------*/
996 /************************************************************************
997 * snapshot_QueryInterface
999 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
1000 REFIID riid
, void **ppvObject
)
1002 snapshot
*This
= impl_from_IDataObject(iface
);
1003 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1005 if ( (This
==0) || (ppvObject
==0) )
1006 return E_INVALIDARG
;
1010 if (IsEqualIID(&IID_IUnknown
, riid
) ||
1011 IsEqualIID(&IID_IDataObject
, riid
))
1017 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1018 return E_NOINTERFACE
;
1021 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1026 /************************************************************************
1029 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1031 snapshot
*This
= impl_from_IDataObject(iface
);
1033 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1035 return InterlockedIncrement(&This
->ref
);
1038 /************************************************************************
1041 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1043 snapshot
*This
= impl_from_IDataObject(iface
);
1046 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1048 ref
= InterlockedDecrement(&This
->ref
);
1052 EnterCriticalSection(&latest_snapshot_cs
);
1055 LeaveCriticalSection(&latest_snapshot_cs
);
1058 if (theOleClipboard
->latest_snapshot
== This
)
1059 theOleClipboard
->latest_snapshot
= NULL
;
1060 LeaveCriticalSection(&latest_snapshot_cs
);
1062 if(This
->data
) IDataObject_Release(This
->data
);
1063 HeapFree(GetProcessHeap(), 0, This
);
1069 /************************************************************
1070 * get_current_ole_clip_window
1072 * Return the window that owns the ole clipboard.
1074 * If the clipboard is flushed or not owned by ole this will
1077 static HWND
get_current_ole_clip_window(void)
1082 h
= GetClipboardData(dataobject_clipboard_format
);
1084 ptr
= GlobalLock(h
);
1085 if(!ptr
) return NULL
;
1091 /************************************************************
1092 * get_current_dataobject
1094 * Return an unmarshalled IDataObject if there is a current
1095 * (ie non-flushed) object on the ole clipboard.
1097 static HRESULT
get_current_dataobject(IDataObject
**data
)
1099 HRESULT hr
= S_FALSE
;
1100 HWND wnd
= get_current_ole_clip_window();
1107 if(!wnd
) return S_FALSE
;
1109 h
= GetClipboardData(wine_marshal_clipboard_format
);
1110 if(!h
) return S_FALSE
;
1111 if(GlobalSize(h
) <= 1) return S_FALSE
;
1112 ptr
= GlobalLock(h
);
1113 if(!ptr
) return S_FALSE
;
1115 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1116 if(FAILED(hr
)) goto end
;
1118 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1122 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1123 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1125 IStream_Release(stm
);
1132 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1134 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1140 case CF_UNICODETEXT
:
1141 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1142 case CF_ENHMETAFILE
:
1144 case CF_METAFILEPICT
:
1145 return TYMED_MFPICT
;
1149 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1154 /***********************************************************
1157 * Returns a copy of the Ole Private Data
1159 static HRESULT
get_priv_data(ole_priv_data
**data
)
1163 ole_priv_data
*ret
= NULL
;
1167 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1170 ole_priv_data
*src
= GlobalLock(handle
);
1175 /* FIXME: sanity check on size */
1176 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1179 GlobalUnlock(handle
);
1180 return E_OUTOFMEMORY
;
1182 memcpy(ret
, src
, src
->size
);
1183 GlobalUnlock(handle
);
1185 /* Fixup any target device offsets to ptrs */
1186 for(i
= 0; i
< ret
->count
; i
++)
1187 ret
->entries
[i
].fmtetc
.ptd
=
1188 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1192 if(!ret
) /* Non-ole data */
1195 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1197 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1200 if (GetClipboardFormatNameW(cf
, buf
, ARRAY_SIZE(buf
)))
1201 TRACE("cf %04x %s\n", cf
, debugstr_w(buf
));
1203 TRACE("cf %04x\n", cf
);
1205 TRACE("count %d\n", count
);
1206 size
+= count
* sizeof(ret
->entries
[0]);
1208 /* There are holes in fmtetc so zero init */
1209 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1210 if(!ret
) return E_OUTOFMEMORY
;
1214 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1216 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1217 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1218 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1219 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1220 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1221 ret
->entries
[idx
].first_use
= 1;
1229 /************************************************************************
1230 * get_stgmed_for_global
1232 * Returns a stg medium with a copy of the global handle
1234 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1238 med
->pUnkForRelease
= NULL
;
1239 med
->tymed
= TYMED_NULL
;
1241 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1243 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1248 /************************************************************************
1249 * get_stgmed_for_stream
1251 * Returns a stg medium with a stream based on the handle
1253 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1258 med
->pUnkForRelease
= NULL
;
1259 med
->tymed
= TYMED_NULL
;
1261 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1262 if(FAILED(hr
)) return hr
;
1264 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1271 med
->tymed
= TYMED_ISTREAM
;
1275 /************************************************************************
1276 * get_stgmed_for_storage
1278 * Returns a stg medium with a storage based on the handle
1280 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1286 med
->pUnkForRelease
= NULL
;
1287 med
->tymed
= TYMED_NULL
;
1289 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1290 if(FAILED(hr
)) return hr
;
1292 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1299 hr
= StgIsStorageILockBytes(lbs
);
1302 ILockBytes_Release(lbs
);
1304 return SUCCEEDED(hr
) ? E_FAIL
: hr
;
1307 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1308 ILockBytes_Release(lbs
);
1315 med
->tymed
= TYMED_ISTORAGE
;
1319 /************************************************************************
1320 * get_stgmed_for_emf
1322 * Returns a stg medium with an enhanced metafile based on the handle
1324 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1326 med
->pUnkForRelease
= NULL
;
1327 med
->tymed
= TYMED_NULL
;
1329 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1330 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1331 med
->tymed
= TYMED_ENHMF
;
1335 /************************************************************************
1336 * get_stgmed_for_bitmap
1338 * Returns a stg medium with a bitmap based on the handle
1340 static HRESULT
get_stgmed_for_bitmap(HBITMAP hbmp
, STGMEDIUM
*med
)
1344 med
->pUnkForRelease
= NULL
;
1345 med
->tymed
= TYMED_NULL
;
1347 hr
= dup_bitmap(hbmp
, &med
->u
.hBitmap
);
1352 med
->tymed
= TYMED_GDI
;
1356 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1358 const WCHAR
*str1
, *str2
;
1360 if(off1
== 0 && off2
== 0) return TRUE
;
1361 if(off1
== 0 || off2
== 0) return FALSE
;
1363 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1364 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1366 return !lstrcmpW(str1
, str2
);
1369 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1371 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1372 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1374 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1376 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1378 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1381 /* FIXME check devmode? */
1386 /************************************************************************
1389 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1392 snapshot
*This
= impl_from_IDataObject(iface
);
1395 ole_priv_data
*enum_data
= NULL
;
1396 ole_priv_data_entry
*entry
;
1399 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1401 if ( !fmt
|| !med
) return E_INVALIDARG
;
1403 memset(med
, 0, sizeof(*med
));
1405 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1408 hr
= get_current_dataobject(&This
->data
);
1412 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1419 if(fmt
->lindex
!= -1)
1421 hr
= DV_E_FORMATETC
;
1425 if(!IsClipboardFormatAvailable(fmt
->cfFormat
))
1427 hr
= DV_E_FORMATETC
;
1431 hr
= get_priv_data(&enum_data
);
1432 if(FAILED(hr
)) goto end
;
1434 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1437 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1439 hr
= DV_E_FORMATETC
;
1442 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1443 if(!mask
&& (entry
->fmtetc
.tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
| TYMED_ISTORAGE
)))
1444 mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
| TYMED_ISTORAGE
);
1446 else /* non-Ole format */
1447 mask
= fmt
->tymed
& get_tymed_from_nonole_cf(fmt
->cfFormat
);
1455 h
= GetClipboardData(fmt
->cfFormat
);
1458 hr
= DV_E_FORMATETC
;
1462 if(mask
& TYMED_HGLOBAL
)
1463 hr
= get_stgmed_for_global(h
, med
);
1464 else if(mask
& TYMED_ISTREAM
)
1465 hr
= get_stgmed_for_stream(h
, med
);
1466 else if(mask
& TYMED_ISTORAGE
)
1467 hr
= get_stgmed_for_storage(h
, med
);
1468 else if(mask
& TYMED_ENHMF
)
1469 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1470 else if(mask
& TYMED_GDI
)
1471 hr
= get_stgmed_for_bitmap((HBITMAP
)h
, med
);
1474 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1480 HeapFree(GetProcessHeap(), 0, enum_data
);
1481 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1485 /************************************************************************
1486 * snapshot_GetDataHere
1488 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1491 snapshot
*This
= impl_from_IDataObject(iface
);
1494 ole_priv_data
*enum_data
= NULL
;
1495 ole_priv_data_entry
*entry
;
1498 if ( !fmt
|| !med
) return E_INVALIDARG
;
1500 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1502 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1505 hr
= get_current_dataobject(&This
->data
);
1509 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1517 h
= GetClipboardData(fmt
->cfFormat
);
1520 hr
= DV_E_FORMATETC
;
1524 hr
= get_priv_data(&enum_data
);
1525 if(FAILED(hr
)) goto end
;
1527 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1530 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1532 hr
= DV_E_FORMATETC
;
1535 supported
= entry
->fmtetc
.tymed
;
1537 else /* non-Ole format */
1538 supported
= TYMED_HGLOBAL
;
1544 DWORD src_size
= GlobalSize(h
);
1545 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1547 if(dst_size
>= src_size
)
1549 void *src
= GlobalLock(h
);
1550 void *dst
= GlobalLock(med
->u
.hGlobal
);
1552 memcpy(dst
, src
, src_size
);
1553 GlobalUnlock(med
->u
.hGlobal
);
1561 DWORD src_size
= GlobalSize(h
);
1562 void *src
= GlobalLock(h
);
1563 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1567 case TYMED_ISTORAGE
:
1570 if(!(supported
& TYMED_ISTORAGE
))
1575 hr
= get_stgmed_for_storage(h
, ©
);
1578 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1579 ReleaseStgMedium(©
);
1584 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1590 HeapFree(GetProcessHeap(), 0, enum_data
);
1591 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1595 /************************************************************************
1596 * snapshot_QueryGetData
1598 * The OLE Clipboard's implementation of this method delegates to
1599 * a data source if there is one or wraps around the windows clipboard
1600 * function IsClipboardFormatAvailable() otherwise.
1603 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1605 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1607 if (!fmt
) return E_INVALIDARG
;
1609 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1611 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1613 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1616 /************************************************************************
1617 * snapshot_GetCanonicalFormatEtc
1619 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1622 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1624 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1627 return DATA_S_SAMEFORMATETC
;
1630 /************************************************************************
1633 * The OLE Clipboard does not implement this method
1635 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1636 STGMEDIUM
*med
, BOOL release
)
1638 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1642 /************************************************************************
1643 * snapshot_EnumFormatEtc
1646 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1647 IEnumFORMATETC
**enum_fmt
)
1650 ole_priv_data
*data
= NULL
;
1652 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1656 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1657 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1659 hr
= get_priv_data(&data
);
1661 if(FAILED(hr
)) goto end
;
1663 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1666 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1670 /************************************************************************
1673 * The OLE Clipboard does not implement this method
1675 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1676 DWORD flags
, IAdviseSink
*sink
,
1679 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1683 /************************************************************************
1684 * snapshot_DUnadvise
1686 * The OLE Clipboard does not implement this method
1688 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1690 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1694 /************************************************************************
1695 * snapshot_EnumDAdvise
1697 * The OLE Clipboard does not implement this method
1699 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1700 IEnumSTATDATA
** enum_advise
)
1702 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1706 static const IDataObjectVtbl snapshot_vtable
=
1708 snapshot_QueryInterface
,
1712 snapshot_GetDataHere
,
1713 snapshot_QueryGetData
,
1714 snapshot_GetCanonicalFormatEtc
,
1716 snapshot_EnumFormatEtc
,
1719 snapshot_EnumDAdvise
1722 /*---------------------------------------------------------------------*
1723 * Internal implementation methods for the OLE clipboard
1724 *---------------------------------------------------------------------*/
1726 static snapshot
*snapshot_construct(DWORD seq_no
)
1730 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1731 if (!This
) return NULL
;
1733 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1735 This
->seq_no
= seq_no
;
1741 /*********************************************************
1742 * register_clipboard_formats
1744 static void register_clipboard_formats(void)
1746 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1747 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1748 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1749 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1750 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1751 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1752 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1753 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1754 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1755 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1756 'D','e','s','c','r','i','p','t','o','r',0};
1757 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1759 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1760 'D','a','t','a','O','b','j','e','c','t',0};
1762 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1763 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1764 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1765 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1766 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1767 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1768 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1769 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1770 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1771 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1772 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1774 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1777 /***********************************************************************
1778 * OLEClipbrd_Initialize()
1779 * Initializes the OLE clipboard.
1781 void OLEClipbrd_Initialize(void)
1783 register_clipboard_formats();
1785 if ( !theOleClipboard
)
1787 ole_clipbrd
* clipbrd
;
1792 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1793 if (!clipbrd
) return;
1795 clipbrd
->latest_snapshot
= NULL
;
1796 clipbrd
->window
= NULL
;
1797 clipbrd
->src_data
= NULL
;
1798 clipbrd
->cached_enum
= NULL
;
1800 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1803 HeapFree(GetProcessHeap(), 0, clipbrd
);
1807 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1810 HeapFree(GetProcessHeap(), 0, clipbrd
);
1814 theOleClipboard
= clipbrd
;
1818 /*********************************************************************
1819 * set_clipboard_formats
1821 * Enumerate all formats supported by the source and make
1822 * those formats available using delayed rendering using SetClipboardData.
1823 * Cache the enumeration list and make that list visible as the
1824 * 'Ole Private Data' format on the clipboard.
1827 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1831 IEnumFORMATETC
*enum_fmt
;
1832 HGLOBAL priv_data_handle
;
1833 DWORD_PTR target_offset
;
1834 ole_priv_data
*priv_data
;
1835 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1837 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1838 if(FAILED(hr
)) return hr
;
1840 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1843 needed
+= sizeof(priv_data
->entries
[0]);
1846 needed
+= fmt
.ptd
->tdSize
;
1847 CoTaskMemFree(fmt
.ptd
);
1851 /* Windows pads the list with two empty ole_priv_data_entries, one
1852 * after the entries array and one after the target device data.
1853 * Allocating with zero init to zero these pads. */
1855 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1856 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1857 priv_data
= GlobalLock(priv_data_handle
);
1859 priv_data
->unk1
= 0;
1860 priv_data
->size
= needed
;
1861 priv_data
->unk2
= 1;
1862 priv_data
->count
= count
;
1863 priv_data
->unk3
[0] = 0;
1864 priv_data
->unk3
[1] = 0;
1866 IEnumFORMATETC_Reset(enum_fmt
);
1869 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1871 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1873 TRACE("%s\n", dump_fmtetc(&fmt
));
1875 priv_data
->entries
[idx
].fmtetc
= fmt
;
1878 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1879 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1880 target_offset
+= fmt
.ptd
->tdSize
;
1881 CoTaskMemFree(fmt
.ptd
);
1884 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1885 priv_data
->entries
[idx
].unk
[0] = 0;
1886 priv_data
->entries
[idx
].unk
[1] = 0;
1888 if (priv_data
->entries
[idx
].first_use
)
1889 SetClipboardData(fmt
.cfFormat
, NULL
);
1894 IEnumFORMATETC_Release(enum_fmt
);
1896 /* Cache the list and fixup any target device offsets to ptrs */
1897 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1898 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1899 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1900 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1901 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1903 GlobalUnlock(priv_data_handle
);
1904 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1906 GlobalFree(priv_data_handle
);
1907 return CLIPBRD_E_CANT_SET
;
1913 static HWND
create_clipbrd_window(void);
1915 /***********************************************************************
1916 * get_clipbrd_window
1918 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1921 /* The clipboard window can get destroyed if the thread that created it dies so we may need to create it again */
1922 if (!IsWindow(clipbrd
->window
))
1923 clipbrd
->window
= create_clipbrd_window();
1926 if ( !clipbrd
->window
)
1927 clipbrd
->window
= create_clipbrd_window();
1929 *wnd
= clipbrd
->window
;
1930 return *wnd
? S_OK
: E_FAIL
;
1934 /**********************************************************************
1935 * release_marshal_data
1937 * Releases the data and sets the stream back to zero size.
1939 static inline void release_marshal_data(IStream
*stm
)
1942 ULARGE_INTEGER size
;
1943 pos
.QuadPart
= size
.QuadPart
= 0;
1945 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1946 CoReleaseMarshalData(stm
);
1947 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1948 IStream_SetSize(stm
, size
);
1951 /***********************************************************************
1952 * expose_marshalled_dataobject
1954 * Sets the marshalled dataobject to the clipboard. In the flushed case
1955 * we set a zero sized HGLOBAL to clear the old marshalled data.
1957 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1964 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1965 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1968 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 1);
1970 if(!h
) return E_OUTOFMEMORY
;
1972 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1975 return CLIPBRD_E_CANT_SET
;
1980 /***********************************************************************
1981 * set_src_dataobject
1983 * Clears and sets the clipboard's src IDataObject.
1985 * To marshal the source dataobject we do something rather different from Windows.
1986 * We set a clipboard format which contains the marshalled data.
1987 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1989 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1994 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1996 if(clipbrd
->src_data
)
1998 release_marshal_data(clipbrd
->marshal_data
);
2000 IDataObject_Release(clipbrd
->src_data
);
2001 clipbrd
->src_data
= NULL
;
2002 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
2003 clipbrd
->cached_enum
= NULL
;
2010 IDataObject_AddRef(data
);
2011 clipbrd
->src_data
= data
;
2013 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
2014 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
2015 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
2016 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
2017 if(FAILED(hr
)) return hr
;
2018 hr
= set_clipboard_formats(clipbrd
, data
);
2023 /***********************************************************************
2024 * OLEClipbrd_UnInitialize()
2025 * Un-Initializes the OLE clipboard
2027 void OLEClipbrd_UnInitialize(void)
2029 ole_clipbrd
*clipbrd
= theOleClipboard
;
2035 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2036 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2038 /* OleUninitialize() does not release the reference to the dataobject, so
2039 take an additional reference here. This reference is then leaked. */
2040 if (clipbrd
->src_data
)
2042 IDataObject_AddRef(clipbrd
->src_data
);
2043 set_src_dataobject(clipbrd
, NULL
);
2046 if ( clipbrd
->window
)
2048 DestroyWindow(clipbrd
->window
);
2049 UnregisterClassW( clipbrd_wndclass
, hinst
);
2052 IStream_Release(clipbrd
->marshal_data
);
2053 HeapFree(GetProcessHeap(), 0, clipbrd
);
2054 theOleClipboard
= NULL
;
2058 /***********************************************************************
2061 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
2063 ole_clipbrd
*clipbrd
;
2065 get_ole_clipbrd(&clipbrd
);
2068 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2073 case WM_RENDERFORMAT
:
2076 if (clipbrd
->cached_enum
)
2080 ole_priv_data_entry
*entry
;
2082 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2083 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2086 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2093 case WM_RENDERALLFORMATS
:
2096 ole_priv_data_entry
*entries
;
2098 TRACE("(): WM_RENDERALLFORMATS\n");
2100 if (!clipbrd
|| !clipbrd
->cached_enum
) break;
2101 entries
= clipbrd
->cached_enum
->entries
;
2102 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2104 if(entries
[i
].first_use
)
2105 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2110 case WM_DESTROYCLIPBOARD
:
2112 TRACE("(): WM_DESTROYCLIPBOARD\n");
2114 set_src_dataobject(clipbrd
, NULL
);
2119 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2126 /***********************************************************************
2127 * create_clipbrd_window
2129 static HWND
create_clipbrd_window(void)
2132 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2133 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2134 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2136 class.cbSize
= sizeof(class);
2138 class.lpfnWndProc
= clipbrd_wndproc
;
2139 class.cbClsExtra
= 0;
2140 class.cbWndExtra
= 0;
2141 class.hInstance
= hinst
;
2144 class.hbrBackground
= 0;
2145 class.lpszMenuName
= NULL
;
2146 class.lpszClassName
= clipbrd_wndclass
;
2147 class.hIconSm
= NULL
;
2149 RegisterClassExW(&class);
2151 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2152 0, 0, 0, 0, HWND_MESSAGE
, NULL
, hinst
, 0);
2155 /*********************************************************************
2156 * set_dataobject_format
2158 * Windows creates a 'DataObject' clipboard format that contains the
2159 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2161 static HRESULT
set_dataobject_format(HWND hwnd
)
2163 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2166 if(!h
) return E_OUTOFMEMORY
;
2168 data
= GlobalLock(h
);
2172 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2175 return CLIPBRD_E_CANT_SET
;
2181 /*---------------------------------------------------------------------*
2182 * Win32 OLE clipboard API
2183 *---------------------------------------------------------------------*/
2185 /***********************************************************************
2186 * OleSetClipboard [OLE32.@]
2187 * Places a pointer to the specified data object onto the clipboard,
2188 * making the data object accessible to the OleGetClipboard function.
2192 * S_OK IDataObject pointer placed on the clipboard
2193 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2194 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2195 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2196 * CLIPBRD_E_CANT_SET SetClipboard failed
2199 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2202 ole_clipbrd
*clipbrd
;
2205 TRACE("(%p)\n", data
);
2207 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2209 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2211 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2213 if ( !EmptyClipboard() )
2215 hr
= CLIPBRD_E_CANT_EMPTY
;
2219 hr
= set_src_dataobject(clipbrd
, data
);
2220 if(FAILED(hr
)) goto end
;
2224 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2225 if(FAILED(hr
)) goto end
;
2226 hr
= set_dataobject_format(wnd
);
2231 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2235 expose_marshalled_dataobject(clipbrd
, NULL
);
2236 set_src_dataobject(clipbrd
, NULL
);
2243 /***********************************************************************
2244 * OleGetClipboard [OLE32.@]
2245 * Returns a pointer to our internal IDataObject which represents the conceptual
2246 * state of the Windows clipboard. If the current clipboard already contains
2247 * an IDataObject, our internal IDataObject will delegate to this object.
2249 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2252 ole_clipbrd
*clipbrd
;
2255 TRACE("(%p)\n", obj
);
2257 if(!obj
) return E_INVALIDARG
;
2260 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2262 seq_no
= GetClipboardSequenceNumber();
2263 EnterCriticalSection(&latest_snapshot_cs
);
2264 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2265 clipbrd
->latest_snapshot
= NULL
;
2267 if(!clipbrd
->latest_snapshot
)
2269 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2270 if(!clipbrd
->latest_snapshot
)
2272 LeaveCriticalSection(&latest_snapshot_cs
);
2273 return E_OUTOFMEMORY
;
2277 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2278 IDataObject_AddRef(*obj
);
2279 LeaveCriticalSection(&latest_snapshot_cs
);
2284 /******************************************************************************
2285 * OleFlushClipboard [OLE32.@]
2286 * Renders the data from the source IDataObject into the windows clipboard
2288 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2289 * by copying the storage into global memory. Subsequently the default
2290 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2291 * back to TYMED_IStorage.
2293 HRESULT WINAPI
OleFlushClipboard(void)
2296 ole_clipbrd
*clipbrd
;
2301 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2303 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2306 * Already flushed or no source DataObject? Nothing to do.
2308 if (!clipbrd
->src_data
) return S_OK
;
2310 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2312 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2314 hr
= set_dataobject_format(NULL
);
2316 expose_marshalled_dataobject(clipbrd
, NULL
);
2317 set_src_dataobject(clipbrd
, NULL
);
2319 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2325 /***********************************************************************
2326 * OleIsCurrentClipboard [OLE32.@]
2328 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2331 ole_clipbrd
*clipbrd
;
2334 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2336 if (data
== NULL
) return S_FALSE
;
2338 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;