2 * OLE 2 clipboard support
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * This file contains the implementation for the OLE Clipboard and its
23 * internal interfaces. The OLE clipboard interacts with an IDataObject
24 * interface via the OleSetClipboard, OleGetClipboard and
25 * OleIsCurrentClipboard API's. An internal IDataObject delegates
26 * to a client supplied IDataObject or the WIN32 clipboard API depending
27 * on whether OleSetClipboard has been invoked.
28 * Here are some operating scenarios:
30 * 1. OleSetClipboard called: In this case the internal IDataObject
31 * delegates to the client supplied IDataObject. Additionally OLE takes
32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject
33 * items are placed on the Windows clipboard. This allows non OLE aware
34 * applications to access these. A local WinProc fields WM_RENDERFORMAT
35 * and WM_RENDERALLFORMATS messages in this case.
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41 * IDataObject delegates to the source IDataObjects functionality directly,
42 * thereby bypassing the Windows clipboard.
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
47 * - Support for pasting between different processes. OLE clipboard support
48 * currently works only for in process copy and paste. Since we internally
49 * store a pointer to the source's IDataObject and delegate to that, this
50 * will fail if the IDataObject client belongs to a different process.
51 * - IDataObject::GetDataHere is not implemented
52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53 * by copying the storage into global memory. Subsequently the default
54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55 * back to TYMED_IStorage.
56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57 * clipboard in OleSetClipboard.
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
77 #include "wine/debug.h"
80 #include "storage32.h"
82 #include "compobj_private.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
86 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
88 /* Structure of 'Ole Private Data' clipboard format */
92 DWORD first_use
; /* Has this cf been added to the list already */
94 } ole_priv_data_entry
;
99 DWORD size
; /* in bytes of the entire structure */
101 DWORD count
; /* no. of format entries */
103 ole_priv_data_entry entries
[1]; /* array of size count */
104 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
107 /*****************************************************************************
110 * Returns a ptr to a target device at a given offset from the
111 * start of the ole_priv_data.
113 * Used when unpacking ole private data from the clipboard.
115 static inline DVTARGETDEVICE
*td_offs_to_ptr(ole_priv_data
*data
, DWORD_PTR off
)
117 if(off
== 0) return NULL
;
118 return (DVTARGETDEVICE
*)((char*)data
+ off
);
121 /*****************************************************************************
124 * Get the offset from the start of the ole_priv_data of the idx'th
127 * Used when packing ole private data to the clipboard.
129 static inline DWORD_PTR
td_get_offs(ole_priv_data
*data
, DWORD idx
)
131 if(data
->entries
[idx
].fmtetc
.ptd
== NULL
) return 0;
132 return (char*)data
->entries
[idx
].fmtetc
.ptd
- (char*)data
;
135 /****************************************************************************
136 * Consumer snapshot. Represents the state of the ole clipboard
137 * returned by OleGetClipboard().
139 typedef struct snapshot
141 const IDataObjectVtbl
* lpVtbl
;
144 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
146 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
149 /****************************************************************************
152 typedef struct ole_clipbrd
154 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
156 HWND window
; /* Hidden clipboard window */
157 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
158 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
159 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
162 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
164 return (snapshot
*)((char*)iface
- FIELD_OFFSET(snapshot
, lpVtbl
));
167 typedef struct PresentationDataHeader
170 DWORD dwObjectExtentX
;
171 DWORD dwObjectExtentY
;
173 } PresentationDataHeader
;
176 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
178 static ole_clipbrd
* theOleClipboard
;
180 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
182 struct oletls
*info
= COM_CurrentInfo();
186 return CO_E_NOTINITIALIZED
;
187 *clipbrd
= theOleClipboard
;
193 * Name of our registered OLE clipboard window class
195 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
197 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};
199 UINT ownerlink_clipboard_format
= 0;
200 UINT filename_clipboard_format
= 0;
201 UINT filenameW_clipboard_format
= 0;
202 UINT dataobject_clipboard_format
= 0;
203 UINT embedded_object_clipboard_format
= 0;
204 UINT embed_source_clipboard_format
= 0;
205 UINT custom_link_source_clipboard_format
= 0;
206 UINT link_source_clipboard_format
= 0;
207 UINT object_descriptor_clipboard_format
= 0;
208 UINT link_source_descriptor_clipboard_format
= 0;
209 UINT ole_private_data_clipboard_format
= 0;
211 static UINT wine_marshal_clipboard_format
;
213 static inline char *dump_fmtetc(FORMATETC
*fmt
)
215 static char buf
[100];
217 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
218 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
222 /*---------------------------------------------------------------------*
223 * Implementation of the internal IEnumFORMATETC interface returned by
224 * the OLE clipboard's IDataObject.
225 *---------------------------------------------------------------------*/
227 typedef struct enum_fmtetc
229 const IEnumFORMATETCVtbl
*lpVtbl
;
232 UINT pos
; /* current enumerator position */
236 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
238 return (enum_fmtetc
*)((char*)iface
- FIELD_OFFSET(enum_fmtetc
, lpVtbl
));
241 /************************************************************************
242 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
244 * See Windows documentation for more details on IUnknown methods.
246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
247 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
249 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
251 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
255 if(IsEqualIID(riid
, &IID_IUnknown
) ||
256 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
263 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
264 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
268 TRACE("-- Interface: E_NOINTERFACE\n");
269 return E_NOINTERFACE
;
272 /************************************************************************
273 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
276 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
278 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
279 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
281 return InterlockedIncrement(&This
->ref
);
284 /************************************************************************
285 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
287 * See Windows documentation for more details on IUnknown methods.
289 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
291 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
294 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
296 ref
= InterlockedDecrement(&This
->ref
);
299 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
300 HeapFree(GetProcessHeap(), 0, This
->data
);
301 HeapFree(GetProcessHeap(), 0, This
);
306 /************************************************************************
307 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
309 * Standard enumerator members for IEnumFORMATETC
311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
312 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
314 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
316 HRESULT hres
= S_FALSE
;
318 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
320 if (This
->pos
< This
->data
->count
)
322 cfetch
= This
->data
->count
- This
->pos
;
329 for(i
= 0; i
< cfetch
; i
++)
331 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
334 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
335 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
336 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
337 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
348 *pceltFethed
= cfetch
;
354 /************************************************************************
355 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
357 * Standard enumerator members for IEnumFORMATETC
359 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
361 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
362 TRACE("(%p)->(num=%u)\n", This
, celt
);
365 if (This
->pos
> This
->data
->count
)
367 This
->pos
= This
->data
->count
;
373 /************************************************************************
374 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
376 * Standard enumerator members for IEnumFORMATETC
378 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
380 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
381 TRACE("(%p)->()\n", This
);
387 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
389 /************************************************************************
390 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
392 * Standard enumerator members for IEnumFORMATETC
394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
395 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
397 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
398 ole_priv_data
*new_data
;
401 TRACE("(%p)->(%p)\n", This
, obj
);
403 if ( !obj
) return E_INVALIDARG
;
406 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
407 if(!new_data
) return E_OUTOFMEMORY
;
408 memcpy(new_data
, This
->data
, This
->data
->size
);
410 /* Fixup any target device ptrs */
411 for(i
= 0; i
< This
->data
->count
; i
++)
412 new_data
->entries
[i
].fmtetc
.ptd
=
413 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
415 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
418 static const IEnumFORMATETCVtbl efvt
=
420 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
421 OLEClipbrd_IEnumFORMATETC_AddRef
,
422 OLEClipbrd_IEnumFORMATETC_Release
,
423 OLEClipbrd_IEnumFORMATETC_Next
,
424 OLEClipbrd_IEnumFORMATETC_Skip
,
425 OLEClipbrd_IEnumFORMATETC_Reset
,
426 OLEClipbrd_IEnumFORMATETC_Clone
429 /************************************************************************
430 * enum_fmtetc_construct
432 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
434 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
439 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
440 if (!ef
) return E_OUTOFMEMORY
;
447 TRACE("(%p)->()\n", ef
);
448 *obj
= (IEnumFORMATETC
*)ef
;
452 /***********************************************************************
455 * Helper method to duplicate an HGLOBAL chunk of memory
457 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
459 void *src_ptr
, *dst_ptr
;
463 if ( !src
) return S_FALSE
;
465 size
= GlobalSize(src
);
467 *dst
= GlobalAlloc( flags
, size
);
468 if ( !*dst
) return E_OUTOFMEMORY
;
470 src_ptr
= GlobalLock(src
);
471 dst_ptr
= GlobalLock(*dst
);
473 memcpy(dst_ptr
, src_ptr
, size
);
481 /************************************************************
482 * render_embed_source_hack
484 * This is clearly a hack and has no place in the clipboard code.
487 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
490 HGLOBAL hStorage
= 0;
492 ILockBytes
*ptrILockBytes
;
494 memset(&std
, 0, sizeof(STGMEDIUM
));
495 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
497 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
498 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
499 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
500 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
501 ILockBytes_Release(ptrILockBytes
);
503 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
505 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
506 GlobalFree(hStorage
);
510 if (1) /* check whether the presentation data is already -not- present */
514 METAFILEPICT
*mfp
= 0;
516 fmt2
.cfFormat
= CF_METAFILEPICT
;
518 fmt2
.dwAspect
= DVASPECT_CONTENT
;
520 fmt2
.tymed
= TYMED_MFPICT
;
522 memset(&std2
, 0, sizeof(STGMEDIUM
));
523 std2
.tymed
= TYMED_MFPICT
;
525 /* Get the metafile picture out of it */
527 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
529 mfp
= GlobalLock(std2
.u
.hGlobal
);
534 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
535 IStream
*pStream
= 0;
537 PresentationDataHeader pdh
;
541 CHAR strOleTypeName
[51];
542 BYTE OlePresStreamHeader
[] =
544 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
545 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
546 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00
550 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
552 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
553 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
555 pdh
.dwObjectExtentX
= mfp
->xExt
;
556 pdh
.dwObjectExtentY
= mfp
->yExt
;
559 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
561 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
563 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
564 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
566 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
568 IStream_Release(pStream
);
570 HeapFree(GetProcessHeap(), 0, mfBits
);
572 GlobalUnlock(std2
.u
.hGlobal
);
573 ReleaseStgMedium(&std2
);
575 ReadClassStg(std
.u
.pstg
, &clsID
);
576 ProgIDFromCLSID(&clsID
, &strProgID
);
578 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
579 OLECONVERT_CreateOleStream(std
.u
.pstg
);
580 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
584 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
586 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
587 GlobalFree(hStorage
);
588 hr
= CLIPBRD_E_CANT_SET
;
591 ReleaseStgMedium(&std
);
595 /************************************************************************
596 * find_format_in_list
598 * Returns the first entry that matches the provided clipboard format.
600 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
603 for(i
= 0; i
< num
; i
++)
604 if(entries
[i
].fmtetc
.cfFormat
== cf
)
610 /***************************************************************************
611 * get_data_from_storage
613 * Returns storage data in an HGLOBAL.
615 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
626 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
627 if(!h
) return E_OUTOFMEMORY
;
629 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
632 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
633 ILockBytes_Release(lbs
);
642 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
644 med
.pUnkForRelease
= NULL
;
646 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
650 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
651 if(FAILED(hr
)) goto end
;
653 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
654 ReleaseStgMedium(&med
);
655 if(FAILED(hr
)) goto end
;
660 IStorage_Release(stg
);
661 if(FAILED(hr
)) GlobalFree(h
);
665 /***************************************************************************
666 * get_data_from_stream
668 * Returns stream data in an HGLOBAL.
670 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
680 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
681 if(!h
) return E_OUTOFMEMORY
;
683 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
684 if(FAILED(hr
)) goto error
;
687 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
689 med
.pUnkForRelease
= NULL
;
691 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
698 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
699 if(FAILED(hr
)) goto error
;
702 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
703 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
704 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
705 ReleaseStgMedium(&med
);
706 if(FAILED(hr
)) goto error
;
709 IStream_Release(stm
);
713 if(stm
) IStream_Release(stm
);
718 /***************************************************************************
719 * get_data_from_global
721 * Returns global data in an HGLOBAL.
723 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
733 mem_fmt
.tymed
= TYMED_HGLOBAL
;
735 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
736 if(FAILED(hr
)) return hr
;
738 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
740 if(SUCCEEDED(hr
)) *mem
= h
;
742 ReleaseStgMedium(&med
);
747 /***********************************************************************
750 * Render the clipboard data. Note that this call will delegate to the
751 * source data object.
753 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
755 HGLOBAL clip_data
= NULL
;
758 /* Embed source hack */
759 if(fmt
->cfFormat
== embed_source_clipboard_format
)
761 return render_embed_source_hack(data
, fmt
);
764 if(fmt
->tymed
& TYMED_ISTORAGE
)
766 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
768 else if(fmt
->tymed
& TYMED_ISTREAM
)
770 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
772 else if(fmt
->tymed
& TYMED_HGLOBAL
)
774 hr
= get_data_from_global(data
, fmt
, &clip_data
);
778 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
784 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
786 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
787 GlobalFree(clip_data
);
788 hr
= CLIPBRD_E_CANT_SET
;
795 /*---------------------------------------------------------------------*
796 * Implementation of the internal IDataObject interface exposed by
798 *---------------------------------------------------------------------*/
801 /************************************************************************
802 * snapshot_QueryInterface
804 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
805 REFIID riid
, void **ppvObject
)
807 snapshot
*This
= impl_from_IDataObject(iface
);
808 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
810 if ( (This
==0) || (ppvObject
==0) )
815 if (IsEqualIID(&IID_IUnknown
, riid
) ||
816 IsEqualIID(&IID_IDataObject
, riid
))
822 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
823 return E_NOINTERFACE
;
826 IUnknown_AddRef((IUnknown
*)*ppvObject
);
831 /************************************************************************
834 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
836 snapshot
*This
= impl_from_IDataObject(iface
);
838 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
840 return InterlockedIncrement(&This
->ref
);
843 /************************************************************************
846 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
848 snapshot
*This
= impl_from_IDataObject(iface
);
851 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
853 ref
= InterlockedDecrement(&This
->ref
);
857 ole_clipbrd
*clipbrd
;
858 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
860 if(This
->data
) IDataObject_Release(This
->data
);
862 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
863 clipbrd
->latest_snapshot
= NULL
;
864 HeapFree(GetProcessHeap(), 0, This
);
870 /************************************************************
871 * get_current_ole_clip_window
873 * Return the window that owns the ole clipboard.
875 * If the clipboard is flushed or not owned by ole this will
878 static HWND
get_current_ole_clip_window(void)
883 h
= GetClipboardData(dataobject_clipboard_format
);
886 if(!ptr
) return NULL
;
892 /************************************************************
893 * get_current_dataobject
895 * Return an unmarshalled IDataObject if there is a current
896 * (ie non-flushed) object on the ole clipboard.
898 static HRESULT
get_current_dataobject(IDataObject
**data
)
900 HRESULT hr
= S_FALSE
;
901 HWND wnd
= get_current_ole_clip_window();
908 if(!wnd
) return S_FALSE
;
910 h
= GetClipboardData(wine_marshal_clipboard_format
);
911 if(!h
) return S_FALSE
;
912 if(GlobalSize(h
) == 0) return S_FALSE
;
914 if(!ptr
) return S_FALSE
;
916 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
917 if(FAILED(hr
)) goto end
;
919 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
923 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
924 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
926 IStream_Release(stm
);
933 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
935 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
942 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
945 case CF_METAFILEPICT
:
948 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
953 /***********************************************************
956 * Returns a copy of the Ole Private Data
958 static HRESULT
get_priv_data(ole_priv_data
**data
)
962 ole_priv_data
*ret
= NULL
;
966 handle
= GetClipboardData( ole_private_data_clipboard_format
);
969 ole_priv_data
*src
= GlobalLock(handle
);
974 /* FIXME: sanity check on size */
975 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
978 GlobalUnlock(handle
);
979 return E_OUTOFMEMORY
;
981 memcpy(ret
, src
, src
->size
);
982 GlobalUnlock(handle
);
984 /* Fixup any target device offsets to ptrs */
985 for(i
= 0; i
< ret
->count
; i
++)
986 ret
->entries
[i
].fmtetc
.ptd
=
987 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
991 if(!ret
) /* Non-ole data */
994 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
996 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
999 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
1000 TRACE("cf %04x %s\n", cf
, buf
);
1002 TRACE("count %d\n", count
);
1003 size
+= count
* sizeof(ret
->entries
[0]);
1005 /* There are holes in fmtetc so zero init */
1006 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1007 if(!ret
) return E_OUTOFMEMORY
;
1011 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1013 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1014 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1015 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1016 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1017 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1018 ret
->entries
[idx
].first_use
= 1;
1026 /************************************************************************
1027 * get_stgmed_for_global
1029 * Returns a stg medium with a copy of the global handle
1031 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1035 med
->pUnkForRelease
= NULL
;
1036 med
->tymed
= TYMED_NULL
;
1038 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1040 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1045 /************************************************************************
1046 * get_stgmed_for_stream
1048 * Returns a stg medium with a stream based on the handle
1050 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1055 med
->pUnkForRelease
= NULL
;
1056 med
->tymed
= TYMED_NULL
;
1058 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1059 if(FAILED(hr
)) return hr
;
1061 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1068 med
->tymed
= TYMED_ISTREAM
;
1072 /************************************************************************
1073 * get_stgmed_for_storage
1075 * Returns a stg medium with a storage based on the handle
1077 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1083 med
->pUnkForRelease
= NULL
;
1084 med
->tymed
= TYMED_NULL
;
1086 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1087 if(FAILED(hr
)) return hr
;
1089 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1096 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1097 ILockBytes_Release(lbs
);
1104 med
->tymed
= TYMED_ISTORAGE
;
1108 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1110 const WCHAR
*str1
, *str2
;
1112 if(off1
== 0 && off2
== 0) return TRUE
;
1113 if(off1
== 0 || off2
== 0) return FALSE
;
1115 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1116 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1118 return !lstrcmpW(str1
, str2
);
1121 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1123 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1124 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1126 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1128 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1130 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1133 /* FIXME check devmode? */
1138 /************************************************************************
1141 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1144 snapshot
*This
= impl_from_IDataObject(iface
);
1147 ole_priv_data
*enum_data
= NULL
;
1148 ole_priv_data_entry
*entry
;
1151 TRACE("(%p, %p {%s}, %p)\n", iface
, fmt
, dump_fmtetc(fmt
), med
);
1153 if ( !fmt
|| !med
) return E_INVALIDARG
;
1155 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1158 hr
= get_current_dataobject(&This
->data
);
1162 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1167 h
= GetClipboardData(fmt
->cfFormat
);
1170 hr
= DV_E_FORMATETC
;
1174 hr
= get_priv_data(&enum_data
);
1175 if(FAILED(hr
)) goto end
;
1177 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1180 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1182 hr
= DV_E_FORMATETC
;
1185 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1186 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1188 else /* non-Ole format */
1189 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1191 if(mask
& TYMED_ISTORAGE
)
1192 hr
= get_stgmed_for_storage(h
, med
);
1193 else if(mask
& TYMED_HGLOBAL
)
1194 hr
= get_stgmed_for_global(h
, med
);
1195 else if(mask
& TYMED_ISTREAM
)
1196 hr
= get_stgmed_for_stream(h
, med
);
1199 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask
, fmt
->tymed
);
1205 HeapFree(GetProcessHeap(), 0, enum_data
);
1206 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1210 /************************************************************************
1211 * snapshot_GetDataHere
1213 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1216 snapshot
*This
= impl_from_IDataObject(iface
);
1219 ole_priv_data
*enum_data
= NULL
;
1220 ole_priv_data_entry
*entry
;
1223 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface
, fmt
, dump_fmtetc(fmt
), med
, med
->tymed
);
1225 if ( !fmt
|| !med
) return E_INVALIDARG
;
1227 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1230 hr
= get_current_dataobject(&This
->data
);
1234 hr
= IDataObject_GetDataHere(This
->data
, fmt
, med
);
1242 h
= GetClipboardData(fmt
->cfFormat
);
1245 hr
= DV_E_FORMATETC
;
1249 hr
= get_priv_data(&enum_data
);
1250 if(FAILED(hr
)) goto end
;
1252 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1255 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1257 hr
= DV_E_FORMATETC
;
1260 supported
= entry
->fmtetc
.tymed
;
1262 else /* non-Ole format */
1263 supported
= TYMED_HGLOBAL
;
1269 DWORD src_size
= GlobalSize(h
);
1270 DWORD dst_size
= GlobalSize(med
->u
.hGlobal
);
1272 if(dst_size
>= src_size
)
1274 void *src
= GlobalLock(h
);
1275 void *dst
= GlobalLock(med
->u
.hGlobal
);
1277 memcpy(dst
, src
, src_size
);
1278 GlobalUnlock(med
->u
.hGlobal
);
1286 DWORD src_size
= GlobalSize(h
);
1287 void *src
= GlobalLock(h
);
1288 hr
= IStream_Write(med
->u
.pstm
, src
, src_size
, NULL
);
1292 case TYMED_ISTORAGE
:
1295 if(!(supported
& TYMED_ISTORAGE
))
1300 hr
= get_stgmed_for_storage(h
, ©
);
1303 hr
= IStorage_CopyTo(copy
.u
.pstg
, 0, NULL
, NULL
, med
->u
.pstg
);
1304 ReleaseStgMedium(©
);
1309 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported
, med
->tymed
);
1315 HeapFree(GetProcessHeap(), 0, enum_data
);
1316 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1320 /************************************************************************
1321 * snapshot_QueryGetData
1323 * The OLE Clipboard's implementation of this method delegates to
1324 * a data source if there is one or wraps around the windows clipboard
1325 * function IsClipboardFormatAvailable() otherwise.
1328 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1330 FIXME("(%p, %p {%s})\n", iface
, fmt
, dump_fmtetc(fmt
));
1332 if (!fmt
) return E_INVALIDARG
;
1334 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1336 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1338 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1341 /************************************************************************
1342 * snapshot_GetCanonicalFormatEtc
1344 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1347 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1349 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1352 return DATA_S_SAMEFORMATETC
;
1355 /************************************************************************
1358 * The OLE Clipboard does not implement this method
1360 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1361 STGMEDIUM
*med
, BOOL release
)
1363 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1367 /************************************************************************
1368 * snapshot_EnumFormatEtc
1371 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1372 IEnumFORMATETC
**enum_fmt
)
1375 ole_priv_data
*data
= NULL
;
1377 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1381 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1382 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1384 hr
= get_priv_data(&data
);
1386 if(FAILED(hr
)) goto end
;
1388 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1391 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1395 /************************************************************************
1398 * The OLE Clipboard does not implement this method
1400 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1401 DWORD flags
, IAdviseSink
*sink
,
1404 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1408 /************************************************************************
1409 * snapshot_DUnadvise
1411 * The OLE Clipboard does not implement this method
1413 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1415 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1419 /************************************************************************
1420 * snapshot_EnumDAdvise
1422 * The OLE Clipboard does not implement this method
1424 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1425 IEnumSTATDATA
** enum_advise
)
1427 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1431 static const IDataObjectVtbl snapshot_vtable
=
1433 snapshot_QueryInterface
,
1437 snapshot_GetDataHere
,
1438 snapshot_QueryGetData
,
1439 snapshot_GetCanonicalFormatEtc
,
1441 snapshot_EnumFormatEtc
,
1444 snapshot_EnumDAdvise
1447 /*---------------------------------------------------------------------*
1448 * Internal implementation methods for the OLE clipboard
1449 *---------------------------------------------------------------------*/
1451 static snapshot
*snapshot_construct(DWORD seq_no
)
1455 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1456 if (!This
) return NULL
;
1458 This
->lpVtbl
= &snapshot_vtable
;
1460 This
->seq_no
= seq_no
;
1466 /*********************************************************
1467 * register_clipboard_formats
1469 static void register_clipboard_formats(void)
1471 static const WCHAR OwnerLink
[] = {'O','w','n','e','r','L','i','n','k',0};
1472 static const WCHAR FileName
[] = {'F','i','l','e','N','a','m','e',0};
1473 static const WCHAR FileNameW
[] = {'F','i','l','e','N','a','m','e','W',0};
1474 static const WCHAR DataObject
[] = {'D','a','t','a','O','b','j','e','c','t',0};
1475 static const WCHAR EmbeddedObject
[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1476 static const WCHAR EmbedSource
[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1477 static const WCHAR CustomLinkSource
[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1478 static const WCHAR LinkSource
[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1479 static const WCHAR ObjectDescriptor
[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1480 static const WCHAR LinkSourceDescriptor
[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1481 'D','e','s','c','r','i','p','t','o','r',0};
1482 static const WCHAR OlePrivateData
[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1484 static const WCHAR WineMarshalledDataObject
[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1485 'D','a','t','a','O','b','j','e','c','t',0};
1487 ownerlink_clipboard_format
= RegisterClipboardFormatW(OwnerLink
);
1488 filename_clipboard_format
= RegisterClipboardFormatW(FileName
);
1489 filenameW_clipboard_format
= RegisterClipboardFormatW(FileNameW
);
1490 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObject
);
1491 embedded_object_clipboard_format
= RegisterClipboardFormatW(EmbeddedObject
);
1492 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSource
);
1493 custom_link_source_clipboard_format
= RegisterClipboardFormatW(CustomLinkSource
);
1494 link_source_clipboard_format
= RegisterClipboardFormatW(LinkSource
);
1495 object_descriptor_clipboard_format
= RegisterClipboardFormatW(ObjectDescriptor
);
1496 link_source_descriptor_clipboard_format
= RegisterClipboardFormatW(LinkSourceDescriptor
);
1497 ole_private_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateData
);
1499 wine_marshal_clipboard_format
= RegisterClipboardFormatW(WineMarshalledDataObject
);
1502 /***********************************************************************
1503 * OLEClipbrd_Initialize()
1504 * Initializes the OLE clipboard.
1506 void OLEClipbrd_Initialize(void)
1508 register_clipboard_formats();
1510 if ( !theOleClipboard
)
1512 ole_clipbrd
* clipbrd
;
1517 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1518 if (!clipbrd
) return;
1520 clipbrd
->latest_snapshot
= NULL
;
1521 clipbrd
->window
= NULL
;
1522 clipbrd
->src_data
= NULL
;
1523 clipbrd
->cached_enum
= NULL
;
1525 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1528 HeapFree(GetProcessHeap(), 0, clipbrd
);
1532 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1535 HeapFree(GetProcessHeap(), 0, clipbrd
);
1539 theOleClipboard
= clipbrd
;
1543 /***********************************************************************
1544 * OLEClipbrd_UnInitialize()
1545 * Un-Initializes the OLE clipboard
1547 void OLEClipbrd_UnInitialize(void)
1549 ole_clipbrd
*clipbrd
= theOleClipboard
;
1555 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1556 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1558 if ( clipbrd
->window
)
1560 DestroyWindow(clipbrd
->window
);
1561 UnregisterClassW( clipbrd_wndclass
, hinst
);
1564 IStream_Release(clipbrd
->marshal_data
);
1565 HeapFree(GetProcessHeap(), 0, clipbrd
);
1566 theOleClipboard
= NULL
;
1570 /*********************************************************************
1571 * set_clipboard_formats
1573 * Enumerate all formats supported by the source and make
1574 * those formats available using delayed rendering using SetClipboardData.
1575 * Cache the enumeration list and make that list visibile as the
1576 * 'Ole Private Data' format on the clipboard.
1579 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1583 IEnumFORMATETC
*enum_fmt
;
1584 HGLOBAL priv_data_handle
;
1585 DWORD_PTR target_offset
;
1586 ole_priv_data
*priv_data
;
1587 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1589 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1590 if(FAILED(hr
)) return hr
;
1592 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1595 needed
+= sizeof(priv_data
->entries
[0]);
1598 needed
+= fmt
.ptd
->tdSize
;
1599 CoTaskMemFree(fmt
.ptd
);
1603 /* Windows pads the list with two empty ole_priv_data_entries, one
1604 * after the entries array and one after the target device data.
1605 * Allocating with zero init to zero these pads. */
1607 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1608 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1609 priv_data
= GlobalLock(priv_data_handle
);
1611 priv_data
->unk1
= 0;
1612 priv_data
->size
= needed
;
1613 priv_data
->unk2
= 1;
1614 priv_data
->count
= count
;
1615 priv_data
->unk3
[0] = 0;
1616 priv_data
->unk3
[1] = 0;
1618 IEnumFORMATETC_Reset(enum_fmt
);
1621 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1623 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1625 TRACE("%s\n", dump_fmtetc(&fmt
));
1627 priv_data
->entries
[idx
].fmtetc
= fmt
;
1630 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1631 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1632 target_offset
+= fmt
.ptd
->tdSize
;
1633 CoTaskMemFree(fmt
.ptd
);
1636 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1637 priv_data
->entries
[idx
].unk
[0] = 0;
1638 priv_data
->entries
[idx
].unk
[1] = 0;
1640 if (priv_data
->entries
[idx
].first_use
)
1641 SetClipboardData(fmt
.cfFormat
, NULL
);
1646 IEnumFORMATETC_Release(enum_fmt
);
1648 /* Cache the list and fixup any target device offsets to ptrs */
1649 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1650 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1651 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1652 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1653 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1655 GlobalUnlock(priv_data_handle
);
1656 SetClipboardData(ole_private_data_clipboard_format
, priv_data_handle
);
1661 static HWND
create_clipbrd_window(void);
1663 /***********************************************************************
1664 * get_clipbrd_window
1666 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1668 if ( !clipbrd
->window
)
1669 clipbrd
->window
= create_clipbrd_window();
1671 *wnd
= clipbrd
->window
;
1672 return *wnd
? S_OK
: E_FAIL
;
1676 /**********************************************************************
1677 * release_marshal_data
1679 * Releases the data and sets the stream back to zero size.
1681 static inline void release_marshal_data(IStream
*stm
)
1684 ULARGE_INTEGER size
;
1685 pos
.QuadPart
= size
.QuadPart
= 0;
1687 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1688 CoReleaseMarshalData(stm
);
1689 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1690 IStream_SetSize(stm
, size
);
1693 /***********************************************************************
1694 * expose_marshalled_dataobject
1696 * Sets the marshalled dataobject to the clipboard. In the flushed case
1697 * we set a zero sized HGLOBAL to clear the old marshalled data.
1699 static HRESULT
expose_marshalled_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1706 GetHGlobalFromStream(clipbrd
->marshal_data
, &h_stm
);
1707 dup_global_mem(h_stm
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
1710 h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 0);
1712 if(!h
) return E_OUTOFMEMORY
;
1714 SetClipboardData(wine_marshal_clipboard_format
, h
);
1718 /***********************************************************************
1719 * set_src_dataobject
1721 * Clears and sets the clipboard's src IDataObject.
1723 * To marshal the source dataobject we do something rather different from Windows.
1724 * We set a clipboard format which contains the marshalled data.
1725 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1727 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1732 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1734 if(clipbrd
->src_data
)
1736 release_marshal_data(clipbrd
->marshal_data
);
1738 IDataObject_Release(clipbrd
->src_data
);
1739 clipbrd
->src_data
= NULL
;
1740 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1741 clipbrd
->cached_enum
= NULL
;
1748 IDataObject_AddRef(data
);
1749 clipbrd
->src_data
= data
;
1751 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1752 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1753 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1754 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1755 if(FAILED(hr
)) return hr
;
1756 hr
= set_clipboard_formats(clipbrd
, data
);
1761 /***********************************************************************
1764 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1766 ole_clipbrd
*clipbrd
;
1768 get_ole_clipbrd(&clipbrd
);
1772 case WM_RENDERFORMAT
:
1775 ole_priv_data_entry
*entry
;
1777 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
1778 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
1781 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
1786 case WM_RENDERALLFORMATS
:
1789 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
1791 TRACE("(): WM_RENDERALLFORMATS\n");
1793 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
1795 if(entries
[i
].first_use
)
1796 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
1801 case WM_DESTROYCLIPBOARD
:
1803 TRACE("(): WM_DESTROYCLIPBOARD\n");
1805 set_src_dataobject(clipbrd
, NULL
);
1810 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
1817 /***********************************************************************
1818 * create_clipbrd_window
1820 static HWND
create_clipbrd_window(void)
1823 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1824 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1825 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1827 class.cbSize
= sizeof(class);
1829 class.lpfnWndProc
= clipbrd_wndproc
;
1830 class.cbClsExtra
= 0;
1831 class.cbWndExtra
= 0;
1832 class.hInstance
= hinst
;
1835 class.hbrBackground
= 0;
1836 class.lpszMenuName
= NULL
;
1837 class.lpszClassName
= clipbrd_wndclass
;
1838 class.hIconSm
= NULL
;
1840 RegisterClassExW(&class);
1842 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
1843 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1844 NULL
, NULL
, hinst
, 0);
1847 /*********************************************************************
1848 * set_dataobject_format
1850 * Windows creates a 'DataObject' clipboard format that contains the
1851 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1853 static HRESULT
set_dataobject_format(HWND hwnd
)
1855 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
1858 if(!h
) return E_OUTOFMEMORY
;
1860 data
= GlobalLock(h
);
1864 if(!SetClipboardData(dataobject_clipboard_format
, h
))
1867 return CLIPBRD_E_CANT_SET
;
1873 /*---------------------------------------------------------------------*
1874 * Win32 OLE clipboard API
1875 *---------------------------------------------------------------------*/
1877 /***********************************************************************
1878 * OleSetClipboard [OLE32.@]
1879 * Places a pointer to the specified data object onto the clipboard,
1880 * making the data object accessible to the OleGetClipboard function.
1884 * S_OK IDataObject pointer placed on the clipboard
1885 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1886 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1887 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1888 * CLIPBRD_E_CANT_SET SetClipboard failed
1891 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
1894 ole_clipbrd
*clipbrd
;
1897 TRACE("(%p)\n", data
);
1899 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1901 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1903 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
1905 if ( !EmptyClipboard() )
1907 hr
= CLIPBRD_E_CANT_EMPTY
;
1911 hr
= set_src_dataobject(clipbrd
, data
);
1912 if(FAILED(hr
)) goto end
;
1916 hr
= expose_marshalled_dataobject(clipbrd
, data
);
1917 if(FAILED(hr
)) goto end
;
1918 hr
= set_dataobject_format(wnd
);
1923 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1927 expose_marshalled_dataobject(clipbrd
, NULL
);
1928 set_src_dataobject(clipbrd
, NULL
);
1935 /***********************************************************************
1936 * OleGetClipboard [OLE32.@]
1937 * Returns a pointer to our internal IDataObject which represents the conceptual
1938 * state of the Windows clipboard. If the current clipboard already contains
1939 * an IDataObject, our internal IDataObject will delegate to this object.
1941 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
1944 ole_clipbrd
*clipbrd
;
1947 TRACE("(%p)\n", obj
);
1949 if(!obj
) return E_INVALIDARG
;
1951 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1953 seq_no
= GetClipboardSequenceNumber();
1954 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
1955 clipbrd
->latest_snapshot
= NULL
;
1957 if(!clipbrd
->latest_snapshot
)
1959 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
1960 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
1963 *obj
= (IDataObject
*)&clipbrd
->latest_snapshot
->lpVtbl
;
1964 IDataObject_AddRef(*obj
);
1969 /******************************************************************************
1970 * OleFlushClipboard [OLE32.@]
1971 * Renders the data from the source IDataObject into the windows clipboard
1973 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1974 * by copying the storage into global memory. Subsequently the default
1975 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1976 * back to TYMED_IStorage.
1978 HRESULT WINAPI
OleFlushClipboard(void)
1981 ole_clipbrd
*clipbrd
;
1986 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1988 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1991 * Already flushed or no source DataObject? Nothing to do.
1993 if (!clipbrd
->src_data
) return S_OK
;
1995 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
1997 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
1999 hr
= set_dataobject_format(NULL
);
2001 expose_marshalled_dataobject(clipbrd
, NULL
);
2002 set_src_dataobject(clipbrd
, NULL
);
2004 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
2010 /***********************************************************************
2011 * OleIsCurrentClipboard [OLE32.@]
2013 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
2016 ole_clipbrd
*clipbrd
;
2019 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
2021 if (data
== NULL
) return S_FALSE
;
2023 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;