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.
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
76 #include "wine/debug.h"
79 #include "storage32.h"
81 #include "compobj_private.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(ole);
85 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
87 /* Structure of 'Ole Private Data' clipboard format */
91 DWORD first_use; /* Has this cf been added to the list already */
93 } ole_priv_data_entry;
98 DWORD size; /* in bytes of the entire structure */
100 DWORD count; /* no. of format entries */
102 ole_priv_data_entry entries[1]; /* array of size count */
103 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
106 /*****************************************************************************
107 * create_empty_priv_data
109 * Create an empty data structure. The only thing that really matters
110 * here is setting count and size members. This is used by the enumerator as a
111 * convenience when there's an empty list.
113 static HRESULT create_empty_priv_data(ole_priv_data **data)
118 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr));
119 if(!ptr) return E_OUTOFMEMORY;
120 ptr->size = sizeof(*ptr);
127 /****************************************************************************
130 typedef struct ole_clipbrd
132 const IDataObjectVtbl* lpvtbl; /* Exposed IDataObject vtable */
136 HWND hWndClipboard; /* Hidden clipboard window */
137 IDataObject *pIDataObjectSrc; /* Source object passed to OleSetClipboard */
138 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
141 static inline ole_clipbrd *impl_from_IDataObject(IDataObject *iface)
143 return (ole_clipbrd*)((char*)iface - FIELD_OFFSET(ole_clipbrd, lpvtbl));
146 typedef struct PresentationDataHeader
149 DWORD dwObjectExtentX;
150 DWORD dwObjectExtentY;
152 } PresentationDataHeader;
155 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
157 static ole_clipbrd* theOleClipboard;
161 * Name of our registered OLE clipboard window class
163 static const CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
165 static UINT dataobject_clipboard_format;
166 static UINT ole_priv_data_clipboard_format;
167 static UINT embed_source_clipboard_format;
169 /*---------------------------------------------------------------------*
170 * Implementation of the internal IEnumFORMATETC interface returned by
171 * the OLE clipboard's IDataObject.
172 *---------------------------------------------------------------------*/
174 typedef struct enum_fmtetc
176 const IEnumFORMATETCVtbl *lpVtbl;
179 UINT pos; /* current enumerator position */
183 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
185 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
188 /************************************************************************
189 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
191 * See Windows documentation for more details on IUnknown methods.
193 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
194 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
196 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
198 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
202 if(IsEqualIID(riid, &IID_IUnknown) ||
203 IsEqualIID(riid, &IID_IEnumFORMATETC))
210 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
211 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
215 TRACE("-- Interface: E_NOINTERFACE\n");
216 return E_NOINTERFACE;
219 /************************************************************************
220 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
223 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
225 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
226 TRACE("(%p)->(count=%u)\n",This, This->ref);
228 return InterlockedIncrement(&This->ref);
231 /************************************************************************
232 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
234 * See Windows documentation for more details on IUnknown methods.
236 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
238 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
241 TRACE("(%p)->(count=%u)\n",This, This->ref);
243 ref = InterlockedDecrement(&This->ref);
246 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
247 HeapFree(GetProcessHeap(), 0, This->data);
248 HeapFree(GetProcessHeap(), 0, This);
253 /************************************************************************
254 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
256 * Standard enumerator members for IEnumFORMATETC
258 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
259 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
261 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
263 HRESULT hres = S_FALSE;
265 TRACE("(%p)->(pos=%u)\n", This, This->pos);
267 if (This->pos < This->data->count)
269 cfetch = This->data->count - This->pos;
276 for(i = 0; i < cfetch; i++)
278 rgelt[i] = This->data->entries[This->pos++].fmtetc;
281 DVTARGETDEVICE *target = (DVTARGETDEVICE *)((char *)This->data + (DWORD)rgelt[i].ptd);
282 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
283 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
284 memcpy(rgelt[i].ptd, target, target->tdSize);
295 *pceltFethed = cfetch;
301 /************************************************************************
302 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
304 * Standard enumerator members for IEnumFORMATETC
306 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
308 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
309 TRACE("(%p)->(num=%u)\n", This, celt);
312 if (This->pos > This->data->count)
314 This->pos = This->data->count;
320 /************************************************************************
321 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
323 * Standard enumerator members for IEnumFORMATETC
325 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
327 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
328 TRACE("(%p)->()\n", This);
334 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
336 /************************************************************************
337 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
339 * Standard enumerator members for IEnumFORMATETC
341 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
342 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
344 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
345 ole_priv_data *new_data;
347 TRACE("(%p)->(%p)\n", This, obj);
349 if ( !obj ) return E_INVALIDARG;
352 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
353 if(!new_data) return E_OUTOFMEMORY;
355 return enum_fmtetc_construct(new_data, This->pos, obj);
358 static const IEnumFORMATETCVtbl efvt =
360 OLEClipbrd_IEnumFORMATETC_QueryInterface,
361 OLEClipbrd_IEnumFORMATETC_AddRef,
362 OLEClipbrd_IEnumFORMATETC_Release,
363 OLEClipbrd_IEnumFORMATETC_Next,
364 OLEClipbrd_IEnumFORMATETC_Skip,
365 OLEClipbrd_IEnumFORMATETC_Reset,
366 OLEClipbrd_IEnumFORMATETC_Clone
369 /************************************************************************
370 * enum_fmtetc_construct
372 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
374 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
379 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
380 if (!ef) return E_OUTOFMEMORY;
387 TRACE("(%p)->()\n", ef);
388 *obj = (IEnumFORMATETC *)ef;
392 /***********************************************************************
395 * Helper method to duplicate an HGLOBAL chunk of memory
397 static HRESULT dup_global_mem( HGLOBAL src, HGLOBAL *dst )
399 void *src_ptr, *dst_ptr;
403 if ( !src ) return S_FALSE;
405 size = GlobalSize(src);
407 *dst = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, size );
408 if ( !*dst ) return E_OUTOFMEMORY;
410 src_ptr = GlobalLock(src);
411 dst_ptr = GlobalLock(*dst);
413 memcpy(dst_ptr, src_ptr, size);
421 /************************************************************
422 * render_embed_source_hack
424 * This is clearly a hack and has no place in the clipboard code.
427 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
430 HGLOBAL hStorage = 0;
432 ILockBytes *ptrILockBytes;
434 memset(&std, 0, sizeof(STGMEDIUM));
435 std.tymed = fmt->tymed = TYMED_ISTORAGE;
437 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
438 if (hStorage == NULL) return E_OUTOFMEMORY;
439 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
440 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
441 ILockBytes_Release(ptrILockBytes);
443 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, fmt, &std)))
445 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
446 GlobalFree(hStorage);
450 if (1) /* check whether the presentation data is already -not- present */
454 METAFILEPICT *mfp = 0;
456 fmt2.cfFormat = CF_METAFILEPICT;
458 fmt2.dwAspect = DVASPECT_CONTENT;
460 fmt2.tymed = TYMED_MFPICT;
462 memset(&std2, 0, sizeof(STGMEDIUM));
463 std2.tymed = TYMED_MFPICT;
465 /* Get the metafile picture out of it */
467 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
469 mfp = GlobalLock(std2.u.hGlobal);
474 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
475 IStream *pStream = 0;
477 PresentationDataHeader pdh;
481 CHAR strOleTypeName[51];
482 BYTE OlePresStreamHeader [] =
484 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
485 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
486 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
487 0x00, 0x00, 0x00, 0x00
490 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
492 memset(&pdh, 0, sizeof(PresentationDataHeader));
493 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
495 pdh.dwObjectExtentX = mfp->xExt;
496 pdh.dwObjectExtentY = mfp->yExt;
499 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
501 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
503 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
504 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
506 hr = IStream_Write(pStream, mfBits, nSize, NULL);
508 IStream_Release(pStream);
510 HeapFree(GetProcessHeap(), 0, mfBits);
512 GlobalUnlock(std2.u.hGlobal);
513 ReleaseStgMedium(&std2);
515 ReadClassStg(std.u.pstg, &clsID);
516 ProgIDFromCLSID(&clsID, &strProgID);
518 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
519 OLECONVERT_CreateOleStream(std.u.pstg);
520 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
524 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
526 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
527 GlobalFree(hStorage);
528 hr = CLIPBRD_E_CANT_SET;
531 ReleaseStgMedium(&std);
535 /************************************************************************
536 * find_format_in_list
538 * Returns the first entry that matches the provided clipboard format.
540 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
543 for(i = 0; i < num; i++)
544 if(entries[i].fmtetc.cfFormat == cf)
550 /***************************************************************************
551 * get_data_from_stream
553 * Returns stream data in an HGLOBAL.
555 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
565 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
566 if(!h) return E_OUTOFMEMORY;
568 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
569 if(FAILED(hr)) goto error;
572 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
574 med.pUnkForRelease = NULL;
576 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
583 hr = IDataObject_GetData(data, &stm_fmt, &med);
584 if(FAILED(hr)) goto error;
587 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
588 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
589 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
590 ReleaseStgMedium(&med);
591 if(FAILED(hr)) goto error;
594 IStream_Release(stm);
598 if(stm) IStream_Release(stm);
603 /***************************************************************************
604 * get_data_from_global
606 * Returns global data in an HGLOBAL.
608 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
618 mem_fmt.tymed = TYMED_HGLOBAL;
620 hr = IDataObject_GetData(data, &mem_fmt, &med);
621 if(FAILED(hr)) return hr;
623 hr = dup_global_mem(med.u.hGlobal, &h);
625 if(SUCCEEDED(hr)) *mem = h;
627 ReleaseStgMedium(&med);
632 /***********************************************************************
635 * Render the clipboard data. Note that this call will delegate to the
636 * source data object.
638 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
640 HGLOBAL clip_data = NULL;
643 /* Embed source hack */
644 if(fmt->cfFormat == embed_source_clipboard_format)
646 return render_embed_source_hack(data, fmt);
649 if(fmt->tymed & TYMED_ISTREAM)
651 hr = get_data_from_stream(data, fmt, &clip_data);
653 else if(fmt->tymed & TYMED_HGLOBAL)
655 hr = get_data_from_global(data, fmt, &clip_data);
659 FIXME("Unhandled tymed %x\n", fmt->tymed);
665 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
667 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
668 GlobalFree(clip_data);
669 hr = CLIPBRD_E_CANT_SET;
676 /***********************************************************************
679 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
681 ole_clipbrd *clipbrd = theOleClipboard;
685 case WM_RENDERFORMAT:
688 ole_priv_data_entry *entry;
690 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
691 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
694 render_format(clipbrd->pIDataObjectSrc, &entry->fmtetc);
699 case WM_RENDERALLFORMATS:
702 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
704 TRACE("(): WM_RENDERALLFORMATS\n");
706 for(i = 0; i < clipbrd->cached_enum->count; i++)
708 if(entries[i].first_use)
709 render_format(clipbrd->pIDataObjectSrc, &entries[i].fmtetc);
714 case WM_DESTROYCLIPBOARD:
716 TRACE("(): WM_DESTROYCLIPBOARD\n");
718 if ( clipbrd->pIDataObjectSrc )
720 IDataObject_Release(clipbrd->pIDataObjectSrc);
721 clipbrd->pIDataObjectSrc = NULL;
722 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
723 clipbrd->cached_enum = NULL;
729 return DefWindowProcA(hwnd, message, wparam, lparam);
736 /*---------------------------------------------------------------------*
737 * Implementation of the internal IDataObject interface exposed by
739 *---------------------------------------------------------------------*/
742 /************************************************************************
743 * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
745 * See Windows documentation for more details on IUnknown methods.
747 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
752 ole_clipbrd *This = impl_from_IDataObject(iface);
753 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
755 if ( (This==0) || (ppvObject==0) )
760 if (IsEqualIID(&IID_IUnknown, riid) ||
761 IsEqualIID(&IID_IDataObject, riid))
767 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
768 return E_NOINTERFACE;
771 IUnknown_AddRef((IUnknown*)*ppvObject);
776 /************************************************************************
777 * OLEClipbrd_IDataObject_AddRef (IUnknown)
779 * See Windows documentation for more details on IUnknown methods.
781 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
784 ole_clipbrd *This = impl_from_IDataObject(iface);
786 TRACE("(%p)->(count=%u)\n",This, This->ref);
788 return InterlockedIncrement(&This->ref);
791 /***********************************************************************
792 * OLEClipbrd_DestroyWindow(HWND)
793 * Destroy the clipboard window and unregister its class
795 static void OLEClipbrd_DestroyWindow(HWND hwnd)
798 UnregisterClassA( OLEClipbrd_WNDCLASS, 0 );
801 static void OLEClipbrd_Destroy(ole_clipbrd* This)
807 theOleClipboard = NULL;
809 if ( This->hWndClipboard )
810 OLEClipbrd_DestroyWindow(This->hWndClipboard);
812 HeapFree(GetProcessHeap(), 0, This);
815 /************************************************************************
816 * OLEClipbrd_IDataObject_Release (IUnknown)
818 * See Windows documentation for more details on IUnknown methods.
820 static ULONG WINAPI OLEClipbrd_IDataObject_Release(
823 ole_clipbrd *This = impl_from_IDataObject(iface);
826 TRACE("(%p)->(count=%u)\n",This, This->ref);
828 ref = InterlockedDecrement(&This->ref);
832 OLEClipbrd_Destroy(This);
839 /************************************************************************
840 * OLEClipbrd_IDataObject_GetData (IDataObject)
842 * The OLE Clipboard's implementation of this method delegates to
843 * a data source if there is one or wraps around the windows clipboard
845 * See Windows documentation for more details on IDataObject methods.
847 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
849 LPFORMATETC pformatetcIn,
854 ole_clipbrd *This = impl_from_IDataObject(iface);
856 TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
858 if ( !pformatetcIn || !pmedium )
862 * If we have a data source placed on the clipboard (via OleSetClipboard)
863 * simply delegate to the source object's QueryGetData
864 * NOTE: This code assumes that the IDataObject is in the same address space!
865 * We will need to add marshalling support when Wine handles multiple processes.
867 if ( This->pIDataObjectSrc )
869 return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
872 if ( pformatetcIn->lindex != -1 )
873 return DV_E_FORMATETC;
875 if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
878 if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
879 return DV_E_DVASPECT;
883 * Otherwise, get the data from the windows clipboard using GetClipboardData
885 if ( !OpenClipboard(theOleClipboard->hWndClipboard)) return CLIPBRD_E_CANT_OPEN;
887 hData = GetClipboardData(pformatetcIn->cfFormat);
889 /* Must make a copy of global handle returned by GetClipboardData; it
890 * is not valid after we call CloseClipboard
891 * Application is responsible for freeing the memory (Forte Agent does this)
893 src = GlobalLock(hData);
899 size = GlobalSize(hData);
900 hDest = GlobalAlloc(GHND, size);
901 dest = GlobalLock(hDest);
902 memcpy(dest, src, size);
909 * Return the clipboard data in the storage medium structure
911 pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
912 pmedium->u.hGlobal = hData;
913 pmedium->pUnkForRelease = NULL;
915 if ( !CloseClipboard() ) return CLIPBRD_E_CANT_CLOSE;
917 return (hData == 0) ? DV_E_FORMATETC : S_OK;
920 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
922 LPFORMATETC pformatetc,
929 /************************************************************************
930 * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
932 * The OLE Clipboard's implementation of this method delegates to
933 * a data source if there is one or wraps around the windows clipboard
934 * function IsClipboardFormatAvailable() otherwise.
936 * See Windows documentation for more details on IDataObject methods.
938 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
940 LPFORMATETC pformatetc)
942 TRACE("(%p, %p)\n", iface, pformatetc);
947 if ( pformatetc->dwAspect != DVASPECT_CONTENT )
948 return DV_E_FORMATETC;
950 if ( pformatetc->lindex != -1 )
951 return DV_E_FORMATETC;
954 * Delegate to the Windows clipboard function IsClipboardFormatAvailable
956 return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
959 /************************************************************************
960 * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
962 * See Windows documentation for more details on IDataObject methods.
964 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
966 LPFORMATETC pformatectIn,
967 LPFORMATETC pformatetcOut)
969 TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
971 if ( !pformatectIn || !pformatetcOut )
974 *pformatetcOut = *pformatectIn;
975 return DATA_S_SAMEFORMATETC;
978 /************************************************************************
979 * OLEClipbrd_IDataObject_SetData (IDataObject)
981 * The OLE Clipboard's does not implement this method
983 * See Windows documentation for more details on IDataObject methods.
985 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
987 LPFORMATETC pformatetc,
995 /************************************************************************
996 * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
998 * See Windows documentation for more details on IDataObject methods.
1000 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
1003 IEnumFORMATETC** enum_fmt)
1006 ole_clipbrd *This = impl_from_IDataObject(iface);
1008 ole_priv_data *data = NULL;
1010 TRACE("(%p, %x, %p)\n", iface, dwDirection, enum_fmt);
1014 if ( dwDirection != DATADIR_GET ) return E_NOTIMPL;
1015 if ( !OpenClipboard(This->hWndClipboard) ) return CLIPBRD_E_CANT_OPEN;
1017 handle = GetClipboardData( ole_priv_data_clipboard_format );
1020 ole_priv_data *src = GlobalLock(handle);
1023 /* FIXME: sanity check on size */
1024 data = HeapAlloc(GetProcessHeap(), 0, src->size);
1027 GlobalUnlock(handle);
1031 memcpy(data, src, src->size);
1032 GlobalUnlock(handle);
1036 if(!data) hr = create_empty_priv_data(&data);
1037 if(FAILED(hr)) goto end;
1039 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1042 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1046 /************************************************************************
1047 * OLEClipbrd_IDataObject_DAdvise (IDataObject)
1049 * The OLE Clipboard's does not implement this method
1051 * See Windows documentation for more details on IDataObject methods.
1053 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
1055 FORMATETC* pformatetc,
1057 IAdviseSink* pAdvSink,
1058 DWORD* pdwConnection)
1064 /************************************************************************
1065 * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
1067 * The OLE Clipboard's does not implement this method
1069 * See Windows documentation for more details on IDataObject methods.
1071 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
1079 /************************************************************************
1080 * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
1082 * The OLE Clipboard does not implement this method
1084 * See Windows documentation for more details on IDataObject methods.
1086 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
1088 IEnumSTATDATA** ppenumAdvise)
1094 static const IDataObjectVtbl OLEClipbrd_IDataObject_VTable =
1096 OLEClipbrd_IDataObject_QueryInterface,
1097 OLEClipbrd_IDataObject_AddRef,
1098 OLEClipbrd_IDataObject_Release,
1099 OLEClipbrd_IDataObject_GetData,
1100 OLEClipbrd_IDataObject_GetDataHere,
1101 OLEClipbrd_IDataObject_QueryGetData,
1102 OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
1103 OLEClipbrd_IDataObject_SetData,
1104 OLEClipbrd_IDataObject_EnumFormatEtc,
1105 OLEClipbrd_IDataObject_DAdvise,
1106 OLEClipbrd_IDataObject_DUnadvise,
1107 OLEClipbrd_IDataObject_EnumDAdvise
1110 /*---------------------------------------------------------------------*
1111 * Internal implementation methods for the OLE clipboard
1112 *---------------------------------------------------------------------*/
1114 /*********************************************************
1115 * Construct the OLEClipbrd class.
1117 static ole_clipbrd* OLEClipbrd_Construct(void)
1121 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1122 if (!This) return NULL;
1124 This->lpvtbl = &OLEClipbrd_IDataObject_VTable;
1127 This->hWndClipboard = NULL;
1128 This->pIDataObjectSrc = NULL;
1129 This->cached_enum = NULL;
1131 theOleClipboard = This;
1135 static void register_clipboard_formats(void)
1137 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1138 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1139 static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1141 if(!dataobject_clipboard_format)
1142 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1143 if(!ole_priv_data_clipboard_format)
1144 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1145 if(!embed_source_clipboard_format)
1146 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1149 /***********************************************************************
1150 * OLEClipbrd_Initialize()
1151 * Initializes the OLE clipboard.
1153 void OLEClipbrd_Initialize(void)
1155 register_clipboard_formats();
1157 if ( !theOleClipboard )
1160 theOleClipboard = OLEClipbrd_Construct();
1165 /***********************************************************************
1166 * OLEClipbrd_UnInitialize()
1167 * Un-Initializes the OLE clipboard
1169 void OLEClipbrd_UnInitialize(void)
1173 * Destroy the clipboard if no one holds a reference to us.
1174 * Note that the clipboard was created with a reference count of 1.
1176 if ( theOleClipboard && (theOleClipboard->ref <= 1) )
1178 OLEClipbrd_Destroy( theOleClipboard );
1182 WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");
1186 /***********************************************************************
1187 * OLEClipbrd_CreateWindow()
1188 * Create the clipboard window
1190 static HWND OLEClipbrd_CreateWindow(void)
1196 * Register the clipboard window class if necessary
1198 ZeroMemory( &wcex, sizeof(WNDCLASSEXA));
1200 wcex.cbSize = sizeof(WNDCLASSEXA);
1201 /* Windows creates this class with a style mask of 0
1202 * We don't bother doing this since the FindClassByAtom code
1203 * would have to be changed to deal with this idiosyncrasy. */
1204 wcex.style = CS_GLOBALCLASS;
1205 wcex.lpfnWndProc = clipbrd_wndproc;
1207 wcex.lpszClassName = OLEClipbrd_WNDCLASS;
1209 RegisterClassExA(&wcex);
1212 * Create a hidden window to receive OLE clipboard messages
1216 * If we need to store state info we can store it here.
1217 * For now we don't need this functionality.
1218 * ClipboardWindowInfo clipboardInfo;
1219 * ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo));
1222 hwnd = CreateWindowA(OLEClipbrd_WNDCLASS,
1224 WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1225 CW_USEDEFAULT, CW_USEDEFAULT,
1226 CW_USEDEFAULT, CW_USEDEFAULT,
1230 0 /*(LPVOID)&clipboardInfo */);
1235 /*********************************************************************
1236 * set_clipboard_formats
1238 * Enumerate all HGLOBAL formats supported by the source and make
1239 * those formats available using delayed rendering using SetClipboardData.
1241 * TODO: We need to additionally handle TYMED_IStorage and
1242 * TYMED_IStream data by copying into global memory.
1244 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1248 IEnumFORMATETC *enum_fmt;
1249 HGLOBAL priv_data_handle;
1250 DWORD target_offset;
1251 ole_priv_data *priv_data;
1252 DWORD count = 0, needed = sizeof(*priv_data), idx;
1254 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1255 if(FAILED(hr)) return hr;
1257 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1260 needed += sizeof(priv_data->entries[0]);
1263 needed += fmt.ptd->tdSize;
1264 CoTaskMemFree(fmt.ptd);
1268 /* Windows pads the list with two empty ole_priv_data_entries, one
1269 * after the entries array and one after the target device data.
1270 * Allocating with zero init to zero these pads. */
1272 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1273 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1274 priv_data = GlobalLock(priv_data_handle);
1276 priv_data->unk1 = 0;
1277 priv_data->size = needed;
1278 priv_data->unk2 = 1;
1279 priv_data->count = count;
1280 priv_data->unk3[0] = 0;
1281 priv_data->unk3[1] = 0;
1283 IEnumFORMATETC_Reset(enum_fmt);
1286 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1288 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1290 if (fmt.tymed == TYMED_HGLOBAL)
1293 TRACE("(cfFormat=%d:%s)\n", fmt.cfFormat,
1294 GetClipboardFormatNameA(fmt.cfFormat, fmt_name, sizeof(fmt_name)-1) ? fmt_name : "");
1296 SetClipboardData(fmt.cfFormat, NULL);
1299 priv_data->entries[idx].fmtetc = fmt;
1302 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1303 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1304 target_offset += fmt.ptd->tdSize;
1305 CoTaskMemFree(fmt.ptd);
1308 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1309 priv_data->entries[idx].unk[0] = 0;
1310 priv_data->entries[idx].unk[1] = 0;
1315 IEnumFORMATETC_Release(enum_fmt);
1317 /* Cache the list and fixup any target device offsets to ptrs */
1318 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1319 memcpy(clipbrd->cached_enum, priv_data, needed);
1320 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1321 if(clipbrd->cached_enum->entries[idx].fmtetc.ptd)
1322 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1323 (DVTARGETDEVICE *)((char*)clipbrd->cached_enum + (DWORD)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1325 GlobalUnlock(priv_data_handle);
1326 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1331 /*********************************************************************
1332 * set_dataobject_format
1334 * Windows creates a 'DataObject' clipboard format that contains the
1335 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1337 static HRESULT set_dataobject_format(HWND hwnd)
1339 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1342 if(!h) return E_OUTOFMEMORY;
1344 data = GlobalLock(h);
1348 if(!SetClipboardData(dataobject_clipboard_format, h))
1351 return CLIPBRD_E_CANT_SET;
1357 /*---------------------------------------------------------------------*
1358 * Win32 OLE clipboard API
1359 *---------------------------------------------------------------------*/
1361 /***********************************************************************
1362 * OleSetClipboard [OLE32.@]
1363 * Places a pointer to the specified data object onto the clipboard,
1364 * making the data object accessible to the OleGetClipboard function.
1368 * S_OK IDataObject pointer placed on the clipboard
1369 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1370 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1371 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1372 * CLIPBRD_E_CANT_SET SetClipboard failed
1375 HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)
1378 struct oletls *info = COM_CurrentInfo();
1380 TRACE("(%p)\n", pDataObj);
1383 WARN("Could not allocate tls\n");
1385 if(!info->ole_inits)
1386 return CO_E_NOTINITIALIZED;
1388 OLEClipbrd_Initialize();
1391 * If the Ole clipboard window hasn't been created yet, create it now.
1393 if ( !theOleClipboard->hWndClipboard )
1394 theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
1396 if ( !theOleClipboard->hWndClipboard ) return E_FAIL;
1398 if ( !OpenClipboard(theOleClipboard->hWndClipboard) ) return CLIPBRD_E_CANT_OPEN;
1401 * Empty the current clipboard and make our window the clipboard owner
1402 * NOTE: This will trigger a WM_DESTROYCLIPBOARD message
1404 if ( !EmptyClipboard() )
1406 hr = CLIPBRD_E_CANT_EMPTY;
1411 * If we are already holding on to an IDataObject first release that.
1413 if ( theOleClipboard->pIDataObjectSrc )
1415 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1416 theOleClipboard->pIDataObjectSrc = NULL;
1417 HeapFree(GetProcessHeap(), 0, theOleClipboard->cached_enum);
1418 theOleClipboard->cached_enum = NULL;
1421 /* A NULL value indicates that the clipboard should be emptied. */
1422 theOleClipboard->pIDataObjectSrc = pDataObj;
1425 IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
1426 hr = set_clipboard_formats(theOleClipboard, pDataObj);
1427 if(FAILED(hr)) goto end;
1430 hr = set_dataobject_format(theOleClipboard->hWndClipboard);
1434 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1438 if (theOleClipboard->pIDataObjectSrc)
1440 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1441 theOleClipboard->pIDataObjectSrc = NULL;
1442 HeapFree(GetProcessHeap(), 0, theOleClipboard->cached_enum);
1443 theOleClipboard->cached_enum = NULL;
1451 /***********************************************************************
1452 * OleGetClipboard [OLE32.@]
1453 * Returns a pointer to our internal IDataObject which represents the conceptual
1454 * state of the Windows clipboard. If the current clipboard already contains
1455 * an IDataObject, our internal IDataObject will delegate to this object.
1457 HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
1463 * Make sure we have a clipboard object
1465 OLEClipbrd_Initialize();
1467 if (!theOleClipboard)
1468 return E_OUTOFMEMORY;
1470 /* Return a reference counted IDataObject */
1471 hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl),
1472 &IID_IDataObject, (void**)ppDataObj);
1476 /******************************************************************************
1477 * OleFlushClipboard [OLE32.@]
1478 * Renders the data from the source IDataObject into the windows clipboard
1480 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1481 * by copying the storage into global memory. Subsequently the default
1482 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1483 * back to TYMED_IStorage.
1485 HRESULT WINAPI OleFlushClipboard(void)
1487 IEnumFORMATETC* penumFormatetc = NULL;
1493 OLEClipbrd_Initialize();
1496 * Already flushed or no source DataObject? Nothing to do.
1498 if (!theOleClipboard->pIDataObjectSrc)
1501 if (!OpenClipboard(theOleClipboard->hWndClipboard))
1502 return CLIPBRD_E_CANT_OPEN;
1505 * Render all HGLOBAL formats supported by the source into
1506 * the windows clipboard.
1508 if ( FAILED( hr = IDataObject_EnumFormatEtc( theOleClipboard->pIDataObjectSrc,
1514 while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
1516 if ( rgelt.tymed == TYMED_HGLOBAL )
1519 TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
1520 GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
1523 if ( FAILED(render_format( theOleClipboard->pIDataObjectSrc, &rgelt )) )
1528 IEnumFORMATETC_Release(penumFormatetc);
1530 hr = set_dataobject_format(NULL);
1532 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1533 theOleClipboard->pIDataObjectSrc = NULL;
1534 HeapFree(GetProcessHeap(), 0, theOleClipboard->cached_enum);
1535 theOleClipboard->cached_enum = NULL;
1539 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1545 /***********************************************************************
1546 * OleIsCurrentClipboard [OLE32.@]
1548 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject)
1552 * Make sure we have a clipboard object
1554 OLEClipbrd_Initialize();
1556 if (!theOleClipboard)
1557 return E_OUTOFMEMORY;
1559 if (pDataObject == NULL)
1562 return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;