2 * OLE 2 clipboard support
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * This file contains the implementation for the OLE Clipboard and its
23 * internal interfaces. The OLE clipboard interacts with an IDataObject
24 * interface via the OleSetClipboard, OleGetClipboard and
25 * OleIsCurrentClipboard API's. An internal IDataObject delegates
26 * to a client supplied IDataObject or the WIN32 clipboard API depending
27 * on whether OleSetClipboard has been invoked.
28 * Here are some operating scenarios:
30 * 1. OleSetClipboard called: In this case the internal IDataObject
31 * delegates to the client supplied IDataObject. Additionally OLE takes
32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject
33 * items are placed on the Windows clipboard. This allows non OLE aware
34 * applications to access these. A local WinProc fields WM_RENDERFORMAT
35 * and WM_RENDERALLFORMATS messages in this case.
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41 * IDataObject delegates to the source IDataObjects functionality directly,
42 * thereby bypassing the Windows clipboard.
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
47 * - Support for pasting between different processes. OLE clipboard support
48 * currently works only for in process copy and paste. Since we internally
49 * store a pointer to the source's IDataObject and delegate to that, this
50 * will fail if the IDataObject client belongs to a different process.
51 * - IDataObject::GetDataHere is not implemented
52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53 * by copying the storage into global memory. Subsequently the default
54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55 * back to TYMED_IStorage.
56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57 * clipboard in OleSetClipboard.
67 #define NONAMELESSUNION
76 #include "wine/debug.h"
79 #include "storage32.h"
81 #include "compobj_private.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
85 /* Structure of 'Ole Private Data' clipboard format */
89 DWORD first_use
; /* Has this cf been added to the list already */
91 } ole_priv_data_entry
;
96 DWORD size
; /* in bytes of the entire structure */
98 DWORD count
; /* no. of format entries */
100 ole_priv_data_entry entries
[1]; /* array of size count */
101 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
104 /*****************************************************************************
107 * Returns a ptr to a target device at a given offset from the
108 * start of the ole_priv_data.
110 * Used when unpacking ole private data from the clipboard.
112 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
114 if(off
== 0) return NULL
;
115 return (DVTARGETDEVICE
*)((char*)data
+ off
);
118 /*****************************************************************************
121 * Get the offset from the start of the ole_priv_data of the idx'th
124 * Used when packing ole private data to the clipboard.
126 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
128 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
129 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
132 /****************************************************************************
133 * Consumer snapshot. Represents the state of the ole clipboard
134 * returned by OleGetClipboard().
136 typedef struct snapshot
138 IDataObject IDataObject_iface
;
141 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
143 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
146 /****************************************************************************
149 typedef struct ole_clipbrd
151 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
153 HWND window
; /* Hidden clipboard window */
154 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
155 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
156 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
159 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
161 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
164 typedef struct PresentationDataHeader
167 DWORD dwObjectExtentX
;
168 DWORD dwObjectExtentY
;
170 } PresentationDataHeader
;
173 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
175 static ole_clipbrd
* theOleClipboard
;
177 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
179 struct oletls
*info
= COM_CurrentInfo();
183 return CO_E_NOTINITIALIZED
;
184 *clipbrd
= theOleClipboard
;
190 * Name of our registered OLE clipboard window class
192 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
194 UINT ownerlink_clipboard_format
= 0;
195 UINT filename_clipboard_format
= 0;
196 UINT filenameW_clipboard_format
= 0;
197 UINT dataobject_clipboard_format
= 0;
198 UINT embedded_object_clipboard_format
= 0;
199 UINT embed_source_clipboard_format
= 0;
200 UINT custom_link_source_clipboard_format
= 0;
201 UINT link_source_clipboard_format
= 0;
202 UINT object_descriptor_clipboard_format
= 0;
203 UINT link_source_descriptor_clipboard_format
= 0;
204 UINT ole_private_data_clipboard_format
= 0;
206 static UINT wine_marshal_clipboard_format
;
208 static inline const char *dump_fmtetc(FORMATETC
*fmt
)
210 if (!fmt
) return "(null)";
211 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
212 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
215 /*---------------------------------------------------------------------*
216 * Implementation of the internal IEnumFORMATETC interface returned by
217 * the OLE clipboard's IDataObject.
218 *---------------------------------------------------------------------*/
220 typedef struct enum_fmtetc
222 IEnumFORMATETC IEnumFORMATETC_iface
;
225 UINT pos
; /* current enumerator position */
229 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
231 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
234 /************************************************************************
235 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
237 * See Windows documentation for more details on IUnknown methods.
239 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
240 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
242 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
244 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
248 if(IsEqualIID(riid
, &IID_IUnknown
) ||
249 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
256 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
257 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
261 TRACE("-- Interface: E_NOINTERFACE\n");
262 return E_NOINTERFACE
;
265 /************************************************************************
266 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
269 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
271 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
272 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
274 return InterlockedIncrement(&This
->ref
);
277 /************************************************************************
278 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
280 * See Windows documentation for more details on IUnknown methods.
282 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
284 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
287 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
289 ref
= InterlockedDecrement(&This
->ref
);
292 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
293 HeapFree(GetProcessHeap(), 0, This
->data
);
294 HeapFree(GetProcessHeap(), 0, This
);
299 /************************************************************************
300 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
302 * Standard enumerator members for IEnumFORMATETC
304 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
305 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
307 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
309 HRESULT hres
= S_FALSE
;
311 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
313 if (This
->pos
< This
->data
->count
)
315 cfetch
= This
->data
->count
- This
->pos
;
322 for(i
= 0; i
< cfetch
; i
++)
324 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
327 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
328 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
329 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
330 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
341 *pceltFethed
= cfetch
;
347 /************************************************************************
348 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
350 * Standard enumerator members for IEnumFORMATETC
352 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
354 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
355 TRACE("(%p)->(num=%u)\n", This
, celt
);
358 if (This
->pos
> This
->data
->count
)
360 This
->pos
= This
->data
->count
;
366 /************************************************************************
367 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
369 * Standard enumerator members for IEnumFORMATETC
371 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
373 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
374 TRACE("(%p)->()\n", This
);
380 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
382 /************************************************************************
383 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
385 * Standard enumerator members for IEnumFORMATETC
387 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
388 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
390 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
391 ole_priv_data
*new_data
;
394 TRACE("(%p)->(%p)\n", This
, obj
);
396 if ( !obj
) return E_INVALIDARG
;
399 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
400 if(!new_data
) return E_OUTOFMEMORY
;
401 memcpy(new_data
, This
->data
, This
->data
->size
);
403 /* Fixup any target device ptrs */
404 for(i
= 0; i
< This
->data
->count
; i
++)
405 new_data
->entries
[i
].fmtetc
.ptd
=
406 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
408 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
411 static const IEnumFORMATETCVtbl efvt
=
413 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
414 OLEClipbrd_IEnumFORMATETC_AddRef
,
415 OLEClipbrd_IEnumFORMATETC_Release
,
416 OLEClipbrd_IEnumFORMATETC_Next
,
417 OLEClipbrd_IEnumFORMATETC_Skip
,
418 OLEClipbrd_IEnumFORMATETC_Reset
,
419 OLEClipbrd_IEnumFORMATETC_Clone
422 /************************************************************************
423 * enum_fmtetc_construct
425 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
427 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
432 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
433 if (!ef
) return E_OUTOFMEMORY
;
436 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
440 TRACE("(%p)->()\n", ef
);
441 *obj
= &ef
->IEnumFORMATETC_iface
;
445 /***********************************************************************
448 * Helper method to duplicate an HGLOBAL chunk of memory
450 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
452 void *src_ptr
, *dst_ptr
;
456 if ( !src
) return S_FALSE
;
458 size
= GlobalSize(src
);
460 *dst
= GlobalAlloc( flags
, size
);
461 if ( !*dst
) return E_OUTOFMEMORY
;
463 src_ptr
= GlobalLock(src
);
464 dst_ptr
= GlobalLock(*dst
);
466 memcpy(dst_ptr
, src_ptr
, size
);
474 /***********************************************************************
477 * Helper function to duplicate a handle to a METAFILEPICT, and the
478 * contained HMETAFILE.
480 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
484 METAFILEPICT
*dest_ptr
;
488 /* Copy the METAFILEPICT structure. */
489 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
490 if (FAILED(hr
)) return hr
;
492 dest_ptr
= GlobalLock(dest
);
493 if (!dest_ptr
) return E_FAIL
;
495 /* Give the new METAFILEPICT a separate HMETAFILE. */
496 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
511 /***********************************************************************
514 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
515 * free the contained HMETAFILE.
517 static void free_metafilepict(HGLOBAL src
)
519 METAFILEPICT
*src_ptr
;
521 src_ptr
= GlobalLock(src
);
524 DeleteMetaFile(src_ptr
->hMF
);
530 /***********************************************************************
533 * Helper function to duplicate an HBITMAP.
535 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
538 HGDIOBJ orig_src_bitmap
;
542 src_dc
= CreateCompatibleDC(NULL
);
543 orig_src_bitmap
= SelectObject(src_dc
, src
);
544 GetObjectW(src
, sizeof bm
, &bm
);
545 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
548 HDC dest_dc
= CreateCompatibleDC(NULL
);
549 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
550 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
551 SelectObject(dest_dc
, orig_dest_bitmap
);
554 SelectObject(src_dc
, orig_src_bitmap
);
557 return dest
? S_OK
: E_FAIL
;
560 /************************************************************
561 * render_embed_source_hack
563 * This is clearly a hack and has no place in the clipboard code.
566 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
569 HGLOBAL hStorage
= 0;
571 ILockBytes
*ptrILockBytes
;
573 memset(&std
, 0, sizeof(STGMEDIUM
));
574 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
576 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
577 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
578 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
579 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
580 ILockBytes_Release(ptrILockBytes
);
582 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
584 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
585 GlobalFree(hStorage
);
589 if (1) /* check whether the presentation data is already -not- present */
593 METAFILEPICT
*mfp
= 0;
595 fmt2
.cfFormat
= CF_METAFILEPICT
;
597 fmt2
.dwAspect
= DVASPECT_CONTENT
;
599 fmt2
.tymed
= TYMED_MFPICT
;
601 memset(&std2
, 0, sizeof(STGMEDIUM
));
602 std2
.tymed
= TYMED_MFPICT
;
604 /* Get the metafile picture out of it */
606 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
608 mfp
= GlobalLock(std2
.u
.hGlobal
);
613 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
614 IStream
*pStream
= 0;
616 PresentationDataHeader pdh
;
620 CHAR strOleTypeName
[51];
621 BYTE OlePresStreamHeader
[] =
623 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
624 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
625 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00
629 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
631 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
632 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
634 pdh
.dwObjectExtentX
= mfp
->xExt
;
635 pdh
.dwObjectExtentY
= mfp
->yExt
;
638 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
640 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
642 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
643 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
645 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
647 IStream_Release(pStream
);
649 HeapFree(GetProcessHeap(), 0, mfBits
);
651 GlobalUnlock(std2
.u
.hGlobal
);
652 ReleaseStgMedium(&std2
);
654 ReadClassStg(std
.u
.pstg
, &clsID
);
655 ProgIDFromCLSID(&clsID
, &strProgID
);
657 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
658 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
659 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
660 CoTaskMemFree(strProgID
);
664 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
666 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
667 GlobalFree(hStorage
);
668 hr
= CLIPBRD_E_CANT_SET
;
671 ReleaseStgMedium(&std
);
675 /************************************************************************
676 * find_format_in_list
678 * Returns the first entry that matches the provided clipboard format.
680 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
683 for(i
= 0; i
< num
; i
++)
684 if(entries
[i
].fmtetc
.cfFormat
== cf
)
690 /***************************************************************************
691 * get_data_from_storage
693 * Returns storage data in an HGLOBAL.
695 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
706 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
707 if(!h
) return E_OUTOFMEMORY
;
709 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
712 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
713 ILockBytes_Release(lbs
);
722 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
724 med
.pUnkForRelease
= NULL
;
726 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
730 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
731 if(FAILED(hr
)) goto end
;
733 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
734 ReleaseStgMedium(&med
);
735 if(FAILED(hr
)) goto end
;
740 IStorage_Release(stg
);
741 if(FAILED(hr
)) GlobalFree(h
);
745 /***************************************************************************
746 * get_data_from_stream
748 * Returns stream data in an HGLOBAL.
750 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
760 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
761 if(!h
) return E_OUTOFMEMORY
;
763 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
764 if(FAILED(hr
)) goto error
;
767 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
769 med
.pUnkForRelease
= NULL
;
771 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
778 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
779 if(FAILED(hr
)) goto error
;
782 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
783 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
784 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
785 ReleaseStgMedium(&med
);
786 if(FAILED(hr
)) goto error
;
789 IStream_Release(stm
);
793 if(stm
) IStream_Release(stm
);
798 /***************************************************************************
799 * get_data_from_global
801 * Returns global data in an HGLOBAL.
803 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
813 mem_fmt
.tymed
= TYMED_HGLOBAL
;
815 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
816 if(FAILED(hr
)) return hr
;
818 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
820 if(SUCCEEDED(hr
)) *mem
= h
;
822 ReleaseStgMedium(&med
);
827 /***************************************************************************
828 * get_data_from_enhmetafile
830 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
840 mem_fmt
.tymed
= TYMED_ENHMF
;
842 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
843 if(FAILED(hr
)) return hr
;
845 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
846 if(copy
) *mem
= (HGLOBAL
)copy
;
849 ReleaseStgMedium(&med
);
854 /***************************************************************************
855 * get_data_from_metafilepict
857 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
867 mem_fmt
.tymed
= TYMED_MFPICT
;
869 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
870 if(FAILED(hr
)) return hr
;
872 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
874 if(SUCCEEDED(hr
)) *mem
= copy
;
876 ReleaseStgMedium(&med
);
881 /***************************************************************************
882 * get_data_from_bitmap
884 * Returns bitmap in an HBITMAP.
886 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
896 mem_fmt
.tymed
= TYMED_GDI
;
898 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
899 if(FAILED(hr
)) return hr
;
901 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
903 if(SUCCEEDED(hr
)) *hbm
= copy
;
905 ReleaseStgMedium(&med
);
910 /***********************************************************************
913 * Render the clipboard data. Note that this call will delegate to the
914 * source data object.
916 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
918 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
921 /* Embed source hack */
922 if(fmt
->cfFormat
== embed_source_clipboard_format
)
924 return render_embed_source_hack(data
, fmt
);
927 if(fmt
->tymed
& TYMED_ISTORAGE
)
929 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
931 else if(fmt
->tymed
& TYMED_ISTREAM
)
933 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
935 else if(fmt
->tymed
& TYMED_HGLOBAL
)
937 hr
= get_data_from_global(data
, fmt
, &clip_data
);
939 else if(fmt
->tymed
& TYMED_ENHMF
)
941 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
943 else if(fmt
->tymed
& TYMED_MFPICT
)
945 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
946 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
948 else if(fmt
->tymed
& TYMED_GDI
)
950 /* Returns HBITMAP not HGLOBAL */
951 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
955 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
961 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
963 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
964 if(fmt
->tymed
& TYMED_MFPICT
)
965 free_metafilepict(clip_data
);
966 else if(fmt
->tymed
& TYMED_GDI
)
967 DeleteObject(clip_data
);
969 GlobalFree(clip_data
);
970 hr
= CLIPBRD_E_CANT_SET
;
977 /*---------------------------------------------------------------------*
978 * Implementation of the internal IDataObject interface exposed by
980 *---------------------------------------------------------------------*/
983 /************************************************************************
984 * snapshot_QueryInterface
986 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
987 REFIID riid
, void **ppvObject
)
989 snapshot
*This
= impl_from_IDataObject(iface
);
990 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
992 if ( (This
==0) || (ppvObject
==0) )
997 if (IsEqualIID(&IID_IUnknown
, riid
) ||
998 IsEqualIID(&IID_IDataObject
, riid
))
1004 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1005 return E_NOINTERFACE
;
1008 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1013 /************************************************************************
1016 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1018 snapshot
*This
= impl_from_IDataObject(iface
);
1020 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1022 return InterlockedIncrement(&This
->ref
);
1025 /************************************************************************
1028 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1030 snapshot
*This
= impl_from_IDataObject(iface
);
1033 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1035 ref
= InterlockedDecrement(&This
->ref
);
1039 ole_clipbrd
*clipbrd
;
1040 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
1042 if(This
->data
) IDataObject_Release(This
->data
);
1044 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
1045 clipbrd
->latest_snapshot
= NULL
;
1046 HeapFree(GetProcessHeap(), 0, This
);
1052 /************************************************************
1053 * get_current_ole_clip_window
1055 * Return the window that owns the ole clipboard.
1057 * If the clipboard is flushed or not owned by ole this will
1060 static HWND
get_current_ole_clip_window(void)
1065 h
= GetClipboardData(dataobject_clipboard_format
);
1067 ptr
= GlobalLock(h
);
1068 if(!ptr
) return NULL
;
1074 /************************************************************
1075 * get_current_dataobject
1077 * Return an unmarshalled IDataObject if there is a current
1078 * (ie non-flushed) object on the ole clipboard.
1080 static HRESULT
get_current_dataobject(IDataObject
**data
)
1082 HRESULT hr
= S_FALSE
;
1083 HWND wnd
= get_current_ole_clip_window();
1090 if(!wnd
) return S_FALSE
;
1092 h
= GetClipboardData(wine_marshal_clipboard_format
);
1093 if(!h
) return S_FALSE
;
1094 if(GlobalSize(h
) == 0) return S_FALSE
;
1095 ptr
= GlobalLock(h
);
1096 if(!ptr
) return S_FALSE
;
1098 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1099 if(FAILED(hr
)) goto end
;
1101 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1105 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1106 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1108 IStream_Release(stm
);
1115 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1117 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1123 case CF_UNICODETEXT
:
1124 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1125 case CF_ENHMETAFILE
:
1127 case CF_METAFILEPICT
:
1128 return TYMED_MFPICT
;
1132 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1137 /***********************************************************
1140 * Returns a copy of the Ole Private Data
1142 static HRESULT
get_priv_data(ole_priv_data
**data
)
1146 ole_priv_data
*ret
= NULL
;
1150 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1153 ole_priv_data
*src
= GlobalLock(handle
);
1158 /* FIXME: sanity check on size */
1159 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1162 GlobalUnlock(handle
);
1163 return E_OUTOFMEMORY
;
1165 memcpy(ret
, src
, src
->size
);
1166 GlobalUnlock(handle
);
1168 /* Fixup any target device offsets to ptrs */
1169 for(i
= 0; i
< ret
->count
; i
++)
1170 ret
->entries
[i
].fmtetc
.ptd
=
1171 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1175 if(!ret
) /* Non-ole data */
1178 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1180 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1183 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1184 TRACE("cf %04x %s\n", cf
, buf
);
1186 TRACE("count %d\n", count
);
1187 size
+= count
* sizeof(ret
->entries
[0]);
1189 /* There are holes in fmtetc so zero init */
1190 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1191 if(!ret
) return E_OUTOFMEMORY
;
1195 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1197 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1198 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1199 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1200 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1201 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1202 ret
->entries
[idx
].first_use
= 1;
1210 /************************************************************************
1211 * get_stgmed_for_global
1213 * Returns a stg medium with a copy of the global handle
1215 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1219 med
->pUnkForRelease
= NULL
;
1220 med
->tymed
= TYMED_NULL
;
1222 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1224 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1229 /************************************************************************
1230 * get_stgmed_for_stream
1232 * Returns a stg medium with a stream based on the handle
1234 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1239 med
->pUnkForRelease
= NULL
;
1240 med
->tymed
= TYMED_NULL
;
1242 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1243 if(FAILED(hr
)) return hr
;
1245 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1252 med
->tymed
= TYMED_ISTREAM
;
1256 /************************************************************************
1257 * get_stgmed_for_storage
1259 * Returns a stg medium with a storage based on the handle
1261 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1267 med
->pUnkForRelease
= NULL
;
1268 med
->tymed
= TYMED_NULL
;
1270 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1271 if(FAILED(hr
)) return hr
;
1273 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1280 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1281 ILockBytes_Release(lbs
);
1288 med
->tymed
= TYMED_ISTORAGE
;
1292 /************************************************************************
1293 * get_stgmed_for_emf
1295 * Returns a stg medium with an enhanced metafile based on the handle
1297 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1299 med
->pUnkForRelease
= NULL
;
1300 med
->tymed
= TYMED_NULL
;
1302 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1303 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1304 med
->tymed
= TYMED_ENHMF
;
1308 /************************************************************************
1309 * get_stgmed_for_bitmap
1311 * Returns a stg medium with a bitmap based on the handle
1313 static HRESULT
get_stgmed_for_bitmap(HBITMAP hbmp
, STGMEDIUM
*med
)
1317 med
->pUnkForRelease
= NULL
;
1318 med
->tymed
= TYMED_NULL
;
1320 hr
= dup_bitmap(hbmp
, &med
->u
.hBitmap
);
1325 med
->tymed
= TYMED_GDI
;
1329 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1331 const WCHAR
*str1
, *str2
;
1333 if(off1
== 0 && off2
== 0) return TRUE
;
1334 if(off1
== 0 || off2
== 0) return FALSE
;
1336 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1337 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1339 return !lstrcmpW(str1
, str2
);
1342 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1344 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1345 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1347 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1349 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1351 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1354 /* FIXME check devmode? */
1359 /************************************************************************
1362 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1365 snapshot
*This
= impl_from_IDataObject(iface
);
1368 ole_priv_data
*enum_data
= NULL
;
1369 ole_priv_data_entry
*entry
;
1372 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1374 if ( !fmt
|| !med
) return E_INVALIDARG
;
1376 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1379 hr
= get_current_dataobject(&This
->data
);
1383 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1388 h
= GetClipboardData(fmt
->cfFormat
);
1391 hr
= DV_E_FORMATETC
;
1395 hr
= get_priv_data(&enum_data
);
1396 if(FAILED(hr
)) goto end
;
1398 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1401 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1403 hr
= DV_E_FORMATETC
;
1406 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1407 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1409 else /* non-Ole format */
1410 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1412 if(mask
& TYMED_ISTORAGE
)
1413 hr
= get_stgmed_for_storage(h
, med
);
1414 else if(mask
& TYMED_HGLOBAL
)
1415 hr
= get_stgmed_for_global(h
, med
);
1416 else if(mask
& TYMED_ISTREAM
)
1417 hr
= get_stgmed_for_stream(h
, med
);
1418 else if(mask
& TYMED_ENHMF
)
1419 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1420 else if(mask
& TYMED_GDI
)
1421 hr
= get_stgmed_for_bitmap((HBITMAP
)h
, med
);
1424 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1430 HeapFree(GetProcessHeap(), 0, enum_data
);
1431 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1435 /************************************************************************
1436 * snapshot_GetDataHere
1438 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1441 snapshot
*This
= impl_from_IDataObject(iface
);
1444 ole_priv_data
*enum_data
= NULL
;
1445 ole_priv_data_entry
*entry
;
1448 if ( !fmt
|| !med
) return E_INVALIDARG
;
1450 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1452 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1455 hr
= get_current_dataobject(&This
->data
);
1459 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1467 h
= GetClipboardData(fmt
->cfFormat
);
1470 hr
= DV_E_FORMATETC
;
1474 hr
= get_priv_data(&enum_data
);
1475 if(FAILED(hr
)) goto end
;
1477 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1480 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1482 hr
= DV_E_FORMATETC
;
1485 supported
= entry
->fmtetc
.tymed
;
1487 else /* non-Ole format */
1488 supported
= TYMED_HGLOBAL
;
1494 DWORD src_size
= GlobalSize(h
);
1495 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1497 if(dst_size
>= src_size
)
1499 void *src
= GlobalLock(h
);
1500 void *dst
= GlobalLock(med
->u
.hGlobal
);
1502 memcpy(dst
, src
, src_size
);
1503 GlobalUnlock(med
->u
.hGlobal
);
1511 DWORD src_size
= GlobalSize(h
);
1512 void *src
= GlobalLock(h
);
1513 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1517 case TYMED_ISTORAGE
:
1520 if(!(supported
& TYMED_ISTORAGE
))
1525 hr
= get_stgmed_for_storage(h
, ©
);
1528 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1529 ReleaseStgMedium(©
);
1534 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1540 HeapFree(GetProcessHeap(), 0, enum_data
);
1541 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1545 /************************************************************************
1546 * snapshot_QueryGetData
1548 * The OLE Clipboard's implementation of this method delegates to
1549 * a data source if there is one or wraps around the windows clipboard
1550 * function IsClipboardFormatAvailable() otherwise.
1553 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1555 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1557 if (!fmt
) return E_INVALIDARG
;
1559 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1561 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1563 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1566 /************************************************************************
1567 * snapshot_GetCanonicalFormatEtc
1569 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1572 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1574 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1577 return DATA_S_SAMEFORMATETC
;
1580 /************************************************************************
1583 * The OLE Clipboard does not implement this method
1585 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1586 STGMEDIUM
*med
, BOOL release
)
1588 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1592 /************************************************************************
1593 * snapshot_EnumFormatEtc
1596 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1597 IEnumFORMATETC
**enum_fmt
)
1600 ole_priv_data
*data
= NULL
;
1602 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1606 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1607 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1609 hr
= get_priv_data(&data
);
1611 if(FAILED(hr
)) goto end
;
1613 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1616 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1620 /************************************************************************
1623 * The OLE Clipboard does not implement this method
1625 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1626 DWORD flags
, IAdviseSink
*sink
,
1629 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1633 /************************************************************************
1634 * snapshot_DUnadvise
1636 * The OLE Clipboard does not implement this method
1638 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1640 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1644 /************************************************************************
1645 * snapshot_EnumDAdvise
1647 * The OLE Clipboard does not implement this method
1649 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1650 IEnumSTATDATA
** enum_advise
)
1652 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1656 static const IDataObjectVtbl snapshot_vtable
=
1658 snapshot_QueryInterface
,
1662 snapshot_GetDataHere
,
1663 snapshot_QueryGetData
,
1664 snapshot_GetCanonicalFormatEtc
,
1666 snapshot_EnumFormatEtc
,
1669 snapshot_EnumDAdvise
1672 /*---------------------------------------------------------------------*
1673 * Internal implementation methods for the OLE clipboard
1674 *---------------------------------------------------------------------*/
1676 static snapshot
*snapshot_construct(DWORD seq_no
)
1680 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1681 if (!This
) return NULL
;
1683 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1685 This
->seq_no
= seq_no
;
1691 /*********************************************************
1692 * register_clipboard_formats
1694 static void register_clipboard_formats(void)
1696 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1697 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1698 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1699 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1700 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1701 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1702 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1703 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1704 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1705 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1706 'D','e','s','c','r','i','p','t','o','r',0};
1707 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1709 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1710 'D','a','t','a','O','b','j','e','c','t',0};
1712 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1713 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1714 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1715 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1716 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1717 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1718 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1719 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1720 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1721 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1722 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1724 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1727 /***********************************************************************
1728 * OLEClipbrd_Initialize()
1729 * Initializes the OLE clipboard.
1731 void OLEClipbrd_Initialize(void)
1733 register_clipboard_formats();
1735 if ( !theOleClipboard
)
1737 ole_clipbrd
* clipbrd
;
1742 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1743 if (!clipbrd
) return;
1745 clipbrd
->latest_snapshot
= NULL
;
1746 clipbrd
->window
= NULL
;
1747 clipbrd
->src_data
= NULL
;
1748 clipbrd
->cached_enum
= NULL
;
1750 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1753 HeapFree(GetProcessHeap(), 0, clipbrd
);
1757 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1760 HeapFree(GetProcessHeap(), 0, clipbrd
);
1764 theOleClipboard
= clipbrd
;
1768 /***********************************************************************
1769 * OLEClipbrd_UnInitialize()
1770 * Un-Initializes the OLE clipboard
1772 void OLEClipbrd_UnInitialize(void)
1774 ole_clipbrd
*clipbrd
= theOleClipboard
;
1780 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1781 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1783 if ( clipbrd
->window
)
1785 DestroyWindow(clipbrd
->window
);
1786 UnregisterClassW( clipbrd_wndclass
, hinst
);
1789 IStream_Release(clipbrd
->marshal_data
);
1790 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1791 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1792 HeapFree(GetProcessHeap(), 0, clipbrd
);
1793 theOleClipboard
= NULL
;
1797 /*********************************************************************
1798 * set_clipboard_formats
1800 * Enumerate all formats supported by the source and make
1801 * those formats available using delayed rendering using SetClipboardData.
1802 * Cache the enumeration list and make that list visibile as the
1803 * 'Ole Private Data' format on the clipboard.
1806 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1810 IEnumFORMATETC
*enum_fmt
;
1811 HGLOBAL priv_data_handle
;
1812 DWORD_PTR target_offset
;
1813 ole_priv_data
*priv_data
;
1814 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1816 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1817 if(FAILED(hr
)) return hr
;
1819 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1822 needed
+= sizeof(priv_data
->entries
[0]);
1825 needed
+= fmt
.ptd
->tdSize
;
1826 CoTaskMemFree(fmt
.ptd
);
1830 /* Windows pads the list with two empty ole_priv_data_entries, one
1831 * after the entries array and one after the target device data.
1832 * Allocating with zero init to zero these pads. */
1834 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1835 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1836 priv_data
= GlobalLock(priv_data_handle
);
1838 priv_data
->unk1
= 0;
1839 priv_data
->size
= needed
;
1840 priv_data
->unk2
= 1;
1841 priv_data
->count
= count
;
1842 priv_data
->unk3
[0] = 0;
1843 priv_data
->unk3
[1] = 0;
1845 IEnumFORMATETC_Reset(enum_fmt
);
1848 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1850 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1852 TRACE("%s\n", dump_fmtetc(&fmt
));
1854 priv_data
->entries
[idx
].fmtetc
= fmt
;
1857 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1858 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1859 target_offset
+= fmt
.ptd
->tdSize
;
1860 CoTaskMemFree(fmt
.ptd
);
1863 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1864 priv_data
->entries
[idx
].unk
[0] = 0;
1865 priv_data
->entries
[idx
].unk
[1] = 0;
1867 if (priv_data
->entries
[idx
].first_use
)
1868 SetClipboardData(fmt
.cfFormat
, NULL
);
1873 IEnumFORMATETC_Release(enum_fmt
);
1875 /* Cache the list and fixup any target device offsets to ptrs */
1876 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1877 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1878 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1879 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1880 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1882 GlobalUnlock(priv_data_handle
);
1883 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1885 GlobalFree(priv_data_handle
);
1886 return CLIPBRD_E_CANT_SET
;
1892 static HWND
create_clipbrd_window(void);
1894 /***********************************************************************
1895 * get_clipbrd_window
1897 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1899 if ( !clipbrd
->window
)
1900 clipbrd
->window
= create_clipbrd_window();
1902 *wnd
= clipbrd
->window
;
1903 return *wnd
? S_OK
: E_FAIL
;
1907 /**********************************************************************
1908 * release_marshal_data
1910 * Releases the data and sets the stream back to zero size.
1912 static inline void release_marshal_data(IStream
*stm
)
1915 ULARGE_INTEGER size
;
1916 pos
.QuadPart
= size
.QuadPart
= 0;
1918 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1919 CoReleaseMarshalData(stm
);
1920 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1921 IStream_SetSize(stm
, size
);
1924 /***********************************************************************
1925 * expose_marshalled_dataobject
1927 * Sets the marshalled dataobject to the clipboard. In the flushed case
1928 * we set a zero sized HGLOBAL to clear the old marshalled data.
1930 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1937 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1938 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1941 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1943 if(!h
) return E_OUTOFMEMORY
;
1945 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1948 return CLIPBRD_E_CANT_SET
;
1953 /***********************************************************************
1954 * set_src_dataobject
1956 * Clears and sets the clipboard's src IDataObject.
1958 * To marshal the source dataobject we do something rather different from Windows.
1959 * We set a clipboard format which contains the marshalled data.
1960 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1962 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1967 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1969 if(clipbrd
->src_data
)
1971 release_marshal_data(clipbrd
->marshal_data
);
1973 IDataObject_Release(clipbrd
->src_data
);
1974 clipbrd
->src_data
= NULL
;
1975 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1976 clipbrd
->cached_enum
= NULL
;
1983 IDataObject_AddRef(data
);
1984 clipbrd
->src_data
= data
;
1986 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1987 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1988 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1989 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1990 if(FAILED(hr
)) return hr
;
1991 hr
= set_clipboard_formats(clipbrd
, data
);
1996 /***********************************************************************
1999 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
2001 ole_clipbrd
*clipbrd
;
2003 get_ole_clipbrd(&clipbrd
);
2007 case WM_RENDERFORMAT
:
2010 ole_priv_data_entry
*entry
;
2012 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2013 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2016 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2021 case WM_RENDERALLFORMATS
:
2024 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
2026 TRACE("(): WM_RENDERALLFORMATS\n");
2028 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2030 if(entries
[i
].first_use
)
2031 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2036 case WM_DESTROYCLIPBOARD
:
2038 TRACE("(): WM_DESTROYCLIPBOARD\n");
2040 set_src_dataobject(clipbrd
, NULL
);
2045 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2052 /***********************************************************************
2053 * create_clipbrd_window
2055 static HWND
create_clipbrd_window(void)
2058 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2059 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2060 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2062 class.cbSize
= sizeof(class);
2064 class.lpfnWndProc
= clipbrd_wndproc
;
2065 class.cbClsExtra
= 0;
2066 class.cbWndExtra
= 0;
2067 class.hInstance
= hinst
;
2070 class.hbrBackground
= 0;
2071 class.lpszMenuName
= NULL
;
2072 class.lpszClassName
= clipbrd_wndclass
;
2073 class.hIconSm
= NULL
;
2075 RegisterClassExW(&class);
2077 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2078 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2079 NULL
, NULL
, hinst
, 0);
2082 /*********************************************************************
2083 * set_dataobject_format
2085 * Windows creates a 'DataObject' clipboard format that contains the
2086 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2088 static HRESULT
set_dataobject_format(HWND hwnd
)
2090 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2093 if(!h
) return E_OUTOFMEMORY
;
2095 data
= GlobalLock(h
);
2099 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2102 return CLIPBRD_E_CANT_SET
;
2108 /*---------------------------------------------------------------------*
2109 * Win32 OLE clipboard API
2110 *---------------------------------------------------------------------*/
2112 /***********************************************************************
2113 * OleSetClipboard [OLE32.@]
2114 * Places a pointer to the specified data object onto the clipboard,
2115 * making the data object accessible to the OleGetClipboard function.
2119 * S_OK IDataObject pointer placed on the clipboard
2120 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2121 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2122 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2123 * CLIPBRD_E_CANT_SET SetClipboard failed
2126 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2129 ole_clipbrd
*clipbrd
;
2132 TRACE("(%p)\n", data
);
2134 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2136 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2138 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2140 if ( !EmptyClipboard() )
2142 hr
= CLIPBRD_E_CANT_EMPTY
;
2146 hr
= set_src_dataobject(clipbrd
, data
);
2147 if(FAILED(hr
)) goto end
;
2151 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2152 if(FAILED(hr
)) goto end
;
2153 hr
= set_dataobject_format(wnd
);
2158 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2162 expose_marshalled_dataobject(clipbrd
, NULL
);
2163 set_src_dataobject(clipbrd
, NULL
);
2170 /***********************************************************************
2171 * OleGetClipboard [OLE32.@]
2172 * Returns a pointer to our internal IDataObject which represents the conceptual
2173 * state of the Windows clipboard. If the current clipboard already contains
2174 * an IDataObject, our internal IDataObject will delegate to this object.
2176 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2179 ole_clipbrd
*clipbrd
;
2182 TRACE("(%p)\n", obj
);
2184 if(!obj
) return E_INVALIDARG
;
2186 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2188 seq_no
= GetClipboardSequenceNumber();
2189 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2190 clipbrd
->latest_snapshot
= NULL
;
2192 if(!clipbrd
->latest_snapshot
)
2194 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2195 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
2198 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2199 IDataObject_AddRef(*obj
);
2204 /******************************************************************************
2205 * OleFlushClipboard [OLE32.@]
2206 * Renders the data from the source IDataObject into the windows clipboard
2208 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2209 * by copying the storage into global memory. Subsequently the default
2210 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2211 * back to TYMED_IStorage.
2213 HRESULT WINAPI
OleFlushClipboard(void)
2216 ole_clipbrd
*clipbrd
;
2221 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2223 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2226 * Already flushed or no source DataObject? Nothing to do.
2228 if (!clipbrd
->src_data
) return S_OK
;
2230 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2232 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2234 hr
= set_dataobject_format(NULL
);
2236 expose_marshalled_dataobject(clipbrd
, NULL
);
2237 set_src_dataobject(clipbrd
, NULL
);
2239 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2245 /***********************************************************************
2246 * OleIsCurrentClipboard [OLE32.@]
2248 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2251 ole_clipbrd
*clipbrd
;
2254 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2256 if (data
== NULL
) return S_FALSE
;
2258 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;