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 CRITICAL_SECTION latest_snapshot_cs
;
178 static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug
=
180 0, 0, &latest_snapshot_cs
,
181 { &latest_snapshot_cs_debug
.ProcessLocksList
, &latest_snapshot_cs_debug
.ProcessLocksList
},
182 0, 0, { (DWORD_PTR
)(__FILE__
": clipboard last snapshot") }
184 static CRITICAL_SECTION latest_snapshot_cs
= { &latest_snapshot_cs_debug
, -1, 0, 0, 0, 0 };
186 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
188 struct oletls
*info
= COM_CurrentInfo();
192 return CO_E_NOTINITIALIZED
;
193 *clipbrd
= theOleClipboard
;
199 * Name of our registered OLE clipboard window class
201 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
203 UINT ownerlink_clipboard_format
= 0;
204 UINT filename_clipboard_format
= 0;
205 UINT filenameW_clipboard_format
= 0;
206 UINT dataobject_clipboard_format
= 0;
207 UINT embedded_object_clipboard_format
= 0;
208 UINT embed_source_clipboard_format
= 0;
209 UINT custom_link_source_clipboard_format
= 0;
210 UINT link_source_clipboard_format
= 0;
211 UINT object_descriptor_clipboard_format
= 0;
212 UINT link_source_descriptor_clipboard_format
= 0;
213 UINT ole_private_data_clipboard_format
= 0;
215 static UINT wine_marshal_clipboard_format
;
217 static inline const char *dump_fmtetc(FORMATETC
*fmt
)
219 if (!fmt
) return "(null)";
220 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
221 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
224 /*---------------------------------------------------------------------*
225 * Implementation of the internal IEnumFORMATETC interface returned by
226 * the OLE clipboard's IDataObject.
227 *---------------------------------------------------------------------*/
229 typedef struct enum_fmtetc
231 IEnumFORMATETC IEnumFORMATETC_iface
;
234 UINT pos
; /* current enumerator position */
238 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
240 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
243 /************************************************************************
244 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
246 * See Windows documentation for more details on IUnknown methods.
248 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
249 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
251 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
253 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
257 if(IsEqualIID(riid
, &IID_IUnknown
) ||
258 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
265 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
266 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
270 TRACE("-- Interface: E_NOINTERFACE\n");
271 return E_NOINTERFACE
;
274 /************************************************************************
275 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
278 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
280 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
281 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
283 return InterlockedIncrement(&This
->ref
);
286 /************************************************************************
287 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
289 * See Windows documentation for more details on IUnknown methods.
291 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
293 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
296 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
298 ref
= InterlockedDecrement(&This
->ref
);
301 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
302 HeapFree(GetProcessHeap(), 0, This
->data
);
303 HeapFree(GetProcessHeap(), 0, This
);
308 /************************************************************************
309 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
311 * Standard enumerator members for IEnumFORMATETC
313 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
314 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
316 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
318 HRESULT hres
= S_FALSE
;
320 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
322 if (This
->pos
< This
->data
->count
)
324 cfetch
= This
->data
->count
- This
->pos
;
331 for(i
= 0; i
< cfetch
; i
++)
333 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
336 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
337 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
338 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
339 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
350 *pceltFethed
= cfetch
;
356 /************************************************************************
357 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
359 * Standard enumerator members for IEnumFORMATETC
361 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
363 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
364 TRACE("(%p)->(num=%u)\n", This
, celt
);
367 if (This
->pos
> This
->data
->count
)
369 This
->pos
= This
->data
->count
;
375 /************************************************************************
376 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
378 * Standard enumerator members for IEnumFORMATETC
380 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
382 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
383 TRACE("(%p)->()\n", This
);
389 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
391 /************************************************************************
392 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
394 * Standard enumerator members for IEnumFORMATETC
396 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
397 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
399 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
400 ole_priv_data
*new_data
;
403 TRACE("(%p)->(%p)\n", This
, obj
);
405 if ( !obj
) return E_INVALIDARG
;
408 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
409 if(!new_data
) return E_OUTOFMEMORY
;
410 memcpy(new_data
, This
->data
, This
->data
->size
);
412 /* Fixup any target device ptrs */
413 for(i
= 0; i
< This
->data
->count
; i
++)
414 new_data
->entries
[i
].fmtetc
.ptd
=
415 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
417 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
420 static const IEnumFORMATETCVtbl efvt
=
422 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
423 OLEClipbrd_IEnumFORMATETC_AddRef
,
424 OLEClipbrd_IEnumFORMATETC_Release
,
425 OLEClipbrd_IEnumFORMATETC_Next
,
426 OLEClipbrd_IEnumFORMATETC_Skip
,
427 OLEClipbrd_IEnumFORMATETC_Reset
,
428 OLEClipbrd_IEnumFORMATETC_Clone
431 /************************************************************************
432 * enum_fmtetc_construct
434 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
436 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
441 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
442 if (!ef
) return E_OUTOFMEMORY
;
445 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
449 TRACE("(%p)->()\n", ef
);
450 *obj
= &ef
->IEnumFORMATETC_iface
;
454 /***********************************************************************
457 * Helper method to duplicate an HGLOBAL chunk of memory
459 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
461 void *src_ptr
, *dst_ptr
;
465 if ( !src
) return S_FALSE
;
467 size
= GlobalSize(src
);
469 *dst
= GlobalAlloc( flags
, size
);
470 if ( !*dst
) return E_OUTOFMEMORY
;
472 src_ptr
= GlobalLock(src
);
473 dst_ptr
= GlobalLock(*dst
);
475 memcpy(dst_ptr
, src_ptr
, size
);
483 /***********************************************************************
486 * Helper function to duplicate a handle to a METAFILEPICT, and the
487 * contained HMETAFILE.
489 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
493 METAFILEPICT
*dest_ptr
;
497 /* Copy the METAFILEPICT structure. */
498 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
499 if (FAILED(hr
)) return hr
;
501 dest_ptr
= GlobalLock(dest
);
502 if (!dest_ptr
) return E_FAIL
;
504 /* Give the new METAFILEPICT a separate HMETAFILE. */
505 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
520 /***********************************************************************
523 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
524 * free the contained HMETAFILE.
526 static void free_metafilepict(HGLOBAL src
)
528 METAFILEPICT
*src_ptr
;
530 src_ptr
= GlobalLock(src
);
533 DeleteMetaFile(src_ptr
->hMF
);
539 /***********************************************************************
542 * Helper function to duplicate an HBITMAP.
544 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
547 HGDIOBJ orig_src_bitmap
;
551 src_dc
= CreateCompatibleDC(NULL
);
552 orig_src_bitmap
= SelectObject(src_dc
, src
);
553 GetObjectW(src
, sizeof bm
, &bm
);
554 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
557 HDC dest_dc
= CreateCompatibleDC(NULL
);
558 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
559 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
560 SelectObject(dest_dc
, orig_dest_bitmap
);
563 SelectObject(src_dc
, orig_src_bitmap
);
566 return dest
? S_OK
: E_FAIL
;
569 /************************************************************
570 * render_embed_source_hack
572 * This is clearly a hack and has no place in the clipboard code.
575 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
578 HGLOBAL hStorage
= 0;
580 ILockBytes
*ptrILockBytes
;
582 memset(&std
, 0, sizeof(STGMEDIUM
));
583 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
585 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
586 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
587 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
590 GlobalFree(hStorage
);
594 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
595 ILockBytes_Release(ptrILockBytes
);
597 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
599 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
600 GlobalFree(hStorage
);
604 if (1) /* check whether the presentation data is already -not- present */
608 METAFILEPICT
*mfp
= 0;
610 fmt2
.cfFormat
= CF_METAFILEPICT
;
612 fmt2
.dwAspect
= DVASPECT_CONTENT
;
614 fmt2
.tymed
= TYMED_MFPICT
;
616 memset(&std2
, 0, sizeof(STGMEDIUM
));
617 std2
.tymed
= TYMED_MFPICT
;
619 /* Get the metafile picture out of it */
621 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
623 mfp
= GlobalLock(std2
.u
.hGlobal
);
628 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
629 IStream
*pStream
= 0;
631 PresentationDataHeader pdh
;
635 CHAR strOleTypeName
[51];
636 BYTE OlePresStreamHeader
[] =
638 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
639 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
640 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
641 0x00, 0x00, 0x00, 0x00
644 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
646 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
647 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
649 pdh
.dwObjectExtentX
= mfp
->xExt
;
650 pdh
.dwObjectExtentY
= mfp
->yExt
;
653 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
655 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
657 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
658 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
660 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
662 IStream_Release(pStream
);
664 HeapFree(GetProcessHeap(), 0, mfBits
);
666 GlobalUnlock(std2
.u
.hGlobal
);
667 ReleaseStgMedium(&std2
);
669 ReadClassStg(std
.u
.pstg
, &clsID
);
670 ProgIDFromCLSID(&clsID
, &strProgID
);
672 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
673 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
674 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
675 CoTaskMemFree(strProgID
);
679 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
681 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
682 GlobalFree(hStorage
);
683 hr
= CLIPBRD_E_CANT_SET
;
686 ReleaseStgMedium(&std
);
690 /************************************************************************
691 * find_format_in_list
693 * Returns the first entry that matches the provided clipboard format.
695 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
698 for(i
= 0; i
< num
; i
++)
699 if(entries
[i
].fmtetc
.cfFormat
== cf
)
705 /***************************************************************************
706 * get_data_from_storage
708 * Returns storage data in an HGLOBAL.
710 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
721 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
722 if(!h
) return E_OUTOFMEMORY
;
724 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
727 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
728 ILockBytes_Release(lbs
);
737 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
739 med
.pUnkForRelease
= NULL
;
741 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
745 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
746 if(FAILED(hr
)) goto end
;
748 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
749 ReleaseStgMedium(&med
);
750 if(FAILED(hr
)) goto end
;
755 IStorage_Release(stg
);
756 if(FAILED(hr
)) GlobalFree(h
);
760 /***************************************************************************
761 * get_data_from_stream
763 * Returns stream data in an HGLOBAL.
765 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
775 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
776 if(!h
) return E_OUTOFMEMORY
;
778 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
779 if(FAILED(hr
)) goto error
;
782 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
784 med
.pUnkForRelease
= NULL
;
786 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
793 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
794 if(FAILED(hr
)) goto error
;
797 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
798 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
799 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
800 ReleaseStgMedium(&med
);
801 if(FAILED(hr
)) goto error
;
804 IStream_Release(stm
);
808 if(stm
) IStream_Release(stm
);
813 /***************************************************************************
814 * get_data_from_global
816 * Returns global data in an HGLOBAL.
818 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
828 mem_fmt
.tymed
= TYMED_HGLOBAL
;
830 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
831 if(FAILED(hr
)) return hr
;
833 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
835 if(SUCCEEDED(hr
)) *mem
= h
;
837 ReleaseStgMedium(&med
);
842 /***************************************************************************
843 * get_data_from_enhmetafile
845 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
855 mem_fmt
.tymed
= TYMED_ENHMF
;
857 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
858 if(FAILED(hr
)) return hr
;
860 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
861 if(copy
) *mem
= (HGLOBAL
)copy
;
864 ReleaseStgMedium(&med
);
869 /***************************************************************************
870 * get_data_from_metafilepict
872 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
882 mem_fmt
.tymed
= TYMED_MFPICT
;
884 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
885 if(FAILED(hr
)) return hr
;
887 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
889 if(SUCCEEDED(hr
)) *mem
= copy
;
891 ReleaseStgMedium(&med
);
896 /***************************************************************************
897 * get_data_from_bitmap
899 * Returns bitmap in an HBITMAP.
901 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
911 mem_fmt
.tymed
= TYMED_GDI
;
913 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
914 if(FAILED(hr
)) return hr
;
916 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
918 if(SUCCEEDED(hr
)) *hbm
= copy
;
920 ReleaseStgMedium(&med
);
925 /***********************************************************************
928 * Render the clipboard data. Note that this call will delegate to the
929 * source data object.
931 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
933 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
936 /* Embed source hack */
937 if(fmt
->cfFormat
== embed_source_clipboard_format
)
939 return render_embed_source_hack(data
, fmt
);
942 if(fmt
->tymed
& TYMED_ISTORAGE
)
944 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
946 else if(fmt
->tymed
& TYMED_ISTREAM
)
948 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
950 else if(fmt
->tymed
& TYMED_HGLOBAL
)
952 hr
= get_data_from_global(data
, fmt
, &clip_data
);
954 else if(fmt
->tymed
& TYMED_ENHMF
)
956 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
958 else if(fmt
->tymed
& TYMED_MFPICT
)
960 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
961 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
963 else if(fmt
->tymed
& TYMED_GDI
)
965 /* Returns HBITMAP not HGLOBAL */
966 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
970 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
976 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
978 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
979 if(fmt
->tymed
& TYMED_MFPICT
)
980 free_metafilepict(clip_data
);
981 else if(fmt
->tymed
& TYMED_GDI
)
982 DeleteObject(clip_data
);
984 GlobalFree(clip_data
);
985 hr
= CLIPBRD_E_CANT_SET
;
992 /*---------------------------------------------------------------------*
993 * Implementation of the internal IDataObject interface exposed by
995 *---------------------------------------------------------------------*/
998 /************************************************************************
999 * snapshot_QueryInterface
1001 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
1002 REFIID riid
, void **ppvObject
)
1004 snapshot
*This
= impl_from_IDataObject(iface
);
1005 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1007 if ( (This
==0) || (ppvObject
==0) )
1008 return E_INVALIDARG
;
1012 if (IsEqualIID(&IID_IUnknown
, riid
) ||
1013 IsEqualIID(&IID_IDataObject
, riid
))
1019 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1020 return E_NOINTERFACE
;
1023 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1028 /************************************************************************
1031 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1033 snapshot
*This
= impl_from_IDataObject(iface
);
1035 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1037 return InterlockedIncrement(&This
->ref
);
1040 /************************************************************************
1043 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1045 snapshot
*This
= impl_from_IDataObject(iface
);
1048 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1050 ref
= InterlockedDecrement(&This
->ref
);
1054 EnterCriticalSection(&latest_snapshot_cs
);
1057 LeaveCriticalSection(&latest_snapshot_cs
);
1060 if (theOleClipboard
->latest_snapshot
== This
)
1061 theOleClipboard
->latest_snapshot
= NULL
;
1062 LeaveCriticalSection(&latest_snapshot_cs
);
1064 if(This
->data
) IDataObject_Release(This
->data
);
1065 HeapFree(GetProcessHeap(), 0, This
);
1071 /************************************************************
1072 * get_current_ole_clip_window
1074 * Return the window that owns the ole clipboard.
1076 * If the clipboard is flushed or not owned by ole this will
1079 static HWND
get_current_ole_clip_window(void)
1084 h
= GetClipboardData(dataobject_clipboard_format
);
1086 ptr
= GlobalLock(h
);
1087 if(!ptr
) return NULL
;
1093 /************************************************************
1094 * get_current_dataobject
1096 * Return an unmarshalled IDataObject if there is a current
1097 * (ie non-flushed) object on the ole clipboard.
1099 static HRESULT
get_current_dataobject(IDataObject
**data
)
1101 HRESULT hr
= S_FALSE
;
1102 HWND wnd
= get_current_ole_clip_window();
1109 if(!wnd
) return S_FALSE
;
1111 h
= GetClipboardData(wine_marshal_clipboard_format
);
1112 if(!h
) return S_FALSE
;
1113 if(GlobalSize(h
) == 0) return S_FALSE
;
1114 ptr
= GlobalLock(h
);
1115 if(!ptr
) return S_FALSE
;
1117 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1118 if(FAILED(hr
)) goto end
;
1120 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1124 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1125 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1127 IStream_Release(stm
);
1134 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1136 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1142 case CF_UNICODETEXT
:
1143 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1144 case CF_ENHMETAFILE
:
1146 case CF_METAFILEPICT
:
1147 return TYMED_MFPICT
;
1151 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1156 /***********************************************************
1159 * Returns a copy of the Ole Private Data
1161 static HRESULT
get_priv_data(ole_priv_data
**data
)
1165 ole_priv_data
*ret
= NULL
;
1169 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1172 ole_priv_data
*src
= GlobalLock(handle
);
1177 /* FIXME: sanity check on size */
1178 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1181 GlobalUnlock(handle
);
1182 return E_OUTOFMEMORY
;
1184 memcpy(ret
, src
, src
->size
);
1185 GlobalUnlock(handle
);
1187 /* Fixup any target device offsets to ptrs */
1188 for(i
= 0; i
< ret
->count
; i
++)
1189 ret
->entries
[i
].fmtetc
.ptd
=
1190 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1194 if(!ret
) /* Non-ole data */
1197 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1199 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1202 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1203 TRACE("cf %04x %s\n", cf
, buf
);
1205 TRACE("count %d\n", count
);
1206 size
+= count
* sizeof(ret
->entries
[0]);
1208 /* There are holes in fmtetc so zero init */
1209 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1210 if(!ret
) return E_OUTOFMEMORY
;
1214 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1216 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1217 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1218 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1219 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1220 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1221 ret
->entries
[idx
].first_use
= 1;
1229 /************************************************************************
1230 * get_stgmed_for_global
1232 * Returns a stg medium with a copy of the global handle
1234 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1238 med
->pUnkForRelease
= NULL
;
1239 med
->tymed
= TYMED_NULL
;
1241 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1243 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1248 /************************************************************************
1249 * get_stgmed_for_stream
1251 * Returns a stg medium with a stream based on the handle
1253 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1258 med
->pUnkForRelease
= NULL
;
1259 med
->tymed
= TYMED_NULL
;
1261 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1262 if(FAILED(hr
)) return hr
;
1264 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1271 med
->tymed
= TYMED_ISTREAM
;
1275 /************************************************************************
1276 * get_stgmed_for_storage
1278 * Returns a stg medium with a storage based on the handle
1280 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1286 med
->pUnkForRelease
= NULL
;
1287 med
->tymed
= TYMED_NULL
;
1289 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1290 if(FAILED(hr
)) return hr
;
1292 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1299 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1300 ILockBytes_Release(lbs
);
1307 med
->tymed
= TYMED_ISTORAGE
;
1311 /************************************************************************
1312 * get_stgmed_for_emf
1314 * Returns a stg medium with an enhanced metafile based on the handle
1316 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1318 med
->pUnkForRelease
= NULL
;
1319 med
->tymed
= TYMED_NULL
;
1321 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1322 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1323 med
->tymed
= TYMED_ENHMF
;
1327 /************************************************************************
1328 * get_stgmed_for_bitmap
1330 * Returns a stg medium with a bitmap based on the handle
1332 static HRESULT
get_stgmed_for_bitmap(HBITMAP hbmp
, STGMEDIUM
*med
)
1336 med
->pUnkForRelease
= NULL
;
1337 med
->tymed
= TYMED_NULL
;
1339 hr
= dup_bitmap(hbmp
, &med
->u
.hBitmap
);
1344 med
->tymed
= TYMED_GDI
;
1348 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1350 const WCHAR
*str1
, *str2
;
1352 if(off1
== 0 && off2
== 0) return TRUE
;
1353 if(off1
== 0 || off2
== 0) return FALSE
;
1355 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1356 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1358 return !lstrcmpW(str1
, str2
);
1361 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1363 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1364 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1366 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1368 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1370 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1373 /* FIXME check devmode? */
1378 /************************************************************************
1381 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1384 snapshot
*This
= impl_from_IDataObject(iface
);
1387 ole_priv_data
*enum_data
= NULL
;
1388 ole_priv_data_entry
*entry
;
1391 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1393 if ( !fmt
|| !med
) return E_INVALIDARG
;
1395 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1398 hr
= get_current_dataobject(&This
->data
);
1402 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1407 h
= GetClipboardData(fmt
->cfFormat
);
1410 hr
= DV_E_FORMATETC
;
1414 hr
= get_priv_data(&enum_data
);
1415 if(FAILED(hr
)) goto end
;
1417 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1420 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1422 hr
= DV_E_FORMATETC
;
1425 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1426 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1428 else /* non-Ole format */
1429 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1431 if(mask
& TYMED_ISTORAGE
)
1432 hr
= get_stgmed_for_storage(h
, med
);
1433 else if(mask
& TYMED_HGLOBAL
)
1434 hr
= get_stgmed_for_global(h
, med
);
1435 else if(mask
& TYMED_ISTREAM
)
1436 hr
= get_stgmed_for_stream(h
, med
);
1437 else if(mask
& TYMED_ENHMF
)
1438 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1439 else if(mask
& TYMED_GDI
)
1440 hr
= get_stgmed_for_bitmap((HBITMAP
)h
, med
);
1443 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1449 HeapFree(GetProcessHeap(), 0, enum_data
);
1450 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1454 /************************************************************************
1455 * snapshot_GetDataHere
1457 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1460 snapshot
*This
= impl_from_IDataObject(iface
);
1463 ole_priv_data
*enum_data
= NULL
;
1464 ole_priv_data_entry
*entry
;
1467 if ( !fmt
|| !med
) return E_INVALIDARG
;
1469 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1471 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1474 hr
= get_current_dataobject(&This
->data
);
1478 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1486 h
= GetClipboardData(fmt
->cfFormat
);
1489 hr
= DV_E_FORMATETC
;
1493 hr
= get_priv_data(&enum_data
);
1494 if(FAILED(hr
)) goto end
;
1496 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1499 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1501 hr
= DV_E_FORMATETC
;
1504 supported
= entry
->fmtetc
.tymed
;
1506 else /* non-Ole format */
1507 supported
= TYMED_HGLOBAL
;
1513 DWORD src_size
= GlobalSize(h
);
1514 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1516 if(dst_size
>= src_size
)
1518 void *src
= GlobalLock(h
);
1519 void *dst
= GlobalLock(med
->u
.hGlobal
);
1521 memcpy(dst
, src
, src_size
);
1522 GlobalUnlock(med
->u
.hGlobal
);
1530 DWORD src_size
= GlobalSize(h
);
1531 void *src
= GlobalLock(h
);
1532 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1536 case TYMED_ISTORAGE
:
1539 if(!(supported
& TYMED_ISTORAGE
))
1544 hr
= get_stgmed_for_storage(h
, ©
);
1547 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1548 ReleaseStgMedium(©
);
1553 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1559 HeapFree(GetProcessHeap(), 0, enum_data
);
1560 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1564 /************************************************************************
1565 * snapshot_QueryGetData
1567 * The OLE Clipboard's implementation of this method delegates to
1568 * a data source if there is one or wraps around the windows clipboard
1569 * function IsClipboardFormatAvailable() otherwise.
1572 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1574 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1576 if (!fmt
) return E_INVALIDARG
;
1578 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1580 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1582 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1585 /************************************************************************
1586 * snapshot_GetCanonicalFormatEtc
1588 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1591 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1593 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1596 return DATA_S_SAMEFORMATETC
;
1599 /************************************************************************
1602 * The OLE Clipboard does not implement this method
1604 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1605 STGMEDIUM
*med
, BOOL release
)
1607 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1611 /************************************************************************
1612 * snapshot_EnumFormatEtc
1615 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1616 IEnumFORMATETC
**enum_fmt
)
1619 ole_priv_data
*data
= NULL
;
1621 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1625 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1626 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1628 hr
= get_priv_data(&data
);
1630 if(FAILED(hr
)) goto end
;
1632 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1635 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1639 /************************************************************************
1642 * The OLE Clipboard does not implement this method
1644 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1645 DWORD flags
, IAdviseSink
*sink
,
1648 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1652 /************************************************************************
1653 * snapshot_DUnadvise
1655 * The OLE Clipboard does not implement this method
1657 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1659 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1663 /************************************************************************
1664 * snapshot_EnumDAdvise
1666 * The OLE Clipboard does not implement this method
1668 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1669 IEnumSTATDATA
** enum_advise
)
1671 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1675 static const IDataObjectVtbl snapshot_vtable
=
1677 snapshot_QueryInterface
,
1681 snapshot_GetDataHere
,
1682 snapshot_QueryGetData
,
1683 snapshot_GetCanonicalFormatEtc
,
1685 snapshot_EnumFormatEtc
,
1688 snapshot_EnumDAdvise
1691 /*---------------------------------------------------------------------*
1692 * Internal implementation methods for the OLE clipboard
1693 *---------------------------------------------------------------------*/
1695 static snapshot
*snapshot_construct(DWORD seq_no
)
1699 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1700 if (!This
) return NULL
;
1702 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1704 This
->seq_no
= seq_no
;
1710 /*********************************************************
1711 * register_clipboard_formats
1713 static void register_clipboard_formats(void)
1715 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1716 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1717 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1718 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1719 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1720 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1721 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1722 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1723 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1724 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1725 'D','e','s','c','r','i','p','t','o','r',0};
1726 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1728 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1729 'D','a','t','a','O','b','j','e','c','t',0};
1731 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1732 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1733 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1734 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1735 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1736 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1737 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1738 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1739 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1740 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1741 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1743 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1746 /***********************************************************************
1747 * OLEClipbrd_Initialize()
1748 * Initializes the OLE clipboard.
1750 void OLEClipbrd_Initialize(void)
1752 register_clipboard_formats();
1754 if ( !theOleClipboard
)
1756 ole_clipbrd
* clipbrd
;
1761 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1762 if (!clipbrd
) return;
1764 clipbrd
->latest_snapshot
= NULL
;
1765 clipbrd
->window
= NULL
;
1766 clipbrd
->src_data
= NULL
;
1767 clipbrd
->cached_enum
= NULL
;
1769 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1772 HeapFree(GetProcessHeap(), 0, clipbrd
);
1776 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1779 HeapFree(GetProcessHeap(), 0, clipbrd
);
1783 theOleClipboard
= clipbrd
;
1787 /***********************************************************************
1788 * OLEClipbrd_UnInitialize()
1789 * Un-Initializes the OLE clipboard
1791 void OLEClipbrd_UnInitialize(void)
1793 ole_clipbrd
*clipbrd
= theOleClipboard
;
1799 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1800 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1802 if ( clipbrd
->window
)
1804 DestroyWindow(clipbrd
->window
);
1805 UnregisterClassW( clipbrd_wndclass
, hinst
);
1808 IStream_Release(clipbrd
->marshal_data
);
1809 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1810 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1811 HeapFree(GetProcessHeap(), 0, clipbrd
);
1812 theOleClipboard
= NULL
;
1816 /*********************************************************************
1817 * set_clipboard_formats
1819 * Enumerate all formats supported by the source and make
1820 * those formats available using delayed rendering using SetClipboardData.
1821 * Cache the enumeration list and make that list visible as the
1822 * 'Ole Private Data' format on the clipboard.
1825 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1829 IEnumFORMATETC
*enum_fmt
;
1830 HGLOBAL priv_data_handle
;
1831 DWORD_PTR target_offset
;
1832 ole_priv_data
*priv_data
;
1833 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1835 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1836 if(FAILED(hr
)) return hr
;
1838 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1841 needed
+= sizeof(priv_data
->entries
[0]);
1844 needed
+= fmt
.ptd
->tdSize
;
1845 CoTaskMemFree(fmt
.ptd
);
1849 /* Windows pads the list with two empty ole_priv_data_entries, one
1850 * after the entries array and one after the target device data.
1851 * Allocating with zero init to zero these pads. */
1853 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1854 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1855 priv_data
= GlobalLock(priv_data_handle
);
1857 priv_data
->unk1
= 0;
1858 priv_data
->size
= needed
;
1859 priv_data
->unk2
= 1;
1860 priv_data
->count
= count
;
1861 priv_data
->unk3
[0] = 0;
1862 priv_data
->unk3
[1] = 0;
1864 IEnumFORMATETC_Reset(enum_fmt
);
1867 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1869 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1871 TRACE("%s\n", dump_fmtetc(&fmt
));
1873 priv_data
->entries
[idx
].fmtetc
= fmt
;
1876 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1877 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1878 target_offset
+= fmt
.ptd
->tdSize
;
1879 CoTaskMemFree(fmt
.ptd
);
1882 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1883 priv_data
->entries
[idx
].unk
[0] = 0;
1884 priv_data
->entries
[idx
].unk
[1] = 0;
1886 if (priv_data
->entries
[idx
].first_use
)
1887 SetClipboardData(fmt
.cfFormat
, NULL
);
1892 IEnumFORMATETC_Release(enum_fmt
);
1894 /* Cache the list and fixup any target device offsets to ptrs */
1895 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1896 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1897 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1898 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1899 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1901 GlobalUnlock(priv_data_handle
);
1902 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1904 GlobalFree(priv_data_handle
);
1905 return CLIPBRD_E_CANT_SET
;
1911 static HWND
create_clipbrd_window(void);
1913 /***********************************************************************
1914 * get_clipbrd_window
1916 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1918 if ( !clipbrd
->window
)
1919 clipbrd
->window
= create_clipbrd_window();
1921 *wnd
= clipbrd
->window
;
1922 return *wnd
? S_OK
: E_FAIL
;
1926 /**********************************************************************
1927 * release_marshal_data
1929 * Releases the data and sets the stream back to zero size.
1931 static inline void release_marshal_data(IStream
*stm
)
1934 ULARGE_INTEGER size
;
1935 pos
.QuadPart
= size
.QuadPart
= 0;
1937 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1938 CoReleaseMarshalData(stm
);
1939 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1940 IStream_SetSize(stm
, size
);
1943 /***********************************************************************
1944 * expose_marshalled_dataobject
1946 * Sets the marshalled dataobject to the clipboard. In the flushed case
1947 * we set a zero sized HGLOBAL to clear the old marshalled data.
1949 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1956 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1957 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1960 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1962 if(!h
) return E_OUTOFMEMORY
;
1964 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1967 return CLIPBRD_E_CANT_SET
;
1972 /***********************************************************************
1973 * set_src_dataobject
1975 * Clears and sets the clipboard's src IDataObject.
1977 * To marshal the source dataobject we do something rather different from Windows.
1978 * We set a clipboard format which contains the marshalled data.
1979 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1981 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1986 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1988 if(clipbrd
->src_data
)
1990 release_marshal_data(clipbrd
->marshal_data
);
1992 IDataObject_Release(clipbrd
->src_data
);
1993 clipbrd
->src_data
= NULL
;
1994 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1995 clipbrd
->cached_enum
= NULL
;
2002 IDataObject_AddRef(data
);
2003 clipbrd
->src_data
= data
;
2005 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
2006 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
2007 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
2008 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
2009 if(FAILED(hr
)) return hr
;
2010 hr
= set_clipboard_formats(clipbrd
, data
);
2015 /***********************************************************************
2018 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
2020 ole_clipbrd
*clipbrd
;
2022 get_ole_clipbrd(&clipbrd
);
2026 case WM_RENDERFORMAT
:
2029 ole_priv_data_entry
*entry
;
2031 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
2032 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2035 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2040 case WM_RENDERALLFORMATS
:
2043 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
2045 TRACE("(): WM_RENDERALLFORMATS\n");
2047 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2049 if(entries
[i
].first_use
)
2050 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2055 case WM_DESTROYCLIPBOARD
:
2057 TRACE("(): WM_DESTROYCLIPBOARD\n");
2059 set_src_dataobject(clipbrd
, NULL
);
2064 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2071 /***********************************************************************
2072 * create_clipbrd_window
2074 static HWND
create_clipbrd_window(void)
2077 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2078 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2079 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2081 class.cbSize
= sizeof(class);
2083 class.lpfnWndProc
= clipbrd_wndproc
;
2084 class.cbClsExtra
= 0;
2085 class.cbWndExtra
= 0;
2086 class.hInstance
= hinst
;
2089 class.hbrBackground
= 0;
2090 class.lpszMenuName
= NULL
;
2091 class.lpszClassName
= clipbrd_wndclass
;
2092 class.hIconSm
= NULL
;
2094 RegisterClassExW(&class);
2096 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2097 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2098 NULL
, NULL
, hinst
, 0);
2101 /*********************************************************************
2102 * set_dataobject_format
2104 * Windows creates a 'DataObject' clipboard format that contains the
2105 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2107 static HRESULT
set_dataobject_format(HWND hwnd
)
2109 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2112 if(!h
) return E_OUTOFMEMORY
;
2114 data
= GlobalLock(h
);
2118 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2121 return CLIPBRD_E_CANT_SET
;
2127 /*---------------------------------------------------------------------*
2128 * Win32 OLE clipboard API
2129 *---------------------------------------------------------------------*/
2131 /***********************************************************************
2132 * OleSetClipboard [OLE32.@]
2133 * Places a pointer to the specified data object onto the clipboard,
2134 * making the data object accessible to the OleGetClipboard function.
2138 * S_OK IDataObject pointer placed on the clipboard
2139 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2140 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2141 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2142 * CLIPBRD_E_CANT_SET SetClipboard failed
2145 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2148 ole_clipbrd
*clipbrd
;
2151 TRACE("(%p)\n", data
);
2153 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2155 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2157 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2159 if ( !EmptyClipboard() )
2161 hr
= CLIPBRD_E_CANT_EMPTY
;
2165 hr
= set_src_dataobject(clipbrd
, data
);
2166 if(FAILED(hr
)) goto end
;
2170 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2171 if(FAILED(hr
)) goto end
;
2172 hr
= set_dataobject_format(wnd
);
2177 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2181 expose_marshalled_dataobject(clipbrd
, NULL
);
2182 set_src_dataobject(clipbrd
, NULL
);
2189 /***********************************************************************
2190 * OleGetClipboard [OLE32.@]
2191 * Returns a pointer to our internal IDataObject which represents the conceptual
2192 * state of the Windows clipboard. If the current clipboard already contains
2193 * an IDataObject, our internal IDataObject will delegate to this object.
2195 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2198 ole_clipbrd
*clipbrd
;
2201 TRACE("(%p)\n", obj
);
2203 if(!obj
) return E_INVALIDARG
;
2206 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2208 seq_no
= GetClipboardSequenceNumber();
2209 EnterCriticalSection(&latest_snapshot_cs
);
2210 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2211 clipbrd
->latest_snapshot
= NULL
;
2213 if(!clipbrd
->latest_snapshot
)
2215 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2216 if(!clipbrd
->latest_snapshot
)
2218 LeaveCriticalSection(&latest_snapshot_cs
);
2219 return E_OUTOFMEMORY
;
2223 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2224 IDataObject_AddRef(*obj
);
2225 LeaveCriticalSection(&latest_snapshot_cs
);
2230 /******************************************************************************
2231 * OleFlushClipboard [OLE32.@]
2232 * Renders the data from the source IDataObject into the windows clipboard
2234 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2235 * by copying the storage into global memory. Subsequently the default
2236 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2237 * back to TYMED_IStorage.
2239 HRESULT WINAPI
OleFlushClipboard(void)
2242 ole_clipbrd
*clipbrd
;
2247 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2249 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2252 * Already flushed or no source DataObject? Nothing to do.
2254 if (!clipbrd
->src_data
) return S_OK
;
2256 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2258 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2260 hr
= set_dataobject_format(NULL
);
2262 expose_marshalled_dataobject(clipbrd
, NULL
);
2263 set_src_dataobject(clipbrd
, NULL
);
2265 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2271 /***********************************************************************
2272 * OleIsCurrentClipboard [OLE32.@]
2274 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2277 ole_clipbrd
*clipbrd
;
2280 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2282 if (data
== NULL
) return S_FALSE
;
2284 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;