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 /************************************************************************
1069 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1072 snapshot
*This
= impl_from_IDataObject(iface
);
1075 ole_priv_data
*enum_data
= NULL
;
1076 ole_priv_data_entry
*entry
;
1079 TRACE("(%p,%p,%p)\n", iface
, fmt
, med
);
1081 if ( !fmt
|| !med
) return E_INVALIDARG
;
1083 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1086 hr
= get_current_dataobject(&This
->data
);
1090 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1095 h
= GetClipboardData(fmt
->cfFormat
);
1098 hr
= DV_E_FORMATETC
;
1102 hr
= get_priv_data(&enum_data
);
1103 if(FAILED(hr
)) goto end
;
1105 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1108 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1109 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1111 else /* non-Ole format */
1112 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1114 if(mask
& TYMED_ISTORAGE
)
1115 hr
= get_stgmed_for_storage(h
, med
);
1116 else if(mask
& TYMED_HGLOBAL
)
1117 hr
= get_stgmed_for_global(h
, med
);
1118 else if(mask
& TYMED_ISTREAM
)
1119 hr
= get_stgmed_for_stream(h
, med
);
1122 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry
->fmtetc
.tymed
, fmt
->tymed
);
1128 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1132 /************************************************************************
1133 * snapshot_GetDataHere
1135 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1138 FIXME("(%p, %p, %p): stub\n", iface
, fmt
, med
);
1142 /************************************************************************
1143 * snapshot_QueryGetData
1145 * The OLE Clipboard's implementation of this method delegates to
1146 * a data source if there is one or wraps around the windows clipboard
1147 * function IsClipboardFormatAvailable() otherwise.
1150 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1152 FIXME("(%p, %p)\n", iface
, fmt
);
1154 if (!fmt
) return E_INVALIDARG
;
1156 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1158 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1160 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1163 /************************************************************************
1164 * snapshot_GetCanonicalFormatEtc
1166 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1169 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1171 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1174 return DATA_S_SAMEFORMATETC
;
1177 /************************************************************************
1180 * The OLE Clipboard does not implement this method
1182 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1183 STGMEDIUM
*med
, BOOL release
)
1185 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1189 /************************************************************************
1190 * snapshot_EnumFormatEtc
1193 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1194 IEnumFORMATETC
**enum_fmt
)
1197 ole_priv_data
*data
= NULL
;
1199 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1203 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1204 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1206 hr
= get_priv_data(&data
);
1208 if(FAILED(hr
)) goto end
;
1210 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1213 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1217 /************************************************************************
1220 * The OLE Clipboard does not implement this method
1222 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1223 DWORD flags
, IAdviseSink
*sink
,
1226 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1230 /************************************************************************
1231 * snapshot_DUnadvise
1233 * The OLE Clipboard does not implement this method
1235 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1237 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1241 /************************************************************************
1242 * snapshot_EnumDAdvise
1244 * The OLE Clipboard does not implement this method
1246 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1247 IEnumSTATDATA
** enum_advise
)
1249 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1253 static const IDataObjectVtbl snapshot_vtable
=
1255 snapshot_QueryInterface
,
1259 snapshot_GetDataHere
,
1260 snapshot_QueryGetData
,
1261 snapshot_GetCanonicalFormatEtc
,
1263 snapshot_EnumFormatEtc
,
1266 snapshot_EnumDAdvise
1269 /*---------------------------------------------------------------------*
1270 * Internal implementation methods for the OLE clipboard
1271 *---------------------------------------------------------------------*/
1273 static snapshot
*snapshot_construct(DWORD seq_no
)
1277 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1278 if (!This
) return NULL
;
1280 This
->lpVtbl
= &snapshot_vtable
;
1282 This
->seq_no
= seq_no
;
1288 /*********************************************************
1289 * register_clipboard_formats
1291 static void register_clipboard_formats(void)
1293 static const WCHAR DataObjectW
[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1294 static const WCHAR OlePrivateDataW
[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1295 static const WCHAR EmbedSourceW
[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1297 if(!dataobject_clipboard_format
)
1298 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObjectW
);
1299 if(!ole_priv_data_clipboard_format
)
1300 ole_priv_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateDataW
);
1301 if(!embed_source_clipboard_format
)
1302 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSourceW
);
1305 /***********************************************************************
1306 * OLEClipbrd_Initialize()
1307 * Initializes the OLE clipboard.
1309 void OLEClipbrd_Initialize(void)
1311 register_clipboard_formats();
1313 if ( !theOleClipboard
)
1315 ole_clipbrd
* clipbrd
;
1320 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1321 if (!clipbrd
) return;
1323 clipbrd
->latest_snapshot
= NULL
;
1324 clipbrd
->window
= NULL
;
1325 clipbrd
->src_data
= NULL
;
1326 clipbrd
->cached_enum
= NULL
;
1328 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1331 HeapFree(GetProcessHeap(), 0, clipbrd
);
1335 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1338 HeapFree(GetProcessHeap(), 0, clipbrd
);
1342 theOleClipboard
= clipbrd
;
1346 /***********************************************************************
1347 * OLEClipbrd_UnInitialize()
1348 * Un-Initializes the OLE clipboard
1350 void OLEClipbrd_UnInitialize(void)
1352 ole_clipbrd
*clipbrd
= theOleClipboard
;
1358 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1359 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1361 if ( clipbrd
->window
)
1363 DestroyWindow(clipbrd
->window
);
1364 UnregisterClassW( clipbrd_wndclass
, hinst
);
1367 IStream_Release(clipbrd
->marshal_data
);
1368 HeapFree(GetProcessHeap(), 0, clipbrd
);
1369 theOleClipboard
= NULL
;
1373 /*********************************************************************
1374 * set_clipboard_formats
1376 * Enumerate all formats supported by the source and make
1377 * those formats available using delayed rendering using SetClipboardData.
1378 * Cache the enumeration list and make that list visibile as the
1379 * 'Ole Private Data' format on the clipboard.
1382 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1386 IEnumFORMATETC
*enum_fmt
;
1387 HGLOBAL priv_data_handle
;
1388 DWORD_PTR target_offset
;
1389 ole_priv_data
*priv_data
;
1390 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1392 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1393 if(FAILED(hr
)) return hr
;
1395 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1398 needed
+= sizeof(priv_data
->entries
[0]);
1401 needed
+= fmt
.ptd
->tdSize
;
1402 CoTaskMemFree(fmt
.ptd
);
1406 /* Windows pads the list with two empty ole_priv_data_entries, one
1407 * after the entries array and one after the target device data.
1408 * Allocating with zero init to zero these pads. */
1410 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1411 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1412 priv_data
= GlobalLock(priv_data_handle
);
1414 priv_data
->unk1
= 0;
1415 priv_data
->size
= needed
;
1416 priv_data
->unk2
= 1;
1417 priv_data
->count
= count
;
1418 priv_data
->unk3
[0] = 0;
1419 priv_data
->unk3
[1] = 0;
1421 IEnumFORMATETC_Reset(enum_fmt
);
1424 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1426 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1428 TRACE("%s\n", dump_fmtetc(&fmt
));
1430 priv_data
->entries
[idx
].fmtetc
= fmt
;
1433 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1434 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1435 target_offset
+= fmt
.ptd
->tdSize
;
1436 CoTaskMemFree(fmt
.ptd
);
1439 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1440 priv_data
->entries
[idx
].unk
[0] = 0;
1441 priv_data
->entries
[idx
].unk
[1] = 0;
1443 if (priv_data
->entries
[idx
].first_use
)
1444 SetClipboardData(fmt
.cfFormat
, NULL
);
1449 IEnumFORMATETC_Release(enum_fmt
);
1451 /* Cache the list and fixup any target device offsets to ptrs */
1452 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1453 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1454 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1455 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1456 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1458 GlobalUnlock(priv_data_handle
);
1459 SetClipboardData(ole_priv_data_clipboard_format
, priv_data_handle
);
1464 static HWND
create_clipbrd_window(void);
1466 /***********************************************************************
1467 * get_clipbrd_window
1469 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1471 if ( !clipbrd
->window
)
1472 clipbrd
->window
= create_clipbrd_window();
1474 *wnd
= clipbrd
->window
;
1475 return *wnd
? S_OK
: E_FAIL
;
1479 /**********************************************************************
1480 * release_marshal_data
1482 * Releases the data and sets the stream back to zero size.
1484 static inline void release_marshal_data(IStream
*stm
)
1487 ULARGE_INTEGER size
;
1488 pos
.QuadPart
= size
.QuadPart
= 0;
1490 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1491 CoReleaseMarshalData(stm
);
1492 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1493 IStream_SetSize(stm
, size
);
1496 /***********************************************************************
1497 * set_src_dataobject
1499 * Clears and sets the clipboard's src IDataObject.
1501 * To marshal the source dataobject we do something rather different from Windows.
1502 * We set a window prop which contains the marshalled data.
1503 * Windows set two props one of which is an IID, the other is an endpoint number.
1505 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1510 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1512 if(clipbrd
->src_data
)
1514 RemovePropW(wnd
, wine_marshal_dataobject
);
1515 release_marshal_data(clipbrd
->marshal_data
);
1517 IDataObject_Release(clipbrd
->src_data
);
1518 clipbrd
->src_data
= NULL
;
1519 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1520 clipbrd
->cached_enum
= NULL
;
1528 IDataObject_AddRef(data
);
1529 clipbrd
->src_data
= data
;
1531 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1532 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1533 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1534 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1535 if(FAILED(hr
)) return hr
;
1536 GetHGlobalFromStream(clipbrd
->marshal_data
, &h
);
1537 SetPropW(wnd
, wine_marshal_dataobject
, h
);
1538 hr
= set_clipboard_formats(clipbrd
, data
);
1543 /***********************************************************************
1546 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1548 ole_clipbrd
*clipbrd
;
1550 get_ole_clipbrd(&clipbrd
);
1554 case WM_RENDERFORMAT
:
1557 ole_priv_data_entry
*entry
;
1559 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
1560 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
1563 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
1568 case WM_RENDERALLFORMATS
:
1571 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
1573 TRACE("(): WM_RENDERALLFORMATS\n");
1575 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
1577 if(entries
[i
].first_use
)
1578 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
1583 case WM_DESTROYCLIPBOARD
:
1585 TRACE("(): WM_DESTROYCLIPBOARD\n");
1587 set_src_dataobject(clipbrd
, NULL
);
1592 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
1599 /***********************************************************************
1600 * create_clipbrd_window
1602 static HWND
create_clipbrd_window(void)
1605 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1606 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1607 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1609 class.cbSize
= sizeof(class);
1611 class.lpfnWndProc
= clipbrd_wndproc
;
1612 class.cbClsExtra
= 0;
1613 class.cbWndExtra
= 0;
1614 class.hInstance
= hinst
;
1617 class.hbrBackground
= 0;
1618 class.lpszMenuName
= NULL
;
1619 class.lpszClassName
= clipbrd_wndclass
;
1620 class.hIconSm
= NULL
;
1622 RegisterClassExW(&class);
1624 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
1625 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1626 NULL
, NULL
, hinst
, 0);
1629 /*********************************************************************
1630 * set_dataobject_format
1632 * Windows creates a 'DataObject' clipboard format that contains the
1633 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1635 static HRESULT
set_dataobject_format(HWND hwnd
)
1637 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
1640 if(!h
) return E_OUTOFMEMORY
;
1642 data
= GlobalLock(h
);
1646 if(!SetClipboardData(dataobject_clipboard_format
, h
))
1649 return CLIPBRD_E_CANT_SET
;
1655 /*---------------------------------------------------------------------*
1656 * Win32 OLE clipboard API
1657 *---------------------------------------------------------------------*/
1659 /***********************************************************************
1660 * OleSetClipboard [OLE32.@]
1661 * Places a pointer to the specified data object onto the clipboard,
1662 * making the data object accessible to the OleGetClipboard function.
1666 * S_OK IDataObject pointer placed on the clipboard
1667 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1668 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1669 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1670 * CLIPBRD_E_CANT_SET SetClipboard failed
1673 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
1676 ole_clipbrd
*clipbrd
;
1679 TRACE("(%p)\n", data
);
1681 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1683 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1685 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
1687 if ( !EmptyClipboard() )
1689 hr
= CLIPBRD_E_CANT_EMPTY
;
1693 hr
= set_src_dataobject(clipbrd
, data
);
1694 if(FAILED(hr
)) goto end
;
1696 hr
= set_dataobject_format(wnd
);
1700 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1704 set_src_dataobject(clipbrd
, NULL
);
1711 /***********************************************************************
1712 * OleGetClipboard [OLE32.@]
1713 * Returns a pointer to our internal IDataObject which represents the conceptual
1714 * state of the Windows clipboard. If the current clipboard already contains
1715 * an IDataObject, our internal IDataObject will delegate to this object.
1717 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
1720 ole_clipbrd
*clipbrd
;
1723 TRACE("(%p)\n", obj
);
1725 if(!obj
) return E_INVALIDARG
;
1727 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1729 seq_no
= GetClipboardSequenceNumber();
1730 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
1731 clipbrd
->latest_snapshot
= NULL
;
1733 if(!clipbrd
->latest_snapshot
)
1735 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
1736 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
1739 *obj
= (IDataObject
*)&clipbrd
->latest_snapshot
->lpVtbl
;
1740 IDataObject_AddRef(*obj
);
1745 /******************************************************************************
1746 * OleFlushClipboard [OLE32.@]
1747 * Renders the data from the source IDataObject into the windows clipboard
1749 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1750 * by copying the storage into global memory. Subsequently the default
1751 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1752 * back to TYMED_IStorage.
1754 HRESULT WINAPI
OleFlushClipboard(void)
1757 ole_clipbrd
*clipbrd
;
1762 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1764 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1767 * Already flushed or no source DataObject? Nothing to do.
1769 if (!clipbrd
->src_data
) return S_OK
;
1771 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
1773 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
1775 hr
= set_dataobject_format(NULL
);
1777 set_src_dataobject(clipbrd
, NULL
);
1779 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1785 /***********************************************************************
1786 * OleIsCurrentClipboard [OLE32.@]
1788 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
1791 ole_clipbrd
*clipbrd
;
1794 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1796 if (data
== NULL
) return S_FALSE
;
1798 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;