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 * create_empty_priv_data
138 * Create an empty data structure. The only thing that really matters
139 * here is setting count and size members. This is used by the enumerator as a
140 * convenience when there's an empty list.
142 static HRESULT
create_empty_priv_data(ole_priv_data
**data
)
147 ptr
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr
));
148 if(!ptr
) return E_OUTOFMEMORY
;
149 ptr
->size
= sizeof(*ptr
);
155 /****************************************************************************
156 * Consumer snapshot. Represents the state of the ole clipboard
157 * returned by OleGetClipboard().
159 typedef struct snapshot
161 const IDataObjectVtbl
* lpVtbl
;
164 DWORD seq_no
; /* Clipboard sequence number corresponding to this snapshot */
166 IDataObject
*data
; /* If we unmarshal a remote data object we hold a ref here */
169 /****************************************************************************
172 typedef struct ole_clipbrd
174 snapshot
*latest_snapshot
; /* Latest consumer snapshot */
176 HWND window
; /* Hidden clipboard window */
177 IDataObject
*src_data
; /* Source object passed to OleSetClipboard */
178 ole_priv_data
*cached_enum
; /* Cached result from the enumeration of src data object */
179 IStream
*marshal_data
; /* Stream onto which to marshal src_data */
182 static inline snapshot
*impl_from_IDataObject(IDataObject
*iface
)
184 return (snapshot
*)((char*)iface
- FIELD_OFFSET(snapshot
, lpVtbl
));
187 typedef struct PresentationDataHeader
190 DWORD dwObjectExtentX
;
191 DWORD dwObjectExtentY
;
193 } PresentationDataHeader
;
196 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
198 static ole_clipbrd
* theOleClipboard
;
200 static inline HRESULT
get_ole_clipbrd(ole_clipbrd
**clipbrd
)
202 struct oletls
*info
= COM_CurrentInfo();
206 return CO_E_NOTINITIALIZED
;
207 *clipbrd
= theOleClipboard
;
213 * Name of our registered OLE clipboard window class
215 static const WCHAR clipbrd_wndclass
[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
217 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};
219 static UINT dataobject_clipboard_format
;
220 static UINT ole_priv_data_clipboard_format
;
221 static UINT embed_source_clipboard_format
;
223 static inline char *dump_fmtetc(FORMATETC
*fmt
)
225 static char buf
[100];
227 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
228 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
232 /*---------------------------------------------------------------------*
233 * Implementation of the internal IEnumFORMATETC interface returned by
234 * the OLE clipboard's IDataObject.
235 *---------------------------------------------------------------------*/
237 typedef struct enum_fmtetc
239 const IEnumFORMATETCVtbl
*lpVtbl
;
242 UINT pos
; /* current enumerator position */
246 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
248 return (enum_fmtetc
*)((char*)iface
- FIELD_OFFSET(enum_fmtetc
, lpVtbl
));
251 /************************************************************************
252 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
254 * See Windows documentation for more details on IUnknown methods.
256 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
257 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
259 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
261 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
265 if(IsEqualIID(riid
, &IID_IUnknown
) ||
266 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
273 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
274 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
278 TRACE("-- Interface: E_NOINTERFACE\n");
279 return E_NOINTERFACE
;
282 /************************************************************************
283 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
286 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
288 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
289 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
291 return InterlockedIncrement(&This
->ref
);
294 /************************************************************************
295 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
297 * See Windows documentation for more details on IUnknown methods.
299 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
301 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
304 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
306 ref
= InterlockedDecrement(&This
->ref
);
309 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
310 HeapFree(GetProcessHeap(), 0, This
->data
);
311 HeapFree(GetProcessHeap(), 0, This
);
316 /************************************************************************
317 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
319 * Standard enumerator members for IEnumFORMATETC
321 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
322 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
324 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
326 HRESULT hres
= S_FALSE
;
328 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
330 if (This
->pos
< This
->data
->count
)
332 cfetch
= This
->data
->count
- This
->pos
;
339 for(i
= 0; i
< cfetch
; i
++)
341 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
344 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
345 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
346 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
347 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
358 *pceltFethed
= cfetch
;
364 /************************************************************************
365 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
367 * Standard enumerator members for IEnumFORMATETC
369 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
371 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
372 TRACE("(%p)->(num=%u)\n", This
, celt
);
375 if (This
->pos
> This
->data
->count
)
377 This
->pos
= This
->data
->count
;
383 /************************************************************************
384 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
386 * Standard enumerator members for IEnumFORMATETC
388 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
390 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
391 TRACE("(%p)->()\n", This
);
397 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
399 /************************************************************************
400 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
402 * Standard enumerator members for IEnumFORMATETC
404 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
405 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
407 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
408 ole_priv_data
*new_data
;
411 TRACE("(%p)->(%p)\n", This
, obj
);
413 if ( !obj
) return E_INVALIDARG
;
416 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
417 if(!new_data
) return E_OUTOFMEMORY
;
418 memcpy(new_data
, This
->data
, This
->data
->size
);
420 /* Fixup any target device ptrs */
421 for(i
= 0; i
< This
->data
->count
; i
++)
422 new_data
->entries
[i
].fmtetc
.ptd
=
423 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
425 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
428 static const IEnumFORMATETCVtbl efvt
=
430 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
431 OLEClipbrd_IEnumFORMATETC_AddRef
,
432 OLEClipbrd_IEnumFORMATETC_Release
,
433 OLEClipbrd_IEnumFORMATETC_Next
,
434 OLEClipbrd_IEnumFORMATETC_Skip
,
435 OLEClipbrd_IEnumFORMATETC_Reset
,
436 OLEClipbrd_IEnumFORMATETC_Clone
439 /************************************************************************
440 * enum_fmtetc_construct
442 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
444 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
449 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
450 if (!ef
) return E_OUTOFMEMORY
;
457 TRACE("(%p)->()\n", ef
);
458 *obj
= (IEnumFORMATETC
*)ef
;
462 /***********************************************************************
465 * Helper method to duplicate an HGLOBAL chunk of memory
467 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
469 void *src_ptr
, *dst_ptr
;
473 if ( !src
) return S_FALSE
;
475 size
= GlobalSize(src
);
477 *dst
= GlobalAlloc( flags
, size
);
478 if ( !*dst
) return E_OUTOFMEMORY
;
480 src_ptr
= GlobalLock(src
);
481 dst_ptr
= GlobalLock(*dst
);
483 memcpy(dst_ptr
, src_ptr
, size
);
491 /************************************************************
492 * render_embed_source_hack
494 * This is clearly a hack and has no place in the clipboard code.
497 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
500 HGLOBAL hStorage
= 0;
502 ILockBytes
*ptrILockBytes
;
504 memset(&std
, 0, sizeof(STGMEDIUM
));
505 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
507 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
508 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
509 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
510 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
511 ILockBytes_Release(ptrILockBytes
);
513 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
515 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
516 GlobalFree(hStorage
);
520 if (1) /* check whether the presentation data is already -not- present */
524 METAFILEPICT
*mfp
= 0;
526 fmt2
.cfFormat
= CF_METAFILEPICT
;
528 fmt2
.dwAspect
= DVASPECT_CONTENT
;
530 fmt2
.tymed
= TYMED_MFPICT
;
532 memset(&std2
, 0, sizeof(STGMEDIUM
));
533 std2
.tymed
= TYMED_MFPICT
;
535 /* Get the metafile picture out of it */
537 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
539 mfp
= GlobalLock(std2
.u
.hGlobal
);
544 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
545 IStream
*pStream
= 0;
547 PresentationDataHeader pdh
;
551 CHAR strOleTypeName
[51];
552 BYTE OlePresStreamHeader
[] =
554 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
555 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
556 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00
560 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
562 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
563 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
565 pdh
.dwObjectExtentX
= mfp
->xExt
;
566 pdh
.dwObjectExtentY
= mfp
->yExt
;
569 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
571 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
573 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
574 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
576 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
578 IStream_Release(pStream
);
580 HeapFree(GetProcessHeap(), 0, mfBits
);
582 GlobalUnlock(std2
.u
.hGlobal
);
583 ReleaseStgMedium(&std2
);
585 ReadClassStg(std
.u
.pstg
, &clsID
);
586 ProgIDFromCLSID(&clsID
, &strProgID
);
588 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
589 OLECONVERT_CreateOleStream(std
.u
.pstg
);
590 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
594 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
596 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
597 GlobalFree(hStorage
);
598 hr
= CLIPBRD_E_CANT_SET
;
601 ReleaseStgMedium(&std
);
605 /************************************************************************
606 * find_format_in_list
608 * Returns the first entry that matches the provided clipboard format.
610 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
613 for(i
= 0; i
< num
; i
++)
614 if(entries
[i
].fmtetc
.cfFormat
== cf
)
620 /***************************************************************************
621 * get_data_from_storage
623 * Returns storage data in an HGLOBAL.
625 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
636 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
637 if(!h
) return E_OUTOFMEMORY
;
639 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
642 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
643 ILockBytes_Release(lbs
);
652 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
654 med
.pUnkForRelease
= NULL
;
656 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
660 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
661 if(FAILED(hr
)) goto end
;
663 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
664 ReleaseStgMedium(&med
);
665 if(FAILED(hr
)) goto end
;
670 IStorage_Release(stg
);
671 if(FAILED(hr
)) GlobalFree(h
);
675 /***************************************************************************
676 * get_data_from_stream
678 * Returns stream data in an HGLOBAL.
680 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
690 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
691 if(!h
) return E_OUTOFMEMORY
;
693 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
694 if(FAILED(hr
)) goto error
;
697 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
699 med
.pUnkForRelease
= NULL
;
701 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
708 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
709 if(FAILED(hr
)) goto error
;
712 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
713 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
714 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
715 ReleaseStgMedium(&med
);
716 if(FAILED(hr
)) goto error
;
719 IStream_Release(stm
);
723 if(stm
) IStream_Release(stm
);
728 /***************************************************************************
729 * get_data_from_global
731 * Returns global data in an HGLOBAL.
733 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
743 mem_fmt
.tymed
= TYMED_HGLOBAL
;
745 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
746 if(FAILED(hr
)) return hr
;
748 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
750 if(SUCCEEDED(hr
)) *mem
= h
;
752 ReleaseStgMedium(&med
);
757 /***********************************************************************
760 * Render the clipboard data. Note that this call will delegate to the
761 * source data object.
763 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
765 HGLOBAL clip_data
= NULL
;
768 /* Embed source hack */
769 if(fmt
->cfFormat
== embed_source_clipboard_format
)
771 return render_embed_source_hack(data
, fmt
);
774 if(fmt
->tymed
& TYMED_ISTORAGE
)
776 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
778 else if(fmt
->tymed
& TYMED_ISTREAM
)
780 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
782 else if(fmt
->tymed
& TYMED_HGLOBAL
)
784 hr
= get_data_from_global(data
, fmt
, &clip_data
);
788 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
794 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
796 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
797 GlobalFree(clip_data
);
798 hr
= CLIPBRD_E_CANT_SET
;
805 /*---------------------------------------------------------------------*
806 * Implementation of the internal IDataObject interface exposed by
808 *---------------------------------------------------------------------*/
811 /************************************************************************
812 * snapshot_QueryInterface
814 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
815 REFIID riid
, void **ppvObject
)
817 snapshot
*This
= impl_from_IDataObject(iface
);
818 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
820 if ( (This
==0) || (ppvObject
==0) )
825 if (IsEqualIID(&IID_IUnknown
, riid
) ||
826 IsEqualIID(&IID_IDataObject
, riid
))
832 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
833 return E_NOINTERFACE
;
836 IUnknown_AddRef((IUnknown
*)*ppvObject
);
841 /************************************************************************
844 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
846 snapshot
*This
= impl_from_IDataObject(iface
);
848 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
850 return InterlockedIncrement(&This
->ref
);
853 /************************************************************************
856 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
858 snapshot
*This
= impl_from_IDataObject(iface
);
861 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
863 ref
= InterlockedDecrement(&This
->ref
);
867 ole_clipbrd
*clipbrd
;
868 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
870 if(This
->data
) IDataObject_Release(This
->data
);
872 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
873 clipbrd
->latest_snapshot
= NULL
;
874 HeapFree(GetProcessHeap(), 0, This
);
880 /************************************************************
881 * get_current_ole_clip_window
883 * Return the window that owns the ole clipboard.
885 * If the clipboard is flushed or not owned by ole this will
888 static HWND
get_current_ole_clip_window(void)
893 h
= GetClipboardData(dataobject_clipboard_format
);
896 if(!ptr
) return NULL
;
902 /************************************************************
903 * get_current_dataobject
905 * Return an unmarshalled IDataObject if there is a current
906 * (ie non-flushed) object on the ole clipboard.
908 static HRESULT
get_current_dataobject(IDataObject
**data
)
910 HRESULT hr
= S_FALSE
;
911 HWND wnd
= get_current_ole_clip_window();
918 if(!wnd
) return S_FALSE
;
920 h
= GetPropW(wnd
, wine_marshal_dataobject
);
921 if(!h
) return S_FALSE
;
923 if(!ptr
) return S_FALSE
;
925 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
926 if(FAILED(hr
)) goto end
;
928 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
932 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
933 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
935 IStream_Release(stm
);
942 /***********************************************************
945 * Returns a copy of the Ole Private Data
947 static HRESULT
get_priv_data(ole_priv_data
**data
)
954 handle
= GetClipboardData( ole_priv_data_clipboard_format
);
957 ole_priv_data
*src
= GlobalLock(handle
);
962 /* FIXME: sanity check on size */
963 *data
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
966 GlobalUnlock(handle
);
967 return E_OUTOFMEMORY
;
969 memcpy(*data
, src
, src
->size
);
970 GlobalUnlock(handle
);
972 /* Fixup any target device offsets to ptrs */
973 for(i
= 0; i
< (*data
)->count
; i
++)
974 (*data
)->entries
[i
].fmtetc
.ptd
=
975 td_offs_to_ptr(*data
, (DWORD_PTR
)(*data
)->entries
[i
].fmtetc
.ptd
);
979 if(!*data
) hr
= create_empty_priv_data(data
);
984 /************************************************************************
985 * get_stgmed_for_global
987 * Returns a stg medium with a copy of the global handle
989 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
993 med
->pUnkForRelease
= NULL
;
994 med
->tymed
= TYMED_NULL
;
996 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
998 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1003 /************************************************************************
1004 * get_stgmed_for_stream
1006 * Returns a stg medium with a stream based on the handle
1008 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1013 med
->pUnkForRelease
= NULL
;
1014 med
->tymed
= TYMED_NULL
;
1016 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1017 if(FAILED(hr
)) return hr
;
1019 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1026 med
->tymed
= TYMED_ISTREAM
;
1030 /************************************************************************
1031 * get_stgmed_for_storage
1033 * Returns a stg medium with a storage based on the handle
1035 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1041 med
->pUnkForRelease
= NULL
;
1042 med
->tymed
= TYMED_NULL
;
1044 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1045 if(FAILED(hr
)) return hr
;
1047 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1054 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1055 ILockBytes_Release(lbs
);
1062 med
->tymed
= TYMED_ISTORAGE
;
1066 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1068 const WCHAR
*str1
, *str2
;
1070 if(off1
== 0 && off2
== 0) return TRUE
;
1071 if(off1
== 0 || off2
== 0) return FALSE
;
1073 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1074 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1076 return !lstrcmpW(str1
, str2
);
1079 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1081 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1082 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1084 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1086 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1088 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1091 /* FIXME check devmode? */
1096 /************************************************************************
1099 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1102 snapshot
*This
= impl_from_IDataObject(iface
);
1105 ole_priv_data
*enum_data
= NULL
;
1106 ole_priv_data_entry
*entry
;
1109 TRACE("(%p,%p,%p)\n", iface
, fmt
, med
);
1111 if ( !fmt
|| !med
) return E_INVALIDARG
;
1113 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1116 hr
= get_current_dataobject(&This
->data
);
1120 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1125 h
= GetClipboardData(fmt
->cfFormat
);
1128 hr
= DV_E_FORMATETC
;
1132 hr
= get_priv_data(&enum_data
);
1133 if(FAILED(hr
)) goto end
;
1135 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1138 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1140 hr
= DV_E_FORMATETC
;
1143 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1144 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1146 else /* non-Ole format */
1147 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1149 if(mask
& TYMED_ISTORAGE
)
1150 hr
= get_stgmed_for_storage(h
, med
);
1151 else if(mask
& TYMED_HGLOBAL
)
1152 hr
= get_stgmed_for_global(h
, med
);
1153 else if(mask
& TYMED_ISTREAM
)
1154 hr
= get_stgmed_for_stream(h
, med
);
1157 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry
->fmtetc
.tymed
, fmt
->tymed
);
1163 HeapFree(GetProcessHeap(), 0, enum_data
);
1164 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1168 /************************************************************************
1169 * snapshot_GetDataHere
1171 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1174 FIXME("(%p, %p, %p): stub\n", iface
, fmt
, med
);
1178 /************************************************************************
1179 * snapshot_QueryGetData
1181 * The OLE Clipboard's implementation of this method delegates to
1182 * a data source if there is one or wraps around the windows clipboard
1183 * function IsClipboardFormatAvailable() otherwise.
1186 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1188 FIXME("(%p, %p)\n", iface
, fmt
);
1190 if (!fmt
) return E_INVALIDARG
;
1192 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1194 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1196 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1199 /************************************************************************
1200 * snapshot_GetCanonicalFormatEtc
1202 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1205 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1207 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1210 return DATA_S_SAMEFORMATETC
;
1213 /************************************************************************
1216 * The OLE Clipboard does not implement this method
1218 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1219 STGMEDIUM
*med
, BOOL release
)
1221 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1225 /************************************************************************
1226 * snapshot_EnumFormatEtc
1229 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1230 IEnumFORMATETC
**enum_fmt
)
1233 ole_priv_data
*data
= NULL
;
1235 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1239 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1240 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1242 hr
= get_priv_data(&data
);
1244 if(FAILED(hr
)) goto end
;
1246 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1249 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1253 /************************************************************************
1256 * The OLE Clipboard does not implement this method
1258 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1259 DWORD flags
, IAdviseSink
*sink
,
1262 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1266 /************************************************************************
1267 * snapshot_DUnadvise
1269 * The OLE Clipboard does not implement this method
1271 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1273 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1277 /************************************************************************
1278 * snapshot_EnumDAdvise
1280 * The OLE Clipboard does not implement this method
1282 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1283 IEnumSTATDATA
** enum_advise
)
1285 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1289 static const IDataObjectVtbl snapshot_vtable
=
1291 snapshot_QueryInterface
,
1295 snapshot_GetDataHere
,
1296 snapshot_QueryGetData
,
1297 snapshot_GetCanonicalFormatEtc
,
1299 snapshot_EnumFormatEtc
,
1302 snapshot_EnumDAdvise
1305 /*---------------------------------------------------------------------*
1306 * Internal implementation methods for the OLE clipboard
1307 *---------------------------------------------------------------------*/
1309 static snapshot
*snapshot_construct(DWORD seq_no
)
1313 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1314 if (!This
) return NULL
;
1316 This
->lpVtbl
= &snapshot_vtable
;
1318 This
->seq_no
= seq_no
;
1324 /*********************************************************
1325 * register_clipboard_formats
1327 static void register_clipboard_formats(void)
1329 static const WCHAR DataObjectW
[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1330 static const WCHAR OlePrivateDataW
[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1331 static const WCHAR EmbedSourceW
[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1333 if(!dataobject_clipboard_format
)
1334 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObjectW
);
1335 if(!ole_priv_data_clipboard_format
)
1336 ole_priv_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateDataW
);
1337 if(!embed_source_clipboard_format
)
1338 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSourceW
);
1341 /***********************************************************************
1342 * OLEClipbrd_Initialize()
1343 * Initializes the OLE clipboard.
1345 void OLEClipbrd_Initialize(void)
1347 register_clipboard_formats();
1349 if ( !theOleClipboard
)
1351 ole_clipbrd
* clipbrd
;
1356 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1357 if (!clipbrd
) return;
1359 clipbrd
->latest_snapshot
= NULL
;
1360 clipbrd
->window
= NULL
;
1361 clipbrd
->src_data
= NULL
;
1362 clipbrd
->cached_enum
= NULL
;
1364 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1367 HeapFree(GetProcessHeap(), 0, clipbrd
);
1371 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1374 HeapFree(GetProcessHeap(), 0, clipbrd
);
1378 theOleClipboard
= clipbrd
;
1382 /***********************************************************************
1383 * OLEClipbrd_UnInitialize()
1384 * Un-Initializes the OLE clipboard
1386 void OLEClipbrd_UnInitialize(void)
1388 ole_clipbrd
*clipbrd
= theOleClipboard
;
1394 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1395 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1397 if ( clipbrd
->window
)
1399 DestroyWindow(clipbrd
->window
);
1400 UnregisterClassW( clipbrd_wndclass
, hinst
);
1403 IStream_Release(clipbrd
->marshal_data
);
1404 HeapFree(GetProcessHeap(), 0, clipbrd
);
1405 theOleClipboard
= NULL
;
1409 /*********************************************************************
1410 * set_clipboard_formats
1412 * Enumerate all formats supported by the source and make
1413 * those formats available using delayed rendering using SetClipboardData.
1414 * Cache the enumeration list and make that list visibile as the
1415 * 'Ole Private Data' format on the clipboard.
1418 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1422 IEnumFORMATETC
*enum_fmt
;
1423 HGLOBAL priv_data_handle
;
1424 DWORD_PTR target_offset
;
1425 ole_priv_data
*priv_data
;
1426 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1428 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1429 if(FAILED(hr
)) return hr
;
1431 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1434 needed
+= sizeof(priv_data
->entries
[0]);
1437 needed
+= fmt
.ptd
->tdSize
;
1438 CoTaskMemFree(fmt
.ptd
);
1442 /* Windows pads the list with two empty ole_priv_data_entries, one
1443 * after the entries array and one after the target device data.
1444 * Allocating with zero init to zero these pads. */
1446 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1447 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1448 priv_data
= GlobalLock(priv_data_handle
);
1450 priv_data
->unk1
= 0;
1451 priv_data
->size
= needed
;
1452 priv_data
->unk2
= 1;
1453 priv_data
->count
= count
;
1454 priv_data
->unk3
[0] = 0;
1455 priv_data
->unk3
[1] = 0;
1457 IEnumFORMATETC_Reset(enum_fmt
);
1460 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1462 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1464 TRACE("%s\n", dump_fmtetc(&fmt
));
1466 priv_data
->entries
[idx
].fmtetc
= fmt
;
1469 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1470 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1471 target_offset
+= fmt
.ptd
->tdSize
;
1472 CoTaskMemFree(fmt
.ptd
);
1475 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1476 priv_data
->entries
[idx
].unk
[0] = 0;
1477 priv_data
->entries
[idx
].unk
[1] = 0;
1479 if (priv_data
->entries
[idx
].first_use
)
1480 SetClipboardData(fmt
.cfFormat
, NULL
);
1485 IEnumFORMATETC_Release(enum_fmt
);
1487 /* Cache the list and fixup any target device offsets to ptrs */
1488 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1489 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1490 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1491 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1492 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1494 GlobalUnlock(priv_data_handle
);
1495 SetClipboardData(ole_priv_data_clipboard_format
, priv_data_handle
);
1500 static HWND
create_clipbrd_window(void);
1502 /***********************************************************************
1503 * get_clipbrd_window
1505 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1507 if ( !clipbrd
->window
)
1508 clipbrd
->window
= create_clipbrd_window();
1510 *wnd
= clipbrd
->window
;
1511 return *wnd
? S_OK
: E_FAIL
;
1515 /**********************************************************************
1516 * release_marshal_data
1518 * Releases the data and sets the stream back to zero size.
1520 static inline void release_marshal_data(IStream
*stm
)
1523 ULARGE_INTEGER size
;
1524 pos
.QuadPart
= size
.QuadPart
= 0;
1526 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1527 CoReleaseMarshalData(stm
);
1528 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1529 IStream_SetSize(stm
, size
);
1532 /***********************************************************************
1533 * set_src_dataobject
1535 * Clears and sets the clipboard's src IDataObject.
1537 * To marshal the source dataobject we do something rather different from Windows.
1538 * We set a window prop which contains the marshalled data.
1539 * Windows set two props one of which is an IID, the other is an endpoint number.
1541 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1546 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1548 if(clipbrd
->src_data
)
1550 RemovePropW(wnd
, wine_marshal_dataobject
);
1551 release_marshal_data(clipbrd
->marshal_data
);
1553 IDataObject_Release(clipbrd
->src_data
);
1554 clipbrd
->src_data
= NULL
;
1555 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1556 clipbrd
->cached_enum
= NULL
;
1564 IDataObject_AddRef(data
);
1565 clipbrd
->src_data
= data
;
1567 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1568 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1569 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1570 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1571 if(FAILED(hr
)) return hr
;
1572 GetHGlobalFromStream(clipbrd
->marshal_data
, &h
);
1573 SetPropW(wnd
, wine_marshal_dataobject
, h
);
1574 hr
= set_clipboard_formats(clipbrd
, data
);
1579 /***********************************************************************
1582 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1584 ole_clipbrd
*clipbrd
;
1586 get_ole_clipbrd(&clipbrd
);
1590 case WM_RENDERFORMAT
:
1593 ole_priv_data_entry
*entry
;
1595 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
1596 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
1599 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
1604 case WM_RENDERALLFORMATS
:
1607 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
1609 TRACE("(): WM_RENDERALLFORMATS\n");
1611 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
1613 if(entries
[i
].first_use
)
1614 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
1619 case WM_DESTROYCLIPBOARD
:
1621 TRACE("(): WM_DESTROYCLIPBOARD\n");
1623 set_src_dataobject(clipbrd
, NULL
);
1628 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
1635 /***********************************************************************
1636 * create_clipbrd_window
1638 static HWND
create_clipbrd_window(void)
1641 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1642 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1643 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1645 class.cbSize
= sizeof(class);
1647 class.lpfnWndProc
= clipbrd_wndproc
;
1648 class.cbClsExtra
= 0;
1649 class.cbWndExtra
= 0;
1650 class.hInstance
= hinst
;
1653 class.hbrBackground
= 0;
1654 class.lpszMenuName
= NULL
;
1655 class.lpszClassName
= clipbrd_wndclass
;
1656 class.hIconSm
= NULL
;
1658 RegisterClassExW(&class);
1660 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
1661 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1662 NULL
, NULL
, hinst
, 0);
1665 /*********************************************************************
1666 * set_dataobject_format
1668 * Windows creates a 'DataObject' clipboard format that contains the
1669 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1671 static HRESULT
set_dataobject_format(HWND hwnd
)
1673 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
1676 if(!h
) return E_OUTOFMEMORY
;
1678 data
= GlobalLock(h
);
1682 if(!SetClipboardData(dataobject_clipboard_format
, h
))
1685 return CLIPBRD_E_CANT_SET
;
1691 /*---------------------------------------------------------------------*
1692 * Win32 OLE clipboard API
1693 *---------------------------------------------------------------------*/
1695 /***********************************************************************
1696 * OleSetClipboard [OLE32.@]
1697 * Places a pointer to the specified data object onto the clipboard,
1698 * making the data object accessible to the OleGetClipboard function.
1702 * S_OK IDataObject pointer placed on the clipboard
1703 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1704 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1705 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1706 * CLIPBRD_E_CANT_SET SetClipboard failed
1709 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
1712 ole_clipbrd
*clipbrd
;
1715 TRACE("(%p)\n", data
);
1717 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1719 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1721 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
1723 if ( !EmptyClipboard() )
1725 hr
= CLIPBRD_E_CANT_EMPTY
;
1729 hr
= set_src_dataobject(clipbrd
, data
);
1730 if(FAILED(hr
)) goto end
;
1733 hr
= set_dataobject_format(wnd
);
1737 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1741 set_src_dataobject(clipbrd
, NULL
);
1748 /***********************************************************************
1749 * OleGetClipboard [OLE32.@]
1750 * Returns a pointer to our internal IDataObject which represents the conceptual
1751 * state of the Windows clipboard. If the current clipboard already contains
1752 * an IDataObject, our internal IDataObject will delegate to this object.
1754 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
1757 ole_clipbrd
*clipbrd
;
1760 TRACE("(%p)\n", obj
);
1762 if(!obj
) return E_INVALIDARG
;
1764 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1766 seq_no
= GetClipboardSequenceNumber();
1767 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
1768 clipbrd
->latest_snapshot
= NULL
;
1770 if(!clipbrd
->latest_snapshot
)
1772 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
1773 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
1776 *obj
= (IDataObject
*)&clipbrd
->latest_snapshot
->lpVtbl
;
1777 IDataObject_AddRef(*obj
);
1782 /******************************************************************************
1783 * OleFlushClipboard [OLE32.@]
1784 * Renders the data from the source IDataObject into the windows clipboard
1786 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1787 * by copying the storage into global memory. Subsequently the default
1788 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1789 * back to TYMED_IStorage.
1791 HRESULT WINAPI
OleFlushClipboard(void)
1794 ole_clipbrd
*clipbrd
;
1799 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1801 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1804 * Already flushed or no source DataObject? Nothing to do.
1806 if (!clipbrd
->src_data
) return S_OK
;
1808 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
1810 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
1812 hr
= set_dataobject_format(NULL
);
1814 set_src_dataobject(clipbrd
, NULL
);
1816 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1822 /***********************************************************************
1823 * OleIsCurrentClipboard [OLE32.@]
1825 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
1828 ole_clipbrd
*clipbrd
;
1831 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1833 if (data
== NULL
) return S_FALSE
;
1835 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;