2 * OLE 2 clipboard support
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * This file contains the implementation for the OLE Clipboard and its
23 * internal interfaces. The OLE clipboard interacts with an IDataObject
24 * interface via the OleSetClipboard, OleGetClipboard and
25 * OleIsCurrentClipboard API's. An internal IDataObject delegates
26 * to a client supplied IDataObject or the WIN32 clipboard API depending
27 * on whether OleSetClipboard has been invoked.
28 * Here are some operating scenarios:
30 * 1. OleSetClipboard called: In this case the internal IDataObject
31 * delegates to the client supplied IDataObject. Additionally OLE takes
32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject
33 * items are placed on the Windows clipboard. This allows non OLE aware
34 * applications to access these. A local WinProc fields WM_RENDERFORMAT
35 * and WM_RENDERALLFORMATS messages in this case.
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41 * IDataObject delegates to the source IDataObjects functionality directly,
42 * thereby bypassing the Windows clipboard.
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
47 * - Support for pasting between different processes. OLE clipboard support
48 * currently works only for in process copy and paste. Since we internally
49 * store a pointer to the source's IDataObject and delegate to that, this
50 * will fail if the IDataObject client belongs to a different process.
51 * - IDataObject::GetDataHere is not implemented
52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53 * by copying the storage into global memory. Subsequently the default
54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55 * back to TYMED_IStorage.
56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57 * clipboard in OleSetClipboard.
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
77 #include "wine/debug.h"
80 #include "storage32.h"
82 #include "compobj_private.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(ole);
86 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
88 /* Structure of 'Ole Private Data' clipboard format */
92 DWORD first_use; /* Has this cf been added to the list already */
94 } ole_priv_data_entry;
99 DWORD size; /* in bytes of the entire structure */
101 DWORD count; /* no. of format entries */
103 ole_priv_data_entry entries[1]; /* array of size count */
104 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
107 /*****************************************************************************
110 * Returns a ptr to a target device at a given offset from the
111 * start of the ole_priv_data.
113 * Used when unpacking ole private data from the clipboard.
115 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
117 if(off == 0) return NULL;
118 return (DVTARGETDEVICE*)((char*)data + off);
121 /*****************************************************************************
124 * Get the offset from the start of the ole_priv_data of the idx'th
127 * Used when packing ole private data to the clipboard.
129 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
131 if(data->entries[idx].fmtetc.ptd == NULL) return 0;
132 return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
135 /****************************************************************************
136 * Consumer snapshot. Represents the state of the ole clipboard
137 * returned by OleGetClipboard().
139 typedef struct snapshot
141 const IDataObjectVtbl* lpVtbl;
144 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */
146 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */
149 /****************************************************************************
152 typedef struct ole_clipbrd
154 snapshot *latest_snapshot; /* Latest consumer snapshot */
156 HWND window; /* Hidden clipboard window */
157 IDataObject *src_data; /* Source object passed to OleSetClipboard */
158 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
159 IStream *marshal_data; /* Stream onto which to marshal src_data */
162 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
164 return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
167 typedef struct PresentationDataHeader
170 DWORD dwObjectExtentX;
171 DWORD dwObjectExtentY;
173 } PresentationDataHeader;
176 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
178 static ole_clipbrd* theOleClipboard;
180 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
182 struct oletls *info = COM_CurrentInfo();
186 return CO_E_NOTINITIALIZED;
187 *clipbrd = theOleClipboard;
193 * Name of our registered OLE clipboard window class
195 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
197 static const WCHAR wine_marshal_dataobject[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0};
199 UINT ownerlink_clipboard_format = 0;
200 UINT filename_clipboard_format = 0;
201 UINT filenameW_clipboard_format = 0;
202 UINT dataobject_clipboard_format = 0;
203 UINT embedded_object_clipboard_format = 0;
204 UINT embed_source_clipboard_format = 0;
205 UINT custom_link_source_clipboard_format = 0;
206 UINT link_source_clipboard_format = 0;
207 UINT object_descriptor_clipboard_format = 0;
208 UINT link_source_descriptor_clipboard_format = 0;
209 UINT ole_private_data_clipboard_format = 0;
211 static UINT wine_marshal_clipboard_format;
213 static inline char *dump_fmtetc(FORMATETC *fmt)
215 static char buf[100];
217 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
218 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
222 /*---------------------------------------------------------------------*
223 * Implementation of the internal IEnumFORMATETC interface returned by
224 * the OLE clipboard's IDataObject.
225 *---------------------------------------------------------------------*/
227 typedef struct enum_fmtetc
229 const IEnumFORMATETCVtbl *lpVtbl;
232 UINT pos; /* current enumerator position */
236 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
238 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
241 /************************************************************************
242 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
244 * See Windows documentation for more details on IUnknown methods.
246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
247 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
249 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
251 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
255 if(IsEqualIID(riid, &IID_IUnknown) ||
256 IsEqualIID(riid, &IID_IEnumFORMATETC))
263 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
264 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
268 TRACE("-- Interface: E_NOINTERFACE\n");
269 return E_NOINTERFACE;
272 /************************************************************************
273 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
276 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
278 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
279 TRACE("(%p)->(count=%u)\n",This, This->ref);
281 return InterlockedIncrement(&This->ref);
284 /************************************************************************
285 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
287 * See Windows documentation for more details on IUnknown methods.
289 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
291 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
294 TRACE("(%p)->(count=%u)\n",This, This->ref);
296 ref = InterlockedDecrement(&This->ref);
299 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
300 HeapFree(GetProcessHeap(), 0, This->data);
301 HeapFree(GetProcessHeap(), 0, This);
306 /************************************************************************
307 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
309 * Standard enumerator members for IEnumFORMATETC
311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
312 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
314 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
316 HRESULT hres = S_FALSE;
318 TRACE("(%p)->(pos=%u)\n", This, This->pos);
320 if (This->pos < This->data->count)
322 cfetch = This->data->count - This->pos;
329 for(i = 0; i < cfetch; i++)
331 rgelt[i] = This->data->entries[This->pos++].fmtetc;
334 DVTARGETDEVICE *target = rgelt[i].ptd;
335 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
336 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
337 memcpy(rgelt[i].ptd, target, target->tdSize);
348 *pceltFethed = cfetch;
354 /************************************************************************
355 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
357 * Standard enumerator members for IEnumFORMATETC
359 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
361 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
362 TRACE("(%p)->(num=%u)\n", This, celt);
365 if (This->pos > This->data->count)
367 This->pos = This->data->count;
373 /************************************************************************
374 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
376 * Standard enumerator members for IEnumFORMATETC
378 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
380 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
381 TRACE("(%p)->()\n", This);
387 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
389 /************************************************************************
390 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
392 * Standard enumerator members for IEnumFORMATETC
394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
395 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
397 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
398 ole_priv_data *new_data;
401 TRACE("(%p)->(%p)\n", This, obj);
403 if ( !obj ) return E_INVALIDARG;
406 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
407 if(!new_data) return E_OUTOFMEMORY;
408 memcpy(new_data, This->data, This->data->size);
410 /* Fixup any target device ptrs */
411 for(i = 0; i < This->data->count; i++)
412 new_data->entries[i].fmtetc.ptd =
413 td_offs_to_ptr(new_data, td_get_offs(This->data, i));
415 return enum_fmtetc_construct(new_data, This->pos, obj);
418 static const IEnumFORMATETCVtbl efvt =
420 OLEClipbrd_IEnumFORMATETC_QueryInterface,
421 OLEClipbrd_IEnumFORMATETC_AddRef,
422 OLEClipbrd_IEnumFORMATETC_Release,
423 OLEClipbrd_IEnumFORMATETC_Next,
424 OLEClipbrd_IEnumFORMATETC_Skip,
425 OLEClipbrd_IEnumFORMATETC_Reset,
426 OLEClipbrd_IEnumFORMATETC_Clone
429 /************************************************************************
430 * enum_fmtetc_construct
432 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
434 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
439 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
440 if (!ef) return E_OUTOFMEMORY;
447 TRACE("(%p)->()\n", ef);
448 *obj = (IEnumFORMATETC *)ef;
452 /***********************************************************************
455 * Helper method to duplicate an HGLOBAL chunk of memory
457 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
459 void *src_ptr, *dst_ptr;
463 if ( !src ) return S_FALSE;
465 size = GlobalSize(src);
467 *dst = GlobalAlloc( flags, size );
468 if ( !*dst ) return E_OUTOFMEMORY;
470 src_ptr = GlobalLock(src);
471 dst_ptr = GlobalLock(*dst);
473 memcpy(dst_ptr, src_ptr, size);
481 /************************************************************
482 * render_embed_source_hack
484 * This is clearly a hack and has no place in the clipboard code.
487 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
490 HGLOBAL hStorage = 0;
492 ILockBytes *ptrILockBytes;
494 memset(&std, 0, sizeof(STGMEDIUM));
495 std.tymed = fmt->tymed = TYMED_ISTORAGE;
497 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
498 if (hStorage == NULL) return E_OUTOFMEMORY;
499 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
500 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
501 ILockBytes_Release(ptrILockBytes);
503 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
505 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
506 GlobalFree(hStorage);
510 if (1) /* check whether the presentation data is already -not- present */
514 METAFILEPICT *mfp = 0;
516 fmt2.cfFormat = CF_METAFILEPICT;
518 fmt2.dwAspect = DVASPECT_CONTENT;
520 fmt2.tymed = TYMED_MFPICT;
522 memset(&std2, 0, sizeof(STGMEDIUM));
523 std2.tymed = TYMED_MFPICT;
525 /* Get the metafile picture out of it */
527 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
529 mfp = GlobalLock(std2.u.hGlobal);
534 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
535 IStream *pStream = 0;
537 PresentationDataHeader pdh;
541 CHAR strOleTypeName[51];
542 BYTE OlePresStreamHeader [] =
544 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
545 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
546 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00
550 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
552 memset(&pdh, 0, sizeof(PresentationDataHeader));
553 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
555 pdh.dwObjectExtentX = mfp->xExt;
556 pdh.dwObjectExtentY = mfp->yExt;
559 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
561 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
563 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
564 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
566 hr = IStream_Write(pStream, mfBits, nSize, NULL);
568 IStream_Release(pStream);
570 HeapFree(GetProcessHeap(), 0, mfBits);
572 GlobalUnlock(std2.u.hGlobal);
573 ReleaseStgMedium(&std2);
575 ReadClassStg(std.u.pstg, &clsID);
576 ProgIDFromCLSID(&clsID, &strProgID);
578 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
579 OLECONVERT_CreateOleStream(std.u.pstg);
580 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
584 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
586 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
587 GlobalFree(hStorage);
588 hr = CLIPBRD_E_CANT_SET;
591 ReleaseStgMedium(&std);
595 /************************************************************************
596 * find_format_in_list
598 * Returns the first entry that matches the provided clipboard format.
600 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
603 for(i = 0; i < num; i++)
604 if(entries[i].fmtetc.cfFormat == cf)
610 /***************************************************************************
611 * get_data_from_storage
613 * Returns storage data in an HGLOBAL.
615 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
626 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
627 if(!h) return E_OUTOFMEMORY;
629 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
632 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
633 ILockBytes_Release(lbs);
642 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
644 med.pUnkForRelease = NULL;
646 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
650 hr = IDataObject_GetData(data, &stg_fmt, &med);
651 if(FAILED(hr)) goto end;
653 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
654 ReleaseStgMedium(&med);
655 if(FAILED(hr)) goto end;
660 IStorage_Release(stg);
661 if(FAILED(hr)) GlobalFree(h);
665 /***************************************************************************
666 * get_data_from_stream
668 * Returns stream data in an HGLOBAL.
670 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
680 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
681 if(!h) return E_OUTOFMEMORY;
683 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
684 if(FAILED(hr)) goto error;
687 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
689 med.pUnkForRelease = NULL;
691 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
698 hr = IDataObject_GetData(data, &stm_fmt, &med);
699 if(FAILED(hr)) goto error;
702 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
703 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
704 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
705 ReleaseStgMedium(&med);
706 if(FAILED(hr)) goto error;
709 IStream_Release(stm);
713 if(stm) IStream_Release(stm);
718 /***************************************************************************
719 * get_data_from_global
721 * Returns global data in an HGLOBAL.
723 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
733 mem_fmt.tymed = TYMED_HGLOBAL;
735 hr = IDataObject_GetData(data, &mem_fmt, &med);
736 if(FAILED(hr)) return hr;
738 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
740 if(SUCCEEDED(hr)) *mem = h;
742 ReleaseStgMedium(&med);
747 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
757 mem_fmt.tymed = TYMED_ENHMF;
759 hr = IDataObject_GetData(data, &mem_fmt, &med);
760 if(FAILED(hr)) return hr;
762 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
763 if(copy) *mem = (HGLOBAL)copy;
766 ReleaseStgMedium(&med);
771 /***********************************************************************
774 * Render the clipboard data. Note that this call will delegate to the
775 * source data object.
777 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
779 HGLOBAL clip_data = NULL;
782 /* Embed source hack */
783 if(fmt->cfFormat == embed_source_clipboard_format)
785 return render_embed_source_hack(data, fmt);
788 if(fmt->tymed & TYMED_ISTORAGE)
790 hr = get_data_from_storage(data, fmt, &clip_data);
792 else if(fmt->tymed & TYMED_ISTREAM)
794 hr = get_data_from_stream(data, fmt, &clip_data);
796 else if(fmt->tymed & TYMED_HGLOBAL)
798 hr = get_data_from_global(data, fmt, &clip_data);
800 else if(fmt->tymed & TYMED_ENHMF)
802 hr = get_data_from_enhmetafile(data, fmt, &clip_data);
806 FIXME("Unhandled tymed %x\n", fmt->tymed);
812 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
814 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
815 GlobalFree(clip_data);
816 hr = CLIPBRD_E_CANT_SET;
823 /*---------------------------------------------------------------------*
824 * Implementation of the internal IDataObject interface exposed by
826 *---------------------------------------------------------------------*/
829 /************************************************************************
830 * snapshot_QueryInterface
832 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
833 REFIID riid, void **ppvObject)
835 snapshot *This = impl_from_IDataObject(iface);
836 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
838 if ( (This==0) || (ppvObject==0) )
843 if (IsEqualIID(&IID_IUnknown, riid) ||
844 IsEqualIID(&IID_IDataObject, riid))
850 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
851 return E_NOINTERFACE;
854 IUnknown_AddRef((IUnknown*)*ppvObject);
859 /************************************************************************
862 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
864 snapshot *This = impl_from_IDataObject(iface);
866 TRACE("(%p)->(count=%u)\n", This, This->ref);
868 return InterlockedIncrement(&This->ref);
871 /************************************************************************
874 static ULONG WINAPI snapshot_Release(IDataObject *iface)
876 snapshot *This = impl_from_IDataObject(iface);
879 TRACE("(%p)->(count=%u)\n", This, This->ref);
881 ref = InterlockedDecrement(&This->ref);
885 ole_clipbrd *clipbrd;
886 HRESULT hr = get_ole_clipbrd(&clipbrd);
888 if(This->data) IDataObject_Release(This->data);
890 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
891 clipbrd->latest_snapshot = NULL;
892 HeapFree(GetProcessHeap(), 0, This);
898 /************************************************************
899 * get_current_ole_clip_window
901 * Return the window that owns the ole clipboard.
903 * If the clipboard is flushed or not owned by ole this will
906 static HWND get_current_ole_clip_window(void)
911 h = GetClipboardData(dataobject_clipboard_format);
914 if(!ptr) return NULL;
920 /************************************************************
921 * get_current_dataobject
923 * Return an unmarshalled IDataObject if there is a current
924 * (ie non-flushed) object on the ole clipboard.
926 static HRESULT get_current_dataobject(IDataObject **data)
928 HRESULT hr = S_FALSE;
929 HWND wnd = get_current_ole_clip_window();
936 if(!wnd) return S_FALSE;
938 h = GetClipboardData(wine_marshal_clipboard_format);
939 if(!h) return S_FALSE;
940 if(GlobalSize(h) == 0) return S_FALSE;
942 if(!ptr) return S_FALSE;
944 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
945 if(FAILED(hr)) goto end;
947 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
951 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
952 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
954 IStream_Release(stm);
961 static DWORD get_tymed_from_nonole_cf(UINT cf)
963 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
970 return TYMED_ISTREAM | TYMED_HGLOBAL;
973 case CF_METAFILEPICT:
976 FIXME("returning TYMED_NULL for cf %04x\n", cf);
981 /***********************************************************
984 * Returns a copy of the Ole Private Data
986 static HRESULT get_priv_data(ole_priv_data **data)
990 ole_priv_data *ret = NULL;
994 handle = GetClipboardData( ole_private_data_clipboard_format );
997 ole_priv_data *src = GlobalLock(handle);
1002 /* FIXME: sanity check on size */
1003 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1006 GlobalUnlock(handle);
1007 return E_OUTOFMEMORY;
1009 memcpy(ret, src, src->size);
1010 GlobalUnlock(handle);
1012 /* Fixup any target device offsets to ptrs */
1013 for(i = 0; i < ret->count; i++)
1014 ret->entries[i].fmtetc.ptd =
1015 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1019 if(!ret) /* Non-ole data */
1022 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1024 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1027 GetClipboardFormatNameA(cf, buf, sizeof(buf));
1028 TRACE("cf %04x %s\n", cf, buf);
1030 TRACE("count %d\n", count);
1031 size += count * sizeof(ret->entries[0]);
1033 /* There are holes in fmtetc so zero init */
1034 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1035 if(!ret) return E_OUTOFMEMORY;
1039 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1041 ret->entries[idx].fmtetc.cfFormat = cf;
1042 ret->entries[idx].fmtetc.ptd = NULL;
1043 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1044 ret->entries[idx].fmtetc.lindex = -1;
1045 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1046 ret->entries[idx].first_use = 1;
1054 /************************************************************************
1055 * get_stgmed_for_global
1057 * Returns a stg medium with a copy of the global handle
1059 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1063 med->pUnkForRelease = NULL;
1064 med->tymed = TYMED_NULL;
1066 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1068 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1073 /************************************************************************
1074 * get_stgmed_for_stream
1076 * Returns a stg medium with a stream based on the handle
1078 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1083 med->pUnkForRelease = NULL;
1084 med->tymed = TYMED_NULL;
1086 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1087 if(FAILED(hr)) return hr;
1089 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1096 med->tymed = TYMED_ISTREAM;
1100 /************************************************************************
1101 * get_stgmed_for_storage
1103 * Returns a stg medium with a storage based on the handle
1105 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1111 med->pUnkForRelease = NULL;
1112 med->tymed = TYMED_NULL;
1114 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1115 if(FAILED(hr)) return hr;
1117 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1124 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1125 ILockBytes_Release(lbs);
1132 med->tymed = TYMED_ISTORAGE;
1136 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1138 const WCHAR *str1, *str2;
1140 if(off1 == 0 && off2 == 0) return TRUE;
1141 if(off1 == 0 || off2 == 0) return FALSE;
1143 str1 = (const WCHAR*)((const char*)t1 + off1);
1144 str2 = (const WCHAR*)((const char*)t2 + off2);
1146 return !lstrcmpW(str1, str2);
1149 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1151 if(t1 == NULL && t2 == NULL) return TRUE;
1152 if(t1 == NULL || t2 == NULL) return FALSE;
1154 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1156 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1158 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1161 /* FIXME check devmode? */
1166 /************************************************************************
1169 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1172 snapshot *This = impl_from_IDataObject(iface);
1175 ole_priv_data *enum_data = NULL;
1176 ole_priv_data_entry *entry;
1179 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1181 if ( !fmt || !med ) return E_INVALIDARG;
1183 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1186 hr = get_current_dataobject(&This->data);
1190 hr = IDataObject_GetData(This->data, fmt, med);
1195 h = GetClipboardData(fmt->cfFormat);
1198 hr = DV_E_FORMATETC;
1202 hr = get_priv_data(&enum_data);
1203 if(FAILED(hr)) goto end;
1205 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1208 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1210 hr = DV_E_FORMATETC;
1213 mask = fmt->tymed & entry->fmtetc.tymed;
1214 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1216 else /* non-Ole format */
1217 mask = fmt->tymed & TYMED_HGLOBAL;
1219 if(mask & TYMED_ISTORAGE)
1220 hr = get_stgmed_for_storage(h, med);
1221 else if(mask & TYMED_HGLOBAL)
1222 hr = get_stgmed_for_global(h, med);
1223 else if(mask & TYMED_ISTREAM)
1224 hr = get_stgmed_for_stream(h, med);
1227 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1233 HeapFree(GetProcessHeap(), 0, enum_data);
1234 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1238 /************************************************************************
1239 * snapshot_GetDataHere
1241 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1244 snapshot *This = impl_from_IDataObject(iface);
1247 ole_priv_data *enum_data = NULL;
1248 ole_priv_data_entry *entry;
1251 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1253 if ( !fmt || !med ) return E_INVALIDARG;
1255 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1258 hr = get_current_dataobject(&This->data);
1262 hr = IDataObject_GetDataHere(This->data, fmt, med);
1270 h = GetClipboardData(fmt->cfFormat);
1273 hr = DV_E_FORMATETC;
1277 hr = get_priv_data(&enum_data);
1278 if(FAILED(hr)) goto end;
1280 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1283 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1285 hr = DV_E_FORMATETC;
1288 supported = entry->fmtetc.tymed;
1290 else /* non-Ole format */
1291 supported = TYMED_HGLOBAL;
1297 DWORD src_size = GlobalSize(h);
1298 DWORD dst_size = GlobalSize(med->u.hGlobal);
1300 if(dst_size >= src_size)
1302 void *src = GlobalLock(h);
1303 void *dst = GlobalLock(med->u.hGlobal);
1305 memcpy(dst, src, src_size);
1306 GlobalUnlock(med->u.hGlobal);
1314 DWORD src_size = GlobalSize(h);
1315 void *src = GlobalLock(h);
1316 hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1320 case TYMED_ISTORAGE:
1323 if(!(supported & TYMED_ISTORAGE))
1328 hr = get_stgmed_for_storage(h, ©);
1331 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1332 ReleaseStgMedium(©);
1337 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1343 HeapFree(GetProcessHeap(), 0, enum_data);
1344 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1348 /************************************************************************
1349 * snapshot_QueryGetData
1351 * The OLE Clipboard's implementation of this method delegates to
1352 * a data source if there is one or wraps around the windows clipboard
1353 * function IsClipboardFormatAvailable() otherwise.
1356 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1358 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1360 if (!fmt) return E_INVALIDARG;
1362 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1364 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1366 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1369 /************************************************************************
1370 * snapshot_GetCanonicalFormatEtc
1372 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1375 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1377 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1380 return DATA_S_SAMEFORMATETC;
1383 /************************************************************************
1386 * The OLE Clipboard does not implement this method
1388 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1389 STGMEDIUM *med, BOOL release)
1391 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1395 /************************************************************************
1396 * snapshot_EnumFormatEtc
1399 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1400 IEnumFORMATETC **enum_fmt)
1403 ole_priv_data *data = NULL;
1405 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1409 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1410 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1412 hr = get_priv_data(&data);
1414 if(FAILED(hr)) goto end;
1416 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1419 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1423 /************************************************************************
1426 * The OLE Clipboard does not implement this method
1428 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1429 DWORD flags, IAdviseSink *sink,
1432 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1436 /************************************************************************
1437 * snapshot_DUnadvise
1439 * The OLE Clipboard does not implement this method
1441 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1443 TRACE("(%p, %d): not implemented\n", iface, conn);
1447 /************************************************************************
1448 * snapshot_EnumDAdvise
1450 * The OLE Clipboard does not implement this method
1452 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1453 IEnumSTATDATA** enum_advise)
1455 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1459 static const IDataObjectVtbl snapshot_vtable =
1461 snapshot_QueryInterface,
1465 snapshot_GetDataHere,
1466 snapshot_QueryGetData,
1467 snapshot_GetCanonicalFormatEtc,
1469 snapshot_EnumFormatEtc,
1472 snapshot_EnumDAdvise
1475 /*---------------------------------------------------------------------*
1476 * Internal implementation methods for the OLE clipboard
1477 *---------------------------------------------------------------------*/
1479 static snapshot *snapshot_construct(DWORD seq_no)
1483 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1484 if (!This) return NULL;
1486 This->lpVtbl = &snapshot_vtable;
1488 This->seq_no = seq_no;
1494 /*********************************************************
1495 * register_clipboard_formats
1497 static void register_clipboard_formats(void)
1499 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1500 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1501 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1502 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1503 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1504 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1505 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1506 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1507 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1508 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1509 'D','e','s','c','r','i','p','t','o','r',0};
1510 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1512 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1513 'D','a','t','a','O','b','j','e','c','t',0};
1515 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1516 filename_clipboard_format = RegisterClipboardFormatW(FileName);
1517 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1518 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1519 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1520 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1521 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1522 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1523 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1524 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1525 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1527 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1530 /***********************************************************************
1531 * OLEClipbrd_Initialize()
1532 * Initializes the OLE clipboard.
1534 void OLEClipbrd_Initialize(void)
1536 register_clipboard_formats();
1538 if ( !theOleClipboard )
1540 ole_clipbrd* clipbrd;
1545 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1546 if (!clipbrd) return;
1548 clipbrd->latest_snapshot = NULL;
1549 clipbrd->window = NULL;
1550 clipbrd->src_data = NULL;
1551 clipbrd->cached_enum = NULL;
1553 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1556 HeapFree(GetProcessHeap(), 0, clipbrd);
1560 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1563 HeapFree(GetProcessHeap(), 0, clipbrd);
1567 theOleClipboard = clipbrd;
1571 /***********************************************************************
1572 * OLEClipbrd_UnInitialize()
1573 * Un-Initializes the OLE clipboard
1575 void OLEClipbrd_UnInitialize(void)
1577 ole_clipbrd *clipbrd = theOleClipboard;
1583 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1584 HINSTANCE hinst = GetModuleHandleW(ole32W);
1586 if ( clipbrd->window )
1588 DestroyWindow(clipbrd->window);
1589 UnregisterClassW( clipbrd_wndclass, hinst );
1592 IStream_Release(clipbrd->marshal_data);
1593 HeapFree(GetProcessHeap(), 0, clipbrd);
1594 theOleClipboard = NULL;
1598 /*********************************************************************
1599 * set_clipboard_formats
1601 * Enumerate all formats supported by the source and make
1602 * those formats available using delayed rendering using SetClipboardData.
1603 * Cache the enumeration list and make that list visibile as the
1604 * 'Ole Private Data' format on the clipboard.
1607 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1611 IEnumFORMATETC *enum_fmt;
1612 HGLOBAL priv_data_handle;
1613 DWORD_PTR target_offset;
1614 ole_priv_data *priv_data;
1615 DWORD count = 0, needed = sizeof(*priv_data), idx;
1617 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1618 if(FAILED(hr)) return hr;
1620 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1623 needed += sizeof(priv_data->entries[0]);
1626 needed += fmt.ptd->tdSize;
1627 CoTaskMemFree(fmt.ptd);
1631 /* Windows pads the list with two empty ole_priv_data_entries, one
1632 * after the entries array and one after the target device data.
1633 * Allocating with zero init to zero these pads. */
1635 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1636 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1637 priv_data = GlobalLock(priv_data_handle);
1639 priv_data->unk1 = 0;
1640 priv_data->size = needed;
1641 priv_data->unk2 = 1;
1642 priv_data->count = count;
1643 priv_data->unk3[0] = 0;
1644 priv_data->unk3[1] = 0;
1646 IEnumFORMATETC_Reset(enum_fmt);
1649 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1651 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1653 TRACE("%s\n", dump_fmtetc(&fmt));
1655 priv_data->entries[idx].fmtetc = fmt;
1658 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1659 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1660 target_offset += fmt.ptd->tdSize;
1661 CoTaskMemFree(fmt.ptd);
1664 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1665 priv_data->entries[idx].unk[0] = 0;
1666 priv_data->entries[idx].unk[1] = 0;
1668 if (priv_data->entries[idx].first_use)
1669 SetClipboardData(fmt.cfFormat, NULL);
1674 IEnumFORMATETC_Release(enum_fmt);
1676 /* Cache the list and fixup any target device offsets to ptrs */
1677 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1678 memcpy(clipbrd->cached_enum, priv_data, needed);
1679 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1680 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1681 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1683 GlobalUnlock(priv_data_handle);
1684 SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1689 static HWND create_clipbrd_window(void);
1691 /***********************************************************************
1692 * get_clipbrd_window
1694 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1696 if ( !clipbrd->window )
1697 clipbrd->window = create_clipbrd_window();
1699 *wnd = clipbrd->window;
1700 return *wnd ? S_OK : E_FAIL;
1704 /**********************************************************************
1705 * release_marshal_data
1707 * Releases the data and sets the stream back to zero size.
1709 static inline void release_marshal_data(IStream *stm)
1712 ULARGE_INTEGER size;
1713 pos.QuadPart = size.QuadPart = 0;
1715 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1716 CoReleaseMarshalData(stm);
1717 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1718 IStream_SetSize(stm, size);
1721 /***********************************************************************
1722 * expose_marshalled_dataobject
1724 * Sets the marshalled dataobject to the clipboard. In the flushed case
1725 * we set a zero sized HGLOBAL to clear the old marshalled data.
1727 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1734 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1735 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1738 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1740 if(!h) return E_OUTOFMEMORY;
1742 SetClipboardData(wine_marshal_clipboard_format, h);
1746 /***********************************************************************
1747 * set_src_dataobject
1749 * Clears and sets the clipboard's src IDataObject.
1751 * To marshal the source dataobject we do something rather different from Windows.
1752 * We set a clipboard format which contains the marshalled data.
1753 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1755 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1760 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1762 if(clipbrd->src_data)
1764 release_marshal_data(clipbrd->marshal_data);
1766 IDataObject_Release(clipbrd->src_data);
1767 clipbrd->src_data = NULL;
1768 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1769 clipbrd->cached_enum = NULL;
1776 IDataObject_AddRef(data);
1777 clipbrd->src_data = data;
1779 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1780 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1781 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1782 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1783 if(FAILED(hr)) return hr;
1784 hr = set_clipboard_formats(clipbrd, data);
1789 /***********************************************************************
1792 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1794 ole_clipbrd *clipbrd;
1796 get_ole_clipbrd(&clipbrd);
1800 case WM_RENDERFORMAT:
1803 ole_priv_data_entry *entry;
1805 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1806 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1809 render_format(clipbrd->src_data, &entry->fmtetc);
1814 case WM_RENDERALLFORMATS:
1817 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1819 TRACE("(): WM_RENDERALLFORMATS\n");
1821 for(i = 0; i < clipbrd->cached_enum->count; i++)
1823 if(entries[i].first_use)
1824 render_format(clipbrd->src_data, &entries[i].fmtetc);
1829 case WM_DESTROYCLIPBOARD:
1831 TRACE("(): WM_DESTROYCLIPBOARD\n");
1833 set_src_dataobject(clipbrd, NULL);
1838 return DefWindowProcW(hwnd, message, wparam, lparam);
1845 /***********************************************************************
1846 * create_clipbrd_window
1848 static HWND create_clipbrd_window(void)
1851 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1852 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1853 HINSTANCE hinst = GetModuleHandleW(ole32W);
1855 class.cbSize = sizeof(class);
1857 class.lpfnWndProc = clipbrd_wndproc;
1858 class.cbClsExtra = 0;
1859 class.cbWndExtra = 0;
1860 class.hInstance = hinst;
1863 class.hbrBackground = 0;
1864 class.lpszMenuName = NULL;
1865 class.lpszClassName = clipbrd_wndclass;
1866 class.hIconSm = NULL;
1868 RegisterClassExW(&class);
1870 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1871 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1872 NULL, NULL, hinst, 0);
1875 /*********************************************************************
1876 * set_dataobject_format
1878 * Windows creates a 'DataObject' clipboard format that contains the
1879 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1881 static HRESULT set_dataobject_format(HWND hwnd)
1883 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1886 if(!h) return E_OUTOFMEMORY;
1888 data = GlobalLock(h);
1892 if(!SetClipboardData(dataobject_clipboard_format, h))
1895 return CLIPBRD_E_CANT_SET;
1901 /*---------------------------------------------------------------------*
1902 * Win32 OLE clipboard API
1903 *---------------------------------------------------------------------*/
1905 /***********************************************************************
1906 * OleSetClipboard [OLE32.@]
1907 * Places a pointer to the specified data object onto the clipboard,
1908 * making the data object accessible to the OleGetClipboard function.
1912 * S_OK IDataObject pointer placed on the clipboard
1913 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1914 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1915 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1916 * CLIPBRD_E_CANT_SET SetClipboard failed
1919 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1922 ole_clipbrd *clipbrd;
1925 TRACE("(%p)\n", data);
1927 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1929 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1931 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1933 if ( !EmptyClipboard() )
1935 hr = CLIPBRD_E_CANT_EMPTY;
1939 hr = set_src_dataobject(clipbrd, data);
1940 if(FAILED(hr)) goto end;
1944 hr = expose_marshalled_dataobject(clipbrd, data);
1945 if(FAILED(hr)) goto end;
1946 hr = set_dataobject_format(wnd);
1951 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1955 expose_marshalled_dataobject(clipbrd, NULL);
1956 set_src_dataobject(clipbrd, NULL);
1963 /***********************************************************************
1964 * OleGetClipboard [OLE32.@]
1965 * Returns a pointer to our internal IDataObject which represents the conceptual
1966 * state of the Windows clipboard. If the current clipboard already contains
1967 * an IDataObject, our internal IDataObject will delegate to this object.
1969 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1972 ole_clipbrd *clipbrd;
1975 TRACE("(%p)\n", obj);
1977 if(!obj) return E_INVALIDARG;
1979 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1981 seq_no = GetClipboardSequenceNumber();
1982 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1983 clipbrd->latest_snapshot = NULL;
1985 if(!clipbrd->latest_snapshot)
1987 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1988 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1991 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1992 IDataObject_AddRef(*obj);
1997 /******************************************************************************
1998 * OleFlushClipboard [OLE32.@]
1999 * Renders the data from the source IDataObject into the windows clipboard
2001 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2002 * by copying the storage into global memory. Subsequently the default
2003 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2004 * back to TYMED_IStorage.
2006 HRESULT WINAPI OleFlushClipboard(void)
2009 ole_clipbrd *clipbrd;
2014 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2016 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2019 * Already flushed or no source DataObject? Nothing to do.
2021 if (!clipbrd->src_data) return S_OK;
2023 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2025 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2027 hr = set_dataobject_format(NULL);
2029 expose_marshalled_dataobject(clipbrd, NULL);
2030 set_src_dataobject(clipbrd, NULL);
2032 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2038 /***********************************************************************
2039 * OleIsCurrentClipboard [OLE32.@]
2041 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2044 ole_clipbrd *clipbrd;
2047 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2049 if (data == NULL) return S_FALSE;
2051 return (data == clipbrd->src_data) ? S_OK : S_FALSE;