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 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
88 /* Structure of 'Ole Private Data' clipboard format */
92 DWORD first_use
; /* Has this cf been added to the list already */
94 } ole_priv_data_entry
;
99 DWORD size
; /* in bytes of the entire structure */
101 DWORD count
; /* no. of format entries */
103 ole_priv_data_entry entries
[1]; /* array of size count */
104 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
107 /*****************************************************************************
110 * Returns a ptr to a target device at a given offset from the
111 * start of the ole_priv_data.
113 * Used when unpacking ole private data from the clipboard.
115 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
117 if(off
== 0) return NULL
;
118 return (DVTARGETDEVICE
*)((char*)data
+ off
);
121 /*****************************************************************************
124 * Get the offset from the start of the ole_priv_data of the idx'th
127 * Used when packing ole private data to the clipboard.
129 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
131 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
132 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
135 /****************************************************************************
136 * Consumer snapshot. Represents the state of the ole clipboard
137 * returned by OleGetClipboard().
139 typedef struct snapshot
141 IDataObject IDataObject_iface
;
144 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
146 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
149 /****************************************************************************
152 typedef struct ole_clipbrd
154 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
156 HWND window
; /* Hidden clipboard window */
157 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
158 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
159 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
162 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
164 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
167 typedef struct PresentationDataHeader
170 DWORD dwObjectExtentX
;
171 DWORD dwObjectExtentY
;
173 } PresentationDataHeader
;
176 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
178 static ole_clipbrd
* theOleClipboard
;
180 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
182 struct oletls
*info
= COM_CurrentInfo();
186 return CO_E_NOTINITIALIZED
;
187 *clipbrd
= theOleClipboard
;
193 * Name of our registered OLE clipboard window class
195 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
197 UINT ownerlink_clipboard_format
= 0;
198 UINT filename_clipboard_format
= 0;
199 UINT filenameW_clipboard_format
= 0;
200 UINT dataobject_clipboard_format
= 0;
201 UINT embedded_object_clipboard_format
= 0;
202 UINT embed_source_clipboard_format
= 0;
203 UINT custom_link_source_clipboard_format
= 0;
204 UINT link_source_clipboard_format
= 0;
205 UINT object_descriptor_clipboard_format
= 0;
206 UINT link_source_descriptor_clipboard_format
= 0;
207 UINT ole_private_data_clipboard_format
= 0;
209 static UINT wine_marshal_clipboard_format
;
211 static inline const char *dump_fmtetc(FORMATETC
*fmt
)
213 if (!fmt
) return "(null)";
214 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
215 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
218 /*---------------------------------------------------------------------*
219 * Implementation of the internal IEnumFORMATETC interface returned by
220 * the OLE clipboard's IDataObject.
221 *---------------------------------------------------------------------*/
223 typedef struct enum_fmtetc
225 IEnumFORMATETC IEnumFORMATETC_iface
;
228 UINT pos
; /* current enumerator position */
232 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
234 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
237 /************************************************************************
238 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
240 * See Windows documentation for more details on IUnknown methods.
242 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
243 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
245 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
247 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
251 if(IsEqualIID(riid
, &IID_IUnknown
) ||
252 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
259 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
260 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
264 TRACE("-- Interface: E_NOINTERFACE\n");
265 return E_NOINTERFACE
;
268 /************************************************************************
269 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
272 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
274 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
275 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
277 return InterlockedIncrement(&This
->ref
);
280 /************************************************************************
281 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
283 * See Windows documentation for more details on IUnknown methods.
285 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
287 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
290 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
292 ref
= InterlockedDecrement(&This
->ref
);
295 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
296 HeapFree(GetProcessHeap(), 0, This
->data
);
297 HeapFree(GetProcessHeap(), 0, This
);
302 /************************************************************************
303 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
305 * Standard enumerator members for IEnumFORMATETC
307 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
308 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
310 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
312 HRESULT hres
= S_FALSE
;
314 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
316 if (This
->pos
< This
->data
->count
)
318 cfetch
= This
->data
->count
- This
->pos
;
325 for(i
= 0; i
< cfetch
; i
++)
327 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
330 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
331 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
332 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
333 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
344 *pceltFethed
= cfetch
;
350 /************************************************************************
351 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
353 * Standard enumerator members for IEnumFORMATETC
355 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
357 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
358 TRACE("(%p)->(num=%u)\n", This
, celt
);
361 if (This
->pos
> This
->data
->count
)
363 This
->pos
= This
->data
->count
;
369 /************************************************************************
370 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
372 * Standard enumerator members for IEnumFORMATETC
374 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
376 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
377 TRACE("(%p)->()\n", This
);
383 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
385 /************************************************************************
386 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
388 * Standard enumerator members for IEnumFORMATETC
390 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
391 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
393 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
394 ole_priv_data
*new_data
;
397 TRACE("(%p)->(%p)\n", This
, obj
);
399 if ( !obj
) return E_INVALIDARG
;
402 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
403 if(!new_data
) return E_OUTOFMEMORY
;
404 memcpy(new_data
, This
->data
, This
->data
->size
);
406 /* Fixup any target device ptrs */
407 for(i
= 0; i
< This
->data
->count
; i
++)
408 new_data
->entries
[i
].fmtetc
.ptd
=
409 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
411 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
414 static const IEnumFORMATETCVtbl efvt
=
416 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
417 OLEClipbrd_IEnumFORMATETC_AddRef
,
418 OLEClipbrd_IEnumFORMATETC_Release
,
419 OLEClipbrd_IEnumFORMATETC_Next
,
420 OLEClipbrd_IEnumFORMATETC_Skip
,
421 OLEClipbrd_IEnumFORMATETC_Reset
,
422 OLEClipbrd_IEnumFORMATETC_Clone
425 /************************************************************************
426 * enum_fmtetc_construct
428 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
430 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
435 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
436 if (!ef
) return E_OUTOFMEMORY
;
439 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
443 TRACE("(%p)->()\n", ef
);
444 *obj
= &ef
->IEnumFORMATETC_iface
;
448 /***********************************************************************
451 * Helper method to duplicate an HGLOBAL chunk of memory
453 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
455 void *src_ptr
, *dst_ptr
;
459 if ( !src
) return S_FALSE
;
461 size
= GlobalSize(src
);
463 *dst
= GlobalAlloc( flags
, size
);
464 if ( !*dst
) return E_OUTOFMEMORY
;
466 src_ptr
= GlobalLock(src
);
467 dst_ptr
= GlobalLock(*dst
);
469 memcpy(dst_ptr
, src_ptr
, size
);
477 /***********************************************************************
480 * Helper function to duplicate a handle to a METAFILEPICT, and the
481 * contained HMETAFILE.
483 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
487 METAFILEPICT
*dest_ptr
;
491 /* Copy the METAFILEPICT structure. */
492 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
493 if (FAILED(hr
)) return hr
;
495 dest_ptr
= GlobalLock(dest
);
496 if (!dest_ptr
) return E_FAIL
;
498 /* Give the new METAFILEPICT a separate HMETAFILE. */
499 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
514 /***********************************************************************
517 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
518 * free the contained HMETAFILE.
520 static void free_metafilepict(HGLOBAL src
)
522 METAFILEPICT
*src_ptr
;
524 src_ptr
= GlobalLock(src
);
527 DeleteMetaFile(src_ptr
->hMF
);
533 /***********************************************************************
536 * Helper function to duplicate an HBITMAP.
538 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
541 HGDIOBJ orig_src_bitmap
;
545 src_dc
= CreateCompatibleDC(NULL
);
546 orig_src_bitmap
= SelectObject(src_dc
, src
);
547 GetObjectW(src
, sizeof bm
, &bm
);
548 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
551 HDC dest_dc
= CreateCompatibleDC(NULL
);
552 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
553 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
554 SelectObject(dest_dc
, orig_dest_bitmap
);
557 SelectObject(src_dc
, orig_src_bitmap
);
560 return dest
? S_OK
: E_FAIL
;
563 /************************************************************
564 * render_embed_source_hack
566 * This is clearly a hack and has no place in the clipboard code.
569 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
572 HGLOBAL hStorage
= 0;
574 ILockBytes
*ptrILockBytes
;
576 memset(&std
, 0, sizeof(STGMEDIUM
));
577 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
579 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
580 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
581 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
582 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
583 ILockBytes_Release(ptrILockBytes
);
585 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
587 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
588 GlobalFree(hStorage
);
592 if (1) /* check whether the presentation data is already -not- present */
596 METAFILEPICT
*mfp
= 0;
598 fmt2
.cfFormat
= CF_METAFILEPICT
;
600 fmt2
.dwAspect
= DVASPECT_CONTENT
;
602 fmt2
.tymed
= TYMED_MFPICT
;
604 memset(&std2
, 0, sizeof(STGMEDIUM
));
605 std2
.tymed
= TYMED_MFPICT
;
607 /* Get the metafile picture out of it */
609 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
611 mfp
= GlobalLock(std2
.u
.hGlobal
);
616 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
617 IStream
*pStream
= 0;
619 PresentationDataHeader pdh
;
623 CHAR strOleTypeName
[51];
624 BYTE OlePresStreamHeader
[] =
626 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
627 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
628 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
629 0x00, 0x00, 0x00, 0x00
632 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
634 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
635 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
637 pdh
.dwObjectExtentX
= mfp
->xExt
;
638 pdh
.dwObjectExtentY
= mfp
->yExt
;
641 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
643 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
645 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
646 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
648 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
650 IStream_Release(pStream
);
652 HeapFree(GetProcessHeap(), 0, mfBits
);
654 GlobalUnlock(std2
.u
.hGlobal
);
655 ReleaseStgMedium(&std2
);
657 ReadClassStg(std
.u
.pstg
, &clsID
);
658 ProgIDFromCLSID(&clsID
, &strProgID
);
660 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
661 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
662 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
663 CoTaskMemFree(strProgID
);
667 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
669 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
670 GlobalFree(hStorage
);
671 hr
= CLIPBRD_E_CANT_SET
;
674 ReleaseStgMedium(&std
);
678 /************************************************************************
679 * find_format_in_list
681 * Returns the first entry that matches the provided clipboard format.
683 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
686 for(i
= 0; i
< num
; i
++)
687 if(entries
[i
].fmtetc
.cfFormat
== cf
)
693 /***************************************************************************
694 * get_data_from_storage
696 * Returns storage data in an HGLOBAL.
698 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
709 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
710 if(!h
) return E_OUTOFMEMORY
;
712 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
715 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
716 ILockBytes_Release(lbs
);
725 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
727 med
.pUnkForRelease
= NULL
;
729 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
733 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
734 if(FAILED(hr
)) goto end
;
736 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
737 ReleaseStgMedium(&med
);
738 if(FAILED(hr
)) goto end
;
743 IStorage_Release(stg
);
744 if(FAILED(hr
)) GlobalFree(h
);
748 /***************************************************************************
749 * get_data_from_stream
751 * Returns stream data in an HGLOBAL.
753 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
763 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
764 if(!h
) return E_OUTOFMEMORY
;
766 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
767 if(FAILED(hr
)) goto error
;
770 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
772 med
.pUnkForRelease
= NULL
;
774 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
781 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
782 if(FAILED(hr
)) goto error
;
785 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
786 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
787 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
788 ReleaseStgMedium(&med
);
789 if(FAILED(hr
)) goto error
;
792 IStream_Release(stm
);
796 if(stm
) IStream_Release(stm
);
801 /***************************************************************************
802 * get_data_from_global
804 * Returns global data in an HGLOBAL.
806 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
816 mem_fmt
.tymed
= TYMED_HGLOBAL
;
818 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
819 if(FAILED(hr
)) return hr
;
821 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
823 if(SUCCEEDED(hr
)) *mem
= h
;
825 ReleaseStgMedium(&med
);
830 /***************************************************************************
831 * get_data_from_enhmetafile
833 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
843 mem_fmt
.tymed
= TYMED_ENHMF
;
845 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
846 if(FAILED(hr
)) return hr
;
848 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
849 if(copy
) *mem
= (HGLOBAL
)copy
;
852 ReleaseStgMedium(&med
);
857 /***************************************************************************
858 * get_data_from_metafilepict
860 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
870 mem_fmt
.tymed
= TYMED_MFPICT
;
872 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
873 if(FAILED(hr
)) return hr
;
875 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
877 if(SUCCEEDED(hr
)) *mem
= copy
;
879 ReleaseStgMedium(&med
);
884 /***************************************************************************
885 * get_data_from_bitmap
887 * Returns bitmap in an HBITMAP.
889 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
899 mem_fmt
.tymed
= TYMED_GDI
;
901 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
902 if(FAILED(hr
)) return hr
;
904 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
906 if(SUCCEEDED(hr
)) *hbm
= copy
;
908 ReleaseStgMedium(&med
);
913 /***********************************************************************
916 * Render the clipboard data. Note that this call will delegate to the
917 * source data object.
919 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
921 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
924 /* Embed source hack */
925 if(fmt
->cfFormat
== embed_source_clipboard_format
)
927 return render_embed_source_hack(data
, fmt
);
930 if(fmt
->tymed
& TYMED_ISTORAGE
)
932 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
934 else if(fmt
->tymed
& TYMED_ISTREAM
)
936 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
938 else if(fmt
->tymed
& TYMED_HGLOBAL
)
940 hr
= get_data_from_global(data
, fmt
, &clip_data
);
942 else if(fmt
->tymed
& TYMED_ENHMF
)
944 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
946 else if(fmt
->tymed
& TYMED_MFPICT
)
948 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
949 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
951 else if(fmt
->tymed
& TYMED_GDI
)
953 /* Returns HBITMAP not HGLOBAL */
954 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
958 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
964 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
966 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
967 if(fmt
->tymed
& TYMED_MFPICT
)
968 free_metafilepict(clip_data
);
969 else if(fmt
->tymed
& TYMED_GDI
)
970 DeleteObject(clip_data
);
972 GlobalFree(clip_data
);
973 hr
= CLIPBRD_E_CANT_SET
;
980 /*---------------------------------------------------------------------*
981 * Implementation of the internal IDataObject interface exposed by
983 *---------------------------------------------------------------------*/
986 /************************************************************************
987 * snapshot_QueryInterface
989 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
990 REFIID riid
, void **ppvObject
)
992 snapshot
*This
= impl_from_IDataObject(iface
);
993 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
995 if ( (This
==0) || (ppvObject
==0) )
1000 if (IsEqualIID(&IID_IUnknown
, riid
) ||
1001 IsEqualIID(&IID_IDataObject
, riid
))
1007 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1008 return E_NOINTERFACE
;
1011 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1016 /************************************************************************
1019 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1021 snapshot
*This
= impl_from_IDataObject(iface
);
1023 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1025 return InterlockedIncrement(&This
->ref
);
1028 /************************************************************************
1031 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1033 snapshot
*This
= impl_from_IDataObject(iface
);
1036 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1038 ref
= InterlockedDecrement(&This
->ref
);
1042 ole_clipbrd
*clipbrd
;
1043 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
1045 if(This
->data
) IDataObject_Release(This
->data
);
1047 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
1048 clipbrd
->latest_snapshot
= NULL
;
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 visibile 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
);
2010 case WM_RENDERFORMAT
:
2013 ole_priv_data_entry
*entry
;
2015 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2016 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2019 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2024 case WM_RENDERALLFORMATS
:
2027 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
2029 TRACE("(): WM_RENDERALLFORMATS\n");
2031 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2033 if(entries
[i
].first_use
)
2034 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2039 case WM_DESTROYCLIPBOARD
:
2041 TRACE("(): WM_DESTROYCLIPBOARD\n");
2043 set_src_dataobject(clipbrd
, NULL
);
2048 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2055 /***********************************************************************
2056 * create_clipbrd_window
2058 static HWND
create_clipbrd_window(void)
2061 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2062 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2063 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2065 class.cbSize
= sizeof(class);
2067 class.lpfnWndProc
= clipbrd_wndproc
;
2068 class.cbClsExtra
= 0;
2069 class.cbWndExtra
= 0;
2070 class.hInstance
= hinst
;
2073 class.hbrBackground
= 0;
2074 class.lpszMenuName
= NULL
;
2075 class.lpszClassName
= clipbrd_wndclass
;
2076 class.hIconSm
= NULL
;
2078 RegisterClassExW(&class);
2080 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2081 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2082 NULL
, NULL
, hinst
, 0);
2085 /*********************************************************************
2086 * set_dataobject_format
2088 * Windows creates a 'DataObject' clipboard format that contains the
2089 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2091 static HRESULT
set_dataobject_format(HWND hwnd
)
2093 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2096 if(!h
) return E_OUTOFMEMORY
;
2098 data
= GlobalLock(h
);
2102 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2105 return CLIPBRD_E_CANT_SET
;
2111 /*---------------------------------------------------------------------*
2112 * Win32 OLE clipboard API
2113 *---------------------------------------------------------------------*/
2115 /***********************************************************************
2116 * OleSetClipboard [OLE32.@]
2117 * Places a pointer to the specified data object onto the clipboard,
2118 * making the data object accessible to the OleGetClipboard function.
2122 * S_OK IDataObject pointer placed on the clipboard
2123 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2124 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2125 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2126 * CLIPBRD_E_CANT_SET SetClipboard failed
2129 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2132 ole_clipbrd
*clipbrd
;
2135 TRACE("(%p)\n", data
);
2137 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2139 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2141 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2143 if ( !EmptyClipboard() )
2145 hr
= CLIPBRD_E_CANT_EMPTY
;
2149 hr
= set_src_dataobject(clipbrd
, data
);
2150 if(FAILED(hr
)) goto end
;
2154 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2155 if(FAILED(hr
)) goto end
;
2156 hr
= set_dataobject_format(wnd
);
2161 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2165 expose_marshalled_dataobject(clipbrd
, NULL
);
2166 set_src_dataobject(clipbrd
, NULL
);
2173 /***********************************************************************
2174 * OleGetClipboard [OLE32.@]
2175 * Returns a pointer to our internal IDataObject which represents the conceptual
2176 * state of the Windows clipboard. If the current clipboard already contains
2177 * an IDataObject, our internal IDataObject will delegate to this object.
2179 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2182 ole_clipbrd
*clipbrd
;
2185 TRACE("(%p)\n", obj
);
2187 if(!obj
) return E_INVALIDARG
;
2189 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2191 seq_no
= GetClipboardSequenceNumber();
2192 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2193 clipbrd
->latest_snapshot
= NULL
;
2195 if(!clipbrd
->latest_snapshot
)
2197 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2198 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
2201 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2202 IDataObject_AddRef(*obj
);
2207 /******************************************************************************
2208 * OleFlushClipboard [OLE32.@]
2209 * Renders the data from the source IDataObject into the windows clipboard
2211 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2212 * by copying the storage into global memory. Subsequently the default
2213 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2214 * back to TYMED_IStorage.
2216 HRESULT WINAPI
OleFlushClipboard(void)
2219 ole_clipbrd
*clipbrd
;
2224 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2226 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2229 * Already flushed or no source DataObject? Nothing to do.
2231 if (!clipbrd
->src_data
) return S_OK
;
2233 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2235 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2237 hr
= set_dataobject_format(NULL
);
2239 expose_marshalled_dataobject(clipbrd
, NULL
);
2240 set_src_dataobject(clipbrd
, NULL
);
2242 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2248 /***********************************************************************
2249 * OleIsCurrentClipboard [OLE32.@]
2251 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2254 ole_clipbrd
*clipbrd
;
2257 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2259 if (data
== NULL
) return S_FALSE
;
2261 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;