2 * OLE 2 clipboard support
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * This file contains the implementation for the OLE Clipboard and its
23 * internal interfaces. The OLE clipboard interacts with an IDataObject
24 * interface via the OleSetClipboard, OleGetClipboard and
25 * OleIsCurrentClipboard API's. An internal IDataObject delegates
26 * to a client supplied IDataObject or the WIN32 clipboard API depending
27 * on whether OleSetClipboard has been invoked.
28 * Here are some operating scenarios:
30 * 1. OleSetClipboard called: In this case the internal IDataObject
31 * delegates to the client supplied IDataObject. Additionally OLE takes
32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject
33 * items are placed on the Windows clipboard. This allows non OLE aware
34 * applications to access these. A local WinProc fields WM_RENDERFORMAT
35 * and WM_RENDERALLFORMATS messages in this case.
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41 * IDataObject delegates to the source IDataObjects functionality directly,
42 * thereby bypassing the Windows clipboard.
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
47 * - Support for pasting between different processes. OLE clipboard support
48 * currently works only for in process copy and paste. Since we internally
49 * store a pointer to the source's IDataObject and delegate to that, this
50 * will fail if the IDataObject client belongs to a different process.
51 * - IDataObject::GetDataHere is not implemented
52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53 * by copying the storage into global memory. Subsequently the default
54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55 * back to TYMED_IStorage.
56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57 * clipboard in OleSetClipboard.
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
77 #include "wine/debug.h"
80 #include "storage32.h"
82 #include "compobj_private.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
86 /* Structure of 'Ole Private Data' clipboard format */
90 DWORD first_use
; /* Has this cf been added to the list already */
92 } ole_priv_data_entry
;
97 DWORD size
; /* in bytes of the entire structure */
99 DWORD count
; /* no. of format entries */
101 ole_priv_data_entry entries
[1]; /* array of size count */
102 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
105 /*****************************************************************************
108 * Returns a ptr to a target device at a given offset from the
109 * start of the ole_priv_data.
111 * Used when unpacking ole private data from the clipboard.
113 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
115 if(off
== 0) return NULL
;
116 return (DVTARGETDEVICE
*)((char*)data
+ off
);
119 /*****************************************************************************
122 * Get the offset from the start of the ole_priv_data of the idx'th
125 * Used when packing ole private data to the clipboard.
127 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
129 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
130 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
133 /****************************************************************************
134 * Consumer snapshot. Represents the state of the ole clipboard
135 * returned by OleGetClipboard().
137 typedef struct snapshot
139 IDataObject IDataObject_iface
;
142 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
144 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
147 /****************************************************************************
150 typedef struct ole_clipbrd
152 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
154 HWND window
; /* Hidden clipboard window */
155 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
156 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
157 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
160 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
162 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
165 typedef struct PresentationDataHeader
168 DWORD dwObjectExtentX
;
169 DWORD dwObjectExtentY
;
171 } PresentationDataHeader
;
174 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
176 static ole_clipbrd
* theOleClipboard
;
178 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
180 struct oletls
*info
= COM_CurrentInfo();
184 return CO_E_NOTINITIALIZED
;
185 *clipbrd
= theOleClipboard
;
191 * Name of our registered OLE clipboard window class
193 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
195 UINT ownerlink_clipboard_format
= 0;
196 UINT filename_clipboard_format
= 0;
197 UINT filenameW_clipboard_format
= 0;
198 UINT dataobject_clipboard_format
= 0;
199 UINT embedded_object_clipboard_format
= 0;
200 UINT embed_source_clipboard_format
= 0;
201 UINT custom_link_source_clipboard_format
= 0;
202 UINT link_source_clipboard_format
= 0;
203 UINT object_descriptor_clipboard_format
= 0;
204 UINT link_source_descriptor_clipboard_format
= 0;
205 UINT ole_private_data_clipboard_format
= 0;
207 static UINT wine_marshal_clipboard_format
;
209 static inline const char *dump_fmtetc(FORMATETC
*fmt
)
211 if (!fmt
) return "(null)";
212 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
213 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
216 /*---------------------------------------------------------------------*
217 * Implementation of the internal IEnumFORMATETC interface returned by
218 * the OLE clipboard's IDataObject.
219 *---------------------------------------------------------------------*/
221 typedef struct enum_fmtetc
223 IEnumFORMATETC IEnumFORMATETC_iface
;
226 UINT pos
; /* current enumerator position */
230 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
232 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
235 /************************************************************************
236 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
238 * See Windows documentation for more details on IUnknown methods.
240 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
241 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
243 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
245 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
249 if(IsEqualIID(riid
, &IID_IUnknown
) ||
250 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
257 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
258 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
262 TRACE("-- Interface: E_NOINTERFACE\n");
263 return E_NOINTERFACE
;
266 /************************************************************************
267 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
270 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
272 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
273 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
275 return InterlockedIncrement(&This
->ref
);
278 /************************************************************************
279 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
281 * See Windows documentation for more details on IUnknown methods.
283 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
285 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
288 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
290 ref
= InterlockedDecrement(&This
->ref
);
293 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
294 HeapFree(GetProcessHeap(), 0, This
->data
);
295 HeapFree(GetProcessHeap(), 0, This
);
300 /************************************************************************
301 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
303 * Standard enumerator members for IEnumFORMATETC
305 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
306 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
308 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
310 HRESULT hres
= S_FALSE
;
312 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
314 if (This
->pos
< This
->data
->count
)
316 cfetch
= This
->data
->count
- This
->pos
;
323 for(i
= 0; i
< cfetch
; i
++)
325 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
328 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
329 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
330 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
331 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
342 *pceltFethed
= cfetch
;
348 /************************************************************************
349 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
351 * Standard enumerator members for IEnumFORMATETC
353 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
355 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
356 TRACE("(%p)->(num=%u)\n", This
, celt
);
359 if (This
->pos
> This
->data
->count
)
361 This
->pos
= This
->data
->count
;
367 /************************************************************************
368 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
370 * Standard enumerator members for IEnumFORMATETC
372 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
374 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
375 TRACE("(%p)->()\n", This
);
381 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
383 /************************************************************************
384 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
386 * Standard enumerator members for IEnumFORMATETC
388 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
389 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
391 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
392 ole_priv_data
*new_data
;
395 TRACE("(%p)->(%p)\n", This
, obj
);
397 if ( !obj
) return E_INVALIDARG
;
400 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
401 if(!new_data
) return E_OUTOFMEMORY
;
402 memcpy(new_data
, This
->data
, This
->data
->size
);
404 /* Fixup any target device ptrs */
405 for(i
= 0; i
< This
->data
->count
; i
++)
406 new_data
->entries
[i
].fmtetc
.ptd
=
407 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
409 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
412 static const IEnumFORMATETCVtbl efvt
=
414 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
415 OLEClipbrd_IEnumFORMATETC_AddRef
,
416 OLEClipbrd_IEnumFORMATETC_Release
,
417 OLEClipbrd_IEnumFORMATETC_Next
,
418 OLEClipbrd_IEnumFORMATETC_Skip
,
419 OLEClipbrd_IEnumFORMATETC_Reset
,
420 OLEClipbrd_IEnumFORMATETC_Clone
423 /************************************************************************
424 * enum_fmtetc_construct
426 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
428 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
433 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
434 if (!ef
) return E_OUTOFMEMORY
;
437 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
441 TRACE("(%p)->()\n", ef
);
442 *obj
= &ef
->IEnumFORMATETC_iface
;
446 /***********************************************************************
449 * Helper method to duplicate an HGLOBAL chunk of memory
451 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
453 void *src_ptr
, *dst_ptr
;
457 if ( !src
) return S_FALSE
;
459 size
= GlobalSize(src
);
461 *dst
= GlobalAlloc( flags
, size
);
462 if ( !*dst
) return E_OUTOFMEMORY
;
464 src_ptr
= GlobalLock(src
);
465 dst_ptr
= GlobalLock(*dst
);
467 memcpy(dst_ptr
, src_ptr
, size
);
475 /***********************************************************************
478 * Helper function to duplicate a handle to a METAFILEPICT, and the
479 * contained HMETAFILE.
481 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
485 METAFILEPICT
*dest_ptr
;
489 /* Copy the METAFILEPICT structure. */
490 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
491 if (FAILED(hr
)) return hr
;
493 dest_ptr
= GlobalLock(dest
);
494 if (!dest_ptr
) return E_FAIL
;
496 /* Give the new METAFILEPICT a separate HMETAFILE. */
497 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
512 /***********************************************************************
515 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
516 * free the contained HMETAFILE.
518 static void free_metafilepict(HGLOBAL src
)
520 METAFILEPICT
*src_ptr
;
522 src_ptr
= GlobalLock(src
);
525 DeleteMetaFile(src_ptr
->hMF
);
531 /***********************************************************************
534 * Helper function to duplicate an HBITMAP.
536 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
539 HGDIOBJ orig_src_bitmap
;
543 src_dc
= CreateCompatibleDC(NULL
);
544 orig_src_bitmap
= SelectObject(src_dc
, src
);
545 GetObjectW(src
, sizeof bm
, &bm
);
546 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
549 HDC dest_dc
= CreateCompatibleDC(NULL
);
550 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
551 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
552 SelectObject(dest_dc
, orig_dest_bitmap
);
555 SelectObject(src_dc
, orig_src_bitmap
);
558 return dest
? S_OK
: E_FAIL
;
561 /************************************************************
562 * render_embed_source_hack
564 * This is clearly a hack and has no place in the clipboard code.
567 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
570 HGLOBAL hStorage
= 0;
572 ILockBytes
*ptrILockBytes
;
574 memset(&std
, 0, sizeof(STGMEDIUM
));
575 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
577 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
578 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
579 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
580 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
581 ILockBytes_Release(ptrILockBytes
);
583 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
585 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
586 GlobalFree(hStorage
);
590 if (1) /* check whether the presentation data is already -not- present */
594 METAFILEPICT
*mfp
= 0;
596 fmt2
.cfFormat
= CF_METAFILEPICT
;
598 fmt2
.dwAspect
= DVASPECT_CONTENT
;
600 fmt2
.tymed
= TYMED_MFPICT
;
602 memset(&std2
, 0, sizeof(STGMEDIUM
));
603 std2
.tymed
= TYMED_MFPICT
;
605 /* Get the metafile picture out of it */
607 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
609 mfp
= GlobalLock(std2
.u
.hGlobal
);
614 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
615 IStream
*pStream
= 0;
617 PresentationDataHeader pdh
;
621 CHAR strOleTypeName
[51];
622 BYTE OlePresStreamHeader
[] =
624 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
625 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
626 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
627 0x00, 0x00, 0x00, 0x00
630 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
632 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
633 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
635 pdh
.dwObjectExtentX
= mfp
->xExt
;
636 pdh
.dwObjectExtentY
= mfp
->yExt
;
639 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
641 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
643 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
644 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
646 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
648 IStream_Release(pStream
);
650 HeapFree(GetProcessHeap(), 0, mfBits
);
652 GlobalUnlock(std2
.u
.hGlobal
);
653 ReleaseStgMedium(&std2
);
655 ReadClassStg(std
.u
.pstg
, &clsID
);
656 ProgIDFromCLSID(&clsID
, &strProgID
);
658 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
659 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
660 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
661 CoTaskMemFree(strProgID
);
665 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
667 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
668 GlobalFree(hStorage
);
669 hr
= CLIPBRD_E_CANT_SET
;
672 ReleaseStgMedium(&std
);
676 /************************************************************************
677 * find_format_in_list
679 * Returns the first entry that matches the provided clipboard format.
681 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
684 for(i
= 0; i
< num
; i
++)
685 if(entries
[i
].fmtetc
.cfFormat
== cf
)
691 /***************************************************************************
692 * get_data_from_storage
694 * Returns storage data in an HGLOBAL.
696 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
707 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
708 if(!h
) return E_OUTOFMEMORY
;
710 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
713 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
714 ILockBytes_Release(lbs
);
723 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
725 med
.pUnkForRelease
= NULL
;
727 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
731 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
732 if(FAILED(hr
)) goto end
;
734 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
735 ReleaseStgMedium(&med
);
736 if(FAILED(hr
)) goto end
;
741 IStorage_Release(stg
);
742 if(FAILED(hr
)) GlobalFree(h
);
746 /***************************************************************************
747 * get_data_from_stream
749 * Returns stream data in an HGLOBAL.
751 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
761 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
762 if(!h
) return E_OUTOFMEMORY
;
764 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
765 if(FAILED(hr
)) goto error
;
768 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
770 med
.pUnkForRelease
= NULL
;
772 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
779 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
780 if(FAILED(hr
)) goto error
;
783 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
784 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
785 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
786 ReleaseStgMedium(&med
);
787 if(FAILED(hr
)) goto error
;
790 IStream_Release(stm
);
794 if(stm
) IStream_Release(stm
);
799 /***************************************************************************
800 * get_data_from_global
802 * Returns global data in an HGLOBAL.
804 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
814 mem_fmt
.tymed
= TYMED_HGLOBAL
;
816 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
817 if(FAILED(hr
)) return hr
;
819 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
821 if(SUCCEEDED(hr
)) *mem
= h
;
823 ReleaseStgMedium(&med
);
828 /***************************************************************************
829 * get_data_from_enhmetafile
831 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
841 mem_fmt
.tymed
= TYMED_ENHMF
;
843 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
844 if(FAILED(hr
)) return hr
;
846 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
847 if(copy
) *mem
= (HGLOBAL
)copy
;
850 ReleaseStgMedium(&med
);
855 /***************************************************************************
856 * get_data_from_metafilepict
858 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
868 mem_fmt
.tymed
= TYMED_MFPICT
;
870 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
871 if(FAILED(hr
)) return hr
;
873 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
875 if(SUCCEEDED(hr
)) *mem
= copy
;
877 ReleaseStgMedium(&med
);
882 /***************************************************************************
883 * get_data_from_bitmap
885 * Returns bitmap in an HBITMAP.
887 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
897 mem_fmt
.tymed
= TYMED_GDI
;
899 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
900 if(FAILED(hr
)) return hr
;
902 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
904 if(SUCCEEDED(hr
)) *hbm
= copy
;
906 ReleaseStgMedium(&med
);
911 /***********************************************************************
914 * Render the clipboard data. Note that this call will delegate to the
915 * source data object.
917 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
919 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
922 /* Embed source hack */
923 if(fmt
->cfFormat
== embed_source_clipboard_format
)
925 return render_embed_source_hack(data
, fmt
);
928 if(fmt
->tymed
& TYMED_ISTORAGE
)
930 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
932 else if(fmt
->tymed
& TYMED_ISTREAM
)
934 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
936 else if(fmt
->tymed
& TYMED_HGLOBAL
)
938 hr
= get_data_from_global(data
, fmt
, &clip_data
);
940 else if(fmt
->tymed
& TYMED_ENHMF
)
942 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
944 else if(fmt
->tymed
& TYMED_MFPICT
)
946 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
947 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
949 else if(fmt
->tymed
& TYMED_GDI
)
951 /* Returns HBITMAP not HGLOBAL */
952 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
956 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
962 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
964 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
965 if(fmt
->tymed
& TYMED_MFPICT
)
966 free_metafilepict(clip_data
);
967 else if(fmt
->tymed
& TYMED_GDI
)
968 DeleteObject(clip_data
);
970 GlobalFree(clip_data
);
971 hr
= CLIPBRD_E_CANT_SET
;
978 /*---------------------------------------------------------------------*
979 * Implementation of the internal IDataObject interface exposed by
981 *---------------------------------------------------------------------*/
984 /************************************************************************
985 * snapshot_QueryInterface
987 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
988 REFIID riid
, void **ppvObject
)
990 snapshot
*This
= impl_from_IDataObject(iface
);
991 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
993 if ( (This
==0) || (ppvObject
==0) )
998 if (IsEqualIID(&IID_IUnknown
, riid
) ||
999 IsEqualIID(&IID_IDataObject
, riid
))
1005 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1006 return E_NOINTERFACE
;
1009 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1014 /************************************************************************
1017 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1019 snapshot
*This
= impl_from_IDataObject(iface
);
1021 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1023 return InterlockedIncrement(&This
->ref
);
1026 /************************************************************************
1029 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1031 snapshot
*This
= impl_from_IDataObject(iface
);
1034 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1036 ref
= InterlockedDecrement(&This
->ref
);
1040 ole_clipbrd
*clipbrd
;
1041 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
1043 if(This
->data
) IDataObject_Release(This
->data
);
1045 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
1046 clipbrd
->latest_snapshot
= NULL
;
1047 HeapFree(GetProcessHeap(), 0, This
);
1053 /************************************************************
1054 * get_current_ole_clip_window
1056 * Return the window that owns the ole clipboard.
1058 * If the clipboard is flushed or not owned by ole this will
1061 static HWND
get_current_ole_clip_window(void)
1066 h
= GetClipboardData(dataobject_clipboard_format
);
1068 ptr
= GlobalLock(h
);
1069 if(!ptr
) return NULL
;
1075 /************************************************************
1076 * get_current_dataobject
1078 * Return an unmarshalled IDataObject if there is a current
1079 * (ie non-flushed) object on the ole clipboard.
1081 static HRESULT
get_current_dataobject(IDataObject
**data
)
1083 HRESULT hr
= S_FALSE
;
1084 HWND wnd
= get_current_ole_clip_window();
1091 if(!wnd
) return S_FALSE
;
1093 h
= GetClipboardData(wine_marshal_clipboard_format
);
1094 if(!h
) return S_FALSE
;
1095 if(GlobalSize(h
) == 0) return S_FALSE
;
1096 ptr
= GlobalLock(h
);
1097 if(!ptr
) return S_FALSE
;
1099 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1100 if(FAILED(hr
)) goto end
;
1102 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1106 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1107 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1109 IStream_Release(stm
);
1116 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1118 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1124 case CF_UNICODETEXT
:
1125 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1126 case CF_ENHMETAFILE
:
1128 case CF_METAFILEPICT
:
1129 return TYMED_MFPICT
;
1133 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1138 /***********************************************************
1141 * Returns a copy of the Ole Private Data
1143 static HRESULT
get_priv_data(ole_priv_data
**data
)
1147 ole_priv_data
*ret
= NULL
;
1151 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1154 ole_priv_data
*src
= GlobalLock(handle
);
1159 /* FIXME: sanity check on size */
1160 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1163 GlobalUnlock(handle
);
1164 return E_OUTOFMEMORY
;
1166 memcpy(ret
, src
, src
->size
);
1167 GlobalUnlock(handle
);
1169 /* Fixup any target device offsets to ptrs */
1170 for(i
= 0; i
< ret
->count
; i
++)
1171 ret
->entries
[i
].fmtetc
.ptd
=
1172 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1176 if(!ret
) /* Non-ole data */
1179 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1181 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1184 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1185 TRACE("cf %04x %s\n", cf
, buf
);
1187 TRACE("count %d\n", count
);
1188 size
+= count
* sizeof(ret
->entries
[0]);
1190 /* There are holes in fmtetc so zero init */
1191 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1192 if(!ret
) return E_OUTOFMEMORY
;
1196 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1198 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1199 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1200 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1201 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1202 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1203 ret
->entries
[idx
].first_use
= 1;
1211 /************************************************************************
1212 * get_stgmed_for_global
1214 * Returns a stg medium with a copy of the global handle
1216 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1220 med
->pUnkForRelease
= NULL
;
1221 med
->tymed
= TYMED_NULL
;
1223 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1225 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1230 /************************************************************************
1231 * get_stgmed_for_stream
1233 * Returns a stg medium with a stream based on the handle
1235 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1240 med
->pUnkForRelease
= NULL
;
1241 med
->tymed
= TYMED_NULL
;
1243 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1244 if(FAILED(hr
)) return hr
;
1246 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1253 med
->tymed
= TYMED_ISTREAM
;
1257 /************************************************************************
1258 * get_stgmed_for_storage
1260 * Returns a stg medium with a storage based on the handle
1262 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1268 med
->pUnkForRelease
= NULL
;
1269 med
->tymed
= TYMED_NULL
;
1271 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1272 if(FAILED(hr
)) return hr
;
1274 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1281 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1282 ILockBytes_Release(lbs
);
1289 med
->tymed
= TYMED_ISTORAGE
;
1293 /************************************************************************
1294 * get_stgmed_for_emf
1296 * Returns a stg medium with an enhanced metafile based on the handle
1298 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1300 med
->pUnkForRelease
= NULL
;
1301 med
->tymed
= TYMED_NULL
;
1303 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1304 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1305 med
->tymed
= TYMED_ENHMF
;
1309 /************************************************************************
1310 * get_stgmed_for_bitmap
1312 * Returns a stg medium with a bitmap based on the handle
1314 static HRESULT
get_stgmed_for_bitmap(HBITMAP hbmp
, STGMEDIUM
*med
)
1318 med
->pUnkForRelease
= NULL
;
1319 med
->tymed
= TYMED_NULL
;
1321 hr
= dup_bitmap(hbmp
, &med
->u
.hBitmap
);
1326 med
->tymed
= TYMED_GDI
;
1330 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1332 const WCHAR
*str1
, *str2
;
1334 if(off1
== 0 && off2
== 0) return TRUE
;
1335 if(off1
== 0 || off2
== 0) return FALSE
;
1337 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1338 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1340 return !lstrcmpW(str1
, str2
);
1343 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1345 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1346 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1348 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1350 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1352 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1355 /* FIXME check devmode? */
1360 /************************************************************************
1363 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1366 snapshot
*This
= impl_from_IDataObject(iface
);
1369 ole_priv_data
*enum_data
= NULL
;
1370 ole_priv_data_entry
*entry
;
1373 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1375 if ( !fmt
|| !med
) return E_INVALIDARG
;
1377 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1380 hr
= get_current_dataobject(&This
->data
);
1384 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1389 h
= GetClipboardData(fmt
->cfFormat
);
1392 hr
= DV_E_FORMATETC
;
1396 hr
= get_priv_data(&enum_data
);
1397 if(FAILED(hr
)) goto end
;
1399 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1402 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1404 hr
= DV_E_FORMATETC
;
1407 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1408 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1410 else /* non-Ole format */
1411 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1413 if(mask
& TYMED_ISTORAGE
)
1414 hr
= get_stgmed_for_storage(h
, med
);
1415 else if(mask
& TYMED_HGLOBAL
)
1416 hr
= get_stgmed_for_global(h
, med
);
1417 else if(mask
& TYMED_ISTREAM
)
1418 hr
= get_stgmed_for_stream(h
, med
);
1419 else if(mask
& TYMED_ENHMF
)
1420 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1421 else if(mask
& TYMED_GDI
)
1422 hr
= get_stgmed_for_bitmap((HBITMAP
)h
, med
);
1425 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1431 HeapFree(GetProcessHeap(), 0, enum_data
);
1432 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1436 /************************************************************************
1437 * snapshot_GetDataHere
1439 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1442 snapshot
*This
= impl_from_IDataObject(iface
);
1445 ole_priv_data
*enum_data
= NULL
;
1446 ole_priv_data_entry
*entry
;
1449 if ( !fmt
|| !med
) return E_INVALIDARG
;
1451 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1453 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1456 hr
= get_current_dataobject(&This
->data
);
1460 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1468 h
= GetClipboardData(fmt
->cfFormat
);
1471 hr
= DV_E_FORMATETC
;
1475 hr
= get_priv_data(&enum_data
);
1476 if(FAILED(hr
)) goto end
;
1478 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1481 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1483 hr
= DV_E_FORMATETC
;
1486 supported
= entry
->fmtetc
.tymed
;
1488 else /* non-Ole format */
1489 supported
= TYMED_HGLOBAL
;
1495 DWORD src_size
= GlobalSize(h
);
1496 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1498 if(dst_size
>= src_size
)
1500 void *src
= GlobalLock(h
);
1501 void *dst
= GlobalLock(med
->u
.hGlobal
);
1503 memcpy(dst
, src
, src_size
);
1504 GlobalUnlock(med
->u
.hGlobal
);
1512 DWORD src_size
= GlobalSize(h
);
1513 void *src
= GlobalLock(h
);
1514 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1518 case TYMED_ISTORAGE
:
1521 if(!(supported
& TYMED_ISTORAGE
))
1526 hr
= get_stgmed_for_storage(h
, ©
);
1529 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1530 ReleaseStgMedium(©
);
1535 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1541 HeapFree(GetProcessHeap(), 0, enum_data
);
1542 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1546 /************************************************************************
1547 * snapshot_QueryGetData
1549 * The OLE Clipboard's implementation of this method delegates to
1550 * a data source if there is one or wraps around the windows clipboard
1551 * function IsClipboardFormatAvailable() otherwise.
1554 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1556 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1558 if (!fmt
) return E_INVALIDARG
;
1560 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1562 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1564 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1567 /************************************************************************
1568 * snapshot_GetCanonicalFormatEtc
1570 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1573 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1575 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1578 return DATA_S_SAMEFORMATETC
;
1581 /************************************************************************
1584 * The OLE Clipboard does not implement this method
1586 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1587 STGMEDIUM
*med
, BOOL release
)
1589 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1593 /************************************************************************
1594 * snapshot_EnumFormatEtc
1597 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1598 IEnumFORMATETC
**enum_fmt
)
1601 ole_priv_data
*data
= NULL
;
1603 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1607 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1608 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1610 hr
= get_priv_data(&data
);
1612 if(FAILED(hr
)) goto end
;
1614 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1617 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1621 /************************************************************************
1624 * The OLE Clipboard does not implement this method
1626 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1627 DWORD flags
, IAdviseSink
*sink
,
1630 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1634 /************************************************************************
1635 * snapshot_DUnadvise
1637 * The OLE Clipboard does not implement this method
1639 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1641 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1645 /************************************************************************
1646 * snapshot_EnumDAdvise
1648 * The OLE Clipboard does not implement this method
1650 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1651 IEnumSTATDATA
** enum_advise
)
1653 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1657 static const IDataObjectVtbl snapshot_vtable
=
1659 snapshot_QueryInterface
,
1663 snapshot_GetDataHere
,
1664 snapshot_QueryGetData
,
1665 snapshot_GetCanonicalFormatEtc
,
1667 snapshot_EnumFormatEtc
,
1670 snapshot_EnumDAdvise
1673 /*---------------------------------------------------------------------*
1674 * Internal implementation methods for the OLE clipboard
1675 *---------------------------------------------------------------------*/
1677 static snapshot
*snapshot_construct(DWORD seq_no
)
1681 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1682 if (!This
) return NULL
;
1684 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1686 This
->seq_no
= seq_no
;
1692 /*********************************************************
1693 * register_clipboard_formats
1695 static void register_clipboard_formats(void)
1697 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1698 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1699 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1700 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1701 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1702 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1703 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1704 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1705 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1706 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1707 'D','e','s','c','r','i','p','t','o','r',0};
1708 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1710 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1711 'D','a','t','a','O','b','j','e','c','t',0};
1713 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1714 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1715 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1716 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1717 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1718 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1719 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1720 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1721 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1722 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1723 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1725 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1728 /***********************************************************************
1729 * OLEClipbrd_Initialize()
1730 * Initializes the OLE clipboard.
1732 void OLEClipbrd_Initialize(void)
1734 register_clipboard_formats();
1736 if ( !theOleClipboard
)
1738 ole_clipbrd
* clipbrd
;
1743 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1744 if (!clipbrd
) return;
1746 clipbrd
->latest_snapshot
= NULL
;
1747 clipbrd
->window
= NULL
;
1748 clipbrd
->src_data
= NULL
;
1749 clipbrd
->cached_enum
= NULL
;
1751 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1754 HeapFree(GetProcessHeap(), 0, clipbrd
);
1758 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1761 HeapFree(GetProcessHeap(), 0, clipbrd
);
1765 theOleClipboard
= clipbrd
;
1769 /***********************************************************************
1770 * OLEClipbrd_UnInitialize()
1771 * Un-Initializes the OLE clipboard
1773 void OLEClipbrd_UnInitialize(void)
1775 ole_clipbrd
*clipbrd
= theOleClipboard
;
1781 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1782 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1784 if ( clipbrd
->window
)
1786 DestroyWindow(clipbrd
->window
);
1787 UnregisterClassW( clipbrd_wndclass
, hinst
);
1790 IStream_Release(clipbrd
->marshal_data
);
1791 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1792 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1793 HeapFree(GetProcessHeap(), 0, clipbrd
);
1794 theOleClipboard
= NULL
;
1798 /*********************************************************************
1799 * set_clipboard_formats
1801 * Enumerate all formats supported by the source and make
1802 * those formats available using delayed rendering using SetClipboardData.
1803 * Cache the enumeration list and make that list visibile as the
1804 * 'Ole Private Data' format on the clipboard.
1807 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1811 IEnumFORMATETC
*enum_fmt
;
1812 HGLOBAL priv_data_handle
;
1813 DWORD_PTR target_offset
;
1814 ole_priv_data
*priv_data
;
1815 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1817 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1818 if(FAILED(hr
)) return hr
;
1820 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1823 needed
+= sizeof(priv_data
->entries
[0]);
1826 needed
+= fmt
.ptd
->tdSize
;
1827 CoTaskMemFree(fmt
.ptd
);
1831 /* Windows pads the list with two empty ole_priv_data_entries, one
1832 * after the entries array and one after the target device data.
1833 * Allocating with zero init to zero these pads. */
1835 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1836 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1837 priv_data
= GlobalLock(priv_data_handle
);
1839 priv_data
->unk1
= 0;
1840 priv_data
->size
= needed
;
1841 priv_data
->unk2
= 1;
1842 priv_data
->count
= count
;
1843 priv_data
->unk3
[0] = 0;
1844 priv_data
->unk3
[1] = 0;
1846 IEnumFORMATETC_Reset(enum_fmt
);
1849 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1851 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1853 TRACE("%s\n", dump_fmtetc(&fmt
));
1855 priv_data
->entries
[idx
].fmtetc
= fmt
;
1858 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1859 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1860 target_offset
+= fmt
.ptd
->tdSize
;
1861 CoTaskMemFree(fmt
.ptd
);
1864 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1865 priv_data
->entries
[idx
].unk
[0] = 0;
1866 priv_data
->entries
[idx
].unk
[1] = 0;
1868 if (priv_data
->entries
[idx
].first_use
)
1869 SetClipboardData(fmt
.cfFormat
, NULL
);
1874 IEnumFORMATETC_Release(enum_fmt
);
1876 /* Cache the list and fixup any target device offsets to ptrs */
1877 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1878 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1879 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1880 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1881 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1883 GlobalUnlock(priv_data_handle
);
1884 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1886 GlobalFree(priv_data_handle
);
1887 return CLIPBRD_E_CANT_SET
;
1893 static HWND
create_clipbrd_window(void);
1895 /***********************************************************************
1896 * get_clipbrd_window
1898 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1900 if ( !clipbrd
->window
)
1901 clipbrd
->window
= create_clipbrd_window();
1903 *wnd
= clipbrd
->window
;
1904 return *wnd
? S_OK
: E_FAIL
;
1908 /**********************************************************************
1909 * release_marshal_data
1911 * Releases the data and sets the stream back to zero size.
1913 static inline void release_marshal_data(IStream
*stm
)
1916 ULARGE_INTEGER size
;
1917 pos
.QuadPart
= size
.QuadPart
= 0;
1919 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1920 CoReleaseMarshalData(stm
);
1921 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1922 IStream_SetSize(stm
, size
);
1925 /***********************************************************************
1926 * expose_marshalled_dataobject
1928 * Sets the marshalled dataobject to the clipboard. In the flushed case
1929 * we set a zero sized HGLOBAL to clear the old marshalled data.
1931 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1938 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1939 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1942 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1944 if(!h
) return E_OUTOFMEMORY
;
1946 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1949 return CLIPBRD_E_CANT_SET
;
1954 /***********************************************************************
1955 * set_src_dataobject
1957 * Clears and sets the clipboard's src IDataObject.
1959 * To marshal the source dataobject we do something rather different from Windows.
1960 * We set a clipboard format which contains the marshalled data.
1961 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1963 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1968 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1970 if(clipbrd
->src_data
)
1972 release_marshal_data(clipbrd
->marshal_data
);
1974 IDataObject_Release(clipbrd
->src_data
);
1975 clipbrd
->src_data
= NULL
;
1976 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1977 clipbrd
->cached_enum
= NULL
;
1984 IDataObject_AddRef(data
);
1985 clipbrd
->src_data
= data
;
1987 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1988 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1989 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1990 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1991 if(FAILED(hr
)) return hr
;
1992 hr
= set_clipboard_formats(clipbrd
, data
);
1997 /***********************************************************************
2000 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
2002 ole_clipbrd
*clipbrd
;
2004 get_ole_clipbrd(&clipbrd
);
2008 case WM_RENDERFORMAT
:
2011 ole_priv_data_entry
*entry
;
2013 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2014 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2017 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2022 case WM_RENDERALLFORMATS
:
2025 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
2027 TRACE("(): WM_RENDERALLFORMATS\n");
2029 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2031 if(entries
[i
].first_use
)
2032 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2037 case WM_DESTROYCLIPBOARD
:
2039 TRACE("(): WM_DESTROYCLIPBOARD\n");
2041 set_src_dataobject(clipbrd
, NULL
);
2046 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2053 /***********************************************************************
2054 * create_clipbrd_window
2056 static HWND
create_clipbrd_window(void)
2059 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2060 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2061 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2063 class.cbSize
= sizeof(class);
2065 class.lpfnWndProc
= clipbrd_wndproc
;
2066 class.cbClsExtra
= 0;
2067 class.cbWndExtra
= 0;
2068 class.hInstance
= hinst
;
2071 class.hbrBackground
= 0;
2072 class.lpszMenuName
= NULL
;
2073 class.lpszClassName
= clipbrd_wndclass
;
2074 class.hIconSm
= NULL
;
2076 RegisterClassExW(&class);
2078 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2079 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2080 NULL
, NULL
, hinst
, 0);
2083 /*********************************************************************
2084 * set_dataobject_format
2086 * Windows creates a 'DataObject' clipboard format that contains the
2087 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2089 static HRESULT
set_dataobject_format(HWND hwnd
)
2091 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2094 if(!h
) return E_OUTOFMEMORY
;
2096 data
= GlobalLock(h
);
2100 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2103 return CLIPBRD_E_CANT_SET
;
2109 /*---------------------------------------------------------------------*
2110 * Win32 OLE clipboard API
2111 *---------------------------------------------------------------------*/
2113 /***********************************************************************
2114 * OleSetClipboard [OLE32.@]
2115 * Places a pointer to the specified data object onto the clipboard,
2116 * making the data object accessible to the OleGetClipboard function.
2120 * S_OK IDataObject pointer placed on the clipboard
2121 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2122 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2123 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2124 * CLIPBRD_E_CANT_SET SetClipboard failed
2127 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2130 ole_clipbrd
*clipbrd
;
2133 TRACE("(%p)\n", data
);
2135 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2137 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2139 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2141 if ( !EmptyClipboard() )
2143 hr
= CLIPBRD_E_CANT_EMPTY
;
2147 hr
= set_src_dataobject(clipbrd
, data
);
2148 if(FAILED(hr
)) goto end
;
2152 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2153 if(FAILED(hr
)) goto end
;
2154 hr
= set_dataobject_format(wnd
);
2159 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2163 expose_marshalled_dataobject(clipbrd
, NULL
);
2164 set_src_dataobject(clipbrd
, NULL
);
2171 /***********************************************************************
2172 * OleGetClipboard [OLE32.@]
2173 * Returns a pointer to our internal IDataObject which represents the conceptual
2174 * state of the Windows clipboard. If the current clipboard already contains
2175 * an IDataObject, our internal IDataObject will delegate to this object.
2177 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2180 ole_clipbrd
*clipbrd
;
2183 TRACE("(%p)\n", obj
);
2185 if(!obj
) return E_INVALIDARG
;
2187 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2189 seq_no
= GetClipboardSequenceNumber();
2190 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2191 clipbrd
->latest_snapshot
= NULL
;
2193 if(!clipbrd
->latest_snapshot
)
2195 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2196 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
2199 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2200 IDataObject_AddRef(*obj
);
2205 /******************************************************************************
2206 * OleFlushClipboard [OLE32.@]
2207 * Renders the data from the source IDataObject into the windows clipboard
2209 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2210 * by copying the storage into global memory. Subsequently the default
2211 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2212 * back to TYMED_IStorage.
2214 HRESULT WINAPI
OleFlushClipboard(void)
2217 ole_clipbrd
*clipbrd
;
2222 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2224 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2227 * Already flushed or no source DataObject? Nothing to do.
2229 if (!clipbrd
->src_data
) return S_OK
;
2231 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2233 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2235 hr
= set_dataobject_format(NULL
);
2237 expose_marshalled_dataobject(clipbrd
, NULL
);
2238 set_src_dataobject(clipbrd
, NULL
);
2240 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2246 /***********************************************************************
2247 * OleIsCurrentClipboard [OLE32.@]
2249 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2252 ole_clipbrd
*clipbrd
;
2255 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2257 if (data
== NULL
) return S_FALSE
;
2259 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;