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.
61 #define WIN32_NO_STATUS
70 #define NONAMELESSUNION
71 #define NONAMELESSSTRUCT
76 //#include "winuser.h"
77 //#include "winerror.h"
80 #include <wine/debug.h>
83 #include "storage32.h"
85 #include "compobj_private.h"
87 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
89 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
91 /* Structure of 'Ole Private Data' clipboard format */
95 DWORD first_use
; /* Has this cf been added to the list already */
97 } ole_priv_data_entry
;
102 DWORD size
; /* in bytes of the entire structure */
104 DWORD count
; /* no. of format entries */
106 ole_priv_data_entry entries
[1]; /* array of size count */
107 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
110 /*****************************************************************************
113 * Returns a ptr to a target device at a given offset from the
114 * start of the ole_priv_data.
116 * Used when unpacking ole private data from the clipboard.
118 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
120 if(off
== 0) return NULL
;
121 return (DVTARGETDEVICE
*)((char*)data
+ off
);
124 /*****************************************************************************
127 * Get the offset from the start of the ole_priv_data of the idx'th
130 * Used when packing ole private data to the clipboard.
132 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
134 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
135 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
138 /****************************************************************************
139 * Consumer snapshot. Represents the state of the ole clipboard
140 * returned by OleGetClipboard().
142 typedef struct snapshot
144 IDataObject IDataObject_iface
;
147 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
149 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
152 /****************************************************************************
155 typedef struct ole_clipbrd
157 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
159 HWND window
; /* Hidden clipboard window */
160 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
161 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
162 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
165 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
167 return CONTAINING_RECORD(iface
, snapshot
, IDataObject_iface
);
170 typedef struct PresentationDataHeader
173 DWORD dwObjectExtentX
;
174 DWORD dwObjectExtentY
;
176 } PresentationDataHeader
;
179 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
181 static ole_clipbrd
* theOleClipboard
;
183 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
185 struct oletls
*info
= COM_CurrentInfo();
189 return CO_E_NOTINITIALIZED
;
190 *clipbrd
= theOleClipboard
;
196 * Name of our registered OLE clipboard window class
198 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
200 static const WCHAR wine_marshal_dataobject
[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0};
202 UINT ownerlink_clipboard_format
= 0;
203 UINT filename_clipboard_format
= 0;
204 UINT filenameW_clipboard_format
= 0;
205 UINT dataobject_clipboard_format
= 0;
206 UINT embedded_object_clipboard_format
= 0;
207 UINT embed_source_clipboard_format
= 0;
208 UINT custom_link_source_clipboard_format
= 0;
209 UINT link_source_clipboard_format
= 0;
210 UINT object_descriptor_clipboard_format
= 0;
211 UINT link_source_descriptor_clipboard_format
= 0;
212 UINT ole_private_data_clipboard_format
= 0;
214 static UINT wine_marshal_clipboard_format
;
216 static inline char *dump_fmtetc(FORMATETC
*fmt
)
218 static char buf
[100];
220 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
221 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
225 /*---------------------------------------------------------------------*
226 * Implementation of the internal IEnumFORMATETC interface returned by
227 * the OLE clipboard's IDataObject.
228 *---------------------------------------------------------------------*/
230 typedef struct enum_fmtetc
232 IEnumFORMATETC IEnumFORMATETC_iface
;
235 UINT pos
; /* current enumerator position */
239 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
241 return CONTAINING_RECORD(iface
, enum_fmtetc
, IEnumFORMATETC_iface
);
244 /************************************************************************
245 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
247 * See Windows documentation for more details on IUnknown methods.
249 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
250 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
252 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
254 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
258 if(IsEqualIID(riid
, &IID_IUnknown
) ||
259 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
266 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
267 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
271 TRACE("-- Interface: E_NOINTERFACE\n");
272 return E_NOINTERFACE
;
275 /************************************************************************
276 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
279 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
281 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
282 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
284 return InterlockedIncrement(&This
->ref
);
287 /************************************************************************
288 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
290 * See Windows documentation for more details on IUnknown methods.
292 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
294 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
297 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
299 ref
= InterlockedDecrement(&This
->ref
);
302 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
303 HeapFree(GetProcessHeap(), 0, This
->data
);
304 HeapFree(GetProcessHeap(), 0, This
);
309 /************************************************************************
310 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
312 * Standard enumerator members for IEnumFORMATETC
314 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
315 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
317 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
319 HRESULT hres
= S_FALSE
;
321 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
323 if (This
->pos
< This
->data
->count
)
325 cfetch
= This
->data
->count
- This
->pos
;
332 for(i
= 0; i
< cfetch
; i
++)
334 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
337 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
338 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
339 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
340 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
351 *pceltFethed
= cfetch
;
357 /************************************************************************
358 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
360 * Standard enumerator members for IEnumFORMATETC
362 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
364 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
365 TRACE("(%p)->(num=%u)\n", This
, celt
);
368 if (This
->pos
> This
->data
->count
)
370 This
->pos
= This
->data
->count
;
376 /************************************************************************
377 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
379 * Standard enumerator members for IEnumFORMATETC
381 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
383 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
384 TRACE("(%p)->()\n", This
);
390 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
392 /************************************************************************
393 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
395 * Standard enumerator members for IEnumFORMATETC
397 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
398 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
400 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
401 ole_priv_data
*new_data
;
404 TRACE("(%p)->(%p)\n", This
, obj
);
406 if ( !obj
) return E_INVALIDARG
;
409 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
410 if(!new_data
) return E_OUTOFMEMORY
;
411 memcpy(new_data
, This
->data
, This
->data
->size
);
413 /* Fixup any target device ptrs */
414 for(i
= 0; i
< This
->data
->count
; i
++)
415 new_data
->entries
[i
].fmtetc
.ptd
=
416 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
418 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
421 static const IEnumFORMATETCVtbl efvt
=
423 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
424 OLEClipbrd_IEnumFORMATETC_AddRef
,
425 OLEClipbrd_IEnumFORMATETC_Release
,
426 OLEClipbrd_IEnumFORMATETC_Next
,
427 OLEClipbrd_IEnumFORMATETC_Skip
,
428 OLEClipbrd_IEnumFORMATETC_Reset
,
429 OLEClipbrd_IEnumFORMATETC_Clone
432 /************************************************************************
433 * enum_fmtetc_construct
435 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
437 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
442 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
443 if (!ef
) return E_OUTOFMEMORY
;
446 ef
->IEnumFORMATETC_iface
.lpVtbl
= &efvt
;
450 TRACE("(%p)->()\n", ef
);
451 *obj
= &ef
->IEnumFORMATETC_iface
;
455 /***********************************************************************
458 * Helper method to duplicate an HGLOBAL chunk of memory
460 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
462 void *src_ptr
, *dst_ptr
;
466 if ( !src
) return S_FALSE
;
468 size
= GlobalSize(src
);
470 *dst
= GlobalAlloc( flags
, size
);
471 if ( !*dst
) return E_OUTOFMEMORY
;
473 src_ptr
= GlobalLock(src
);
474 dst_ptr
= GlobalLock(*dst
);
476 memcpy(dst_ptr
, src_ptr
, size
);
484 /***********************************************************************
487 * Helper function to duplicate a handle to a METAFILEPICT, and the
488 * contained HMETAFILE.
490 static HRESULT
dup_metafilepict(HGLOBAL src
, HGLOBAL
*pdest
)
494 METAFILEPICT
*dest_ptr
;
498 /* Copy the METAFILEPICT structure. */
499 hr
= dup_global_mem(src
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &dest
);
500 if (FAILED(hr
)) return hr
;
502 dest_ptr
= GlobalLock(dest
);
503 if (!dest_ptr
) return E_FAIL
;
505 /* Give the new METAFILEPICT a separate HMETAFILE. */
506 dest_ptr
->hMF
= CopyMetaFileW(dest_ptr
->hMF
, NULL
);
521 /***********************************************************************
524 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
525 * free the contained HMETAFILE.
527 static void free_metafilepict(HGLOBAL src
)
529 METAFILEPICT
*src_ptr
;
531 src_ptr
= GlobalLock(src
);
534 DeleteMetaFile(src_ptr
->hMF
);
540 /***********************************************************************
543 * Helper function to duplicate an HBITMAP.
545 static HRESULT
dup_bitmap(HBITMAP src
, HBITMAP
*pdest
)
548 HGDIOBJ orig_src_bitmap
;
552 src_dc
= CreateCompatibleDC(NULL
);
553 orig_src_bitmap
= SelectObject(src_dc
, src
);
554 GetObjectW(src
, sizeof bm
, &bm
);
555 dest
= CreateCompatibleBitmap(src_dc
, bm
.bmWidth
, bm
.bmHeight
);
558 HDC dest_dc
= CreateCompatibleDC(NULL
);
559 HGDIOBJ orig_dest_bitmap
= SelectObject(dest_dc
, dest
);
560 BitBlt(dest_dc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, src_dc
, 0, 0, SRCCOPY
);
561 SelectObject(dest_dc
, orig_dest_bitmap
);
564 SelectObject(src_dc
, orig_src_bitmap
);
567 return dest
? S_OK
: E_FAIL
;
570 /************************************************************
571 * render_embed_source_hack
573 * This is clearly a hack and has no place in the clipboard code.
576 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
579 HGLOBAL hStorage
= 0;
581 ILockBytes
*ptrILockBytes
;
583 memset(&std
, 0, sizeof(STGMEDIUM
));
584 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
586 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
587 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
588 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
589 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
590 ILockBytes_Release(ptrILockBytes
);
592 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
594 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
595 GlobalFree(hStorage
);
599 if (1) /* check whether the presentation data is already -not- present */
603 METAFILEPICT
*mfp
= 0;
605 fmt2
.cfFormat
= CF_METAFILEPICT
;
607 fmt2
.dwAspect
= DVASPECT_CONTENT
;
609 fmt2
.tymed
= TYMED_MFPICT
;
611 memset(&std2
, 0, sizeof(STGMEDIUM
));
612 std2
.tymed
= TYMED_MFPICT
;
614 /* Get the metafile picture out of it */
616 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
618 mfp
= GlobalLock(std2
.u
.hGlobal
);
623 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
624 IStream
*pStream
= 0;
626 PresentationDataHeader pdh
;
630 CHAR strOleTypeName
[51];
631 BYTE OlePresStreamHeader
[] =
633 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
634 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
635 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
636 0x00, 0x00, 0x00, 0x00
639 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
641 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
642 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
644 pdh
.dwObjectExtentX
= mfp
->xExt
;
645 pdh
.dwObjectExtentY
= mfp
->yExt
;
648 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
650 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
652 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
653 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
655 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
657 IStream_Release(pStream
);
659 HeapFree(GetProcessHeap(), 0, mfBits
);
661 GlobalUnlock(std2
.u
.hGlobal
);
662 ReleaseStgMedium(&std2
);
664 ReadClassStg(std
.u
.pstg
, &clsID
);
665 ProgIDFromCLSID(&clsID
, &strProgID
);
667 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
668 STORAGE_CreateOleStream(std
.u
.pstg
, 0);
669 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
670 CoTaskMemFree(strProgID
);
674 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
676 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
677 GlobalFree(hStorage
);
678 hr
= CLIPBRD_E_CANT_SET
;
681 ReleaseStgMedium(&std
);
685 /************************************************************************
686 * find_format_in_list
688 * Returns the first entry that matches the provided clipboard format.
690 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
693 for(i
= 0; i
< num
; i
++)
694 if(entries
[i
].fmtetc
.cfFormat
== cf
)
700 /***************************************************************************
701 * get_data_from_storage
703 * Returns storage data in an HGLOBAL.
705 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
716 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
717 if(!h
) return E_OUTOFMEMORY
;
719 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
722 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
723 ILockBytes_Release(lbs
);
732 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
734 med
.pUnkForRelease
= NULL
;
736 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
740 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
741 if(FAILED(hr
)) goto end
;
743 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
744 ReleaseStgMedium(&med
);
745 if(FAILED(hr
)) goto end
;
750 IStorage_Release(stg
);
751 if(FAILED(hr
)) GlobalFree(h
);
755 /***************************************************************************
756 * get_data_from_stream
758 * Returns stream data in an HGLOBAL.
760 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
770 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
771 if(!h
) return E_OUTOFMEMORY
;
773 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
774 if(FAILED(hr
)) goto error
;
777 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
779 med
.pUnkForRelease
= NULL
;
781 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
788 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
789 if(FAILED(hr
)) goto error
;
792 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
793 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
794 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
795 ReleaseStgMedium(&med
);
796 if(FAILED(hr
)) goto error
;
799 IStream_Release(stm
);
803 if(stm
) IStream_Release(stm
);
808 /***************************************************************************
809 * get_data_from_global
811 * Returns global data in an HGLOBAL.
813 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
823 mem_fmt
.tymed
= TYMED_HGLOBAL
;
825 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
826 if(FAILED(hr
)) return hr
;
828 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
830 if(SUCCEEDED(hr
)) *mem
= h
;
832 ReleaseStgMedium(&med
);
837 /***************************************************************************
838 * get_data_from_enhmetafile
840 static HRESULT
get_data_from_enhmetafile(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
850 mem_fmt
.tymed
= TYMED_ENHMF
;
852 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
853 if(FAILED(hr
)) return hr
;
855 copy
= CopyEnhMetaFileW(med
.u
.hEnhMetaFile
, NULL
);
856 if(copy
) *mem
= (HGLOBAL
)copy
;
859 ReleaseStgMedium(&med
);
864 /***************************************************************************
865 * get_data_from_metafilepict
867 static HRESULT
get_data_from_metafilepict(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
877 mem_fmt
.tymed
= TYMED_MFPICT
;
879 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
880 if(FAILED(hr
)) return hr
;
882 hr
= dup_metafilepict(med
.u
.hMetaFilePict
, ©
);
884 if(SUCCEEDED(hr
)) *mem
= copy
;
886 ReleaseStgMedium(&med
);
891 /***************************************************************************
892 * get_data_from_bitmap
894 * Returns bitmap in an HBITMAP.
896 static HRESULT
get_data_from_bitmap(IDataObject
*data
, FORMATETC
*fmt
, HBITMAP
*hbm
)
906 mem_fmt
.tymed
= TYMED_GDI
;
908 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
909 if(FAILED(hr
)) return hr
;
911 hr
= dup_bitmap(med
.u
.hBitmap
, ©
);
913 if(SUCCEEDED(hr
)) *hbm
= copy
;
915 ReleaseStgMedium(&med
);
920 /***********************************************************************
923 * Render the clipboard data. Note that this call will delegate to the
924 * source data object.
926 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
928 HANDLE clip_data
= NULL
; /* HGLOBAL unless otherwise specified */
931 /* Embed source hack */
932 if(fmt
->cfFormat
== embed_source_clipboard_format
)
934 return render_embed_source_hack(data
, fmt
);
937 if(fmt
->tymed
& TYMED_ISTORAGE
)
939 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
941 else if(fmt
->tymed
& TYMED_ISTREAM
)
943 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
945 else if(fmt
->tymed
& TYMED_HGLOBAL
)
947 hr
= get_data_from_global(data
, fmt
, &clip_data
);
949 else if(fmt
->tymed
& TYMED_ENHMF
)
951 hr
= get_data_from_enhmetafile(data
, fmt
, &clip_data
);
953 else if(fmt
->tymed
& TYMED_MFPICT
)
955 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
956 hr
= get_data_from_metafilepict(data
, fmt
, &clip_data
);
958 else if(fmt
->tymed
& TYMED_GDI
)
960 /* Returns HBITMAP not HGLOBAL */
961 hr
= get_data_from_bitmap(data
, fmt
, (HBITMAP
*)&clip_data
);
965 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
971 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
973 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
974 if(fmt
->tymed
& TYMED_MFPICT
)
975 free_metafilepict(clip_data
);
976 else if(fmt
->tymed
& TYMED_GDI
)
977 DeleteObject(clip_data
);
979 GlobalFree(clip_data
);
980 hr
= CLIPBRD_E_CANT_SET
;
987 /*---------------------------------------------------------------------*
988 * Implementation of the internal IDataObject interface exposed by
990 *---------------------------------------------------------------------*/
993 /************************************************************************
994 * snapshot_QueryInterface
996 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
997 REFIID riid
, void **ppvObject
)
999 snapshot
*This
= impl_from_IDataObject(iface
);
1000 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1002 if ( (This
==0) || (ppvObject
==0) )
1003 return E_INVALIDARG
;
1007 if (IsEqualIID(&IID_IUnknown
, riid
) ||
1008 IsEqualIID(&IID_IDataObject
, riid
))
1014 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1015 return E_NOINTERFACE
;
1018 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1023 /************************************************************************
1026 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
1028 snapshot
*This
= impl_from_IDataObject(iface
);
1030 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1032 return InterlockedIncrement(&This
->ref
);
1035 /************************************************************************
1038 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
1040 snapshot
*This
= impl_from_IDataObject(iface
);
1043 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
1045 ref
= InterlockedDecrement(&This
->ref
);
1049 ole_clipbrd
*clipbrd
;
1050 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
1052 if(This
->data
) IDataObject_Release(This
->data
);
1054 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
1055 clipbrd
->latest_snapshot
= NULL
;
1056 HeapFree(GetProcessHeap(), 0, This
);
1062 /************************************************************
1063 * get_current_ole_clip_window
1065 * Return the window that owns the ole clipboard.
1067 * If the clipboard is flushed or not owned by ole this will
1070 static HWND
get_current_ole_clip_window(void)
1075 h
= GetClipboardData(dataobject_clipboard_format
);
1077 ptr
= GlobalLock(h
);
1078 if(!ptr
) return NULL
;
1084 /************************************************************
1085 * get_current_dataobject
1087 * Return an unmarshalled IDataObject if there is a current
1088 * (ie non-flushed) object on the ole clipboard.
1090 static HRESULT
get_current_dataobject(IDataObject
**data
)
1092 HRESULT hr
= S_FALSE
;
1093 HWND wnd
= get_current_ole_clip_window();
1100 if(!wnd
) return S_FALSE
;
1102 h
= GetClipboardData(wine_marshal_clipboard_format
);
1103 if(!h
) return S_FALSE
;
1104 if(GlobalSize(h
) == 0) return S_FALSE
;
1105 ptr
= GlobalLock(h
);
1106 if(!ptr
) return S_FALSE
;
1108 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
1109 if(FAILED(hr
)) goto end
;
1111 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
1115 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1116 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
1118 IStream_Release(stm
);
1125 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
1127 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1133 case CF_UNICODETEXT
:
1134 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
1135 case CF_ENHMETAFILE
:
1137 case CF_METAFILEPICT
:
1138 return TYMED_MFPICT
;
1140 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
1145 /***********************************************************
1148 * Returns a copy of the Ole Private Data
1150 static HRESULT
get_priv_data(ole_priv_data
**data
)
1154 ole_priv_data
*ret
= NULL
;
1158 handle
= GetClipboardData( ole_private_data_clipboard_format
);
1161 ole_priv_data
*src
= GlobalLock(handle
);
1166 /* FIXME: sanity check on size */
1167 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
1170 GlobalUnlock(handle
);
1171 return E_OUTOFMEMORY
;
1173 memcpy(ret
, src
, src
->size
);
1174 GlobalUnlock(handle
);
1176 /* Fixup any target device offsets to ptrs */
1177 for(i
= 0; i
< ret
->count
; i
++)
1178 ret
->entries
[i
].fmtetc
.ptd
=
1179 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
1183 if(!ret
) /* Non-ole data */
1186 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
1188 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
1191 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1192 TRACE("cf %04x %s\n", cf
, buf
);
1194 TRACE("count %d\n", count
);
1195 size
+= count
* sizeof(ret
->entries
[0]);
1197 /* There are holes in fmtetc so zero init */
1198 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1199 if(!ret
) return E_OUTOFMEMORY
;
1203 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1205 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1206 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1207 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1208 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1209 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1210 ret
->entries
[idx
].first_use
= 1;
1218 /************************************************************************
1219 * get_stgmed_for_global
1221 * Returns a stg medium with a copy of the global handle
1223 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1227 med
->pUnkForRelease
= NULL
;
1228 med
->tymed
= TYMED_NULL
;
1230 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1232 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1237 /************************************************************************
1238 * get_stgmed_for_stream
1240 * Returns a stg medium with a stream based on the handle
1242 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1247 med
->pUnkForRelease
= NULL
;
1248 med
->tymed
= TYMED_NULL
;
1250 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1251 if(FAILED(hr
)) return hr
;
1253 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1260 med
->tymed
= TYMED_ISTREAM
;
1264 /************************************************************************
1265 * get_stgmed_for_storage
1267 * Returns a stg medium with a storage based on the handle
1269 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1275 med
->pUnkForRelease
= NULL
;
1276 med
->tymed
= TYMED_NULL
;
1278 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1279 if(FAILED(hr
)) return hr
;
1281 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1288 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1289 ILockBytes_Release(lbs
);
1296 med
->tymed
= TYMED_ISTORAGE
;
1300 /************************************************************************
1301 * get_stgmed_for_emf
1303 * Returns a stg medium with an enhanced metafile based on the handle
1305 static HRESULT
get_stgmed_for_emf(HENHMETAFILE hemf
, STGMEDIUM
*med
)
1307 med
->pUnkForRelease
= NULL
;
1308 med
->tymed
= TYMED_NULL
;
1310 med
->u
.hEnhMetaFile
= CopyEnhMetaFileW(hemf
, NULL
);
1311 if(!med
->u
.hEnhMetaFile
) return E_OUTOFMEMORY
;
1312 med
->tymed
= TYMED_ENHMF
;
1316 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1318 const WCHAR
*str1
, *str2
;
1320 if(off1
== 0 && off2
== 0) return TRUE
;
1321 if(off1
== 0 || off2
== 0) return FALSE
;
1323 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1324 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1326 return !lstrcmpW(str1
, str2
);
1329 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1331 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1332 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1334 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1336 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1338 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1341 /* FIXME check devmode? */
1346 /************************************************************************
1349 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1352 snapshot
*This
= impl_from_IDataObject(iface
);
1355 ole_priv_data
*enum_data
= NULL
;
1356 ole_priv_data_entry
*entry
;
1359 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1361 if ( !fmt
|| !med
) return E_INVALIDARG
;
1363 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1366 hr
= get_current_dataobject(&This
->data
);
1370 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1375 h
= GetClipboardData(fmt
->cfFormat
);
1378 hr
= DV_E_FORMATETC
;
1382 hr
= get_priv_data(&enum_data
);
1383 if(FAILED(hr
)) goto end
;
1385 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1388 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1390 hr
= DV_E_FORMATETC
;
1393 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1394 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1396 else /* non-Ole format */
1397 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1399 if(mask
& TYMED_ISTORAGE
)
1400 hr
= get_stgmed_for_storage(h
, med
);
1401 else if(mask
& TYMED_HGLOBAL
)
1402 hr
= get_stgmed_for_global(h
, med
);
1403 else if(mask
& TYMED_ISTREAM
)
1404 hr
= get_stgmed_for_stream(h
, med
);
1405 else if(mask
& TYMED_ENHMF
)
1406 hr
= get_stgmed_for_emf((HENHMETAFILE
)h
, med
);
1409 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1415 HeapFree(GetProcessHeap(), 0, enum_data
);
1416 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1420 /************************************************************************
1421 * snapshot_GetDataHere
1423 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1426 snapshot
*This
= impl_from_IDataObject(iface
);
1429 ole_priv_data
*enum_data
= NULL
;
1430 ole_priv_data_entry
*entry
;
1433 if ( !fmt
|| !med
) return E_INVALIDARG
;
1435 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1437 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1440 hr
= get_current_dataobject(&This
->data
);
1444 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1452 h
= GetClipboardData(fmt
->cfFormat
);
1455 hr
= DV_E_FORMATETC
;
1459 hr
= get_priv_data(&enum_data
);
1460 if(FAILED(hr
)) goto end
;
1462 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1465 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1467 hr
= DV_E_FORMATETC
;
1470 supported
= entry
->fmtetc
.tymed
;
1472 else /* non-Ole format */
1473 supported
= TYMED_HGLOBAL
;
1479 DWORD src_size
= GlobalSize(h
);
1480 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1482 if(dst_size
>= src_size
)
1484 void *src
= GlobalLock(h
);
1485 void *dst
= GlobalLock(med
->u
.hGlobal
);
1487 memcpy(dst
, src
, src_size
);
1488 GlobalUnlock(med
->u
.hGlobal
);
1496 DWORD src_size
= GlobalSize(h
);
1497 void *src
= GlobalLock(h
);
1498 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1502 case TYMED_ISTORAGE
:
1505 if(!(supported
& TYMED_ISTORAGE
))
1510 hr
= get_stgmed_for_storage(h
, ©
);
1513 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1514 ReleaseStgMedium(©
);
1519 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1525 HeapFree(GetProcessHeap(), 0, enum_data
);
1526 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1530 /************************************************************************
1531 * snapshot_QueryGetData
1533 * The OLE Clipboard's implementation of this method delegates to
1534 * a data source if there is one or wraps around the windows clipboard
1535 * function IsClipboardFormatAvailable() otherwise.
1538 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1540 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1542 if (!fmt
) return E_INVALIDARG
;
1544 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1546 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1548 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1551 /************************************************************************
1552 * snapshot_GetCanonicalFormatEtc
1554 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1557 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1559 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1562 return DATA_S_SAMEFORMATETC
;
1565 /************************************************************************
1568 * The OLE Clipboard does not implement this method
1570 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1571 STGMEDIUM
*med
, BOOL release
)
1573 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1577 /************************************************************************
1578 * snapshot_EnumFormatEtc
1581 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1582 IEnumFORMATETC
**enum_fmt
)
1585 ole_priv_data
*data
= NULL
;
1587 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1591 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1592 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1594 hr
= get_priv_data(&data
);
1596 if(FAILED(hr
)) goto end
;
1598 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1601 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1605 /************************************************************************
1608 * The OLE Clipboard does not implement this method
1610 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1611 DWORD flags
, IAdviseSink
*sink
,
1614 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1618 /************************************************************************
1619 * snapshot_DUnadvise
1621 * The OLE Clipboard does not implement this method
1623 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1625 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1629 /************************************************************************
1630 * snapshot_EnumDAdvise
1632 * The OLE Clipboard does not implement this method
1634 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1635 IEnumSTATDATA
** enum_advise
)
1637 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1641 static const IDataObjectVtbl snapshot_vtable
=
1643 snapshot_QueryInterface
,
1647 snapshot_GetDataHere
,
1648 snapshot_QueryGetData
,
1649 snapshot_GetCanonicalFormatEtc
,
1651 snapshot_EnumFormatEtc
,
1654 snapshot_EnumDAdvise
1657 /*---------------------------------------------------------------------*
1658 * Internal implementation methods for the OLE clipboard
1659 *---------------------------------------------------------------------*/
1661 static snapshot
*snapshot_construct(DWORD seq_no
)
1665 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1666 if (!This
) return NULL
;
1668 This
->IDataObject_iface
.lpVtbl
= &snapshot_vtable
;
1670 This
->seq_no
= seq_no
;
1676 /*********************************************************
1677 * register_clipboard_formats
1679 static void register_clipboard_formats(void)
1681 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1682 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1683 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1684 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1685 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1686 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1687 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1688 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1689 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1690 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1691 'D','e','s','c','r','i','p','t','o','r',0};
1692 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1694 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1695 'D','a','t','a','O','b','j','e','c','t',0};
1697 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1698 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1699 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1700 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1701 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1702 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1703 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1704 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1705 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1706 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1707 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1709 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1712 /***********************************************************************
1713 * OLEClipbrd_Initialize()
1714 * Initializes the OLE clipboard.
1716 void OLEClipbrd_Initialize(void)
1718 register_clipboard_formats();
1720 if ( !theOleClipboard
)
1722 ole_clipbrd
* clipbrd
;
1727 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1728 if (!clipbrd
) return;
1730 clipbrd
->latest_snapshot
= NULL
;
1731 clipbrd
->window
= NULL
;
1732 clipbrd
->src_data
= NULL
;
1733 clipbrd
->cached_enum
= NULL
;
1735 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1738 HeapFree(GetProcessHeap(), 0, clipbrd
);
1742 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1745 HeapFree(GetProcessHeap(), 0, clipbrd
);
1749 theOleClipboard
= clipbrd
;
1753 /***********************************************************************
1754 * OLEClipbrd_UnInitialize()
1755 * Un-Initializes the OLE clipboard
1757 void OLEClipbrd_UnInitialize(void)
1759 ole_clipbrd
*clipbrd
= theOleClipboard
;
1765 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1766 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1768 if ( clipbrd
->window
)
1770 DestroyWindow(clipbrd
->window
);
1771 UnregisterClassW( clipbrd_wndclass
, hinst
);
1774 IStream_Release(clipbrd
->marshal_data
);
1775 if (clipbrd
->src_data
) IDataObject_Release(clipbrd
->src_data
);
1776 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1777 HeapFree(GetProcessHeap(), 0, clipbrd
);
1778 theOleClipboard
= NULL
;
1782 /*********************************************************************
1783 * set_clipboard_formats
1785 * Enumerate all formats supported by the source and make
1786 * those formats available using delayed rendering using SetClipboardData.
1787 * Cache the enumeration list and make that list visibile as the
1788 * 'Ole Private Data' format on the clipboard.
1791 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1795 IEnumFORMATETC
*enum_fmt
;
1796 HGLOBAL priv_data_handle
;
1797 DWORD_PTR target_offset
;
1798 ole_priv_data
*priv_data
;
1799 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1801 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1802 if(FAILED(hr
)) return hr
;
1804 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1807 needed
+= sizeof(priv_data
->entries
[0]);
1810 needed
+= fmt
.ptd
->tdSize
;
1811 CoTaskMemFree(fmt
.ptd
);
1815 /* Windows pads the list with two empty ole_priv_data_entries, one
1816 * after the entries array and one after the target device data.
1817 * Allocating with zero init to zero these pads. */
1819 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1820 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1821 priv_data
= GlobalLock(priv_data_handle
);
1823 priv_data
->unk1
= 0;
1824 priv_data
->size
= needed
;
1825 priv_data
->unk2
= 1;
1826 priv_data
->count
= count
;
1827 priv_data
->unk3
[0] = 0;
1828 priv_data
->unk3
[1] = 0;
1830 IEnumFORMATETC_Reset(enum_fmt
);
1833 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1835 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1837 TRACE("%s\n", dump_fmtetc(&fmt
));
1839 priv_data
->entries
[idx
].fmtetc
= fmt
;
1842 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1843 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1844 target_offset
+= fmt
.ptd
->tdSize
;
1845 CoTaskMemFree(fmt
.ptd
);
1848 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1849 priv_data
->entries
[idx
].unk
[0] = 0;
1850 priv_data
->entries
[idx
].unk
[1] = 0;
1852 if (priv_data
->entries
[idx
].first_use
)
1853 SetClipboardData(fmt
.cfFormat
, NULL
);
1858 IEnumFORMATETC_Release(enum_fmt
);
1860 /* Cache the list and fixup any target device offsets to ptrs */
1861 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1862 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1863 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1864 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1865 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1867 GlobalUnlock(priv_data_handle
);
1868 if(!SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
))
1870 GlobalFree(priv_data_handle
);
1871 return CLIPBRD_E_CANT_SET
;
1877 static HWND
create_clipbrd_window(void);
1879 /***********************************************************************
1880 * get_clipbrd_window
1882 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1884 if ( !clipbrd
->window
)
1885 clipbrd
->window
= create_clipbrd_window();
1887 *wnd
= clipbrd
->window
;
1888 return *wnd
? S_OK
: E_FAIL
;
1892 /**********************************************************************
1893 * release_marshal_data
1895 * Releases the data and sets the stream back to zero size.
1897 static inline void release_marshal_data(IStream
*stm
)
1900 ULARGE_INTEGER size
;
1901 pos
.QuadPart
= size
.QuadPart
= 0;
1903 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1904 CoReleaseMarshalData(stm
);
1905 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1906 IStream_SetSize(stm
, size
);
1909 /***********************************************************************
1910 * expose_marshalled_dataobject
1912 * Sets the marshalled dataobject to the clipboard. In the flushed case
1913 * we set a zero sized HGLOBAL to clear the old marshalled data.
1915 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1922 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1923 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1926 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1928 if(!h
) return E_OUTOFMEMORY
;
1930 if(!SetClipboardData(wine_marshal_clipboard_format
, h
))
1933 return CLIPBRD_E_CANT_SET
;
1938 /***********************************************************************
1939 * set_src_dataobject
1941 * Clears and sets the clipboard's src IDataObject.
1943 * To marshal the source dataobject we do something rather different from Windows.
1944 * We set a clipboard format which contains the marshalled data.
1945 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1947 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1952 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1954 if(clipbrd
->src_data
)
1956 release_marshal_data(clipbrd
->marshal_data
);
1958 IDataObject_Release(clipbrd
->src_data
);
1959 clipbrd
->src_data
= NULL
;
1960 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1961 clipbrd
->cached_enum
= NULL
;
1968 IDataObject_AddRef(data
);
1969 clipbrd
->src_data
= data
;
1971 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1972 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1973 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1974 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1975 if(FAILED(hr
)) return hr
;
1976 hr
= set_clipboard_formats(clipbrd
, data
);
1981 /***********************************************************************
1984 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1986 ole_clipbrd
*clipbrd
;
1988 get_ole_clipbrd(&clipbrd
);
1992 case WM_RENDERFORMAT
:
1995 ole_priv_data_entry
*entry
;
1997 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
1998 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
2001 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
2006 case WM_RENDERALLFORMATS
:
2009 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
2011 TRACE("(): WM_RENDERALLFORMATS\n");
2013 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
2015 if(entries
[i
].first_use
)
2016 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
2021 case WM_DESTROYCLIPBOARD
:
2023 TRACE("(): WM_DESTROYCLIPBOARD\n");
2025 set_src_dataobject(clipbrd
, NULL
);
2030 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
2037 /***********************************************************************
2038 * create_clipbrd_window
2040 static HWND
create_clipbrd_window(void)
2043 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
2044 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2045 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
2047 class.cbSize
= sizeof(class);
2049 class.lpfnWndProc
= clipbrd_wndproc
;
2050 class.cbClsExtra
= 0;
2051 class.cbWndExtra
= 0;
2052 class.hInstance
= hinst
;
2055 class.hbrBackground
= 0;
2056 class.lpszMenuName
= NULL
;
2057 class.lpszClassName
= clipbrd_wndclass
;
2058 class.hIconSm
= NULL
;
2060 RegisterClassExW(&class);
2062 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
2063 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2064 NULL
, NULL
, hinst
, 0);
2067 /*********************************************************************
2068 * set_dataobject_format
2070 * Windows creates a 'DataObject' clipboard format that contains the
2071 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2073 static HRESULT
set_dataobject_format(HWND hwnd
)
2075 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
2078 if(!h
) return E_OUTOFMEMORY
;
2080 data
= GlobalLock(h
);
2084 if(!SetClipboardData(dataobject_clipboard_format
, h
))
2087 return CLIPBRD_E_CANT_SET
;
2093 /*---------------------------------------------------------------------*
2094 * Win32 OLE clipboard API
2095 *---------------------------------------------------------------------*/
2097 /***********************************************************************
2098 * OleSetClipboard [OLE32.@]
2099 * Places a pointer to the specified data object onto the clipboard,
2100 * making the data object accessible to the OleGetClipboard function.
2104 * S_OK IDataObject pointer placed on the clipboard
2105 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2106 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2107 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2108 * CLIPBRD_E_CANT_SET SetClipboard failed
2111 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
2114 ole_clipbrd
*clipbrd
;
2117 TRACE("(%p)\n", data
);
2119 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2121 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2123 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
2125 if ( !EmptyClipboard() )
2127 hr
= CLIPBRD_E_CANT_EMPTY
;
2131 hr
= set_src_dataobject(clipbrd
, data
);
2132 if(FAILED(hr
)) goto end
;
2136 hr
= expose_marshalled_dataobject(clipbrd
, data
);
2137 if(FAILED(hr
)) goto end
;
2138 hr
= set_dataobject_format(wnd
);
2143 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2147 expose_marshalled_dataobject(clipbrd
, NULL
);
2148 set_src_dataobject(clipbrd
, NULL
);
2155 /***********************************************************************
2156 * OleGetClipboard [OLE32.@]
2157 * Returns a pointer to our internal IDataObject which represents the conceptual
2158 * state of the Windows clipboard. If the current clipboard already contains
2159 * an IDataObject, our internal IDataObject will delegate to this object.
2161 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
2164 ole_clipbrd
*clipbrd
;
2167 TRACE("(%p)\n", obj
);
2169 if(!obj
) return E_INVALIDARG
;
2171 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2173 seq_no
= GetClipboardSequenceNumber();
2174 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
2175 clipbrd
->latest_snapshot
= NULL
;
2177 if(!clipbrd
->latest_snapshot
)
2179 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
2180 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
2183 *obj
= &clipbrd
->latest_snapshot
->IDataObject_iface
;
2184 IDataObject_AddRef(*obj
);
2189 /******************************************************************************
2190 * OleFlushClipboard [OLE32.@]
2191 * Renders the data from the source IDataObject into the windows clipboard
2193 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2194 * by copying the storage into global memory. Subsequently the default
2195 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2196 * back to TYMED_IStorage.
2198 HRESULT WINAPI
OleFlushClipboard(void)
2201 ole_clipbrd
*clipbrd
;
2206 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2208 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
2211 * Already flushed or no source DataObject? Nothing to do.
2213 if (!clipbrd
->src_data
) return S_OK
;
2215 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
2217 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
2219 hr
= set_dataobject_format(NULL
);
2221 expose_marshalled_dataobject(clipbrd
, NULL
);
2222 set_src_dataobject(clipbrd
, NULL
);
2224 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2230 /***********************************************************************
2231 * OleIsCurrentClipboard [OLE32.@]
2233 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2236 ole_clipbrd
*clipbrd
;
2239 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2241 if (data
== NULL
) return S_FALSE
;
2243 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;