push 6a1f8ca2ce22619d48dee86b15ebc76beb30adf4
[wine/hacks.git] / dlls / ole32 / clipboard.c
blobeaffb777853c5176bde633e974cce20906b1b367
1 /*
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
21 * NOTES:
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
46 * TODO:
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.
61 #include <assert.h>
62 #include <stdarg.h>
63 #include <string.h>
64 #include <stdio.h>
66 #define COBJMACROS
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
70 #include "windef.h"
71 #include "winbase.h"
72 #include "wingdi.h"
73 #include "winuser.h"
74 #include "winerror.h"
75 #include "winnls.h"
76 #include "ole2.h"
77 #include "wine/debug.h"
78 #include "olestd.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 */
89 typedef struct
91 FORMATETC fmtetc;
92 DWORD first_use; /* Has this cf been added to the list already */
93 DWORD unk[2];
94 } ole_priv_data_entry;
96 typedef struct
98 DWORD unk1;
99 DWORD size; /* in bytes of the entire structure */
100 DWORD unk2;
101 DWORD count; /* no. of format entries */
102 DWORD unk3[2];
103 ole_priv_data_entry entries[1]; /* array of size count */
104 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
105 } ole_priv_data;
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)
116 ole_priv_data *ptr;
118 *data = NULL;
119 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr));
120 if(!ptr) return E_OUTOFMEMORY;
121 ptr->size = sizeof(*ptr);
122 ptr->count = 0;
123 *data = ptr;
124 return S_OK;
127 /****************************************************************************
128 * Consumer snapshot. Represents the state of the ole clipboard
129 * returned by OleGetClipboard().
131 typedef struct snapshot
133 const IDataObjectVtbl* lpVtbl;
134 LONG ref;
136 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */
138 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */
139 } snapshot;
141 /****************************************************************************
142 * ole_clipbrd
144 typedef struct ole_clipbrd
146 snapshot *latest_snapshot; /* Latest consumer snapshot */
148 HWND window; /* Hidden clipboard window */
149 IDataObject *src_data; /* Source object passed to OleSetClipboard */
150 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
151 IStream *marshal_data; /* Stream onto which to marshal src_data */
152 } ole_clipbrd;
154 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
156 return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
159 typedef struct PresentationDataHeader
161 BYTE unknown1[28];
162 DWORD dwObjectExtentX;
163 DWORD dwObjectExtentY;
164 DWORD dwSize;
165 } PresentationDataHeader;
168 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
170 static ole_clipbrd* theOleClipboard;
172 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
174 struct oletls *info = COM_CurrentInfo();
175 *clipbrd = NULL;
177 if(!info->ole_inits)
178 return CO_E_NOTINITIALIZED;
179 *clipbrd = theOleClipboard;
181 return S_OK;
185 * Name of our registered OLE clipboard window class
187 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
189 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};
191 static UINT dataobject_clipboard_format;
192 static UINT ole_priv_data_clipboard_format;
193 static UINT embed_source_clipboard_format;
195 static inline char *dump_fmtetc(FORMATETC *fmt)
197 static char buf[100];
199 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
200 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
201 return buf;
204 /*---------------------------------------------------------------------*
205 * Implementation of the internal IEnumFORMATETC interface returned by
206 * the OLE clipboard's IDataObject.
207 *---------------------------------------------------------------------*/
209 typedef struct enum_fmtetc
211 const IEnumFORMATETCVtbl *lpVtbl;
212 LONG ref;
214 UINT pos; /* current enumerator position */
215 ole_priv_data *data;
216 } enum_fmtetc;
218 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
220 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
223 /************************************************************************
224 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
226 * See Windows documentation for more details on IUnknown methods.
228 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
229 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
231 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
233 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
235 *ppvObj = NULL;
237 if(IsEqualIID(riid, &IID_IUnknown) ||
238 IsEqualIID(riid, &IID_IEnumFORMATETC))
240 *ppvObj = iface;
243 if(*ppvObj)
245 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
246 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
247 return S_OK;
250 TRACE("-- Interface: E_NOINTERFACE\n");
251 return E_NOINTERFACE;
254 /************************************************************************
255 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
258 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
260 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
261 TRACE("(%p)->(count=%u)\n",This, This->ref);
263 return InterlockedIncrement(&This->ref);
266 /************************************************************************
267 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
269 * See Windows documentation for more details on IUnknown methods.
271 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
273 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
274 ULONG ref;
276 TRACE("(%p)->(count=%u)\n",This, This->ref);
278 ref = InterlockedDecrement(&This->ref);
279 if (!ref)
281 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
282 HeapFree(GetProcessHeap(), 0, This->data);
283 HeapFree(GetProcessHeap(), 0, This);
285 return ref;
288 /************************************************************************
289 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
291 * Standard enumerator members for IEnumFORMATETC
293 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
294 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
296 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
297 UINT cfetch, i;
298 HRESULT hres = S_FALSE;
300 TRACE("(%p)->(pos=%u)\n", This, This->pos);
302 if (This->pos < This->data->count)
304 cfetch = This->data->count - This->pos;
305 if (cfetch >= celt)
307 cfetch = celt;
308 hres = S_OK;
311 for(i = 0; i < cfetch; i++)
313 rgelt[i] = This->data->entries[This->pos++].fmtetc;
314 if(rgelt[i].ptd)
316 DVTARGETDEVICE *target = (DVTARGETDEVICE *)((char *)This->data + (DWORD)rgelt[i].ptd);
317 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
318 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
319 memcpy(rgelt[i].ptd, target, target->tdSize);
323 else
325 cfetch = 0;
328 if (pceltFethed)
330 *pceltFethed = cfetch;
333 return hres;
336 /************************************************************************
337 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
339 * Standard enumerator members for IEnumFORMATETC
341 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
343 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
344 TRACE("(%p)->(num=%u)\n", This, celt);
346 This->pos += celt;
347 if (This->pos > This->data->count)
349 This->pos = This->data->count;
350 return S_FALSE;
352 return S_OK;
355 /************************************************************************
356 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
358 * Standard enumerator members for IEnumFORMATETC
360 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
362 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
363 TRACE("(%p)->()\n", This);
365 This->pos = 0;
366 return S_OK;
369 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
371 /************************************************************************
372 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
374 * Standard enumerator members for IEnumFORMATETC
376 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
377 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
379 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
380 ole_priv_data *new_data;
382 TRACE("(%p)->(%p)\n", This, obj);
384 if ( !obj ) return E_INVALIDARG;
385 *obj = NULL;
387 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
388 if(!new_data) return E_OUTOFMEMORY;
390 return enum_fmtetc_construct(new_data, This->pos, obj);
393 static const IEnumFORMATETCVtbl efvt =
395 OLEClipbrd_IEnumFORMATETC_QueryInterface,
396 OLEClipbrd_IEnumFORMATETC_AddRef,
397 OLEClipbrd_IEnumFORMATETC_Release,
398 OLEClipbrd_IEnumFORMATETC_Next,
399 OLEClipbrd_IEnumFORMATETC_Skip,
400 OLEClipbrd_IEnumFORMATETC_Reset,
401 OLEClipbrd_IEnumFORMATETC_Clone
404 /************************************************************************
405 * enum_fmtetc_construct
407 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
409 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
411 enum_fmtetc* ef;
413 *obj = NULL;
414 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
415 if (!ef) return E_OUTOFMEMORY;
417 ef->ref = 1;
418 ef->lpVtbl = &efvt;
419 ef->data = data;
420 ef->pos = pos;
422 TRACE("(%p)->()\n", ef);
423 *obj = (IEnumFORMATETC *)ef;
424 return S_OK;
427 /***********************************************************************
428 * dup_global_mem
430 * Helper method to duplicate an HGLOBAL chunk of memory
432 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
434 void *src_ptr, *dst_ptr;
435 DWORD size;
437 *dst = NULL;
438 if ( !src ) return S_FALSE;
440 size = GlobalSize(src);
442 *dst = GlobalAlloc( flags, size );
443 if ( !*dst ) return E_OUTOFMEMORY;
445 src_ptr = GlobalLock(src);
446 dst_ptr = GlobalLock(*dst);
448 memcpy(dst_ptr, src_ptr, size);
450 GlobalUnlock(*dst);
451 GlobalUnlock(src);
453 return S_OK;
456 /************************************************************
457 * render_embed_source_hack
459 * This is clearly a hack and has no place in the clipboard code.
462 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
464 STGMEDIUM std;
465 HGLOBAL hStorage = 0;
466 HRESULT hr = S_OK;
467 ILockBytes *ptrILockBytes;
469 memset(&std, 0, sizeof(STGMEDIUM));
470 std.tymed = fmt->tymed = TYMED_ISTORAGE;
472 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
473 if (hStorage == NULL) return E_OUTOFMEMORY;
474 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
475 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
476 ILockBytes_Release(ptrILockBytes);
478 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
480 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
481 GlobalFree(hStorage);
482 return hr;
485 if (1) /* check whether the presentation data is already -not- present */
487 FORMATETC fmt2;
488 STGMEDIUM std2;
489 METAFILEPICT *mfp = 0;
491 fmt2.cfFormat = CF_METAFILEPICT;
492 fmt2.ptd = 0;
493 fmt2.dwAspect = DVASPECT_CONTENT;
494 fmt2.lindex = -1;
495 fmt2.tymed = TYMED_MFPICT;
497 memset(&std2, 0, sizeof(STGMEDIUM));
498 std2.tymed = TYMED_MFPICT;
500 /* Get the metafile picture out of it */
502 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
504 mfp = GlobalLock(std2.u.hGlobal);
507 if (mfp)
509 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
510 IStream *pStream = 0;
511 void *mfBits;
512 PresentationDataHeader pdh;
513 INT nSize;
514 CLSID clsID;
515 LPOLESTR strProgID;
516 CHAR strOleTypeName[51];
517 BYTE OlePresStreamHeader [] =
519 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
520 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
521 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
522 0x00, 0x00, 0x00, 0x00
525 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
527 memset(&pdh, 0, sizeof(PresentationDataHeader));
528 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
530 pdh.dwObjectExtentX = mfp->xExt;
531 pdh.dwObjectExtentY = mfp->yExt;
532 pdh.dwSize = nSize;
534 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
536 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
538 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
539 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
541 hr = IStream_Write(pStream, mfBits, nSize, NULL);
543 IStream_Release(pStream);
545 HeapFree(GetProcessHeap(), 0, mfBits);
547 GlobalUnlock(std2.u.hGlobal);
548 ReleaseStgMedium(&std2);
550 ReadClassStg(std.u.pstg, &clsID);
551 ProgIDFromCLSID(&clsID, &strProgID);
553 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
554 OLECONVERT_CreateOleStream(std.u.pstg);
555 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
559 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
561 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
562 GlobalFree(hStorage);
563 hr = CLIPBRD_E_CANT_SET;
566 ReleaseStgMedium(&std);
567 return hr;
570 /************************************************************************
571 * find_format_in_list
573 * Returns the first entry that matches the provided clipboard format.
575 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
577 DWORD i;
578 for(i = 0; i < num; i++)
579 if(entries[i].fmtetc.cfFormat == cf)
580 return &entries[i];
582 return NULL;
585 /***************************************************************************
586 * get_data_from_storage
588 * Returns storage data in an HGLOBAL.
590 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
592 HGLOBAL h;
593 IStorage *stg;
594 HRESULT hr;
595 FORMATETC stg_fmt;
596 STGMEDIUM med;
597 ILockBytes *lbs;
599 *mem = NULL;
601 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
602 if(!h) return E_OUTOFMEMORY;
604 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
605 if(SUCCEEDED(hr))
607 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
608 ILockBytes_Release(lbs);
610 if(FAILED(hr))
612 GlobalFree(h);
613 return hr;
616 stg_fmt = *fmt;
617 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
618 med.u.pstg = stg;
619 med.pUnkForRelease = NULL;
621 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
622 if(FAILED(hr))
624 med.u.pstg = NULL;
625 hr = IDataObject_GetData(data, &stg_fmt, &med);
626 if(FAILED(hr)) goto end;
628 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
629 ReleaseStgMedium(&med);
630 if(FAILED(hr)) goto end;
632 *mem = h;
634 end:
635 IStorage_Release(stg);
636 if(FAILED(hr)) GlobalFree(h);
637 return hr;
640 /***************************************************************************
641 * get_data_from_stream
643 * Returns stream data in an HGLOBAL.
645 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
647 HGLOBAL h;
648 IStream *stm = NULL;
649 HRESULT hr;
650 FORMATETC stm_fmt;
651 STGMEDIUM med;
653 *mem = NULL;
655 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
656 if(!h) return E_OUTOFMEMORY;
658 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
659 if(FAILED(hr)) goto error;
661 stm_fmt = *fmt;
662 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
663 med.u.pstm = stm;
664 med.pUnkForRelease = NULL;
666 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
667 if(FAILED(hr))
669 LARGE_INTEGER offs;
670 ULARGE_INTEGER pos;
672 med.u.pstm = NULL;
673 hr = IDataObject_GetData(data, &stm_fmt, &med);
674 if(FAILED(hr)) goto error;
676 offs.QuadPart = 0;
677 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
678 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
679 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
680 ReleaseStgMedium(&med);
681 if(FAILED(hr)) goto error;
683 *mem = h;
684 IStream_Release(stm);
685 return S_OK;
687 error:
688 if(stm) IStream_Release(stm);
689 GlobalFree(h);
690 return hr;
693 /***************************************************************************
694 * get_data_from_global
696 * Returns global data in an HGLOBAL.
698 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
700 HGLOBAL h;
701 HRESULT hr;
702 FORMATETC mem_fmt;
703 STGMEDIUM med;
705 *mem = NULL;
707 mem_fmt = *fmt;
708 mem_fmt.tymed = TYMED_HGLOBAL;
710 hr = IDataObject_GetData(data, &mem_fmt, &med);
711 if(FAILED(hr)) return hr;
713 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
715 if(SUCCEEDED(hr)) *mem = h;
717 ReleaseStgMedium(&med);
719 return hr;
722 /***********************************************************************
723 * render_format
725 * Render the clipboard data. Note that this call will delegate to the
726 * source data object.
728 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
730 HGLOBAL clip_data = NULL;
731 HRESULT hr;
733 /* Embed source hack */
734 if(fmt->cfFormat == embed_source_clipboard_format)
736 return render_embed_source_hack(data, fmt);
739 if(fmt->tymed & TYMED_ISTORAGE)
741 hr = get_data_from_storage(data, fmt, &clip_data);
743 else if(fmt->tymed & TYMED_ISTREAM)
745 hr = get_data_from_stream(data, fmt, &clip_data);
747 else if(fmt->tymed & TYMED_HGLOBAL)
749 hr = get_data_from_global(data, fmt, &clip_data);
751 else
753 FIXME("Unhandled tymed %x\n", fmt->tymed);
754 hr = DV_E_FORMATETC;
757 if(SUCCEEDED(hr))
759 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
761 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
762 GlobalFree(clip_data);
763 hr = CLIPBRD_E_CANT_SET;
767 return hr;
770 /*---------------------------------------------------------------------*
771 * Implementation of the internal IDataObject interface exposed by
772 * the OLE clipboard.
773 *---------------------------------------------------------------------*/
776 /************************************************************************
777 * snapshot_QueryInterface
779 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
780 REFIID riid, void **ppvObject)
782 snapshot *This = impl_from_IDataObject(iface);
783 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
785 if ( (This==0) || (ppvObject==0) )
786 return E_INVALIDARG;
788 *ppvObject = 0;
790 if (IsEqualIID(&IID_IUnknown, riid) ||
791 IsEqualIID(&IID_IDataObject, riid))
793 *ppvObject = iface;
795 else
797 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
798 return E_NOINTERFACE;
801 IUnknown_AddRef((IUnknown*)*ppvObject);
803 return S_OK;
806 /************************************************************************
807 * snapshot_AddRef
809 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
811 snapshot *This = impl_from_IDataObject(iface);
813 TRACE("(%p)->(count=%u)\n", This, This->ref);
815 return InterlockedIncrement(&This->ref);
818 /************************************************************************
819 * snapshot_Release
821 static ULONG WINAPI snapshot_Release(IDataObject *iface)
823 snapshot *This = impl_from_IDataObject(iface);
824 ULONG ref;
826 TRACE("(%p)->(count=%u)\n", This, This->ref);
828 ref = InterlockedDecrement(&This->ref);
830 if (ref == 0)
832 ole_clipbrd *clipbrd;
833 HRESULT hr = get_ole_clipbrd(&clipbrd);
835 if(This->data) IDataObject_Release(This->data);
837 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
838 clipbrd->latest_snapshot = NULL;
839 HeapFree(GetProcessHeap(), 0, This);
842 return ref;
845 /************************************************************
846 * get_current_ole_clip_window
848 * Return the window that owns the ole clipboard.
850 * If the clipboard is flushed or not owned by ole this will
851 * return NULL.
853 static HWND get_current_ole_clip_window(void)
855 HGLOBAL h;
856 HWND *ptr, wnd;
858 h = GetClipboardData(dataobject_clipboard_format);
859 if(!h) return NULL;
860 ptr = GlobalLock(h);
861 if(!ptr) return NULL;
862 wnd = *ptr;
863 GlobalUnlock(h);
864 return wnd;
867 /************************************************************
868 * get_current_dataobject
870 * Return an unmarshalled IDataObject if there is a current
871 * (ie non-flushed) object on the ole clipboard.
873 static HRESULT get_current_dataobject(IDataObject **data)
875 HRESULT hr = S_FALSE;
876 HWND wnd = get_current_ole_clip_window();
877 HGLOBAL h;
878 void *ptr;
879 IStream *stm;
880 LARGE_INTEGER pos;
882 *data = NULL;
883 if(!wnd) return S_FALSE;
885 h = GetPropW(wnd, wine_marshal_dataobject);
886 if(!h) return S_FALSE;
887 ptr = GlobalLock(h);
888 if(!ptr) return S_FALSE;
890 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
891 if(FAILED(hr)) goto end;
893 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
894 if(SUCCEEDED(hr))
896 pos.QuadPart = 0;
897 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
898 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
900 IStream_Release(stm);
902 end:
903 GlobalUnlock(h);
904 return hr;
907 /***********************************************************
908 * get_priv_data
910 * Returns a copy of the Ole Private Data
912 static HRESULT get_priv_data(ole_priv_data **data)
914 HGLOBAL handle;
915 HRESULT hr = S_OK;
917 *data = NULL;
919 handle = GetClipboardData( ole_priv_data_clipboard_format );
920 if(handle)
922 ole_priv_data *src = GlobalLock(handle);
923 if(src)
925 /* FIXME: sanity check on size */
926 *data = HeapAlloc(GetProcessHeap(), 0, src->size);
927 if(!*data)
929 GlobalUnlock(handle);
930 return E_OUTOFMEMORY;
932 memcpy(*data, src, src->size);
933 GlobalUnlock(handle);
937 if(!*data) hr = create_empty_priv_data(data);
939 return hr;
942 /************************************************************************
943 * get_stgmed_for_global
945 * Returns a stg medium with a copy of the global handle
947 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
949 HRESULT hr;
951 med->pUnkForRelease = NULL;
952 med->tymed = TYMED_NULL;
954 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
956 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
958 return hr;
961 /************************************************************************
962 * get_stgmed_for_stream
964 * Returns a stg medium with a stream based on the handle
966 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
968 HRESULT hr;
969 HGLOBAL dst;
971 med->pUnkForRelease = NULL;
972 med->tymed = TYMED_NULL;
974 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
975 if(FAILED(hr)) return hr;
977 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
978 if(FAILED(hr))
980 GlobalFree(dst);
981 return hr;
984 med->tymed = TYMED_ISTREAM;
985 return hr;
988 /************************************************************************
989 * get_stgmed_for_storage
991 * Returns a stg medium with a storage based on the handle
993 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
995 HRESULT hr;
996 HGLOBAL dst;
997 ILockBytes *lbs;
999 med->pUnkForRelease = NULL;
1000 med->tymed = TYMED_NULL;
1002 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1003 if(FAILED(hr)) return hr;
1005 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1006 if(FAILED(hr))
1008 GlobalFree(dst);
1009 return hr;
1012 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1013 ILockBytes_Release(lbs);
1014 if(FAILED(hr))
1016 GlobalFree(dst);
1017 return hr;
1020 med->tymed = TYMED_ISTORAGE;
1021 return hr;
1024 /************************************************************************
1025 * snapshot_GetData
1027 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1028 STGMEDIUM *med)
1030 snapshot *This = impl_from_IDataObject(iface);
1031 HANDLE h;
1032 HRESULT hr;
1033 ole_priv_data *enum_data = NULL;
1034 ole_priv_data_entry *entry;
1035 DWORD mask;
1037 TRACE("(%p,%p,%p)\n", iface, fmt, med);
1039 if ( !fmt || !med ) return E_INVALIDARG;
1041 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1043 if(!This->data)
1044 hr = get_current_dataobject(&This->data);
1046 if(This->data)
1048 hr = IDataObject_GetData(This->data, fmt, med);
1049 CloseClipboard();
1050 return hr;
1053 h = GetClipboardData(fmt->cfFormat);
1054 if(!h)
1056 hr = DV_E_FORMATETC;
1057 goto end;
1060 hr = get_priv_data(&enum_data);
1061 if(FAILED(hr)) goto end;
1063 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1064 if(entry)
1066 mask = fmt->tymed & entry->fmtetc.tymed;
1067 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1069 else /* non-Ole format */
1070 mask = fmt->tymed & TYMED_HGLOBAL;
1072 if(mask & TYMED_ISTORAGE)
1073 hr = get_stgmed_for_storage(h, med);
1074 else if(mask & TYMED_HGLOBAL)
1075 hr = get_stgmed_for_global(h, med);
1076 else if(mask & TYMED_ISTREAM)
1077 hr = get_stgmed_for_stream(h, med);
1078 else
1080 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed);
1081 hr = E_FAIL;
1082 goto end;
1085 end:
1086 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1087 return hr;
1090 /************************************************************************
1091 * snapshot_GetDataHere
1093 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1094 STGMEDIUM *med)
1096 FIXME("(%p, %p, %p): stub\n", iface, fmt, med);
1097 return E_NOTIMPL;
1100 /************************************************************************
1101 * snapshot_QueryGetData
1103 * The OLE Clipboard's implementation of this method delegates to
1104 * a data source if there is one or wraps around the windows clipboard
1105 * function IsClipboardFormatAvailable() otherwise.
1108 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1110 FIXME("(%p, %p)\n", iface, fmt);
1112 if (!fmt) return E_INVALIDARG;
1114 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1116 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1118 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1121 /************************************************************************
1122 * snapshot_GetCanonicalFormatEtc
1124 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1125 FORMATETC *fmt_out)
1127 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1129 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1131 *fmt_out = *fmt_in;
1132 return DATA_S_SAMEFORMATETC;
1135 /************************************************************************
1136 * snapshot_SetData
1138 * The OLE Clipboard does not implement this method
1140 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1141 STGMEDIUM *med, BOOL release)
1143 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1144 return E_NOTIMPL;
1147 /************************************************************************
1148 * snapshot_EnumFormatEtc
1151 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1152 IEnumFORMATETC **enum_fmt)
1154 HRESULT hr;
1155 ole_priv_data *data = NULL;
1157 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1159 *enum_fmt = NULL;
1161 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1162 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1164 hr = get_priv_data(&data);
1166 if(FAILED(hr)) goto end;
1168 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1170 end:
1171 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1172 return hr;
1175 /************************************************************************
1176 * snapshot_DAdvise
1178 * The OLE Clipboard does not implement this method
1180 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1181 DWORD flags, IAdviseSink *sink,
1182 DWORD *conn)
1184 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1185 return E_NOTIMPL;
1188 /************************************************************************
1189 * snapshot_DUnadvise
1191 * The OLE Clipboard does not implement this method
1193 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1195 TRACE("(%p, %d): not implemented\n", iface, conn);
1196 return E_NOTIMPL;
1199 /************************************************************************
1200 * snapshot_EnumDAdvise
1202 * The OLE Clipboard does not implement this method
1204 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1205 IEnumSTATDATA** enum_advise)
1207 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1208 return E_NOTIMPL;
1211 static const IDataObjectVtbl snapshot_vtable =
1213 snapshot_QueryInterface,
1214 snapshot_AddRef,
1215 snapshot_Release,
1216 snapshot_GetData,
1217 snapshot_GetDataHere,
1218 snapshot_QueryGetData,
1219 snapshot_GetCanonicalFormatEtc,
1220 snapshot_SetData,
1221 snapshot_EnumFormatEtc,
1222 snapshot_DAdvise,
1223 snapshot_DUnadvise,
1224 snapshot_EnumDAdvise
1227 /*---------------------------------------------------------------------*
1228 * Internal implementation methods for the OLE clipboard
1229 *---------------------------------------------------------------------*/
1231 static snapshot *snapshot_construct(DWORD seq_no)
1233 snapshot *This;
1235 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1236 if (!This) return NULL;
1238 This->lpVtbl = &snapshot_vtable;
1239 This->ref = 0;
1240 This->seq_no = seq_no;
1241 This->data = NULL;
1243 return This;
1246 /*********************************************************
1247 * register_clipboard_formats
1249 static void register_clipboard_formats(void)
1251 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1252 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1253 static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1255 if(!dataobject_clipboard_format)
1256 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1257 if(!ole_priv_data_clipboard_format)
1258 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1259 if(!embed_source_clipboard_format)
1260 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1263 /***********************************************************************
1264 * OLEClipbrd_Initialize()
1265 * Initializes the OLE clipboard.
1267 void OLEClipbrd_Initialize(void)
1269 register_clipboard_formats();
1271 if ( !theOleClipboard )
1273 ole_clipbrd* clipbrd;
1274 HGLOBAL h;
1276 TRACE("()\n");
1278 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1279 if (!clipbrd) return;
1281 clipbrd->latest_snapshot = NULL;
1282 clipbrd->window = NULL;
1283 clipbrd->src_data = NULL;
1284 clipbrd->cached_enum = NULL;
1286 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1287 if(!h)
1289 HeapFree(GetProcessHeap(), 0, clipbrd);
1290 return;
1293 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1295 GlobalFree(h);
1296 HeapFree(GetProcessHeap(), 0, clipbrd);
1297 return;
1300 theOleClipboard = clipbrd;
1304 /***********************************************************************
1305 * OLEClipbrd_UnInitialize()
1306 * Un-Initializes the OLE clipboard
1308 void OLEClipbrd_UnInitialize(void)
1310 ole_clipbrd *clipbrd = theOleClipboard;
1312 TRACE("()\n");
1314 if ( clipbrd )
1316 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1317 HINSTANCE hinst = GetModuleHandleW(ole32W);
1319 if ( clipbrd->window )
1321 DestroyWindow(clipbrd->window);
1322 UnregisterClassW( clipbrd_wndclass, hinst );
1325 IStream_Release(clipbrd->marshal_data);
1326 HeapFree(GetProcessHeap(), 0, clipbrd);
1327 theOleClipboard = NULL;
1331 /*********************************************************************
1332 * set_clipboard_formats
1334 * Enumerate all formats supported by the source and make
1335 * those formats available using delayed rendering using SetClipboardData.
1336 * Cache the enumeration list and make that list visibile as the
1337 * 'Ole Private Data' format on the clipboard.
1340 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1342 HRESULT hr;
1343 FORMATETC fmt;
1344 IEnumFORMATETC *enum_fmt;
1345 HGLOBAL priv_data_handle;
1346 DWORD target_offset;
1347 ole_priv_data *priv_data;
1348 DWORD count = 0, needed = sizeof(*priv_data), idx;
1350 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1351 if(FAILED(hr)) return hr;
1353 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1355 count++;
1356 needed += sizeof(priv_data->entries[0]);
1357 if(fmt.ptd)
1359 needed += fmt.ptd->tdSize;
1360 CoTaskMemFree(fmt.ptd);
1364 /* Windows pads the list with two empty ole_priv_data_entries, one
1365 * after the entries array and one after the target device data.
1366 * Allocating with zero init to zero these pads. */
1368 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1369 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1370 priv_data = GlobalLock(priv_data_handle);
1372 priv_data->unk1 = 0;
1373 priv_data->size = needed;
1374 priv_data->unk2 = 1;
1375 priv_data->count = count;
1376 priv_data->unk3[0] = 0;
1377 priv_data->unk3[1] = 0;
1379 IEnumFORMATETC_Reset(enum_fmt);
1381 idx = 0;
1382 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1384 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1386 TRACE("%s\n", dump_fmtetc(&fmt));
1388 priv_data->entries[idx].fmtetc = fmt;
1389 if(fmt.ptd)
1391 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1392 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1393 target_offset += fmt.ptd->tdSize;
1394 CoTaskMemFree(fmt.ptd);
1397 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1398 priv_data->entries[idx].unk[0] = 0;
1399 priv_data->entries[idx].unk[1] = 0;
1401 if (priv_data->entries[idx].first_use)
1402 SetClipboardData(fmt.cfFormat, NULL);
1404 idx++;
1407 IEnumFORMATETC_Release(enum_fmt);
1409 /* Cache the list and fixup any target device offsets to ptrs */
1410 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1411 memcpy(clipbrd->cached_enum, priv_data, needed);
1412 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1413 if(clipbrd->cached_enum->entries[idx].fmtetc.ptd)
1414 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1415 (DVTARGETDEVICE *)((char*)clipbrd->cached_enum + (DWORD)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1417 GlobalUnlock(priv_data_handle);
1418 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1420 return S_OK;
1423 static HWND create_clipbrd_window(void);
1425 /***********************************************************************
1426 * get_clipbrd_window
1428 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1430 if ( !clipbrd->window )
1431 clipbrd->window = create_clipbrd_window();
1433 *wnd = clipbrd->window;
1434 return *wnd ? S_OK : E_FAIL;
1438 /**********************************************************************
1439 * release_marshal_data
1441 * Releases the data and sets the stream back to zero size.
1443 static inline void release_marshal_data(IStream *stm)
1445 LARGE_INTEGER pos;
1446 ULARGE_INTEGER size;
1447 pos.QuadPart = size.QuadPart = 0;
1449 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1450 CoReleaseMarshalData(stm);
1451 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1452 IStream_SetSize(stm, size);
1455 /***********************************************************************
1456 * set_src_dataobject
1458 * Clears and sets the clipboard's src IDataObject.
1460 * To marshal the source dataobject we do something rather different from Windows.
1461 * We set a window prop which contains the marshalled data.
1462 * Windows set two props one of which is an IID, the other is an endpoint number.
1464 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1466 HRESULT hr;
1467 HWND wnd;
1469 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1471 if(clipbrd->src_data)
1473 RemovePropW(wnd, wine_marshal_dataobject);
1474 release_marshal_data(clipbrd->marshal_data);
1476 IDataObject_Release(clipbrd->src_data);
1477 clipbrd->src_data = NULL;
1478 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1479 clipbrd->cached_enum = NULL;
1482 if(data)
1484 HGLOBAL h;
1485 IUnknown *unk;
1487 IDataObject_AddRef(data);
1488 clipbrd->src_data = data;
1490 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1491 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1492 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1493 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1494 if(FAILED(hr)) return hr;
1495 GetHGlobalFromStream(clipbrd->marshal_data, &h);
1496 SetPropW(wnd, wine_marshal_dataobject, h);
1497 hr = set_clipboard_formats(clipbrd, data);
1499 return hr;
1502 /***********************************************************************
1503 * clipbrd_wndproc
1505 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1507 ole_clipbrd *clipbrd;
1509 get_ole_clipbrd(&clipbrd);
1511 switch (message)
1513 case WM_RENDERFORMAT:
1515 UINT cf = wparam;
1516 ole_priv_data_entry *entry;
1518 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1519 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1521 if(entry)
1522 render_format(clipbrd->src_data, &entry->fmtetc);
1524 break;
1527 case WM_RENDERALLFORMATS:
1529 DWORD i;
1530 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1532 TRACE("(): WM_RENDERALLFORMATS\n");
1534 for(i = 0; i < clipbrd->cached_enum->count; i++)
1536 if(entries[i].first_use)
1537 render_format(clipbrd->src_data, &entries[i].fmtetc);
1539 break;
1542 case WM_DESTROYCLIPBOARD:
1544 TRACE("(): WM_DESTROYCLIPBOARD\n");
1546 set_src_dataobject(clipbrd, NULL);
1547 break;
1550 default:
1551 return DefWindowProcW(hwnd, message, wparam, lparam);
1554 return 0;
1558 /***********************************************************************
1559 * create_clipbrd_window
1561 static HWND create_clipbrd_window(void)
1563 WNDCLASSEXW class;
1564 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1565 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1566 HINSTANCE hinst = GetModuleHandleW(ole32W);
1568 class.cbSize = sizeof(class);
1569 class.style = 0;
1570 class.lpfnWndProc = clipbrd_wndproc;
1571 class.cbClsExtra = 0;
1572 class.cbWndExtra = 0;
1573 class.hInstance = hinst;
1574 class.hIcon = 0;
1575 class.hCursor = 0;
1576 class.hbrBackground = 0;
1577 class.lpszMenuName = NULL;
1578 class.lpszClassName = clipbrd_wndclass;
1579 class.hIconSm = NULL;
1581 RegisterClassExW(&class);
1583 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1584 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1585 NULL, NULL, hinst, 0);
1588 /*********************************************************************
1589 * set_dataobject_format
1591 * Windows creates a 'DataObject' clipboard format that contains the
1592 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1594 static HRESULT set_dataobject_format(HWND hwnd)
1596 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1597 HWND *data;
1599 if(!h) return E_OUTOFMEMORY;
1601 data = GlobalLock(h);
1602 *data = hwnd;
1603 GlobalUnlock(h);
1605 if(!SetClipboardData(dataobject_clipboard_format, h))
1607 GlobalFree(h);
1608 return CLIPBRD_E_CANT_SET;
1611 return S_OK;
1614 /*---------------------------------------------------------------------*
1615 * Win32 OLE clipboard API
1616 *---------------------------------------------------------------------*/
1618 /***********************************************************************
1619 * OleSetClipboard [OLE32.@]
1620 * Places a pointer to the specified data object onto the clipboard,
1621 * making the data object accessible to the OleGetClipboard function.
1623 * RETURNS
1625 * S_OK IDataObject pointer placed on the clipboard
1626 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1627 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1628 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1629 * CLIPBRD_E_CANT_SET SetClipboard failed
1632 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1634 HRESULT hr;
1635 ole_clipbrd *clipbrd;
1636 HWND wnd;
1638 TRACE("(%p)\n", data);
1640 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1642 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1644 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1646 if ( !EmptyClipboard() )
1648 hr = CLIPBRD_E_CANT_EMPTY;
1649 goto end;
1652 hr = set_src_dataobject(clipbrd, data);
1653 if(FAILED(hr)) goto end;
1655 hr = set_dataobject_format(wnd);
1657 end:
1659 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1661 if ( FAILED(hr) )
1663 set_src_dataobject(clipbrd, NULL);
1666 return hr;
1670 /***********************************************************************
1671 * OleGetClipboard [OLE32.@]
1672 * Returns a pointer to our internal IDataObject which represents the conceptual
1673 * state of the Windows clipboard. If the current clipboard already contains
1674 * an IDataObject, our internal IDataObject will delegate to this object.
1676 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1678 HRESULT hr;
1679 ole_clipbrd *clipbrd;
1680 DWORD seq_no;
1682 TRACE("(%p)\n", obj);
1684 if(!obj) return E_INVALIDARG;
1686 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1688 seq_no = GetClipboardSequenceNumber();
1689 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1690 clipbrd->latest_snapshot = NULL;
1692 if(!clipbrd->latest_snapshot)
1694 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1695 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1698 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1699 IDataObject_AddRef(*obj);
1701 return S_OK;
1704 /******************************************************************************
1705 * OleFlushClipboard [OLE32.@]
1706 * Renders the data from the source IDataObject into the windows clipboard
1708 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1709 * by copying the storage into global memory. Subsequently the default
1710 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1711 * back to TYMED_IStorage.
1713 HRESULT WINAPI OleFlushClipboard(void)
1715 HRESULT hr;
1716 ole_clipbrd *clipbrd;
1717 HWND wnd;
1719 TRACE("()\n");
1721 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1723 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1726 * Already flushed or no source DataObject? Nothing to do.
1728 if (!clipbrd->src_data) return S_OK;
1730 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1732 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1734 hr = set_dataobject_format(NULL);
1736 set_src_dataobject(clipbrd, NULL);
1738 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1740 return hr;
1744 /***********************************************************************
1745 * OleIsCurrentClipboard [OLE32.@]
1747 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1749 HRESULT hr;
1750 ole_clipbrd *clipbrd;
1751 TRACE("()\n");
1753 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1755 if (data == NULL) return S_FALSE;
1757 return (data == clipbrd->src_data) ? S_OK : S_FALSE;