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 med
.pUnkForRelease
= NULL
;
814 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
815 if(FAILED(hr
)) return hr
;
817 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
819 if(SUCCEEDED(hr
)) *mem
= h
;
821 ReleaseStgMedium(&med
);
826 /***************************************************************************
827 * get_data_from_enhmetafile
829 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
839 mem_fmt
.tymed
= TYMED_ENHMF
;
841 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
842 if(FAILED(hr
)) return hr
;
844 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
845 if(copy
) *mem
= (HGLOBAL
)copy
;
848 ReleaseStgMedium(&med
);
853 /***************************************************************************
854 * get_data_from_metafilepict
856 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
866 mem_fmt
.tymed
= TYMED_MFPICT
;
868 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
869 if(FAILED(hr
)) return hr
;
871 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
873 if(SUCCEEDED(hr
)) *mem
= copy
;
875 ReleaseStgMedium(&med
);
880 /***************************************************************************
881 * get_data_from_bitmap
883 * Returns bitmap in an HBITMAP.
885 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
895 mem_fmt
.tymed
= TYMED_GDI
;
897 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
898 if(FAILED(hr
)) return hr
;
900 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
902 if(SUCCEEDED(hr
)) *hbm
= copy
;
904 ReleaseStgMedium(&med
);
909 /***********************************************************************
912 * Render the clipboard data. Note that this call will delegate to the
913 * source data object.
915 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
917 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
920 /* Embed source hack */
921 if(fmt
->cfFormat
== embed_source_clipboard_format
)
923 return render_embed_source_hack(data
, fmt
);
926 if(fmt
->tymed
& TYMED_ISTORAGE
)
928 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
930 else if(fmt
->tymed
& TYMED_ISTREAM
)
932 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
934 else if(fmt
->tymed
& TYMED_HGLOBAL
)
936 hr
= get_data_from_global(data
, fmt
, &clip_data
);
938 else if(fmt
->tymed
& TYMED_ENHMF
)
940 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
942 else if(fmt
->tymed
& TYMED_MFPICT
)
944 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
945 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
947 else if(fmt
->tymed
& TYMED_GDI
)
949 /* Returns HBITMAP not HGLOBAL */
950 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
954 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
960 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
962 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
963 if(fmt
->tymed
& TYMED_MFPICT
)
964 free_metafilepict(clip_data
);
965 else if(fmt
->tymed
& TYMED_GDI
)
966 DeleteObject(clip_data
);
968 GlobalFree(clip_data
);
969 hr
= CLIPBRD_E_CANT_SET
;
976 /*---------------------------------------------------------------------*
977 * Implementation of the internal IDataObject interface exposed by
979 *---------------------------------------------------------------------*/
982 /************************************************************************
983 * snapshot_QueryInterface
985 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
986 REFIID riid
, void **ppvObject
)
988 snapshot
*This
= impl_from_IDataObject(iface
);
989 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
991 if ( (This
==0) || (ppvObject
==0) )
996 if (IsEqualIID(&IID_IUnknown
, riid
) ||
997 IsEqualIID(&IID_IDataObject
, riid
))
1003 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1004 return E_NOINTERFACE
;
1007 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1012 /************************************************************************
1015 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1017 snapshot
*This
= impl_from_IDataObject(iface
);
1019 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1021 return InterlockedIncrement(&This
->ref
);
1024 /************************************************************************
1027 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1029 snapshot
*This
= impl_from_IDataObject(iface
);
1032 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1034 ref
= InterlockedDecrement(&This
->ref
);
1038 EnterCriticalSection(&latest_snapshot_cs
);
1041 LeaveCriticalSection(&latest_snapshot_cs
);
1044 if (theOleClipboard
->latest_snapshot
== This
)
1045 theOleClipboard
->latest_snapshot
= NULL
;
1046 LeaveCriticalSection(&latest_snapshot_cs
);
1048 if(This
->data
) IDataObject_Release(This
->data
);
1049 HeapFree(GetProcessHeap(), 0, This
);
1055 /************************************************************
1056 * get_current_ole_clip_window
1058 * Return the window that owns the ole clipboard.
1060 * If the clipboard is flushed or not owned by ole this will
1063 static HWND
get_current_ole_clip_window(void)
1068 h
= GetClipboardData(dataobject_clipboard_format
);
1070 ptr
= GlobalLock(h
);
1071 if(!ptr
) return NULL
;
1077 /************************************************************
1078 * get_current_dataobject
1080 * Return an unmarshalled IDataObject if there is a current
1081 * (ie non-flushed) object on the ole clipboard.
1083 static HRESULT
get_current_dataobject(IDataObject
**data
)
1085 HRESULT hr
= S_FALSE
;
1086 HWND wnd
= get_current_ole_clip_window();
1093 if(!wnd
) return S_FALSE
;
1095 h
= GetClipboardData(wine_marshal_clipboard_format
);
1096 if(!h
) return S_FALSE
;
1097 if(GlobalSize(h
) == 0) return S_FALSE
;
1098 ptr
= GlobalLock(h
);
1099 if(!ptr
) return S_FALSE
;
1101 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1102 if(FAILED(hr
)) goto end
;
1104 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1108 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1109 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1111 IStream_Release(stm
);
1118 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1120 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1126 case CF_UNICODETEXT
:
1127 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1128 case CF_ENHMETAFILE
:
1130 case CF_METAFILEPICT
:
1131 return TYMED_MFPICT
;
1135 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1140 /***********************************************************
1143 * Returns a copy of the Ole Private Data
1145 static HRESULT
get_priv_data(ole_priv_data
**data
)
1149 ole_priv_data
*ret
= NULL
;
1153 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1156 ole_priv_data
*src
= GlobalLock(handle
);
1161 /* FIXME: sanity check on size */
1162 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1165 GlobalUnlock(handle
);
1166 return E_OUTOFMEMORY
;
1168 memcpy(ret
, src
, src
->size
);
1169 GlobalUnlock(handle
);
1171 /* Fixup any target device offsets to ptrs */
1172 for(i
= 0; i
< ret
->count
; i
++)
1173 ret
->entries
[i
].fmtetc
.ptd
=
1174 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1178 if(!ret
) /* Non-ole data */
1181 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1183 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1186 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1187 TRACE("cf %04x %s\n", cf
, buf
);
1189 TRACE("count %d\n", count
);
1190 size
+= count
* sizeof(ret
->entries
[0]);
1192 /* There are holes in fmtetc so zero init */
1193 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1194 if(!ret
) return E_OUTOFMEMORY
;
1198 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1200 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1201 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1202 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1203 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1204 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1205 ret
->entries
[idx
].first_use
= 1;
1213 /************************************************************************
1214 * get_stgmed_for_global
1216 * Returns a stg medium with a copy of the global handle
1218 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1222 med
->pUnkForRelease
= NULL
;
1223 med
->tymed
= TYMED_NULL
;
1225 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1227 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1232 /************************************************************************
1233 * get_stgmed_for_stream
1235 * Returns a stg medium with a stream based on the handle
1237 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1242 med
->pUnkForRelease
= NULL
;
1243 med
->tymed
= TYMED_NULL
;
1245 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1246 if(FAILED(hr
)) return hr
;
1248 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1255 med
->tymed
= TYMED_ISTREAM
;
1259 /************************************************************************
1260 * get_stgmed_for_storage
1262 * Returns a stg medium with a storage based on the handle
1264 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1270 med
->pUnkForRelease
= NULL
;
1271 med
->tymed
= TYMED_NULL
;
1273 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1274 if(FAILED(hr
)) return hr
;
1276 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1283 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1284 ILockBytes_Release(lbs
);
1291 med
->tymed
= TYMED_ISTORAGE
;
1295 /************************************************************************
1296 * get_stgmed_for_emf
1298 * Returns a stg medium with an enhanced metafile based on the handle
1300 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1302 med
->pUnkForRelease
= NULL
;
1303 med
->tymed
= TYMED_NULL
;
1305 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1306 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1307 med
->tymed
= TYMED_ENHMF
;
1311 /************************************************************************
1312 * get_stgmed_for_bitmap
1314 * Returns a stg medium with a bitmap based on the handle
1316 static HRESULT
get_stgmed_for_bitmap(HBITMAP hbmp
, STGMEDIUM
*med
)
1320 med
->pUnkForRelease
= NULL
;
1321 med
->tymed
= TYMED_NULL
;
1323 hr
= dup_bitmap(hbmp
, &med
->u
.hBitmap
);
1328 med
->tymed
= TYMED_GDI
;
1332 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1334 const WCHAR
*str1
, *str2
;
1336 if(off1
== 0 && off2
== 0) return TRUE
;
1337 if(off1
== 0 || off2
== 0) return FALSE
;
1339 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1340 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1342 return !lstrcmpW(str1
, str2
);
1345 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1347 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1348 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1350 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1352 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1354 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1357 /* FIXME check devmode? */
1362 /************************************************************************
1365 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1368 snapshot
*This
= impl_from_IDataObject(iface
);
1371 ole_priv_data
*enum_data
= NULL
;
1372 ole_priv_data_entry
*entry
;
1375 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1377 if ( !fmt
|| !med
) return E_INVALIDARG
;
1379 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1382 hr
= get_current_dataobject(&This
->data
);
1386 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1391 h
= GetClipboardData(fmt
->cfFormat
);
1394 hr
= DV_E_FORMATETC
;
1398 hr
= get_priv_data(&enum_data
);
1399 if(FAILED(hr
)) goto end
;
1401 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1404 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1406 hr
= DV_E_FORMATETC
;
1409 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1410 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1412 else /* non-Ole format */
1413 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1415 if(mask
& TYMED_ISTORAGE
)
1416 hr
= get_stgmed_for_storage(h
, med
);
1417 else if(mask
& TYMED_HGLOBAL
)
1418 hr
= get_stgmed_for_global(h
, med
);
1419 else if(mask
& TYMED_ISTREAM
)
1420 hr
= get_stgmed_for_stream(h
, med
);
1421 else if(mask
& TYMED_ENHMF
)
1422 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1423 else if(mask
& TYMED_GDI
)
1424 hr
= get_stgmed_for_bitmap((HBITMAP
)h
, med
);
1427 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1433 HeapFree(GetProcessHeap(), 0, enum_data
);
1434 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1438 /************************************************************************
1439 * snapshot_GetDataHere
1441 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1444 snapshot
*This
= impl_from_IDataObject(iface
);
1447 ole_priv_data
*enum_data
= NULL
;
1448 ole_priv_data_entry
*entry
;
1451 if ( !fmt
|| !med
) return E_INVALIDARG
;
1453 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1455 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1458 hr
= get_current_dataobject(&This
->data
);
1462 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1470 h
= GetClipboardData(fmt
->cfFormat
);
1473 hr
= DV_E_FORMATETC
;
1477 hr
= get_priv_data(&enum_data
);
1478 if(FAILED(hr
)) goto end
;
1480 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1483 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1485 hr
= DV_E_FORMATETC
;
1488 supported
= entry
->fmtetc
.tymed
;
1490 else /* non-Ole format */
1491 supported
= TYMED_HGLOBAL
;
1497 DWORD src_size
= GlobalSize(h
);
1498 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1500 if(dst_size
>= src_size
)
1502 void *src
= GlobalLock(h
);
1503 void *dst
= GlobalLock(med
->u
.hGlobal
);
1505 memcpy(dst
, src
, src_size
);
1506 GlobalUnlock(med
->u
.hGlobal
);
1514 DWORD src_size
= GlobalSize(h
);
1515 void *src
= GlobalLock(h
);
1516 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1520 case TYMED_ISTORAGE
:
1523 if(!(supported
& TYMED_ISTORAGE
))
1528 hr
= get_stgmed_for_storage(h
, ©
);
1531 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1532 ReleaseStgMedium(©
);
1537 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1543 HeapFree(GetProcessHeap(), 0, enum_data
);
1544 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1548 /************************************************************************
1549 * snapshot_QueryGetData
1551 * The OLE Clipboard's implementation of this method delegates to
1552 * a data source if there is one or wraps around the windows clipboard
1553 * function IsClipboardFormatAvailable() otherwise.
1556 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1558 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1560 if (!fmt
) return E_INVALIDARG
;
1562 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1564 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1566 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1569 /************************************************************************
1570 * snapshot_GetCanonicalFormatEtc
1572 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1575 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1577 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1580 return DATA_S_SAMEFORMATETC
;
1583 /************************************************************************
1586 * The OLE Clipboard does not implement this method
1588 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1589 STGMEDIUM
*med
, BOOL release
)
1591 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1595 /************************************************************************
1596 * snapshot_EnumFormatEtc
1599 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1600 IEnumFORMATETC
**enum_fmt
)
1603 ole_priv_data
*data
= NULL
;
1605 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1609 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1610 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1612 hr
= get_priv_data(&data
);
1614 if(FAILED(hr
)) goto end
;
1616 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1619 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1623 /************************************************************************
1626 * The OLE Clipboard does not implement this method
1628 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1629 DWORD flags
, IAdviseSink
*sink
,
1632 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1636 /************************************************************************
1637 * snapshot_DUnadvise
1639 * The OLE Clipboard does not implement this method
1641 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1643 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1647 /************************************************************************
1648 * snapshot_EnumDAdvise
1650 * The OLE Clipboard does not implement this method
1652 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1653 IEnumSTATDATA
** enum_advise
)
1655 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1659 static const IDataObjectVtbl snapshot_vtable
=
1661 snapshot_QueryInterface
,
1665 snapshot_GetDataHere
,
1666 snapshot_QueryGetData
,
1667 snapshot_GetCanonicalFormatEtc
,
1669 snapshot_EnumFormatEtc
,
1672 snapshot_EnumDAdvise
1675 /*---------------------------------------------------------------------*
1676 * Internal implementation methods for the OLE clipboard
1677 *---------------------------------------------------------------------*/
1679 static snapshot
*snapshot_construct(DWORD seq_no
)
1683 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1684 if (!This
) return NULL
;
1686 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1688 This
->seq_no
= seq_no
;
1694 /*********************************************************
1695 * register_clipboard_formats
1697 static void register_clipboard_formats(void)
1699 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1700 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1701 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1702 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1703 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1704 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1705 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1706 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1707 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1708 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1709 'D','e','s','c','r','i','p','t','o','r',0};
1710 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1712 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1713 'D','a','t','a','O','b','j','e','c','t',0};
1715 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1716 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1717 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1718 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1719 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1720 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1721 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1722 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1723 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1724 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1725 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1727 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1730 /***********************************************************************
1731 * OLEClipbrd_Initialize()
1732 * Initializes the OLE clipboard.
1734 void OLEClipbrd_Initialize(void)
1736 register_clipboard_formats();
1738 if ( !theOleClipboard
)
1740 ole_clipbrd
* clipbrd
;
1745 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1746 if (!clipbrd
) return;
1748 clipbrd
->latest_snapshot
= NULL
;
1749 clipbrd
->window
= NULL
;
1750 clipbrd
->src_data
= NULL
;
1751 clipbrd
->cached_enum
= NULL
;
1753 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1756 HeapFree(GetProcessHeap(), 0, clipbrd
);
1760 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1763 HeapFree(GetProcessHeap(), 0, clipbrd
);
1767 theOleClipboard
= clipbrd
;
1771 /***********************************************************************
1772 * OLEClipbrd_UnInitialize()
1773 * Un-Initializes the OLE clipboard
1775 void OLEClipbrd_UnInitialize(void)
1777 ole_clipbrd
*clipbrd
= theOleClipboard
;
1783 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1784 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1786 if ( clipbrd
->window
)
1788 DestroyWindow(clipbrd
->window
);
1789 UnregisterClassW( clipbrd_wndclass
, hinst
);
1792 IStream_Release(clipbrd
->marshal_data
);
1793 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1794 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1795 HeapFree(GetProcessHeap(), 0, clipbrd
);
1796 theOleClipboard
= NULL
;
1800 /*********************************************************************
1801 * set_clipboard_formats
1803 * Enumerate all formats supported by the source and make
1804 * those formats available using delayed rendering using SetClipboardData.
1805 * Cache the enumeration list and make that list visible as the
1806 * 'Ole Private Data' format on the clipboard.
1809 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1813 IEnumFORMATETC
*enum_fmt
;
1814 HGLOBAL priv_data_handle
;
1815 DWORD_PTR target_offset
;
1816 ole_priv_data
*priv_data
;
1817 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1819 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1820 if(FAILED(hr
)) return hr
;
1822 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1825 needed
+= sizeof(priv_data
->entries
[0]);
1828 needed
+= fmt
.ptd
->tdSize
;
1829 CoTaskMemFree(fmt
.ptd
);
1833 /* Windows pads the list with two empty ole_priv_data_entries, one
1834 * after the entries array and one after the target device data.
1835 * Allocating with zero init to zero these pads. */
1837 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1838 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1839 priv_data
= GlobalLock(priv_data_handle
);
1841 priv_data
->unk1
= 0;
1842 priv_data
->size
= needed
;
1843 priv_data
->unk2
= 1;
1844 priv_data
->count
= count
;
1845 priv_data
->unk3
[0] = 0;
1846 priv_data
->unk3
[1] = 0;
1848 IEnumFORMATETC_Reset(enum_fmt
);
1851 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1853 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1855 TRACE("%s\n", dump_fmtetc(&fmt
));
1857 priv_data
->entries
[idx
].fmtetc
= fmt
;
1860 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1861 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1862 target_offset
+= fmt
.ptd
->tdSize
;
1863 CoTaskMemFree(fmt
.ptd
);
1866 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1867 priv_data
->entries
[idx
].unk
[0] = 0;
1868 priv_data
->entries
[idx
].unk
[1] = 0;
1870 if (priv_data
->entries
[idx
].first_use
)
1871 SetClipboardData(fmt
.cfFormat
, NULL
);
1876 IEnumFORMATETC_Release(enum_fmt
);
1878 /* Cache the list and fixup any target device offsets to ptrs */
1879 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1880 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1881 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1882 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1883 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1885 GlobalUnlock(priv_data_handle
);
1886 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1888 GlobalFree(priv_data_handle
);
1889 return CLIPBRD_E_CANT_SET
;
1895 static HWND
create_clipbrd_window(void);
1897 /***********************************************************************
1898 * get_clipbrd_window
1900 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1902 if ( !clipbrd
->window
)
1903 clipbrd
->window
= create_clipbrd_window();
1905 *wnd
= clipbrd
->window
;
1906 return *wnd
? S_OK
: E_FAIL
;
1910 /**********************************************************************
1911 * release_marshal_data
1913 * Releases the data and sets the stream back to zero size.
1915 static inline void release_marshal_data(IStream
*stm
)
1918 ULARGE_INTEGER size
;
1919 pos
.QuadPart
= size
.QuadPart
= 0;
1921 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1922 CoReleaseMarshalData(stm
);
1923 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1924 IStream_SetSize(stm
, size
);
1927 /***********************************************************************
1928 * expose_marshalled_dataobject
1930 * Sets the marshalled dataobject to the clipboard. In the flushed case
1931 * we set a zero sized HGLOBAL to clear the old marshalled data.
1933 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1940 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1941 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1944 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1946 if(!h
) return E_OUTOFMEMORY
;
1948 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1951 return CLIPBRD_E_CANT_SET
;
1956 /***********************************************************************
1957 * set_src_dataobject
1959 * Clears and sets the clipboard's src IDataObject.
1961 * To marshal the source dataobject we do something rather different from Windows.
1962 * We set a clipboard format which contains the marshalled data.
1963 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1965 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1970 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1972 if(clipbrd
->src_data
)
1974 release_marshal_data(clipbrd
->marshal_data
);
1976 IDataObject_Release(clipbrd
->src_data
);
1977 clipbrd
->src_data
= NULL
;
1978 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1979 clipbrd
->cached_enum
= NULL
;
1986 IDataObject_AddRef(data
);
1987 clipbrd
->src_data
= data
;
1989 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1990 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1991 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1992 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1993 if(FAILED(hr
)) return hr
;
1994 hr
= set_clipboard_formats(clipbrd
, data
);
1999 /***********************************************************************
2002 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
2004 ole_clipbrd
*clipbrd
;
2006 get_ole_clipbrd(&clipbrd
);
2009 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2014 case WM_RENDERFORMAT
:
2017 ole_priv_data_entry
*entry
;
2019 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2020 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2023 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2028 case WM_RENDERALLFORMATS
:
2031 ole_priv_data_entry
*entries
;
2033 TRACE("(): WM_RENDERALLFORMATS\n");
2035 if (!clipbrd
|| !clipbrd
->cached_enum
) break;
2036 entries
= clipbrd
->cached_enum
->entries
;
2037 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2039 if(entries
[i
].first_use
)
2040 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2045 case WM_DESTROYCLIPBOARD
:
2047 TRACE("(): WM_DESTROYCLIPBOARD\n");
2049 set_src_dataobject(clipbrd
, NULL
);
2054 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2061 /***********************************************************************
2062 * create_clipbrd_window
2064 static HWND
create_clipbrd_window(void)
2067 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2068 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2069 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2071 class.cbSize
= sizeof(class);
2073 class.lpfnWndProc
= clipbrd_wndproc
;
2074 class.cbClsExtra
= 0;
2075 class.cbWndExtra
= 0;
2076 class.hInstance
= hinst
;
2079 class.hbrBackground
= 0;
2080 class.lpszMenuName
= NULL
;
2081 class.lpszClassName
= clipbrd_wndclass
;
2082 class.hIconSm
= NULL
;
2084 RegisterClassExW(&class);
2086 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2087 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2088 NULL
, NULL
, hinst
, 0);
2091 /*********************************************************************
2092 * set_dataobject_format
2094 * Windows creates a 'DataObject' clipboard format that contains the
2095 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2097 static HRESULT
set_dataobject_format(HWND hwnd
)
2099 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2102 if(!h
) return E_OUTOFMEMORY
;
2104 data
= GlobalLock(h
);
2108 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2111 return CLIPBRD_E_CANT_SET
;
2117 /*---------------------------------------------------------------------*
2118 * Win32 OLE clipboard API
2119 *---------------------------------------------------------------------*/
2121 /***********************************************************************
2122 * OleSetClipboard [OLE32.@]
2123 * Places a pointer to the specified data object onto the clipboard,
2124 * making the data object accessible to the OleGetClipboard function.
2128 * S_OK IDataObject pointer placed on the clipboard
2129 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2130 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2131 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2132 * CLIPBRD_E_CANT_SET SetClipboard failed
2135 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2138 ole_clipbrd
*clipbrd
;
2141 TRACE("(%p)\n", data
);
2143 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2145 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2147 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2149 if ( !EmptyClipboard() )
2151 hr
= CLIPBRD_E_CANT_EMPTY
;
2155 hr
= set_src_dataobject(clipbrd
, data
);
2156 if(FAILED(hr
)) goto end
;
2160 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2161 if(FAILED(hr
)) goto end
;
2162 hr
= set_dataobject_format(wnd
);
2167 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2171 expose_marshalled_dataobject(clipbrd
, NULL
);
2172 set_src_dataobject(clipbrd
, NULL
);
2179 /***********************************************************************
2180 * OleGetClipboard [OLE32.@]
2181 * Returns a pointer to our internal IDataObject which represents the conceptual
2182 * state of the Windows clipboard. If the current clipboard already contains
2183 * an IDataObject, our internal IDataObject will delegate to this object.
2185 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2188 ole_clipbrd
*clipbrd
;
2191 TRACE("(%p)\n", obj
);
2193 if(!obj
) return E_INVALIDARG
;
2196 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2198 seq_no
= GetClipboardSequenceNumber();
2199 EnterCriticalSection(&latest_snapshot_cs
);
2200 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2201 clipbrd
->latest_snapshot
= NULL
;
2203 if(!clipbrd
->latest_snapshot
)
2205 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2206 if(!clipbrd
->latest_snapshot
)
2208 LeaveCriticalSection(&latest_snapshot_cs
);
2209 return E_OUTOFMEMORY
;
2213 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2214 IDataObject_AddRef(*obj
);
2215 LeaveCriticalSection(&latest_snapshot_cs
);
2220 /******************************************************************************
2221 * OleFlushClipboard [OLE32.@]
2222 * Renders the data from the source IDataObject into the windows clipboard
2224 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2225 * by copying the storage into global memory. Subsequently the default
2226 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2227 * back to TYMED_IStorage.
2229 HRESULT WINAPI
OleFlushClipboard(void)
2232 ole_clipbrd
*clipbrd
;
2237 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2239 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2242 * Already flushed or no source DataObject? Nothing to do.
2244 if (!clipbrd
->src_data
) return S_OK
;
2246 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2248 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2250 hr
= set_dataobject_format(NULL
);
2252 expose_marshalled_dataobject(clipbrd
, NULL
);
2253 set_src_dataobject(clipbrd
, NULL
);
2255 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2261 /***********************************************************************
2262 * OleIsCurrentClipboard [OLE32.@]
2264 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2267 ole_clipbrd
*clipbrd
;
2270 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2272 if (data
== NULL
) return S_FALSE
;
2274 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;