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 static UINT dataobject_clipboard_format
;
200 static UINT ole_priv_data_clipboard_format
;
201 static UINT embed_source_clipboard_format
;
203 static inline char *dump_fmtetc(FORMATETC
*fmt
)
205 static char buf
[100];
207 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
208 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
212 /*---------------------------------------------------------------------*
213 * Implementation of the internal IEnumFORMATETC interface returned by
214 * the OLE clipboard's IDataObject.
215 *---------------------------------------------------------------------*/
217 typedef struct enum_fmtetc
219 const IEnumFORMATETCVtbl
*lpVtbl
;
222 UINT pos
; /* current enumerator position */
226 static inline enum_fmtetc
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
228 return (enum_fmtetc
*)((char*)iface
- FIELD_OFFSET(enum_fmtetc
, lpVtbl
));
231 /************************************************************************
232 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
234 * See Windows documentation for more details on IUnknown methods.
236 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
237 (LPENUMFORMATETC iface
, REFIID riid
, LPVOID
* ppvObj
)
239 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
241 TRACE("(%p)->(IID: %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
245 if(IsEqualIID(riid
, &IID_IUnknown
) ||
246 IsEqualIID(riid
, &IID_IEnumFORMATETC
))
253 IEnumFORMATETC_AddRef((IEnumFORMATETC
*)*ppvObj
);
254 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
258 TRACE("-- Interface: E_NOINTERFACE\n");
259 return E_NOINTERFACE
;
262 /************************************************************************
263 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
266 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface
)
268 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
269 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
271 return InterlockedIncrement(&This
->ref
);
274 /************************************************************************
275 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
277 * See Windows documentation for more details on IUnknown methods.
279 static ULONG WINAPI
OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface
)
281 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
284 TRACE("(%p)->(count=%u)\n",This
, This
->ref
);
286 ref
= InterlockedDecrement(&This
->ref
);
289 TRACE("() - destroying IEnumFORMATETC(%p)\n",This
);
290 HeapFree(GetProcessHeap(), 0, This
->data
);
291 HeapFree(GetProcessHeap(), 0, This
);
296 /************************************************************************
297 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
299 * Standard enumerator members for IEnumFORMATETC
301 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
302 (LPENUMFORMATETC iface
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFethed
)
304 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
306 HRESULT hres
= S_FALSE
;
308 TRACE("(%p)->(pos=%u)\n", This
, This
->pos
);
310 if (This
->pos
< This
->data
->count
)
312 cfetch
= This
->data
->count
- This
->pos
;
319 for(i
= 0; i
< cfetch
; i
++)
321 rgelt
[i
] = This
->data
->entries
[This
->pos
++].fmtetc
;
324 DVTARGETDEVICE
*target
= rgelt
[i
].ptd
;
325 rgelt
[i
].ptd
= CoTaskMemAlloc(target
->tdSize
);
326 if(!rgelt
[i
].ptd
) return E_OUTOFMEMORY
;
327 memcpy(rgelt
[i
].ptd
, target
, target
->tdSize
);
338 *pceltFethed
= cfetch
;
344 /************************************************************************
345 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
347 * Standard enumerator members for IEnumFORMATETC
349 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface
, ULONG celt
)
351 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
352 TRACE("(%p)->(num=%u)\n", This
, celt
);
355 if (This
->pos
> This
->data
->count
)
357 This
->pos
= This
->data
->count
;
363 /************************************************************************
364 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
366 * Standard enumerator members for IEnumFORMATETC
368 static HRESULT WINAPI
OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface
)
370 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
371 TRACE("(%p)->()\n", This
);
377 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
);
379 /************************************************************************
380 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
382 * Standard enumerator members for IEnumFORMATETC
384 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
385 (LPENUMFORMATETC iface
, LPENUMFORMATETC
* obj
)
387 enum_fmtetc
*This
= impl_from_IEnumFORMATETC(iface
);
388 ole_priv_data
*new_data
;
391 TRACE("(%p)->(%p)\n", This
, obj
);
393 if ( !obj
) return E_INVALIDARG
;
396 new_data
= HeapAlloc(GetProcessHeap(), 0, This
->data
->size
);
397 if(!new_data
) return E_OUTOFMEMORY
;
398 memcpy(new_data
, This
->data
, This
->data
->size
);
400 /* Fixup any target device ptrs */
401 for(i
= 0; i
< This
->data
->count
; i
++)
402 new_data
->entries
[i
].fmtetc
.ptd
=
403 td_offs_to_ptr(new_data
, td_get_offs(This
->data
, i
));
405 return enum_fmtetc_construct(new_data
, This
->pos
, obj
);
408 static const IEnumFORMATETCVtbl efvt
=
410 OLEClipbrd_IEnumFORMATETC_QueryInterface
,
411 OLEClipbrd_IEnumFORMATETC_AddRef
,
412 OLEClipbrd_IEnumFORMATETC_Release
,
413 OLEClipbrd_IEnumFORMATETC_Next
,
414 OLEClipbrd_IEnumFORMATETC_Skip
,
415 OLEClipbrd_IEnumFORMATETC_Reset
,
416 OLEClipbrd_IEnumFORMATETC_Clone
419 /************************************************************************
420 * enum_fmtetc_construct
422 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
424 static HRESULT
enum_fmtetc_construct(ole_priv_data
*data
, UINT pos
, IEnumFORMATETC
**obj
)
429 ef
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ef
));
430 if (!ef
) return E_OUTOFMEMORY
;
437 TRACE("(%p)->()\n", ef
);
438 *obj
= (IEnumFORMATETC
*)ef
;
442 /***********************************************************************
445 * Helper method to duplicate an HGLOBAL chunk of memory
447 static HRESULT
dup_global_mem( HGLOBAL src
, DWORD flags
, HGLOBAL
*dst
)
449 void *src_ptr
, *dst_ptr
;
453 if ( !src
) return S_FALSE
;
455 size
= GlobalSize(src
);
457 *dst
= GlobalAlloc( flags
, size
);
458 if ( !*dst
) return E_OUTOFMEMORY
;
460 src_ptr
= GlobalLock(src
);
461 dst_ptr
= GlobalLock(*dst
);
463 memcpy(dst_ptr
, src_ptr
, size
);
471 /************************************************************
472 * render_embed_source_hack
474 * This is clearly a hack and has no place in the clipboard code.
477 static HRESULT
render_embed_source_hack(IDataObject
*data
, LPFORMATETC fmt
)
480 HGLOBAL hStorage
= 0;
482 ILockBytes
*ptrILockBytes
;
484 memset(&std
, 0, sizeof(STGMEDIUM
));
485 std
.tymed
= fmt
->tymed
= TYMED_ISTORAGE
;
487 hStorage
= GlobalAlloc(GMEM_SHARE
|GMEM_MOVEABLE
, 0);
488 if (hStorage
== NULL
) return E_OUTOFMEMORY
;
489 hr
= CreateILockBytesOnHGlobal(hStorage
, FALSE
, &ptrILockBytes
);
490 hr
= StgCreateDocfileOnILockBytes(ptrILockBytes
, STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &std
.u
.pstg
);
491 ILockBytes_Release(ptrILockBytes
);
493 if (FAILED(hr
= IDataObject_GetDataHere(theOleClipboard
->src_data
, fmt
, &std
)))
495 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr
);
496 GlobalFree(hStorage
);
500 if (1) /* check whether the presentation data is already -not- present */
504 METAFILEPICT
*mfp
= 0;
506 fmt2
.cfFormat
= CF_METAFILEPICT
;
508 fmt2
.dwAspect
= DVASPECT_CONTENT
;
510 fmt2
.tymed
= TYMED_MFPICT
;
512 memset(&std2
, 0, sizeof(STGMEDIUM
));
513 std2
.tymed
= TYMED_MFPICT
;
515 /* Get the metafile picture out of it */
517 if (SUCCEEDED(hr
= IDataObject_GetData(theOleClipboard
->src_data
, &fmt2
, &std2
)))
519 mfp
= GlobalLock(std2
.u
.hGlobal
);
524 OLECHAR name
[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
525 IStream
*pStream
= 0;
527 PresentationDataHeader pdh
;
531 CHAR strOleTypeName
[51];
532 BYTE OlePresStreamHeader
[] =
534 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
535 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
536 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x00, 0x00
540 nSize
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
542 memset(&pdh
, 0, sizeof(PresentationDataHeader
));
543 memcpy(&pdh
, OlePresStreamHeader
, sizeof(OlePresStreamHeader
));
545 pdh
.dwObjectExtentX
= mfp
->xExt
;
546 pdh
.dwObjectExtentY
= mfp
->yExt
;
549 hr
= IStorage_CreateStream(std
.u
.pstg
, name
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, 0, &pStream
);
551 hr
= IStream_Write(pStream
, &pdh
, sizeof(PresentationDataHeader
), NULL
);
553 mfBits
= HeapAlloc(GetProcessHeap(), 0, nSize
);
554 nSize
= GetMetaFileBitsEx(mfp
->hMF
, nSize
, mfBits
);
556 hr
= IStream_Write(pStream
, mfBits
, nSize
, NULL
);
558 IStream_Release(pStream
);
560 HeapFree(GetProcessHeap(), 0, mfBits
);
562 GlobalUnlock(std2
.u
.hGlobal
);
563 ReleaseStgMedium(&std2
);
565 ReadClassStg(std
.u
.pstg
, &clsID
);
566 ProgIDFromCLSID(&clsID
, &strProgID
);
568 WideCharToMultiByte( CP_ACP
, 0, strProgID
, -1, strOleTypeName
, sizeof(strOleTypeName
), NULL
, NULL
);
569 OLECONVERT_CreateOleStream(std
.u
.pstg
);
570 OLECONVERT_CreateCompObjStream(std
.u
.pstg
, strOleTypeName
);
574 if ( !SetClipboardData( fmt
->cfFormat
, hStorage
) )
576 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
577 GlobalFree(hStorage
);
578 hr
= CLIPBRD_E_CANT_SET
;
581 ReleaseStgMedium(&std
);
585 /************************************************************************
586 * find_format_in_list
588 * Returns the first entry that matches the provided clipboard format.
590 static inline ole_priv_data_entry
*find_format_in_list(ole_priv_data_entry
*entries
, DWORD num
, UINT cf
)
593 for(i
= 0; i
< num
; i
++)
594 if(entries
[i
].fmtetc
.cfFormat
== cf
)
600 /***************************************************************************
601 * get_data_from_storage
603 * Returns storage data in an HGLOBAL.
605 static HRESULT
get_data_from_storage(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
616 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
617 if(!h
) return E_OUTOFMEMORY
;
619 hr
= CreateILockBytesOnHGlobal(h
, FALSE
, &lbs
);
622 hr
= StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
623 ILockBytes_Release(lbs
);
632 med
.tymed
= stg_fmt
.tymed
= TYMED_ISTORAGE
;
634 med
.pUnkForRelease
= NULL
;
636 hr
= IDataObject_GetDataHere(data
, &stg_fmt
, &med
);
640 hr
= IDataObject_GetData(data
, &stg_fmt
, &med
);
641 if(FAILED(hr
)) goto end
;
643 hr
= IStorage_CopyTo(med
.u
.pstg
, 0, NULL
, NULL
, stg
);
644 ReleaseStgMedium(&med
);
645 if(FAILED(hr
)) goto end
;
650 IStorage_Release(stg
);
651 if(FAILED(hr
)) GlobalFree(h
);
655 /***************************************************************************
656 * get_data_from_stream
658 * Returns stream data in an HGLOBAL.
660 static HRESULT
get_data_from_stream(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
670 h
= GlobalAlloc( GMEM_DDESHARE
|GMEM_MOVEABLE
, 0 );
671 if(!h
) return E_OUTOFMEMORY
;
673 hr
= CreateStreamOnHGlobal(h
, FALSE
, &stm
);
674 if(FAILED(hr
)) goto error
;
677 med
.tymed
= stm_fmt
.tymed
= TYMED_ISTREAM
;
679 med
.pUnkForRelease
= NULL
;
681 hr
= IDataObject_GetDataHere(data
, &stm_fmt
, &med
);
688 hr
= IDataObject_GetData(data
, &stm_fmt
, &med
);
689 if(FAILED(hr
)) goto error
;
692 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_CUR
, &pos
);
693 IStream_Seek(med
.u
.pstm
, offs
, STREAM_SEEK_SET
, NULL
);
694 hr
= IStream_CopyTo(med
.u
.pstm
, stm
, pos
, NULL
, NULL
);
695 ReleaseStgMedium(&med
);
696 if(FAILED(hr
)) goto error
;
699 IStream_Release(stm
);
703 if(stm
) IStream_Release(stm
);
708 /***************************************************************************
709 * get_data_from_global
711 * Returns global data in an HGLOBAL.
713 static HRESULT
get_data_from_global(IDataObject
*data
, FORMATETC
*fmt
, HGLOBAL
*mem
)
723 mem_fmt
.tymed
= TYMED_HGLOBAL
;
725 hr
= IDataObject_GetData(data
, &mem_fmt
, &med
);
726 if(FAILED(hr
)) return hr
;
728 hr
= dup_global_mem(med
.u
.hGlobal
, GMEM_DDESHARE
|GMEM_MOVEABLE
, &h
);
730 if(SUCCEEDED(hr
)) *mem
= h
;
732 ReleaseStgMedium(&med
);
737 /***********************************************************************
740 * Render the clipboard data. Note that this call will delegate to the
741 * source data object.
743 static HRESULT
render_format(IDataObject
*data
, LPFORMATETC fmt
)
745 HGLOBAL clip_data
= NULL
;
748 /* Embed source hack */
749 if(fmt
->cfFormat
== embed_source_clipboard_format
)
751 return render_embed_source_hack(data
, fmt
);
754 if(fmt
->tymed
& TYMED_ISTORAGE
)
756 hr
= get_data_from_storage(data
, fmt
, &clip_data
);
758 else if(fmt
->tymed
& TYMED_ISTREAM
)
760 hr
= get_data_from_stream(data
, fmt
, &clip_data
);
762 else if(fmt
->tymed
& TYMED_HGLOBAL
)
764 hr
= get_data_from_global(data
, fmt
, &clip_data
);
768 FIXME("Unhandled tymed %x\n", fmt
->tymed
);
774 if ( !SetClipboardData(fmt
->cfFormat
, clip_data
) )
776 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
777 GlobalFree(clip_data
);
778 hr
= CLIPBRD_E_CANT_SET
;
785 /*---------------------------------------------------------------------*
786 * Implementation of the internal IDataObject interface exposed by
788 *---------------------------------------------------------------------*/
791 /************************************************************************
792 * snapshot_QueryInterface
794 static HRESULT WINAPI
snapshot_QueryInterface(IDataObject
*iface
,
795 REFIID riid
, void **ppvObject
)
797 snapshot
*This
= impl_from_IDataObject(iface
);
798 TRACE("(%p)->(IID:%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
800 if ( (This
==0) || (ppvObject
==0) )
805 if (IsEqualIID(&IID_IUnknown
, riid
) ||
806 IsEqualIID(&IID_IDataObject
, riid
))
812 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
813 return E_NOINTERFACE
;
816 IUnknown_AddRef((IUnknown
*)*ppvObject
);
821 /************************************************************************
824 static ULONG WINAPI
snapshot_AddRef(IDataObject
*iface
)
826 snapshot
*This
= impl_from_IDataObject(iface
);
828 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
830 return InterlockedIncrement(&This
->ref
);
833 /************************************************************************
836 static ULONG WINAPI
snapshot_Release(IDataObject
*iface
)
838 snapshot
*This
= impl_from_IDataObject(iface
);
841 TRACE("(%p)->(count=%u)\n", This
, This
->ref
);
843 ref
= InterlockedDecrement(&This
->ref
);
847 ole_clipbrd
*clipbrd
;
848 HRESULT hr
= get_ole_clipbrd(&clipbrd
);
850 if(This
->data
) IDataObject_Release(This
->data
);
852 if(SUCCEEDED(hr
) && clipbrd
->latest_snapshot
== This
)
853 clipbrd
->latest_snapshot
= NULL
;
854 HeapFree(GetProcessHeap(), 0, This
);
860 /************************************************************
861 * get_current_ole_clip_window
863 * Return the window that owns the ole clipboard.
865 * If the clipboard is flushed or not owned by ole this will
868 static HWND
get_current_ole_clip_window(void)
873 h
= GetClipboardData(dataobject_clipboard_format
);
876 if(!ptr
) return NULL
;
882 /************************************************************
883 * get_current_dataobject
885 * Return an unmarshalled IDataObject if there is a current
886 * (ie non-flushed) object on the ole clipboard.
888 static HRESULT
get_current_dataobject(IDataObject
**data
)
890 HRESULT hr
= S_FALSE
;
891 HWND wnd
= get_current_ole_clip_window();
898 if(!wnd
) return S_FALSE
;
900 h
= GetPropW(wnd
, wine_marshal_dataobject
);
901 if(!h
) return S_FALSE
;
903 if(!ptr
) return S_FALSE
;
905 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stm
);
906 if(FAILED(hr
)) goto end
;
908 hr
= IStream_Write(stm
, ptr
, GlobalSize(h
), NULL
);
912 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
913 hr
= CoUnmarshalInterface(stm
, &IID_IDataObject
, (void**)data
);
915 IStream_Release(stm
);
922 static DWORD
get_tymed_from_nonole_cf(UINT cf
)
924 if(cf
>= 0xc000) return TYMED_ISTREAM
| TYMED_HGLOBAL
;
931 return TYMED_ISTREAM
| TYMED_HGLOBAL
;
934 case CF_METAFILEPICT
:
937 FIXME("returning TYMED_NULL for cf %04x\n", cf
);
942 /***********************************************************
945 * Returns a copy of the Ole Private Data
947 static HRESULT
get_priv_data(ole_priv_data
**data
)
951 ole_priv_data
*ret
= NULL
;
955 handle
= GetClipboardData( ole_priv_data_clipboard_format
);
958 ole_priv_data
*src
= GlobalLock(handle
);
963 /* FIXME: sanity check on size */
964 ret
= HeapAlloc(GetProcessHeap(), 0, src
->size
);
967 GlobalUnlock(handle
);
968 return E_OUTOFMEMORY
;
970 memcpy(ret
, src
, src
->size
);
971 GlobalUnlock(handle
);
973 /* Fixup any target device offsets to ptrs */
974 for(i
= 0; i
< ret
->count
; i
++)
975 ret
->entries
[i
].fmtetc
.ptd
=
976 td_offs_to_ptr(ret
, (DWORD_PTR
) ret
->entries
[i
].fmtetc
.ptd
);
980 if(!ret
) /* Non-ole data */
983 DWORD count
= 0, idx
, size
= FIELD_OFFSET(ole_priv_data
, entries
);
985 for(cf
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; count
++)
988 GetClipboardFormatNameA(cf
, buf
, sizeof(buf
));
989 TRACE("\tcf %04x %s\n", cf
, buf
);
992 TRACE("count %d\n", count
);
993 size
+= count
* sizeof(ret
->entries
[0]);
995 /* There are holes in fmtetc so zero init */
996 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
997 if(!ret
) return E_OUTOFMEMORY
;
1001 for(cf
= 0, idx
= 0; (cf
= EnumClipboardFormats(cf
)) != 0; idx
++)
1003 ret
->entries
[idx
].fmtetc
.cfFormat
= cf
;
1004 ret
->entries
[idx
].fmtetc
.ptd
= NULL
;
1005 ret
->entries
[idx
].fmtetc
.dwAspect
= DVASPECT_CONTENT
;
1006 ret
->entries
[idx
].fmtetc
.lindex
= -1;
1007 ret
->entries
[idx
].fmtetc
.tymed
= get_tymed_from_nonole_cf(cf
);
1008 ret
->entries
[idx
].first_use
= 1;
1016 /************************************************************************
1017 * get_stgmed_for_global
1019 * Returns a stg medium with a copy of the global handle
1021 static HRESULT
get_stgmed_for_global(HGLOBAL h
, STGMEDIUM
*med
)
1025 med
->pUnkForRelease
= NULL
;
1026 med
->tymed
= TYMED_NULL
;
1028 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &med
->u
.hGlobal
);
1030 if(SUCCEEDED(hr
)) med
->tymed
= TYMED_HGLOBAL
;
1035 /************************************************************************
1036 * get_stgmed_for_stream
1038 * Returns a stg medium with a stream based on the handle
1040 static HRESULT
get_stgmed_for_stream(HGLOBAL h
, STGMEDIUM
*med
)
1045 med
->pUnkForRelease
= NULL
;
1046 med
->tymed
= TYMED_NULL
;
1048 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1049 if(FAILED(hr
)) return hr
;
1051 hr
= CreateStreamOnHGlobal(dst
, TRUE
, &med
->u
.pstm
);
1058 med
->tymed
= TYMED_ISTREAM
;
1062 /************************************************************************
1063 * get_stgmed_for_storage
1065 * Returns a stg medium with a storage based on the handle
1067 static HRESULT
get_stgmed_for_storage(HGLOBAL h
, STGMEDIUM
*med
)
1073 med
->pUnkForRelease
= NULL
;
1074 med
->tymed
= TYMED_NULL
;
1076 hr
= dup_global_mem(h
, GMEM_MOVEABLE
, &dst
);
1077 if(FAILED(hr
)) return hr
;
1079 hr
= CreateILockBytesOnHGlobal(dst
, TRUE
, &lbs
);
1086 hr
= StgOpenStorageOnILockBytes(lbs
, NULL
, STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
, NULL
, 0, &med
->u
.pstg
);
1087 ILockBytes_Release(lbs
);
1094 med
->tymed
= TYMED_ISTORAGE
;
1098 static inline BOOL
string_off_equal(const DVTARGETDEVICE
*t1
, WORD off1
, const DVTARGETDEVICE
*t2
, WORD off2
)
1100 const WCHAR
*str1
, *str2
;
1102 if(off1
== 0 && off2
== 0) return TRUE
;
1103 if(off1
== 0 || off2
== 0) return FALSE
;
1105 str1
= (const WCHAR
*)((const char*)t1
+ off1
);
1106 str2
= (const WCHAR
*)((const char*)t2
+ off2
);
1108 return !lstrcmpW(str1
, str2
);
1111 static inline BOOL
td_equal(const DVTARGETDEVICE
*t1
, const DVTARGETDEVICE
*t2
)
1113 if(t1
== NULL
&& t2
== NULL
) return TRUE
;
1114 if(t1
== NULL
|| t2
== NULL
) return FALSE
;
1116 if(!string_off_equal(t1
, t1
->tdDriverNameOffset
, t2
, t2
->tdDriverNameOffset
))
1118 if(!string_off_equal(t1
, t1
->tdDeviceNameOffset
, t2
, t2
->tdDeviceNameOffset
))
1120 if(!string_off_equal(t1
, t1
->tdPortNameOffset
, t2
, t2
->tdPortNameOffset
))
1123 /* FIXME check devmode? */
1128 /************************************************************************
1131 static HRESULT WINAPI
snapshot_GetData(IDataObject
*iface
, FORMATETC
*fmt
,
1134 snapshot
*This
= impl_from_IDataObject(iface
);
1137 ole_priv_data
*enum_data
= NULL
;
1138 ole_priv_data_entry
*entry
;
1141 TRACE("(%p,%p,%p)\n", iface
, fmt
, med
);
1143 if ( !fmt
|| !med
) return E_INVALIDARG
;
1145 if ( !OpenClipboard(NULL
)) return CLIPBRD_E_CANT_OPEN
;
1148 hr
= get_current_dataobject(&This
->data
);
1152 hr
= IDataObject_GetData(This
->data
, fmt
, med
);
1157 h
= GetClipboardData(fmt
->cfFormat
);
1160 hr
= DV_E_FORMATETC
;
1164 hr
= get_priv_data(&enum_data
);
1165 if(FAILED(hr
)) goto end
;
1167 entry
= find_format_in_list(enum_data
->entries
, enum_data
->count
, fmt
->cfFormat
);
1170 if(!td_equal(fmt
->ptd
, entry
->fmtetc
.ptd
))
1172 hr
= DV_E_FORMATETC
;
1175 mask
= fmt
->tymed
& entry
->fmtetc
.tymed
;
1176 if(!mask
) mask
= fmt
->tymed
& (TYMED_ISTREAM
| TYMED_HGLOBAL
);
1178 else /* non-Ole format */
1179 mask
= fmt
->tymed
& TYMED_HGLOBAL
;
1181 if(mask
& TYMED_ISTORAGE
)
1182 hr
= get_stgmed_for_storage(h
, med
);
1183 else if(mask
& TYMED_HGLOBAL
)
1184 hr
= get_stgmed_for_global(h
, med
);
1185 else if(mask
& TYMED_ISTREAM
)
1186 hr
= get_stgmed_for_stream(h
, med
);
1189 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry
->fmtetc
.tymed
, fmt
->tymed
);
1195 HeapFree(GetProcessHeap(), 0, enum_data
);
1196 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1200 /************************************************************************
1201 * snapshot_GetDataHere
1203 static HRESULT WINAPI
snapshot_GetDataHere(IDataObject
*iface
, FORMATETC
*fmt
,
1206 FIXME("(%p, %p, %p): stub\n", iface
, fmt
, med
);
1210 /************************************************************************
1211 * snapshot_QueryGetData
1213 * The OLE Clipboard's implementation of this method delegates to
1214 * a data source if there is one or wraps around the windows clipboard
1215 * function IsClipboardFormatAvailable() otherwise.
1218 static HRESULT WINAPI
snapshot_QueryGetData(IDataObject
*iface
, FORMATETC
*fmt
)
1220 FIXME("(%p, %p)\n", iface
, fmt
);
1222 if (!fmt
) return E_INVALIDARG
;
1224 if ( fmt
->dwAspect
!= DVASPECT_CONTENT
) return DV_E_FORMATETC
;
1226 if ( fmt
->lindex
!= -1 ) return DV_E_FORMATETC
;
1228 return (IsClipboardFormatAvailable(fmt
->cfFormat
)) ? S_OK
: DV_E_CLIPFORMAT
;
1231 /************************************************************************
1232 * snapshot_GetCanonicalFormatEtc
1234 static HRESULT WINAPI
snapshot_GetCanonicalFormatEtc(IDataObject
*iface
, FORMATETC
*fmt_in
,
1237 TRACE("(%p, %p, %p)\n", iface
, fmt_in
, fmt_out
);
1239 if ( !fmt_in
|| !fmt_out
) return E_INVALIDARG
;
1242 return DATA_S_SAMEFORMATETC
;
1245 /************************************************************************
1248 * The OLE Clipboard does not implement this method
1250 static HRESULT WINAPI
snapshot_SetData(IDataObject
*iface
, FORMATETC
*fmt
,
1251 STGMEDIUM
*med
, BOOL release
)
1253 TRACE("(%p, %p, %p, %d): not implemented\n", iface
, fmt
, med
, release
);
1257 /************************************************************************
1258 * snapshot_EnumFormatEtc
1261 static HRESULT WINAPI
snapshot_EnumFormatEtc(IDataObject
*iface
, DWORD dir
,
1262 IEnumFORMATETC
**enum_fmt
)
1265 ole_priv_data
*data
= NULL
;
1267 TRACE("(%p, %x, %p)\n", iface
, dir
, enum_fmt
);
1271 if ( dir
!= DATADIR_GET
) return E_NOTIMPL
;
1272 if ( !OpenClipboard(NULL
) ) return CLIPBRD_E_CANT_OPEN
;
1274 hr
= get_priv_data(&data
);
1276 if(FAILED(hr
)) goto end
;
1278 hr
= enum_fmtetc_construct( data
, 0, enum_fmt
);
1281 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1285 /************************************************************************
1288 * The OLE Clipboard does not implement this method
1290 static HRESULT WINAPI
snapshot_DAdvise(IDataObject
*iface
, FORMATETC
*fmt
,
1291 DWORD flags
, IAdviseSink
*sink
,
1294 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface
, fmt
, flags
, sink
, conn
);
1298 /************************************************************************
1299 * snapshot_DUnadvise
1301 * The OLE Clipboard does not implement this method
1303 static HRESULT WINAPI
snapshot_DUnadvise(IDataObject
* iface
, DWORD conn
)
1305 TRACE("(%p, %d): not implemented\n", iface
, conn
);
1309 /************************************************************************
1310 * snapshot_EnumDAdvise
1312 * The OLE Clipboard does not implement this method
1314 static HRESULT WINAPI
snapshot_EnumDAdvise(IDataObject
* iface
,
1315 IEnumSTATDATA
** enum_advise
)
1317 TRACE("(%p, %p): not implemented\n", iface
, enum_advise
);
1321 static const IDataObjectVtbl snapshot_vtable
=
1323 snapshot_QueryInterface
,
1327 snapshot_GetDataHere
,
1328 snapshot_QueryGetData
,
1329 snapshot_GetCanonicalFormatEtc
,
1331 snapshot_EnumFormatEtc
,
1334 snapshot_EnumDAdvise
1337 /*---------------------------------------------------------------------*
1338 * Internal implementation methods for the OLE clipboard
1339 *---------------------------------------------------------------------*/
1341 static snapshot
*snapshot_construct(DWORD seq_no
)
1345 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(*This
) );
1346 if (!This
) return NULL
;
1348 This
->lpVtbl
= &snapshot_vtable
;
1350 This
->seq_no
= seq_no
;
1356 /*********************************************************
1357 * register_clipboard_formats
1359 static void register_clipboard_formats(void)
1361 static const WCHAR DataObjectW
[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1362 static const WCHAR OlePrivateDataW
[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1363 static const WCHAR EmbedSourceW
[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1365 if(!dataobject_clipboard_format
)
1366 dataobject_clipboard_format
= RegisterClipboardFormatW(DataObjectW
);
1367 if(!ole_priv_data_clipboard_format
)
1368 ole_priv_data_clipboard_format
= RegisterClipboardFormatW(OlePrivateDataW
);
1369 if(!embed_source_clipboard_format
)
1370 embed_source_clipboard_format
= RegisterClipboardFormatW(EmbedSourceW
);
1373 /***********************************************************************
1374 * OLEClipbrd_Initialize()
1375 * Initializes the OLE clipboard.
1377 void OLEClipbrd_Initialize(void)
1379 register_clipboard_formats();
1381 if ( !theOleClipboard
)
1383 ole_clipbrd
* clipbrd
;
1388 clipbrd
= HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd
) );
1389 if (!clipbrd
) return;
1391 clipbrd
->latest_snapshot
= NULL
;
1392 clipbrd
->window
= NULL
;
1393 clipbrd
->src_data
= NULL
;
1394 clipbrd
->cached_enum
= NULL
;
1396 h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, 0);
1399 HeapFree(GetProcessHeap(), 0, clipbrd
);
1403 if(FAILED(CreateStreamOnHGlobal(h
, TRUE
, &clipbrd
->marshal_data
)))
1406 HeapFree(GetProcessHeap(), 0, clipbrd
);
1410 theOleClipboard
= clipbrd
;
1414 /***********************************************************************
1415 * OLEClipbrd_UnInitialize()
1416 * Un-Initializes the OLE clipboard
1418 void OLEClipbrd_UnInitialize(void)
1420 ole_clipbrd
*clipbrd
= theOleClipboard
;
1426 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1427 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1429 if ( clipbrd
->window
)
1431 DestroyWindow(clipbrd
->window
);
1432 UnregisterClassW( clipbrd_wndclass
, hinst
);
1435 IStream_Release(clipbrd
->marshal_data
);
1436 HeapFree(GetProcessHeap(), 0, clipbrd
);
1437 theOleClipboard
= NULL
;
1441 /*********************************************************************
1442 * set_clipboard_formats
1444 * Enumerate all formats supported by the source and make
1445 * those formats available using delayed rendering using SetClipboardData.
1446 * Cache the enumeration list and make that list visibile as the
1447 * 'Ole Private Data' format on the clipboard.
1450 static HRESULT
set_clipboard_formats(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1454 IEnumFORMATETC
*enum_fmt
;
1455 HGLOBAL priv_data_handle
;
1456 DWORD_PTR target_offset
;
1457 ole_priv_data
*priv_data
;
1458 DWORD count
= 0, needed
= sizeof(*priv_data
), idx
;
1460 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
1461 if(FAILED(hr
)) return hr
;
1463 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1466 needed
+= sizeof(priv_data
->entries
[0]);
1469 needed
+= fmt
.ptd
->tdSize
;
1470 CoTaskMemFree(fmt
.ptd
);
1474 /* Windows pads the list with two empty ole_priv_data_entries, one
1475 * after the entries array and one after the target device data.
1476 * Allocating with zero init to zero these pads. */
1478 needed
+= sizeof(priv_data
->entries
[0]); /* initialisation of needed includes one of these. */
1479 priv_data_handle
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
| GMEM_ZEROINIT
, needed
);
1480 priv_data
= GlobalLock(priv_data_handle
);
1482 priv_data
->unk1
= 0;
1483 priv_data
->size
= needed
;
1484 priv_data
->unk2
= 1;
1485 priv_data
->count
= count
;
1486 priv_data
->unk3
[0] = 0;
1487 priv_data
->unk3
[1] = 0;
1489 IEnumFORMATETC_Reset(enum_fmt
);
1492 target_offset
= FIELD_OFFSET(ole_priv_data
, entries
[count
+ 1]); /* count entries + one pad. */
1494 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
1496 TRACE("%s\n", dump_fmtetc(&fmt
));
1498 priv_data
->entries
[idx
].fmtetc
= fmt
;
1501 memcpy((char*)priv_data
+ target_offset
, fmt
.ptd
, fmt
.ptd
->tdSize
);
1502 priv_data
->entries
[idx
].fmtetc
.ptd
= (DVTARGETDEVICE
*)target_offset
;
1503 target_offset
+= fmt
.ptd
->tdSize
;
1504 CoTaskMemFree(fmt
.ptd
);
1507 priv_data
->entries
[idx
].first_use
= !find_format_in_list(priv_data
->entries
, idx
, fmt
.cfFormat
);
1508 priv_data
->entries
[idx
].unk
[0] = 0;
1509 priv_data
->entries
[idx
].unk
[1] = 0;
1511 if (priv_data
->entries
[idx
].first_use
)
1512 SetClipboardData(fmt
.cfFormat
, NULL
);
1517 IEnumFORMATETC_Release(enum_fmt
);
1519 /* Cache the list and fixup any target device offsets to ptrs */
1520 clipbrd
->cached_enum
= HeapAlloc(GetProcessHeap(), 0, needed
);
1521 memcpy(clipbrd
->cached_enum
, priv_data
, needed
);
1522 for(idx
= 0; idx
< clipbrd
->cached_enum
->count
; idx
++)
1523 clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
=
1524 td_offs_to_ptr(clipbrd
->cached_enum
, (DWORD_PTR
)clipbrd
->cached_enum
->entries
[idx
].fmtetc
.ptd
);
1526 GlobalUnlock(priv_data_handle
);
1527 SetClipboardData(ole_priv_data_clipboard_format
, priv_data_handle
);
1532 static HWND
create_clipbrd_window(void);
1534 /***********************************************************************
1535 * get_clipbrd_window
1537 static inline HRESULT
get_clipbrd_window(ole_clipbrd
*clipbrd
, HWND
*wnd
)
1539 if ( !clipbrd
->window
)
1540 clipbrd
->window
= create_clipbrd_window();
1542 *wnd
= clipbrd
->window
;
1543 return *wnd
? S_OK
: E_FAIL
;
1547 /**********************************************************************
1548 * release_marshal_data
1550 * Releases the data and sets the stream back to zero size.
1552 static inline void release_marshal_data(IStream
*stm
)
1555 ULARGE_INTEGER size
;
1556 pos
.QuadPart
= size
.QuadPart
= 0;
1558 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1559 CoReleaseMarshalData(stm
);
1560 IStream_Seek(stm
, pos
, STREAM_SEEK_SET
, NULL
);
1561 IStream_SetSize(stm
, size
);
1564 /***********************************************************************
1565 * set_src_dataobject
1567 * Clears and sets the clipboard's src IDataObject.
1569 * To marshal the source dataobject we do something rather different from Windows.
1570 * We set a window prop which contains the marshalled data.
1571 * Windows set two props one of which is an IID, the other is an endpoint number.
1573 static HRESULT
set_src_dataobject(ole_clipbrd
*clipbrd
, IDataObject
*data
)
1578 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1580 if(clipbrd
->src_data
)
1582 RemovePropW(wnd
, wine_marshal_dataobject
);
1583 release_marshal_data(clipbrd
->marshal_data
);
1585 IDataObject_Release(clipbrd
->src_data
);
1586 clipbrd
->src_data
= NULL
;
1587 HeapFree(GetProcessHeap(), 0, clipbrd
->cached_enum
);
1588 clipbrd
->cached_enum
= NULL
;
1596 IDataObject_AddRef(data
);
1597 clipbrd
->src_data
= data
;
1599 IDataObject_QueryInterface(data
, &IID_IUnknown
, (void**)&unk
);
1600 hr
= CoMarshalInterface(clipbrd
->marshal_data
, &IID_IDataObject
, unk
,
1601 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1602 IUnknown_Release(unk
); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1603 if(FAILED(hr
)) return hr
;
1604 GetHGlobalFromStream(clipbrd
->marshal_data
, &h
);
1605 SetPropW(wnd
, wine_marshal_dataobject
, h
);
1606 hr
= set_clipboard_formats(clipbrd
, data
);
1611 /***********************************************************************
1614 static LRESULT CALLBACK
clipbrd_wndproc(HWND hwnd
, UINT message
, WPARAM wparam
, LPARAM lparam
)
1616 ole_clipbrd
*clipbrd
;
1618 get_ole_clipbrd(&clipbrd
);
1622 case WM_RENDERFORMAT
:
1625 ole_priv_data_entry
*entry
;
1627 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf
);
1628 entry
= find_format_in_list(clipbrd
->cached_enum
->entries
, clipbrd
->cached_enum
->count
, cf
);
1631 render_format(clipbrd
->src_data
, &entry
->fmtetc
);
1636 case WM_RENDERALLFORMATS
:
1639 ole_priv_data_entry
*entries
= clipbrd
->cached_enum
->entries
;
1641 TRACE("(): WM_RENDERALLFORMATS\n");
1643 for(i
= 0; i
< clipbrd
->cached_enum
->count
; i
++)
1645 if(entries
[i
].first_use
)
1646 render_format(clipbrd
->src_data
, &entries
[i
].fmtetc
);
1651 case WM_DESTROYCLIPBOARD
:
1653 TRACE("(): WM_DESTROYCLIPBOARD\n");
1655 set_src_dataobject(clipbrd
, NULL
);
1660 return DefWindowProcW(hwnd
, message
, wparam
, lparam
);
1667 /***********************************************************************
1668 * create_clipbrd_window
1670 static HWND
create_clipbrd_window(void)
1673 static const WCHAR ole32W
[] = {'o','l','e','3','2',0};
1674 static const WCHAR title
[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1675 HINSTANCE hinst
= GetModuleHandleW(ole32W
);
1677 class.cbSize
= sizeof(class);
1679 class.lpfnWndProc
= clipbrd_wndproc
;
1680 class.cbClsExtra
= 0;
1681 class.cbWndExtra
= 0;
1682 class.hInstance
= hinst
;
1685 class.hbrBackground
= 0;
1686 class.lpszMenuName
= NULL
;
1687 class.lpszClassName
= clipbrd_wndclass
;
1688 class.hIconSm
= NULL
;
1690 RegisterClassExW(&class);
1692 return CreateWindowW(clipbrd_wndclass
, title
, WS_POPUP
| WS_CLIPSIBLINGS
| WS_OVERLAPPED
,
1693 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1694 NULL
, NULL
, hinst
, 0);
1697 /*********************************************************************
1698 * set_dataobject_format
1700 * Windows creates a 'DataObject' clipboard format that contains the
1701 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1703 static HRESULT
set_dataobject_format(HWND hwnd
)
1705 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof(hwnd
));
1708 if(!h
) return E_OUTOFMEMORY
;
1710 data
= GlobalLock(h
);
1714 if(!SetClipboardData(dataobject_clipboard_format
, h
))
1717 return CLIPBRD_E_CANT_SET
;
1723 /*---------------------------------------------------------------------*
1724 * Win32 OLE clipboard API
1725 *---------------------------------------------------------------------*/
1727 /***********************************************************************
1728 * OleSetClipboard [OLE32.@]
1729 * Places a pointer to the specified data object onto the clipboard,
1730 * making the data object accessible to the OleGetClipboard function.
1734 * S_OK IDataObject pointer placed on the clipboard
1735 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1736 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1737 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1738 * CLIPBRD_E_CANT_SET SetClipboard failed
1741 HRESULT WINAPI
OleSetClipboard(IDataObject
* data
)
1744 ole_clipbrd
*clipbrd
;
1747 TRACE("(%p)\n", data
);
1749 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1751 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1753 if ( !OpenClipboard(wnd
) ) return CLIPBRD_E_CANT_OPEN
;
1755 if ( !EmptyClipboard() )
1757 hr
= CLIPBRD_E_CANT_EMPTY
;
1761 hr
= set_src_dataobject(clipbrd
, data
);
1762 if(FAILED(hr
)) goto end
;
1765 hr
= set_dataobject_format(wnd
);
1769 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1773 set_src_dataobject(clipbrd
, NULL
);
1780 /***********************************************************************
1781 * OleGetClipboard [OLE32.@]
1782 * Returns a pointer to our internal IDataObject which represents the conceptual
1783 * state of the Windows clipboard. If the current clipboard already contains
1784 * an IDataObject, our internal IDataObject will delegate to this object.
1786 HRESULT WINAPI
OleGetClipboard(IDataObject
**obj
)
1789 ole_clipbrd
*clipbrd
;
1792 TRACE("(%p)\n", obj
);
1794 if(!obj
) return E_INVALIDARG
;
1796 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1798 seq_no
= GetClipboardSequenceNumber();
1799 if(clipbrd
->latest_snapshot
&& clipbrd
->latest_snapshot
->seq_no
!= seq_no
)
1800 clipbrd
->latest_snapshot
= NULL
;
1802 if(!clipbrd
->latest_snapshot
)
1804 clipbrd
->latest_snapshot
= snapshot_construct(seq_no
);
1805 if(!clipbrd
->latest_snapshot
) return E_OUTOFMEMORY
;
1808 *obj
= (IDataObject
*)&clipbrd
->latest_snapshot
->lpVtbl
;
1809 IDataObject_AddRef(*obj
);
1814 /******************************************************************************
1815 * OleFlushClipboard [OLE32.@]
1816 * Renders the data from the source IDataObject into the windows clipboard
1818 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1819 * by copying the storage into global memory. Subsequently the default
1820 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1821 * back to TYMED_IStorage.
1823 HRESULT WINAPI
OleFlushClipboard(void)
1826 ole_clipbrd
*clipbrd
;
1831 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1833 if(FAILED(hr
= get_clipbrd_window(clipbrd
, &wnd
))) return hr
;
1836 * Already flushed or no source DataObject? Nothing to do.
1838 if (!clipbrd
->src_data
) return S_OK
;
1840 if (!OpenClipboard(wnd
)) return CLIPBRD_E_CANT_OPEN
;
1842 SendMessageW(wnd
, WM_RENDERALLFORMATS
, 0, 0);
1844 hr
= set_dataobject_format(NULL
);
1846 set_src_dataobject(clipbrd
, NULL
);
1848 if ( !CloseClipboard() ) hr
= CLIPBRD_E_CANT_CLOSE
;
1854 /***********************************************************************
1855 * OleIsCurrentClipboard [OLE32.@]
1857 HRESULT WINAPI
OleIsCurrentClipboard(IDataObject
*data
)
1860 ole_clipbrd
*clipbrd
;
1863 if(FAILED(hr
= get_ole_clipbrd(&clipbrd
))) return hr
;
1865 if (data
== NULL
) return S_FALSE
;
1867 return (data
== clipbrd
->src_data
) ? S_OK
: S_FALSE
;