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 /*****************************************************************************
108 * create_empty_priv_data
110 * Create an empty data structure. The only thing that really matters
111 * here is setting count and size members. This is used by the enumerator as a
112 * convenience when there's an empty list.
114 static HRESULT create_empty_priv_data(ole_priv_data **data)
119 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr));
120 if(!ptr) return E_OUTOFMEMORY;
121 ptr->size = sizeof(*ptr);
127 /****************************************************************************
128 * Consumer snapshot. Represents the state of the ole clipboard
129 * returned by OleGetClipboard().
131 typedef struct snapshot
133 const IDataObjectVtbl* lpVtbl;
136 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */
139 /****************************************************************************
142 typedef struct ole_clipbrd
144 snapshot *latest_snapshot; /* Latest consumer snapshot */
146 HWND window; /* Hidden clipboard window */
147 IDataObject *src_data; /* Source object passed to OleSetClipboard */
148 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
149 IStream *marshal_data; /* Stream onto which to marshal src_data */
152 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
154 return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
157 typedef struct PresentationDataHeader
160 DWORD dwObjectExtentX;
161 DWORD dwObjectExtentY;
163 } PresentationDataHeader;
166 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
168 static ole_clipbrd* theOleClipboard;
170 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
172 struct oletls *info = COM_CurrentInfo();
176 return CO_E_NOTINITIALIZED;
177 *clipbrd = theOleClipboard;
183 * Name of our registered OLE clipboard window class
185 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
187 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};
189 static UINT dataobject_clipboard_format;
190 static UINT ole_priv_data_clipboard_format;
191 static UINT embed_source_clipboard_format;
193 static inline char *dump_fmtetc(FORMATETC *fmt)
195 static char buf[100];
197 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
198 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
202 /*---------------------------------------------------------------------*
203 * Implementation of the internal IEnumFORMATETC interface returned by
204 * the OLE clipboard's IDataObject.
205 *---------------------------------------------------------------------*/
207 typedef struct enum_fmtetc
209 const IEnumFORMATETCVtbl *lpVtbl;
212 UINT pos; /* current enumerator position */
216 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
218 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
221 /************************************************************************
222 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
224 * See Windows documentation for more details on IUnknown methods.
226 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
227 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
229 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
231 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
235 if(IsEqualIID(riid, &IID_IUnknown) ||
236 IsEqualIID(riid, &IID_IEnumFORMATETC))
243 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
244 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
248 TRACE("-- Interface: E_NOINTERFACE\n");
249 return E_NOINTERFACE;
252 /************************************************************************
253 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
256 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
258 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
259 TRACE("(%p)->(count=%u)\n",This, This->ref);
261 return InterlockedIncrement(&This->ref);
264 /************************************************************************
265 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
267 * See Windows documentation for more details on IUnknown methods.
269 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
271 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
274 TRACE("(%p)->(count=%u)\n",This, This->ref);
276 ref = InterlockedDecrement(&This->ref);
279 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
280 HeapFree(GetProcessHeap(), 0, This->data);
281 HeapFree(GetProcessHeap(), 0, This);
286 /************************************************************************
287 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
289 * Standard enumerator members for IEnumFORMATETC
291 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
292 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
294 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
296 HRESULT hres = S_FALSE;
298 TRACE("(%p)->(pos=%u)\n", This, This->pos);
300 if (This->pos < This->data->count)
302 cfetch = This->data->count - This->pos;
309 for(i = 0; i < cfetch; i++)
311 rgelt[i] = This->data->entries[This->pos++].fmtetc;
314 DVTARGETDEVICE *target = (DVTARGETDEVICE *)((char *)This->data + (DWORD)rgelt[i].ptd);
315 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
316 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
317 memcpy(rgelt[i].ptd, target, target->tdSize);
328 *pceltFethed = cfetch;
334 /************************************************************************
335 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
337 * Standard enumerator members for IEnumFORMATETC
339 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
341 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
342 TRACE("(%p)->(num=%u)\n", This, celt);
345 if (This->pos > This->data->count)
347 This->pos = This->data->count;
353 /************************************************************************
354 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
356 * Standard enumerator members for IEnumFORMATETC
358 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
360 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
361 TRACE("(%p)->()\n", This);
367 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
369 /************************************************************************
370 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
372 * Standard enumerator members for IEnumFORMATETC
374 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
375 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
377 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
378 ole_priv_data *new_data;
380 TRACE("(%p)->(%p)\n", This, obj);
382 if ( !obj ) return E_INVALIDARG;
385 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
386 if(!new_data) return E_OUTOFMEMORY;
388 return enum_fmtetc_construct(new_data, This->pos, obj);
391 static const IEnumFORMATETCVtbl efvt =
393 OLEClipbrd_IEnumFORMATETC_QueryInterface,
394 OLEClipbrd_IEnumFORMATETC_AddRef,
395 OLEClipbrd_IEnumFORMATETC_Release,
396 OLEClipbrd_IEnumFORMATETC_Next,
397 OLEClipbrd_IEnumFORMATETC_Skip,
398 OLEClipbrd_IEnumFORMATETC_Reset,
399 OLEClipbrd_IEnumFORMATETC_Clone
402 /************************************************************************
403 * enum_fmtetc_construct
405 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
407 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
412 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
413 if (!ef) return E_OUTOFMEMORY;
420 TRACE("(%p)->()\n", ef);
421 *obj = (IEnumFORMATETC *)ef;
425 /***********************************************************************
428 * Helper method to duplicate an HGLOBAL chunk of memory
430 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
432 void *src_ptr, *dst_ptr;
436 if ( !src ) return S_FALSE;
438 size = GlobalSize(src);
440 *dst = GlobalAlloc( flags, size );
441 if ( !*dst ) return E_OUTOFMEMORY;
443 src_ptr = GlobalLock(src);
444 dst_ptr = GlobalLock(*dst);
446 memcpy(dst_ptr, src_ptr, size);
454 /************************************************************
455 * render_embed_source_hack
457 * This is clearly a hack and has no place in the clipboard code.
460 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
463 HGLOBAL hStorage = 0;
465 ILockBytes *ptrILockBytes;
467 memset(&std, 0, sizeof(STGMEDIUM));
468 std.tymed = fmt->tymed = TYMED_ISTORAGE;
470 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
471 if (hStorage == NULL) return E_OUTOFMEMORY;
472 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
473 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
474 ILockBytes_Release(ptrILockBytes);
476 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
478 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
479 GlobalFree(hStorage);
483 if (1) /* check whether the presentation data is already -not- present */
487 METAFILEPICT *mfp = 0;
489 fmt2.cfFormat = CF_METAFILEPICT;
491 fmt2.dwAspect = DVASPECT_CONTENT;
493 fmt2.tymed = TYMED_MFPICT;
495 memset(&std2, 0, sizeof(STGMEDIUM));
496 std2.tymed = TYMED_MFPICT;
498 /* Get the metafile picture out of it */
500 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
502 mfp = GlobalLock(std2.u.hGlobal);
507 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
508 IStream *pStream = 0;
510 PresentationDataHeader pdh;
514 CHAR strOleTypeName[51];
515 BYTE OlePresStreamHeader [] =
517 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
518 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
519 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
520 0x00, 0x00, 0x00, 0x00
523 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
525 memset(&pdh, 0, sizeof(PresentationDataHeader));
526 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
528 pdh.dwObjectExtentX = mfp->xExt;
529 pdh.dwObjectExtentY = mfp->yExt;
532 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
534 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
536 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
537 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
539 hr = IStream_Write(pStream, mfBits, nSize, NULL);
541 IStream_Release(pStream);
543 HeapFree(GetProcessHeap(), 0, mfBits);
545 GlobalUnlock(std2.u.hGlobal);
546 ReleaseStgMedium(&std2);
548 ReadClassStg(std.u.pstg, &clsID);
549 ProgIDFromCLSID(&clsID, &strProgID);
551 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
552 OLECONVERT_CreateOleStream(std.u.pstg);
553 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
557 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
559 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
560 GlobalFree(hStorage);
561 hr = CLIPBRD_E_CANT_SET;
564 ReleaseStgMedium(&std);
568 /************************************************************************
569 * find_format_in_list
571 * Returns the first entry that matches the provided clipboard format.
573 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
576 for(i = 0; i < num; i++)
577 if(entries[i].fmtetc.cfFormat == cf)
583 /***************************************************************************
584 * get_data_from_storage
586 * Returns storage data in an HGLOBAL.
588 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
599 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
600 if(!h) return E_OUTOFMEMORY;
602 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
605 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
606 ILockBytes_Release(lbs);
615 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
617 med.pUnkForRelease = NULL;
619 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
623 hr = IDataObject_GetData(data, &stg_fmt, &med);
624 if(FAILED(hr)) goto end;
626 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
627 ReleaseStgMedium(&med);
628 if(FAILED(hr)) goto end;
633 IStorage_Release(stg);
634 if(FAILED(hr)) GlobalFree(h);
638 /***************************************************************************
639 * get_data_from_stream
641 * Returns stream data in an HGLOBAL.
643 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
653 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
654 if(!h) return E_OUTOFMEMORY;
656 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
657 if(FAILED(hr)) goto error;
660 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
662 med.pUnkForRelease = NULL;
664 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
671 hr = IDataObject_GetData(data, &stm_fmt, &med);
672 if(FAILED(hr)) goto error;
675 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
676 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
677 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
678 ReleaseStgMedium(&med);
679 if(FAILED(hr)) goto error;
682 IStream_Release(stm);
686 if(stm) IStream_Release(stm);
691 /***************************************************************************
692 * get_data_from_global
694 * Returns global data in an HGLOBAL.
696 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
706 mem_fmt.tymed = TYMED_HGLOBAL;
708 hr = IDataObject_GetData(data, &mem_fmt, &med);
709 if(FAILED(hr)) return hr;
711 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
713 if(SUCCEEDED(hr)) *mem = h;
715 ReleaseStgMedium(&med);
720 /***********************************************************************
723 * Render the clipboard data. Note that this call will delegate to the
724 * source data object.
726 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
728 HGLOBAL clip_data = NULL;
731 /* Embed source hack */
732 if(fmt->cfFormat == embed_source_clipboard_format)
734 return render_embed_source_hack(data, fmt);
737 if(fmt->tymed & TYMED_ISTORAGE)
739 hr = get_data_from_storage(data, fmt, &clip_data);
741 else if(fmt->tymed & TYMED_ISTREAM)
743 hr = get_data_from_stream(data, fmt, &clip_data);
745 else if(fmt->tymed & TYMED_HGLOBAL)
747 hr = get_data_from_global(data, fmt, &clip_data);
751 FIXME("Unhandled tymed %x\n", fmt->tymed);
757 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
759 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
760 GlobalFree(clip_data);
761 hr = CLIPBRD_E_CANT_SET;
768 /*---------------------------------------------------------------------*
769 * Implementation of the internal IDataObject interface exposed by
771 *---------------------------------------------------------------------*/
774 /************************************************************************
775 * snapshot_QueryInterface
777 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
778 REFIID riid, void **ppvObject)
780 snapshot *This = impl_from_IDataObject(iface);
781 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
783 if ( (This==0) || (ppvObject==0) )
788 if (IsEqualIID(&IID_IUnknown, riid) ||
789 IsEqualIID(&IID_IDataObject, riid))
795 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
796 return E_NOINTERFACE;
799 IUnknown_AddRef((IUnknown*)*ppvObject);
804 /************************************************************************
807 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
809 snapshot *This = impl_from_IDataObject(iface);
811 TRACE("(%p)->(count=%u)\n", This, This->ref);
813 return InterlockedIncrement(&This->ref);
816 /***********************************************************************
817 * destroy_clipbrd_window
818 * Destroy the clipboard window and unregister its class
820 static void destroy_clipbrd_window(HWND hwnd)
822 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
823 HINSTANCE hinst = GetModuleHandleW(ole32W);
826 UnregisterClassW( clipbrd_wndclass, hinst );
829 static void OLEClipbrd_Destroy(ole_clipbrd* This)
835 if ( This->window ) destroy_clipbrd_window(This->window);
837 IStream_Release(This->marshal_data);
838 HeapFree(GetProcessHeap(), 0, This);
841 /************************************************************************
844 static ULONG WINAPI snapshot_Release(IDataObject *iface)
846 snapshot *This = impl_from_IDataObject(iface);
849 TRACE("(%p)->(count=%u)\n", This, This->ref);
851 ref = InterlockedDecrement(&This->ref);
855 ole_clipbrd *clipbrd;
856 HRESULT hr = get_ole_clipbrd(&clipbrd);
858 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
859 clipbrd->latest_snapshot = NULL;
860 HeapFree(GetProcessHeap(), 0, This);
866 /************************************************************
867 * get_current_ole_clip_window
869 * Return the window that owns the ole clipboard.
871 * If the clipboard is flushed or not owned by ole this will
874 static HWND get_current_ole_clip_window(void)
879 h = GetClipboardData(dataobject_clipboard_format);
882 if(!ptr) return NULL;
888 /************************************************************
889 * get_current_dataobject
891 * Return an unmarshalled IDataObject if there is a current
892 * (ie non-flushed) object on the ole clipboard.
894 static HRESULT get_current_dataobject(IDataObject **data)
896 HRESULT hr = S_FALSE;
897 HWND wnd = get_current_ole_clip_window();
904 if(!wnd) return S_FALSE;
906 h = GetPropW(wnd, wine_marshal_dataobject);
907 if(!h) return S_FALSE;
909 if(!ptr) return S_FALSE;
911 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
912 if(FAILED(hr)) goto end;
914 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
918 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
919 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
921 IStream_Release(stm);
928 /************************************************************************
931 static HRESULT WINAPI snapshot_GetData(IDataObject *iface,
932 FORMATETC *pformatetcIn,
939 TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
941 if ( !pformatetcIn || !pmedium )
944 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
946 hr = get_current_dataobject(&data);
949 hr = IDataObject_GetData(data, pformatetcIn, pmedium);
950 IDataObject_Release(data);
956 * Otherwise, get the data from the windows clipboard using GetClipboardData
959 if ( pformatetcIn->lindex != -1 )
965 if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
971 h = GetClipboardData(pformatetcIn->cfFormat);
972 hr = dup_global_mem(h, GMEM_MOVEABLE, &hData);
975 * Return the clipboard data in the storage medium structure
977 pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
978 pmedium->u.hGlobal = hData;
979 pmedium->pUnkForRelease = NULL;
982 if ( !CloseClipboard() ) return CLIPBRD_E_CANT_CLOSE;
984 if(FAILED(hr)) return hr;
985 return (hData == 0) ? DV_E_FORMATETC : S_OK;
988 /************************************************************************
989 * snapshot_GetDataHere
991 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
994 FIXME("(%p, %p, %p): stub\n", iface, fmt, med);
998 /************************************************************************
999 * snapshot_QueryGetData
1001 * The OLE Clipboard's implementation of this method delegates to
1002 * a data source if there is one or wraps around the windows clipboard
1003 * function IsClipboardFormatAvailable() otherwise.
1006 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1008 FIXME("(%p, %p)\n", iface, fmt);
1010 if (!fmt) return E_INVALIDARG;
1012 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1014 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1016 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1019 /************************************************************************
1020 * snapshot_GetCanonicalFormatEtc
1022 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1025 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1027 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1030 return DATA_S_SAMEFORMATETC;
1033 /************************************************************************
1036 * The OLE Clipboard does not implement this method
1038 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1039 STGMEDIUM *med, BOOL release)
1041 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1045 /************************************************************************
1046 * snapshot_EnumFormatEtc
1049 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1050 IEnumFORMATETC **enum_fmt)
1054 ole_priv_data *data = NULL;
1056 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1060 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1061 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1063 handle = GetClipboardData( ole_priv_data_clipboard_format );
1066 ole_priv_data *src = GlobalLock(handle);
1069 /* FIXME: sanity check on size */
1070 data = HeapAlloc(GetProcessHeap(), 0, src->size);
1073 GlobalUnlock(handle);
1077 memcpy(data, src, src->size);
1078 GlobalUnlock(handle);
1082 if(!data) hr = create_empty_priv_data(&data);
1083 if(FAILED(hr)) goto end;
1085 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1088 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1092 /************************************************************************
1095 * The OLE Clipboard does not implement this method
1097 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1098 DWORD flags, IAdviseSink *sink,
1101 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1105 /************************************************************************
1106 * snapshot_DUnadvise
1108 * The OLE Clipboard does not implement this method
1110 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1112 TRACE("(%p, %d): not implemented\n", iface, conn);
1116 /************************************************************************
1117 * snapshot_EnumDAdvise
1119 * The OLE Clipboard does not implement this method
1121 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1122 IEnumSTATDATA** enum_advise)
1124 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1128 static const IDataObjectVtbl snapshot_vtable =
1130 snapshot_QueryInterface,
1134 snapshot_GetDataHere,
1135 snapshot_QueryGetData,
1136 snapshot_GetCanonicalFormatEtc,
1138 snapshot_EnumFormatEtc,
1141 snapshot_EnumDAdvise
1144 /*---------------------------------------------------------------------*
1145 * Internal implementation methods for the OLE clipboard
1146 *---------------------------------------------------------------------*/
1148 static snapshot *snapshot_construct(DWORD seq_no)
1152 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1153 if (!This) return NULL;
1155 This->lpVtbl = &snapshot_vtable;
1157 This->seq_no = seq_no;
1162 /*********************************************************
1163 * Construct the OLEClipbrd class.
1165 static ole_clipbrd* OLEClipbrd_Construct(void)
1170 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1171 if (!This) return NULL;
1173 This->latest_snapshot = NULL;
1174 This->window = NULL;
1175 This->src_data = NULL;
1176 This->cached_enum = NULL;
1178 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1181 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &This->marshal_data)))
1187 if(h) GlobalFree(h);
1188 HeapFree(GetProcessHeap(), 0, This);
1192 static void register_clipboard_formats(void)
1194 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1195 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1196 static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1198 if(!dataobject_clipboard_format)
1199 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1200 if(!ole_priv_data_clipboard_format)
1201 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1202 if(!embed_source_clipboard_format)
1203 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1206 /***********************************************************************
1207 * OLEClipbrd_Initialize()
1208 * Initializes the OLE clipboard.
1210 void OLEClipbrd_Initialize(void)
1212 register_clipboard_formats();
1214 if ( !theOleClipboard )
1217 theOleClipboard = OLEClipbrd_Construct();
1222 /***********************************************************************
1223 * OLEClipbrd_UnInitialize()
1224 * Un-Initializes the OLE clipboard
1226 void OLEClipbrd_UnInitialize(void)
1230 if ( theOleClipboard )
1232 OLEClipbrd_Destroy( theOleClipboard );
1233 theOleClipboard = NULL;
1237 /*********************************************************************
1238 * set_clipboard_formats
1240 * Enumerate all formats supported by the source and make
1241 * those formats available using delayed rendering using SetClipboardData.
1242 * Cache the enumeration list and make that list visibile as the
1243 * 'Ole Private Data' format on the clipboard.
1246 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1250 IEnumFORMATETC *enum_fmt;
1251 HGLOBAL priv_data_handle;
1252 DWORD target_offset;
1253 ole_priv_data *priv_data;
1254 DWORD count = 0, needed = sizeof(*priv_data), idx;
1256 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1257 if(FAILED(hr)) return hr;
1259 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1262 needed += sizeof(priv_data->entries[0]);
1265 needed += fmt.ptd->tdSize;
1266 CoTaskMemFree(fmt.ptd);
1270 /* Windows pads the list with two empty ole_priv_data_entries, one
1271 * after the entries array and one after the target device data.
1272 * Allocating with zero init to zero these pads. */
1274 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1275 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1276 priv_data = GlobalLock(priv_data_handle);
1278 priv_data->unk1 = 0;
1279 priv_data->size = needed;
1280 priv_data->unk2 = 1;
1281 priv_data->count = count;
1282 priv_data->unk3[0] = 0;
1283 priv_data->unk3[1] = 0;
1285 IEnumFORMATETC_Reset(enum_fmt);
1288 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1290 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1292 TRACE("%s\n", dump_fmtetc(&fmt));
1294 priv_data->entries[idx].fmtetc = fmt;
1297 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1298 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1299 target_offset += fmt.ptd->tdSize;
1300 CoTaskMemFree(fmt.ptd);
1303 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1304 priv_data->entries[idx].unk[0] = 0;
1305 priv_data->entries[idx].unk[1] = 0;
1307 if (priv_data->entries[idx].first_use)
1308 SetClipboardData(fmt.cfFormat, NULL);
1313 IEnumFORMATETC_Release(enum_fmt);
1315 /* Cache the list and fixup any target device offsets to ptrs */
1316 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1317 memcpy(clipbrd->cached_enum, priv_data, needed);
1318 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1319 if(clipbrd->cached_enum->entries[idx].fmtetc.ptd)
1320 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1321 (DVTARGETDEVICE *)((char*)clipbrd->cached_enum + (DWORD)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1323 GlobalUnlock(priv_data_handle);
1324 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1329 static HWND create_clipbrd_window(void);
1331 /***********************************************************************
1332 * get_clipbrd_window
1334 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1336 if ( !clipbrd->window )
1337 clipbrd->window = create_clipbrd_window();
1339 *wnd = clipbrd->window;
1340 return *wnd ? S_OK : E_FAIL;
1344 /**********************************************************************
1345 * release_marshal_data
1347 * Releases the data and sets the stream back to zero size.
1349 static inline void release_marshal_data(IStream *stm)
1352 ULARGE_INTEGER size;
1353 pos.QuadPart = size.QuadPart = 0;
1355 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1356 CoReleaseMarshalData(stm);
1357 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1358 IStream_SetSize(stm, size);
1361 /***********************************************************************
1362 * set_src_dataobject
1364 * Clears and sets the clipboard's src IDataObject.
1366 * To marshal the source dataobject we do something rather different from Windows.
1367 * We set a window prop which contains the marshalled data.
1368 * Windows set two props one of which is an IID, the other is an endpoint number.
1370 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1375 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1377 if(clipbrd->src_data)
1379 RemovePropW(wnd, wine_marshal_dataobject);
1380 release_marshal_data(clipbrd->marshal_data);
1382 IDataObject_Release(clipbrd->src_data);
1383 clipbrd->src_data = NULL;
1384 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1385 clipbrd->cached_enum = NULL;
1393 IDataObject_AddRef(data);
1394 clipbrd->src_data = data;
1396 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1397 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1398 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1399 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1400 if(FAILED(hr)) return hr;
1401 GetHGlobalFromStream(clipbrd->marshal_data, &h);
1402 SetPropW(wnd, wine_marshal_dataobject, h);
1403 hr = set_clipboard_formats(clipbrd, data);
1408 /***********************************************************************
1411 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1413 ole_clipbrd *clipbrd;
1415 get_ole_clipbrd(&clipbrd);
1419 case WM_RENDERFORMAT:
1422 ole_priv_data_entry *entry;
1424 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1425 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1428 render_format(clipbrd->src_data, &entry->fmtetc);
1433 case WM_RENDERALLFORMATS:
1436 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1438 TRACE("(): WM_RENDERALLFORMATS\n");
1440 for(i = 0; i < clipbrd->cached_enum->count; i++)
1442 if(entries[i].first_use)
1443 render_format(clipbrd->src_data, &entries[i].fmtetc);
1448 case WM_DESTROYCLIPBOARD:
1450 TRACE("(): WM_DESTROYCLIPBOARD\n");
1452 set_src_dataobject(clipbrd, NULL);
1457 return DefWindowProcW(hwnd, message, wparam, lparam);
1464 /***********************************************************************
1465 * create_clipbrd_window
1467 static HWND create_clipbrd_window(void)
1470 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1471 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1472 HINSTANCE hinst = GetModuleHandleW(ole32W);
1474 class.cbSize = sizeof(class);
1476 class.lpfnWndProc = clipbrd_wndproc;
1477 class.cbClsExtra = 0;
1478 class.cbWndExtra = 0;
1479 class.hInstance = hinst;
1482 class.hbrBackground = 0;
1483 class.lpszMenuName = NULL;
1484 class.lpszClassName = clipbrd_wndclass;
1485 class.hIconSm = NULL;
1487 RegisterClassExW(&class);
1489 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1490 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1491 NULL, NULL, hinst, 0);
1494 /*********************************************************************
1495 * set_dataobject_format
1497 * Windows creates a 'DataObject' clipboard format that contains the
1498 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1500 static HRESULT set_dataobject_format(HWND hwnd)
1502 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1505 if(!h) return E_OUTOFMEMORY;
1507 data = GlobalLock(h);
1511 if(!SetClipboardData(dataobject_clipboard_format, h))
1514 return CLIPBRD_E_CANT_SET;
1520 /*---------------------------------------------------------------------*
1521 * Win32 OLE clipboard API
1522 *---------------------------------------------------------------------*/
1524 /***********************************************************************
1525 * OleSetClipboard [OLE32.@]
1526 * Places a pointer to the specified data object onto the clipboard,
1527 * making the data object accessible to the OleGetClipboard function.
1531 * S_OK IDataObject pointer placed on the clipboard
1532 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1533 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1534 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1535 * CLIPBRD_E_CANT_SET SetClipboard failed
1538 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1541 ole_clipbrd *clipbrd;
1544 TRACE("(%p)\n", data);
1546 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1548 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1550 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1552 if ( !EmptyClipboard() )
1554 hr = CLIPBRD_E_CANT_EMPTY;
1558 hr = set_src_dataobject(clipbrd, data);
1559 if(FAILED(hr)) goto end;
1561 hr = set_dataobject_format(wnd);
1565 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1569 set_src_dataobject(clipbrd, NULL);
1576 /***********************************************************************
1577 * OleGetClipboard [OLE32.@]
1578 * Returns a pointer to our internal IDataObject which represents the conceptual
1579 * state of the Windows clipboard. If the current clipboard already contains
1580 * an IDataObject, our internal IDataObject will delegate to this object.
1582 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1585 ole_clipbrd *clipbrd;
1588 TRACE("(%p)\n", obj);
1590 if(!obj) return E_INVALIDARG;
1592 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1594 seq_no = GetClipboardSequenceNumber();
1595 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1596 clipbrd->latest_snapshot = NULL;
1598 if(!clipbrd->latest_snapshot)
1600 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1601 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1604 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1605 IDataObject_AddRef(*obj);
1610 /******************************************************************************
1611 * OleFlushClipboard [OLE32.@]
1612 * Renders the data from the source IDataObject into the windows clipboard
1614 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1615 * by copying the storage into global memory. Subsequently the default
1616 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1617 * back to TYMED_IStorage.
1619 HRESULT WINAPI OleFlushClipboard(void)
1621 IEnumFORMATETC* penumFormatetc = NULL;
1624 ole_clipbrd *clipbrd;
1629 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1631 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1634 * Already flushed or no source DataObject? Nothing to do.
1636 if (!clipbrd->src_data) return S_OK;
1638 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1641 * Render all HGLOBAL formats supported by the source into
1642 * the windows clipboard.
1644 if ( FAILED( hr = IDataObject_EnumFormatEtc( clipbrd->src_data,
1650 while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
1652 if ( rgelt.tymed == TYMED_HGLOBAL )
1655 TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
1656 GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
1659 if ( FAILED(render_format( clipbrd->src_data, &rgelt )) )
1664 IEnumFORMATETC_Release(penumFormatetc);
1666 hr = set_dataobject_format(NULL);
1668 set_src_dataobject(clipbrd, NULL);
1672 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1678 /***********************************************************************
1679 * OleIsCurrentClipboard [OLE32.@]
1681 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1684 ole_clipbrd *clipbrd;
1687 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1689 if (data == NULL) return S_FALSE;
1691 return (data == clipbrd->src_data) ? S_OK : S_FALSE;