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 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
317 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
318 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
319 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
320 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
331 *pceltFethed
= cfetch
;
337 /************************************************************************
338 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
340 * Standard enumerator members for IEnumFORMATETC
342 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
344 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
345 TRACE("(%p)->(num=%u)\n", This
, celt
);
348 if (This
->pos
> This
->data
->count
)
350 This
->pos
= This
->data
->count
;
356 /************************************************************************
357 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
359 * Standard enumerator members for IEnumFORMATETC
361 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
363 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
364 TRACE("(%p)->()\n", This
);
370 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
372 /************************************************************************
373 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
375 * Standard enumerator members for IEnumFORMATETC
377 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
378 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
380 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
381 ole_priv_data
*new_data
;
384 TRACE("(%p)->(%p)\n", This
, obj
);
386 if ( !obj
) return E_INVALIDARG
;
389 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
390 if(!new_data
) return E_OUTOFMEMORY
;
391 memcpy(new_data
, This
->data
, This
->data
->size
);
393 /* Fixup any target device ptrs */
394 for(i
= 0; i
< This
->data
->count
; i
++)
395 new_data
->entries
[i
].fmtetc
.ptd
=
396 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
398 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
401 static const IEnumFORMATETCVtbl efvt
=
403 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
404 OLEClipbrd_IEnumFORMATETC_AddRef
,
405 OLEClipbrd_IEnumFORMATETC_Release
,
406 OLEClipbrd_IEnumFORMATETC_Next
,
407 OLEClipbrd_IEnumFORMATETC_Skip
,
408 OLEClipbrd_IEnumFORMATETC_Reset
,
409 OLEClipbrd_IEnumFORMATETC_Clone
412 /************************************************************************
413 * enum_fmtetc_construct
415 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
417 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
422 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
423 if (!ef
) return E_OUTOFMEMORY
;
426 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
430 TRACE("(%p)->()\n", ef
);
431 *obj
= &ef
->IEnumFORMATETC_iface
;
435 /***********************************************************************
438 * Helper method to duplicate an HGLOBAL chunk of memory
440 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
442 void *src_ptr
, *dst_ptr
;
446 if ( !src
) return S_FALSE
;
448 size
= GlobalSize(src
);
450 *dst
= GlobalAlloc( flags
, size
);
451 if ( !*dst
) return E_OUTOFMEMORY
;
453 src_ptr
= GlobalLock(src
);
454 dst_ptr
= GlobalLock(*dst
);
456 memcpy(dst_ptr
, src_ptr
, size
);
464 /***********************************************************************
467 * Helper function to duplicate a handle to a METAFILEPICT, and the
468 * contained HMETAFILE.
470 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
474 METAFILEPICT
*dest_ptr
;
478 /* Copy the METAFILEPICT structure. */
479 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
480 if (FAILED(hr
)) return hr
;
482 dest_ptr
= GlobalLock(dest
);
483 if (!dest_ptr
) return E_FAIL
;
485 /* Give the new METAFILEPICT a separate HMETAFILE. */
486 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
501 /***********************************************************************
504 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
505 * free the contained HMETAFILE.
507 static void free_metafilepict(HGLOBAL src
)
509 METAFILEPICT
*src_ptr
;
511 src_ptr
= GlobalLock(src
);
514 DeleteMetaFile(src_ptr
->hMF
);
520 /***********************************************************************
523 * Helper function to duplicate an HBITMAP.
525 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
528 HGDIOBJ orig_src_bitmap
;
532 src_dc
= CreateCompatibleDC(NULL
);
533 orig_src_bitmap
= SelectObject(src_dc
, src
);
534 GetObjectW(src
, sizeof bm
, &bm
);
535 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
538 HDC dest_dc
= CreateCompatibleDC(NULL
);
539 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
540 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
541 SelectObject(dest_dc
, orig_dest_bitmap
);
544 SelectObject(src_dc
, orig_src_bitmap
);
547 return dest
? S_OK
: E_FAIL
;
550 /************************************************************
551 * render_embed_source_hack
553 * This is clearly a hack and has no place in the clipboard code.
556 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
559 HGLOBAL hStorage
= 0;
561 ILockBytes
*ptrILockBytes
;
563 memset(&std
, 0, sizeof(STGMEDIUM
));
564 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
566 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
567 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
568 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
571 GlobalFree(hStorage
);
575 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
576 ILockBytes_Release(ptrILockBytes
);
578 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
580 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
581 GlobalFree(hStorage
);
585 if (1) /* check whether the presentation data is already -not- present */
589 METAFILEPICT
*mfp
= 0;
591 fmt2
.cfFormat
= CF_METAFILEPICT
;
593 fmt2
.dwAspect
= DVASPECT_CONTENT
;
595 fmt2
.tymed
= TYMED_MFPICT
;
597 memset(&std2
, 0, sizeof(STGMEDIUM
));
598 std2
.tymed
= TYMED_MFPICT
;
600 /* Get the metafile picture out of it */
602 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
604 mfp
= GlobalLock(std2
.u
.hGlobal
);
609 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
610 IStream
*pStream
= 0;
612 PresentationDataHeader pdh
;
616 CHAR strOleTypeName
[51];
617 BYTE OlePresStreamHeader
[] =
619 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
620 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
621 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
622 0x00, 0x00, 0x00, 0x00
625 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
627 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
628 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
630 pdh
.dwObjectExtentX
= mfp
->xExt
;
631 pdh
.dwObjectExtentY
= mfp
->yExt
;
634 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
636 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
638 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
639 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
641 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
643 IStream_Release(pStream
);
645 HeapFree(GetProcessHeap(), 0, mfBits
);
647 GlobalUnlock(std2
.u
.hGlobal
);
648 ReleaseStgMedium(&std2
);
650 ReadClassStg(std
.u
.pstg
, &clsID
);
651 ProgIDFromCLSID(&clsID
, &strProgID
);
653 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
654 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
655 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
656 CoTaskMemFree(strProgID
);
660 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
662 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
663 GlobalFree(hStorage
);
664 hr
= CLIPBRD_E_CANT_SET
;
667 ReleaseStgMedium(&std
);
671 /************************************************************************
672 * find_format_in_list
674 * Returns the first entry that matches the provided clipboard format.
676 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
679 for(i
= 0; i
< num
; i
++)
680 if(entries
[i
].fmtetc
.cfFormat
== cf
)
686 /***************************************************************************
687 * get_data_from_storage
689 * Returns storage data in an HGLOBAL.
691 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
702 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
703 if(!h
) return E_OUTOFMEMORY
;
705 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
708 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
709 ILockBytes_Release(lbs
);
718 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
720 med
.pUnkForRelease
= NULL
;
722 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
726 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
727 if(FAILED(hr
)) goto end
;
729 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
730 ReleaseStgMedium(&med
);
731 if(FAILED(hr
)) goto end
;
736 IStorage_Release(stg
);
737 if(FAILED(hr
)) GlobalFree(h
);
741 /***************************************************************************
742 * get_data_from_stream
744 * Returns stream data in an HGLOBAL.
746 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
756 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
757 if(!h
) return E_OUTOFMEMORY
;
759 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
760 if(FAILED(hr
)) goto error
;
763 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
765 med
.pUnkForRelease
= NULL
;
767 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
774 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
775 if(FAILED(hr
)) goto error
;
778 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
779 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
780 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
781 ReleaseStgMedium(&med
);
782 if(FAILED(hr
)) goto error
;
785 IStream_Release(stm
);
789 if(stm
) IStream_Release(stm
);
794 /***************************************************************************
795 * get_data_from_global
797 * Returns global data in an HGLOBAL.
799 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
809 mem_fmt
.tymed
= TYMED_HGLOBAL
;
811 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
812 if(FAILED(hr
)) return hr
;
814 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
816 if(SUCCEEDED(hr
)) *mem
= h
;
818 ReleaseStgMedium(&med
);
823 /***************************************************************************
824 * get_data_from_enhmetafile
826 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
836 mem_fmt
.tymed
= TYMED_ENHMF
;
838 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
839 if(FAILED(hr
)) return hr
;
841 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
842 if(copy
) *mem
= (HGLOBAL
)copy
;
845 ReleaseStgMedium(&med
);
850 /***************************************************************************
851 * get_data_from_metafilepict
853 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
863 mem_fmt
.tymed
= TYMED_MFPICT
;
865 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
866 if(FAILED(hr
)) return hr
;
868 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
870 if(SUCCEEDED(hr
)) *mem
= copy
;
872 ReleaseStgMedium(&med
);
877 /***************************************************************************
878 * get_data_from_bitmap
880 * Returns bitmap in an HBITMAP.
882 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
892 mem_fmt
.tymed
= TYMED_GDI
;
894 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
895 if(FAILED(hr
)) return hr
;
897 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
899 if(SUCCEEDED(hr
)) *hbm
= copy
;
901 ReleaseStgMedium(&med
);
906 /***********************************************************************
909 * Render the clipboard data. Note that this call will delegate to the
910 * source data object.
912 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
914 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
917 /* Embed source hack */
918 if(fmt
->cfFormat
== embed_source_clipboard_format
)
920 return render_embed_source_hack(data
, fmt
);
923 if(fmt
->tymed
& TYMED_ISTORAGE
)
925 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
927 else if(fmt
->tymed
& TYMED_ISTREAM
)
929 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
931 else if(fmt
->tymed
& TYMED_HGLOBAL
)
933 hr
= get_data_from_global(data
, fmt
, &clip_data
);
935 else if(fmt
->tymed
& TYMED_ENHMF
)
937 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
939 else if(fmt
->tymed
& TYMED_MFPICT
)
941 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
942 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
944 else if(fmt
->tymed
& TYMED_GDI
)
946 /* Returns HBITMAP not HGLOBAL */
947 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
951 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
957 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
959 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
960 if(fmt
->tymed
& TYMED_MFPICT
)
961 free_metafilepict(clip_data
);
962 else if(fmt
->tymed
& TYMED_GDI
)
963 DeleteObject(clip_data
);
965 GlobalFree(clip_data
);
966 hr
= CLIPBRD_E_CANT_SET
;
973 /*---------------------------------------------------------------------*
974 * Implementation of the internal IDataObject interface exposed by
976 *---------------------------------------------------------------------*/
979 /************************************************************************
980 * snapshot_QueryInterface
982 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
983 REFIID riid
, void **ppvObject
)
985 snapshot
*This
= impl_from_IDataObject(iface
);
986 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
988 if ( (This
==0) || (ppvObject
==0) )
993 if (IsEqualIID(&IID_IUnknown
, riid
) ||
994 IsEqualIID(&IID_IDataObject
, riid
))
1000 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1001 return E_NOINTERFACE
;
1004 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1009 /************************************************************************
1012 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1014 snapshot
*This
= impl_from_IDataObject(iface
);
1016 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1018 return InterlockedIncrement(&This
->ref
);
1021 /************************************************************************
1024 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1026 snapshot
*This
= impl_from_IDataObject(iface
);
1029 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1031 ref
= InterlockedDecrement(&This
->ref
);
1035 EnterCriticalSection(&latest_snapshot_cs
);
1038 LeaveCriticalSection(&latest_snapshot_cs
);
1041 if (theOleClipboard
->latest_snapshot
== This
)
1042 theOleClipboard
->latest_snapshot
= NULL
;
1043 LeaveCriticalSection(&latest_snapshot_cs
);
1045 if(This
->data
) IDataObject_Release(This
->data
);
1046 HeapFree(GetProcessHeap(), 0, This
);
1052 /************************************************************
1053 * get_current_ole_clip_window
1055 * Return the window that owns the ole clipboard.
1057 * If the clipboard is flushed or not owned by ole this will
1060 static HWND
get_current_ole_clip_window(void)
1065 h
= GetClipboardData(dataobject_clipboard_format
);
1067 ptr
= GlobalLock(h
);
1068 if(!ptr
) return NULL
;
1074 /************************************************************
1075 * get_current_dataobject
1077 * Return an unmarshalled IDataObject if there is a current
1078 * (ie non-flushed) object on the ole clipboard.
1080 static HRESULT
get_current_dataobject(IDataObject
**data
)
1082 HRESULT hr
= S_FALSE
;
1083 HWND wnd
= get_current_ole_clip_window();
1090 if(!wnd
) return S_FALSE
;
1092 h
= GetClipboardData(wine_marshal_clipboard_format
);
1093 if(!h
) return S_FALSE
;
1094 if(GlobalSize(h
) == 0) return S_FALSE
;
1095 ptr
= GlobalLock(h
);
1096 if(!ptr
) return S_FALSE
;
1098 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1099 if(FAILED(hr
)) goto end
;
1101 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1105 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1106 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1108 IStream_Release(stm
);
1115 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1117 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1123 case CF_UNICODETEXT
:
1124 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1125 case CF_ENHMETAFILE
:
1127 case CF_METAFILEPICT
:
1128 return TYMED_MFPICT
;
1132 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1137 /***********************************************************
1140 * Returns a copy of the Ole Private Data
1142 static HRESULT
get_priv_data(ole_priv_data
**data
)
1146 ole_priv_data
*ret
= NULL
;
1150 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1153 ole_priv_data
*src
= GlobalLock(handle
);
1158 /* FIXME: sanity check on size */
1159 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1162 GlobalUnlock(handle
);
1163 return E_OUTOFMEMORY
;
1165 memcpy(ret
, src
, src
->size
);
1166 GlobalUnlock(handle
);
1168 /* Fixup any target device offsets to ptrs */
1169 for(i
= 0; i
< ret
->count
; i
++)
1170 ret
->entries
[i
].fmtetc
.ptd
=
1171 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1175 if(!ret
) /* Non-ole data */
1178 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1180 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1183 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1184 TRACE("cf %04x %s\n", cf
, buf
);
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 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1379 hr
= get_current_dataobject(&This
->data
);
1383 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1388 h
= GetClipboardData(fmt
->cfFormat
);
1391 hr
= DV_E_FORMATETC
;
1395 hr
= get_priv_data(&enum_data
);
1396 if(FAILED(hr
)) goto end
;
1398 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1401 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1403 hr
= DV_E_FORMATETC
;
1406 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1407 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1409 else /* non-Ole format */
1410 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1412 if(mask
& TYMED_ISTORAGE
)
1413 hr
= get_stgmed_for_storage(h
, med
);
1414 else if(mask
& TYMED_HGLOBAL
)
1415 hr
= get_stgmed_for_global(h
, med
);
1416 else if(mask
& TYMED_ISTREAM
)
1417 hr
= get_stgmed_for_stream(h
, med
);
1418 else if(mask
& TYMED_ENHMF
)
1419 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1420 else if(mask
& TYMED_GDI
)
1421 hr
= get_stgmed_for_bitmap((HBITMAP
)h
, med
);
1424 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1430 HeapFree(GetProcessHeap(), 0, enum_data
);
1431 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1435 /************************************************************************
1436 * snapshot_GetDataHere
1438 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1441 snapshot
*This
= impl_from_IDataObject(iface
);
1444 ole_priv_data
*enum_data
= NULL
;
1445 ole_priv_data_entry
*entry
;
1448 if ( !fmt
|| !med
) return E_INVALIDARG
;
1450 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1452 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1455 hr
= get_current_dataobject(&This
->data
);
1459 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1467 h
= GetClipboardData(fmt
->cfFormat
);
1470 hr
= DV_E_FORMATETC
;
1474 hr
= get_priv_data(&enum_data
);
1475 if(FAILED(hr
)) goto end
;
1477 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1480 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1482 hr
= DV_E_FORMATETC
;
1485 supported
= entry
->fmtetc
.tymed
;
1487 else /* non-Ole format */
1488 supported
= TYMED_HGLOBAL
;
1494 DWORD src_size
= GlobalSize(h
);
1495 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1497 if(dst_size
>= src_size
)
1499 void *src
= GlobalLock(h
);
1500 void *dst
= GlobalLock(med
->u
.hGlobal
);
1502 memcpy(dst
, src
, src_size
);
1503 GlobalUnlock(med
->u
.hGlobal
);
1511 DWORD src_size
= GlobalSize(h
);
1512 void *src
= GlobalLock(h
);
1513 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1517 case TYMED_ISTORAGE
:
1520 if(!(supported
& TYMED_ISTORAGE
))
1525 hr
= get_stgmed_for_storage(h
, ©
);
1528 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1529 ReleaseStgMedium(©
);
1534 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1540 HeapFree(GetProcessHeap(), 0, enum_data
);
1541 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1545 /************************************************************************
1546 * snapshot_QueryGetData
1548 * The OLE Clipboard's implementation of this method delegates to
1549 * a data source if there is one or wraps around the windows clipboard
1550 * function IsClipboardFormatAvailable() otherwise.
1553 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1555 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1557 if (!fmt
) return E_INVALIDARG
;
1559 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1561 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1563 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1566 /************************************************************************
1567 * snapshot_GetCanonicalFormatEtc
1569 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1572 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1574 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1577 return DATA_S_SAMEFORMATETC
;
1580 /************************************************************************
1583 * The OLE Clipboard does not implement this method
1585 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1586 STGMEDIUM
*med
, BOOL release
)
1588 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1592 /************************************************************************
1593 * snapshot_EnumFormatEtc
1596 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1597 IEnumFORMATETC
**enum_fmt
)
1600 ole_priv_data
*data
= NULL
;
1602 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1606 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1607 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1609 hr
= get_priv_data(&data
);
1611 if(FAILED(hr
)) goto end
;
1613 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1616 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1620 /************************************************************************
1623 * The OLE Clipboard does not implement this method
1625 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1626 DWORD flags
, IAdviseSink
*sink
,
1629 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1633 /************************************************************************
1634 * snapshot_DUnadvise
1636 * The OLE Clipboard does not implement this method
1638 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1640 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1644 /************************************************************************
1645 * snapshot_EnumDAdvise
1647 * The OLE Clipboard does not implement this method
1649 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1650 IEnumSTATDATA
** enum_advise
)
1652 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1656 static const IDataObjectVtbl snapshot_vtable
=
1658 snapshot_QueryInterface
,
1662 snapshot_GetDataHere
,
1663 snapshot_QueryGetData
,
1664 snapshot_GetCanonicalFormatEtc
,
1666 snapshot_EnumFormatEtc
,
1669 snapshot_EnumDAdvise
1672 /*---------------------------------------------------------------------*
1673 * Internal implementation methods for the OLE clipboard
1674 *---------------------------------------------------------------------*/
1676 static snapshot
*snapshot_construct(DWORD seq_no
)
1680 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1681 if (!This
) return NULL
;
1683 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1685 This
->seq_no
= seq_no
;
1691 /*********************************************************
1692 * register_clipboard_formats
1694 static void register_clipboard_formats(void)
1696 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1697 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1698 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1699 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1700 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1701 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1702 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1703 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1704 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1705 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1706 'D','e','s','c','r','i','p','t','o','r',0};
1707 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1709 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1710 'D','a','t','a','O','b','j','e','c','t',0};
1712 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1713 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1714 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1715 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1716 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1717 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1718 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1719 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1720 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1721 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1722 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1724 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1727 /***********************************************************************
1728 * OLEClipbrd_Initialize()
1729 * Initializes the OLE clipboard.
1731 void OLEClipbrd_Initialize(void)
1733 register_clipboard_formats();
1735 if ( !theOleClipboard
)
1737 ole_clipbrd
* clipbrd
;
1742 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1743 if (!clipbrd
) return;
1745 clipbrd
->latest_snapshot
= NULL
;
1746 clipbrd
->window
= NULL
;
1747 clipbrd
->src_data
= NULL
;
1748 clipbrd
->cached_enum
= NULL
;
1750 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1753 HeapFree(GetProcessHeap(), 0, clipbrd
);
1757 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1760 HeapFree(GetProcessHeap(), 0, clipbrd
);
1764 theOleClipboard
= clipbrd
;
1768 /***********************************************************************
1769 * OLEClipbrd_UnInitialize()
1770 * Un-Initializes the OLE clipboard
1772 void OLEClipbrd_UnInitialize(void)
1774 ole_clipbrd
*clipbrd
= theOleClipboard
;
1780 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1781 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1783 if ( clipbrd
->window
)
1785 DestroyWindow(clipbrd
->window
);
1786 UnregisterClassW( clipbrd_wndclass
, hinst
);
1789 IStream_Release(clipbrd
->marshal_data
);
1790 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1791 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1792 HeapFree(GetProcessHeap(), 0, clipbrd
);
1793 theOleClipboard
= NULL
;
1797 /*********************************************************************
1798 * set_clipboard_formats
1800 * Enumerate all formats supported by the source and make
1801 * those formats available using delayed rendering using SetClipboardData.
1802 * Cache the enumeration list and make that list visible as the
1803 * 'Ole Private Data' format on the clipboard.
1806 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1810 IEnumFORMATETC
*enum_fmt
;
1811 HGLOBAL priv_data_handle
;
1812 DWORD_PTR target_offset
;
1813 ole_priv_data
*priv_data
;
1814 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1816 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1817 if(FAILED(hr
)) return hr
;
1819 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1822 needed
+= sizeof(priv_data
->entries
[0]);
1825 needed
+= fmt
.ptd
->tdSize
;
1826 CoTaskMemFree(fmt
.ptd
);
1830 /* Windows pads the list with two empty ole_priv_data_entries, one
1831 * after the entries array and one after the target device data.
1832 * Allocating with zero init to zero these pads. */
1834 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1835 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1836 priv_data
= GlobalLock(priv_data_handle
);
1838 priv_data
->unk1
= 0;
1839 priv_data
->size
= needed
;
1840 priv_data
->unk2
= 1;
1841 priv_data
->count
= count
;
1842 priv_data
->unk3
[0] = 0;
1843 priv_data
->unk3
[1] = 0;
1845 IEnumFORMATETC_Reset(enum_fmt
);
1848 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1850 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1852 TRACE("%s\n", dump_fmtetc(&fmt
));
1854 priv_data
->entries
[idx
].fmtetc
= fmt
;
1857 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1858 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1859 target_offset
+= fmt
.ptd
->tdSize
;
1860 CoTaskMemFree(fmt
.ptd
);
1863 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1864 priv_data
->entries
[idx
].unk
[0] = 0;
1865 priv_data
->entries
[idx
].unk
[1] = 0;
1867 if (priv_data
->entries
[idx
].first_use
)
1868 SetClipboardData(fmt
.cfFormat
, NULL
);
1873 IEnumFORMATETC_Release(enum_fmt
);
1875 /* Cache the list and fixup any target device offsets to ptrs */
1876 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1877 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1878 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1879 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1880 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1882 GlobalUnlock(priv_data_handle
);
1883 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1885 GlobalFree(priv_data_handle
);
1886 return CLIPBRD_E_CANT_SET
;
1892 static HWND
create_clipbrd_window(void);
1894 /***********************************************************************
1895 * get_clipbrd_window
1897 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1899 if ( !clipbrd
->window
)
1900 clipbrd
->window
= create_clipbrd_window();
1902 *wnd
= clipbrd
->window
;
1903 return *wnd
? S_OK
: E_FAIL
;
1907 /**********************************************************************
1908 * release_marshal_data
1910 * Releases the data and sets the stream back to zero size.
1912 static inline void release_marshal_data(IStream
*stm
)
1915 ULARGE_INTEGER size
;
1916 pos
.QuadPart
= size
.QuadPart
= 0;
1918 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1919 CoReleaseMarshalData(stm
);
1920 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1921 IStream_SetSize(stm
, size
);
1924 /***********************************************************************
1925 * expose_marshalled_dataobject
1927 * Sets the marshalled dataobject to the clipboard. In the flushed case
1928 * we set a zero sized HGLOBAL to clear the old marshalled data.
1930 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1937 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1938 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1941 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1943 if(!h
) return E_OUTOFMEMORY
;
1945 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1948 return CLIPBRD_E_CANT_SET
;
1953 /***********************************************************************
1954 * set_src_dataobject
1956 * Clears and sets the clipboard's src IDataObject.
1958 * To marshal the source dataobject we do something rather different from Windows.
1959 * We set a clipboard format which contains the marshalled data.
1960 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1962 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1967 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1969 if(clipbrd
->src_data
)
1971 release_marshal_data(clipbrd
->marshal_data
);
1973 IDataObject_Release(clipbrd
->src_data
);
1974 clipbrd
->src_data
= NULL
;
1975 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1976 clipbrd
->cached_enum
= NULL
;
1983 IDataObject_AddRef(data
);
1984 clipbrd
->src_data
= data
;
1986 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1987 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1988 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1989 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1990 if(FAILED(hr
)) return hr
;
1991 hr
= set_clipboard_formats(clipbrd
, data
);
1996 /***********************************************************************
1999 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
2001 ole_clipbrd
*clipbrd
;
2003 get_ole_clipbrd(&clipbrd
);
2006 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2011 case WM_RENDERFORMAT
:
2014 ole_priv_data_entry
*entry
;
2016 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2017 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2020 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2025 case WM_RENDERALLFORMATS
:
2028 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
2030 TRACE("(): WM_RENDERALLFORMATS\n");
2032 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2034 if(entries
[i
].first_use
)
2035 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2040 case WM_DESTROYCLIPBOARD
:
2042 TRACE("(): WM_DESTROYCLIPBOARD\n");
2044 set_src_dataobject(clipbrd
, NULL
);
2049 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2056 /***********************************************************************
2057 * create_clipbrd_window
2059 static HWND
create_clipbrd_window(void)
2062 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2063 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2064 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2066 class.cbSize
= sizeof(class);
2068 class.lpfnWndProc
= clipbrd_wndproc
;
2069 class.cbClsExtra
= 0;
2070 class.cbWndExtra
= 0;
2071 class.hInstance
= hinst
;
2074 class.hbrBackground
= 0;
2075 class.lpszMenuName
= NULL
;
2076 class.lpszClassName
= clipbrd_wndclass
;
2077 class.hIconSm
= NULL
;
2079 RegisterClassExW(&class);
2081 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2082 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2083 NULL
, NULL
, hinst
, 0);
2086 /*********************************************************************
2087 * set_dataobject_format
2089 * Windows creates a 'DataObject' clipboard format that contains the
2090 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2092 static HRESULT
set_dataobject_format(HWND hwnd
)
2094 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2097 if(!h
) return E_OUTOFMEMORY
;
2099 data
= GlobalLock(h
);
2103 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2106 return CLIPBRD_E_CANT_SET
;
2112 /*---------------------------------------------------------------------*
2113 * Win32 OLE clipboard API
2114 *---------------------------------------------------------------------*/
2116 /***********************************************************************
2117 * OleSetClipboard [OLE32.@]
2118 * Places a pointer to the specified data object onto the clipboard,
2119 * making the data object accessible to the OleGetClipboard function.
2123 * S_OK IDataObject pointer placed on the clipboard
2124 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2125 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2126 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2127 * CLIPBRD_E_CANT_SET SetClipboard failed
2130 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2133 ole_clipbrd
*clipbrd
;
2136 TRACE("(%p)\n", data
);
2138 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2140 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2142 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2144 if ( !EmptyClipboard() )
2146 hr
= CLIPBRD_E_CANT_EMPTY
;
2150 hr
= set_src_dataobject(clipbrd
, data
);
2151 if(FAILED(hr
)) goto end
;
2155 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2156 if(FAILED(hr
)) goto end
;
2157 hr
= set_dataobject_format(wnd
);
2162 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2166 expose_marshalled_dataobject(clipbrd
, NULL
);
2167 set_src_dataobject(clipbrd
, NULL
);
2174 /***********************************************************************
2175 * OleGetClipboard [OLE32.@]
2176 * Returns a pointer to our internal IDataObject which represents the conceptual
2177 * state of the Windows clipboard. If the current clipboard already contains
2178 * an IDataObject, our internal IDataObject will delegate to this object.
2180 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2183 ole_clipbrd
*clipbrd
;
2186 TRACE("(%p)\n", obj
);
2188 if(!obj
) return E_INVALIDARG
;
2191 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2193 seq_no
= GetClipboardSequenceNumber();
2194 EnterCriticalSection(&latest_snapshot_cs
);
2195 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2196 clipbrd
->latest_snapshot
= NULL
;
2198 if(!clipbrd
->latest_snapshot
)
2200 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2201 if(!clipbrd
->latest_snapshot
)
2203 LeaveCriticalSection(&latest_snapshot_cs
);
2204 return E_OUTOFMEMORY
;
2208 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2209 IDataObject_AddRef(*obj
);
2210 LeaveCriticalSection(&latest_snapshot_cs
);
2215 /******************************************************************************
2216 * OleFlushClipboard [OLE32.@]
2217 * Renders the data from the source IDataObject into the windows clipboard
2219 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2220 * by copying the storage into global memory. Subsequently the default
2221 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2222 * back to TYMED_IStorage.
2224 HRESULT WINAPI
OleFlushClipboard(void)
2227 ole_clipbrd
*clipbrd
;
2232 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2234 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2237 * Already flushed or no source DataObject? Nothing to do.
2239 if (!clipbrd
->src_data
) return S_OK
;
2241 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2243 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2245 hr
= set_dataobject_format(NULL
);
2247 expose_marshalled_dataobject(clipbrd
, NULL
);
2248 set_src_dataobject(clipbrd
, NULL
);
2250 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2256 /***********************************************************************
2257 * OleIsCurrentClipboard [OLE32.@]
2259 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2262 ole_clipbrd
*clipbrd
;
2265 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2267 if (data
== NULL
) return S_FALSE
;
2269 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;