ole32: Don't set cf_dataobject if we're clearing the clipboard.
[wine/hacks.git] / dlls / ole32 / clipboard.c
blobc28b2f4570837efbdf72dd4f6d2ec203c9508ad5
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 * td_offs_to_ptr
110 * Returns a ptr to a target device at a given offset from the
111 * start of the ole_priv_data.
113 * Used when unpacking ole private data from the clipboard.
115 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
117 if(off == 0) return NULL;
118 return (DVTARGETDEVICE*)((char*)data + off);
121 /*****************************************************************************
122 * td_get_offs
124 * Get the offset from the start of the ole_priv_data of the idx'th
125 * target device.
127 * Used when packing ole private data to the clipboard.
129 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
131 if(data->entries[idx].fmtetc.ptd == NULL) return 0;
132 return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
135 /*****************************************************************************
136 * create_empty_priv_data
138 * Create an empty data structure. The only thing that really matters
139 * here is setting count and size members. This is used by the enumerator as a
140 * convenience when there's an empty list.
142 static HRESULT create_empty_priv_data(ole_priv_data **data)
144 ole_priv_data *ptr;
146 *data = NULL;
147 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr));
148 if(!ptr) return E_OUTOFMEMORY;
149 ptr->size = sizeof(*ptr);
150 ptr->count = 0;
151 *data = ptr;
152 return S_OK;
155 /****************************************************************************
156 * Consumer snapshot. Represents the state of the ole clipboard
157 * returned by OleGetClipboard().
159 typedef struct snapshot
161 const IDataObjectVtbl* lpVtbl;
162 LONG ref;
164 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */
166 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */
167 } snapshot;
169 /****************************************************************************
170 * ole_clipbrd
172 typedef struct ole_clipbrd
174 snapshot *latest_snapshot; /* Latest consumer snapshot */
176 HWND window; /* Hidden clipboard window */
177 IDataObject *src_data; /* Source object passed to OleSetClipboard */
178 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
179 IStream *marshal_data; /* Stream onto which to marshal src_data */
180 } ole_clipbrd;
182 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
184 return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
187 typedef struct PresentationDataHeader
189 BYTE unknown1[28];
190 DWORD dwObjectExtentX;
191 DWORD dwObjectExtentY;
192 DWORD dwSize;
193 } PresentationDataHeader;
196 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
198 static ole_clipbrd* theOleClipboard;
200 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
202 struct oletls *info = COM_CurrentInfo();
203 *clipbrd = NULL;
205 if(!info->ole_inits)
206 return CO_E_NOTINITIALIZED;
207 *clipbrd = theOleClipboard;
209 return S_OK;
213 * Name of our registered OLE clipboard window class
215 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
217 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};
219 static UINT dataobject_clipboard_format;
220 static UINT ole_priv_data_clipboard_format;
221 static UINT embed_source_clipboard_format;
223 static inline char *dump_fmtetc(FORMATETC *fmt)
225 static char buf[100];
227 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
228 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
229 return buf;
232 /*---------------------------------------------------------------------*
233 * Implementation of the internal IEnumFORMATETC interface returned by
234 * the OLE clipboard's IDataObject.
235 *---------------------------------------------------------------------*/
237 typedef struct enum_fmtetc
239 const IEnumFORMATETCVtbl *lpVtbl;
240 LONG ref;
242 UINT pos; /* current enumerator position */
243 ole_priv_data *data;
244 } enum_fmtetc;
246 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
248 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
251 /************************************************************************
252 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
254 * See Windows documentation for more details on IUnknown methods.
256 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
257 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
259 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
261 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
263 *ppvObj = NULL;
265 if(IsEqualIID(riid, &IID_IUnknown) ||
266 IsEqualIID(riid, &IID_IEnumFORMATETC))
268 *ppvObj = iface;
271 if(*ppvObj)
273 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
274 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
275 return S_OK;
278 TRACE("-- Interface: E_NOINTERFACE\n");
279 return E_NOINTERFACE;
282 /************************************************************************
283 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
286 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
288 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
289 TRACE("(%p)->(count=%u)\n",This, This->ref);
291 return InterlockedIncrement(&This->ref);
294 /************************************************************************
295 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
297 * See Windows documentation for more details on IUnknown methods.
299 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
301 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
302 ULONG ref;
304 TRACE("(%p)->(count=%u)\n",This, This->ref);
306 ref = InterlockedDecrement(&This->ref);
307 if (!ref)
309 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
310 HeapFree(GetProcessHeap(), 0, This->data);
311 HeapFree(GetProcessHeap(), 0, This);
313 return ref;
316 /************************************************************************
317 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
319 * Standard enumerator members for IEnumFORMATETC
321 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
322 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
324 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
325 UINT cfetch, i;
326 HRESULT hres = S_FALSE;
328 TRACE("(%p)->(pos=%u)\n", This, This->pos);
330 if (This->pos < This->data->count)
332 cfetch = This->data->count - This->pos;
333 if (cfetch >= celt)
335 cfetch = celt;
336 hres = S_OK;
339 for(i = 0; i < cfetch; i++)
341 rgelt[i] = This->data->entries[This->pos++].fmtetc;
342 if(rgelt[i].ptd)
344 DVTARGETDEVICE *target = rgelt[i].ptd;
345 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
346 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
347 memcpy(rgelt[i].ptd, target, target->tdSize);
351 else
353 cfetch = 0;
356 if (pceltFethed)
358 *pceltFethed = cfetch;
361 return hres;
364 /************************************************************************
365 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
367 * Standard enumerator members for IEnumFORMATETC
369 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
371 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
372 TRACE("(%p)->(num=%u)\n", This, celt);
374 This->pos += celt;
375 if (This->pos > This->data->count)
377 This->pos = This->data->count;
378 return S_FALSE;
380 return S_OK;
383 /************************************************************************
384 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
386 * Standard enumerator members for IEnumFORMATETC
388 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
390 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
391 TRACE("(%p)->()\n", This);
393 This->pos = 0;
394 return S_OK;
397 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
399 /************************************************************************
400 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
402 * Standard enumerator members for IEnumFORMATETC
404 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
405 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
407 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
408 ole_priv_data *new_data;
409 DWORD i;
411 TRACE("(%p)->(%p)\n", This, obj);
413 if ( !obj ) return E_INVALIDARG;
414 *obj = NULL;
416 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
417 if(!new_data) return E_OUTOFMEMORY;
418 memcpy(new_data, This->data, This->data->size);
420 /* Fixup any target device ptrs */
421 for(i = 0; i < This->data->count; i++)
422 new_data->entries[i].fmtetc.ptd =
423 td_offs_to_ptr(new_data, td_get_offs(This->data, i));
425 return enum_fmtetc_construct(new_data, This->pos, obj);
428 static const IEnumFORMATETCVtbl efvt =
430 OLEClipbrd_IEnumFORMATETC_QueryInterface,
431 OLEClipbrd_IEnumFORMATETC_AddRef,
432 OLEClipbrd_IEnumFORMATETC_Release,
433 OLEClipbrd_IEnumFORMATETC_Next,
434 OLEClipbrd_IEnumFORMATETC_Skip,
435 OLEClipbrd_IEnumFORMATETC_Reset,
436 OLEClipbrd_IEnumFORMATETC_Clone
439 /************************************************************************
440 * enum_fmtetc_construct
442 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
444 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
446 enum_fmtetc* ef;
448 *obj = NULL;
449 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
450 if (!ef) return E_OUTOFMEMORY;
452 ef->ref = 1;
453 ef->lpVtbl = &efvt;
454 ef->data = data;
455 ef->pos = pos;
457 TRACE("(%p)->()\n", ef);
458 *obj = (IEnumFORMATETC *)ef;
459 return S_OK;
462 /***********************************************************************
463 * dup_global_mem
465 * Helper method to duplicate an HGLOBAL chunk of memory
467 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
469 void *src_ptr, *dst_ptr;
470 DWORD size;
472 *dst = NULL;
473 if ( !src ) return S_FALSE;
475 size = GlobalSize(src);
477 *dst = GlobalAlloc( flags, size );
478 if ( !*dst ) return E_OUTOFMEMORY;
480 src_ptr = GlobalLock(src);
481 dst_ptr = GlobalLock(*dst);
483 memcpy(dst_ptr, src_ptr, size);
485 GlobalUnlock(*dst);
486 GlobalUnlock(src);
488 return S_OK;
491 /************************************************************
492 * render_embed_source_hack
494 * This is clearly a hack and has no place in the clipboard code.
497 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
499 STGMEDIUM std;
500 HGLOBAL hStorage = 0;
501 HRESULT hr = S_OK;
502 ILockBytes *ptrILockBytes;
504 memset(&std, 0, sizeof(STGMEDIUM));
505 std.tymed = fmt->tymed = TYMED_ISTORAGE;
507 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
508 if (hStorage == NULL) return E_OUTOFMEMORY;
509 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
510 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
511 ILockBytes_Release(ptrILockBytes);
513 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
515 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
516 GlobalFree(hStorage);
517 return hr;
520 if (1) /* check whether the presentation data is already -not- present */
522 FORMATETC fmt2;
523 STGMEDIUM std2;
524 METAFILEPICT *mfp = 0;
526 fmt2.cfFormat = CF_METAFILEPICT;
527 fmt2.ptd = 0;
528 fmt2.dwAspect = DVASPECT_CONTENT;
529 fmt2.lindex = -1;
530 fmt2.tymed = TYMED_MFPICT;
532 memset(&std2, 0, sizeof(STGMEDIUM));
533 std2.tymed = TYMED_MFPICT;
535 /* Get the metafile picture out of it */
537 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
539 mfp = GlobalLock(std2.u.hGlobal);
542 if (mfp)
544 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
545 IStream *pStream = 0;
546 void *mfBits;
547 PresentationDataHeader pdh;
548 INT nSize;
549 CLSID clsID;
550 LPOLESTR strProgID;
551 CHAR strOleTypeName[51];
552 BYTE OlePresStreamHeader [] =
554 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
555 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
556 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00
560 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
562 memset(&pdh, 0, sizeof(PresentationDataHeader));
563 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
565 pdh.dwObjectExtentX = mfp->xExt;
566 pdh.dwObjectExtentY = mfp->yExt;
567 pdh.dwSize = nSize;
569 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
571 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
573 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
574 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
576 hr = IStream_Write(pStream, mfBits, nSize, NULL);
578 IStream_Release(pStream);
580 HeapFree(GetProcessHeap(), 0, mfBits);
582 GlobalUnlock(std2.u.hGlobal);
583 ReleaseStgMedium(&std2);
585 ReadClassStg(std.u.pstg, &clsID);
586 ProgIDFromCLSID(&clsID, &strProgID);
588 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
589 OLECONVERT_CreateOleStream(std.u.pstg);
590 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
594 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
596 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
597 GlobalFree(hStorage);
598 hr = CLIPBRD_E_CANT_SET;
601 ReleaseStgMedium(&std);
602 return hr;
605 /************************************************************************
606 * find_format_in_list
608 * Returns the first entry that matches the provided clipboard format.
610 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
612 DWORD i;
613 for(i = 0; i < num; i++)
614 if(entries[i].fmtetc.cfFormat == cf)
615 return &entries[i];
617 return NULL;
620 /***************************************************************************
621 * get_data_from_storage
623 * Returns storage data in an HGLOBAL.
625 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
627 HGLOBAL h;
628 IStorage *stg;
629 HRESULT hr;
630 FORMATETC stg_fmt;
631 STGMEDIUM med;
632 ILockBytes *lbs;
634 *mem = NULL;
636 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
637 if(!h) return E_OUTOFMEMORY;
639 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
640 if(SUCCEEDED(hr))
642 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
643 ILockBytes_Release(lbs);
645 if(FAILED(hr))
647 GlobalFree(h);
648 return hr;
651 stg_fmt = *fmt;
652 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
653 med.u.pstg = stg;
654 med.pUnkForRelease = NULL;
656 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
657 if(FAILED(hr))
659 med.u.pstg = NULL;
660 hr = IDataObject_GetData(data, &stg_fmt, &med);
661 if(FAILED(hr)) goto end;
663 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
664 ReleaseStgMedium(&med);
665 if(FAILED(hr)) goto end;
667 *mem = h;
669 end:
670 IStorage_Release(stg);
671 if(FAILED(hr)) GlobalFree(h);
672 return hr;
675 /***************************************************************************
676 * get_data_from_stream
678 * Returns stream data in an HGLOBAL.
680 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
682 HGLOBAL h;
683 IStream *stm = NULL;
684 HRESULT hr;
685 FORMATETC stm_fmt;
686 STGMEDIUM med;
688 *mem = NULL;
690 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
691 if(!h) return E_OUTOFMEMORY;
693 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
694 if(FAILED(hr)) goto error;
696 stm_fmt = *fmt;
697 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
698 med.u.pstm = stm;
699 med.pUnkForRelease = NULL;
701 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
702 if(FAILED(hr))
704 LARGE_INTEGER offs;
705 ULARGE_INTEGER pos;
707 med.u.pstm = NULL;
708 hr = IDataObject_GetData(data, &stm_fmt, &med);
709 if(FAILED(hr)) goto error;
711 offs.QuadPart = 0;
712 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
713 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
714 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
715 ReleaseStgMedium(&med);
716 if(FAILED(hr)) goto error;
718 *mem = h;
719 IStream_Release(stm);
720 return S_OK;
722 error:
723 if(stm) IStream_Release(stm);
724 GlobalFree(h);
725 return hr;
728 /***************************************************************************
729 * get_data_from_global
731 * Returns global data in an HGLOBAL.
733 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
735 HGLOBAL h;
736 HRESULT hr;
737 FORMATETC mem_fmt;
738 STGMEDIUM med;
740 *mem = NULL;
742 mem_fmt = *fmt;
743 mem_fmt.tymed = TYMED_HGLOBAL;
745 hr = IDataObject_GetData(data, &mem_fmt, &med);
746 if(FAILED(hr)) return hr;
748 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
750 if(SUCCEEDED(hr)) *mem = h;
752 ReleaseStgMedium(&med);
754 return hr;
757 /***********************************************************************
758 * render_format
760 * Render the clipboard data. Note that this call will delegate to the
761 * source data object.
763 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
765 HGLOBAL clip_data = NULL;
766 HRESULT hr;
768 /* Embed source hack */
769 if(fmt->cfFormat == embed_source_clipboard_format)
771 return render_embed_source_hack(data, fmt);
774 if(fmt->tymed & TYMED_ISTORAGE)
776 hr = get_data_from_storage(data, fmt, &clip_data);
778 else if(fmt->tymed & TYMED_ISTREAM)
780 hr = get_data_from_stream(data, fmt, &clip_data);
782 else if(fmt->tymed & TYMED_HGLOBAL)
784 hr = get_data_from_global(data, fmt, &clip_data);
786 else
788 FIXME("Unhandled tymed %x\n", fmt->tymed);
789 hr = DV_E_FORMATETC;
792 if(SUCCEEDED(hr))
794 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
796 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
797 GlobalFree(clip_data);
798 hr = CLIPBRD_E_CANT_SET;
802 return hr;
805 /*---------------------------------------------------------------------*
806 * Implementation of the internal IDataObject interface exposed by
807 * the OLE clipboard.
808 *---------------------------------------------------------------------*/
811 /************************************************************************
812 * snapshot_QueryInterface
814 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
815 REFIID riid, void **ppvObject)
817 snapshot *This = impl_from_IDataObject(iface);
818 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
820 if ( (This==0) || (ppvObject==0) )
821 return E_INVALIDARG;
823 *ppvObject = 0;
825 if (IsEqualIID(&IID_IUnknown, riid) ||
826 IsEqualIID(&IID_IDataObject, riid))
828 *ppvObject = iface;
830 else
832 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
833 return E_NOINTERFACE;
836 IUnknown_AddRef((IUnknown*)*ppvObject);
838 return S_OK;
841 /************************************************************************
842 * snapshot_AddRef
844 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
846 snapshot *This = impl_from_IDataObject(iface);
848 TRACE("(%p)->(count=%u)\n", This, This->ref);
850 return InterlockedIncrement(&This->ref);
853 /************************************************************************
854 * snapshot_Release
856 static ULONG WINAPI snapshot_Release(IDataObject *iface)
858 snapshot *This = impl_from_IDataObject(iface);
859 ULONG ref;
861 TRACE("(%p)->(count=%u)\n", This, This->ref);
863 ref = InterlockedDecrement(&This->ref);
865 if (ref == 0)
867 ole_clipbrd *clipbrd;
868 HRESULT hr = get_ole_clipbrd(&clipbrd);
870 if(This->data) IDataObject_Release(This->data);
872 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
873 clipbrd->latest_snapshot = NULL;
874 HeapFree(GetProcessHeap(), 0, This);
877 return ref;
880 /************************************************************
881 * get_current_ole_clip_window
883 * Return the window that owns the ole clipboard.
885 * If the clipboard is flushed or not owned by ole this will
886 * return NULL.
888 static HWND get_current_ole_clip_window(void)
890 HGLOBAL h;
891 HWND *ptr, wnd;
893 h = GetClipboardData(dataobject_clipboard_format);
894 if(!h) return NULL;
895 ptr = GlobalLock(h);
896 if(!ptr) return NULL;
897 wnd = *ptr;
898 GlobalUnlock(h);
899 return wnd;
902 /************************************************************
903 * get_current_dataobject
905 * Return an unmarshalled IDataObject if there is a current
906 * (ie non-flushed) object on the ole clipboard.
908 static HRESULT get_current_dataobject(IDataObject **data)
910 HRESULT hr = S_FALSE;
911 HWND wnd = get_current_ole_clip_window();
912 HGLOBAL h;
913 void *ptr;
914 IStream *stm;
915 LARGE_INTEGER pos;
917 *data = NULL;
918 if(!wnd) return S_FALSE;
920 h = GetPropW(wnd, wine_marshal_dataobject);
921 if(!h) return S_FALSE;
922 ptr = GlobalLock(h);
923 if(!ptr) return S_FALSE;
925 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
926 if(FAILED(hr)) goto end;
928 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
929 if(SUCCEEDED(hr))
931 pos.QuadPart = 0;
932 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
933 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
935 IStream_Release(stm);
937 end:
938 GlobalUnlock(h);
939 return hr;
942 /***********************************************************
943 * get_priv_data
945 * Returns a copy of the Ole Private Data
947 static HRESULT get_priv_data(ole_priv_data **data)
949 HGLOBAL handle;
950 HRESULT hr = S_OK;
952 *data = NULL;
954 handle = GetClipboardData( ole_priv_data_clipboard_format );
955 if(handle)
957 ole_priv_data *src = GlobalLock(handle);
958 if(src)
960 DWORD i;
962 /* FIXME: sanity check on size */
963 *data = HeapAlloc(GetProcessHeap(), 0, src->size);
964 if(!*data)
966 GlobalUnlock(handle);
967 return E_OUTOFMEMORY;
969 memcpy(*data, src, src->size);
970 GlobalUnlock(handle);
972 /* Fixup any target device offsets to ptrs */
973 for(i = 0; i < (*data)->count; i++)
974 (*data)->entries[i].fmtetc.ptd =
975 td_offs_to_ptr(*data, (DWORD_PTR)(*data)->entries[i].fmtetc.ptd);
979 if(!*data) hr = create_empty_priv_data(data);
981 return hr;
984 /************************************************************************
985 * get_stgmed_for_global
987 * Returns a stg medium with a copy of the global handle
989 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
991 HRESULT hr;
993 med->pUnkForRelease = NULL;
994 med->tymed = TYMED_NULL;
996 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
998 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1000 return hr;
1003 /************************************************************************
1004 * get_stgmed_for_stream
1006 * Returns a stg medium with a stream based on the handle
1008 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1010 HRESULT hr;
1011 HGLOBAL dst;
1013 med->pUnkForRelease = NULL;
1014 med->tymed = TYMED_NULL;
1016 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1017 if(FAILED(hr)) return hr;
1019 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1020 if(FAILED(hr))
1022 GlobalFree(dst);
1023 return hr;
1026 med->tymed = TYMED_ISTREAM;
1027 return hr;
1030 /************************************************************************
1031 * get_stgmed_for_storage
1033 * Returns a stg medium with a storage based on the handle
1035 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1037 HRESULT hr;
1038 HGLOBAL dst;
1039 ILockBytes *lbs;
1041 med->pUnkForRelease = NULL;
1042 med->tymed = TYMED_NULL;
1044 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1045 if(FAILED(hr)) return hr;
1047 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1048 if(FAILED(hr))
1050 GlobalFree(dst);
1051 return hr;
1054 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1055 ILockBytes_Release(lbs);
1056 if(FAILED(hr))
1058 GlobalFree(dst);
1059 return hr;
1062 med->tymed = TYMED_ISTORAGE;
1063 return hr;
1066 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1068 const WCHAR *str1, *str2;
1070 if(off1 == 0 && off2 == 0) return TRUE;
1071 if(off1 == 0 || off2 == 0) return FALSE;
1073 str1 = (const WCHAR*)((const char*)t1 + off1);
1074 str2 = (const WCHAR*)((const char*)t2 + off2);
1076 return !lstrcmpW(str1, str2);
1079 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1081 if(t1 == NULL && t2 == NULL) return TRUE;
1082 if(t1 == NULL || t2 == NULL) return FALSE;
1084 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1085 return FALSE;
1086 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1087 return FALSE;
1088 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1089 return FALSE;
1091 /* FIXME check devmode? */
1093 return TRUE;
1096 /************************************************************************
1097 * snapshot_GetData
1099 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1100 STGMEDIUM *med)
1102 snapshot *This = impl_from_IDataObject(iface);
1103 HANDLE h;
1104 HRESULT hr;
1105 ole_priv_data *enum_data = NULL;
1106 ole_priv_data_entry *entry;
1107 DWORD mask;
1109 TRACE("(%p,%p,%p)\n", iface, fmt, med);
1111 if ( !fmt || !med ) return E_INVALIDARG;
1113 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1115 if(!This->data)
1116 hr = get_current_dataobject(&This->data);
1118 if(This->data)
1120 hr = IDataObject_GetData(This->data, fmt, med);
1121 CloseClipboard();
1122 return hr;
1125 h = GetClipboardData(fmt->cfFormat);
1126 if(!h)
1128 hr = DV_E_FORMATETC;
1129 goto end;
1132 hr = get_priv_data(&enum_data);
1133 if(FAILED(hr)) goto end;
1135 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1136 if(entry)
1138 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1140 hr = DV_E_FORMATETC;
1141 goto end;
1143 mask = fmt->tymed & entry->fmtetc.tymed;
1144 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1146 else /* non-Ole format */
1147 mask = fmt->tymed & TYMED_HGLOBAL;
1149 if(mask & TYMED_ISTORAGE)
1150 hr = get_stgmed_for_storage(h, med);
1151 else if(mask & TYMED_HGLOBAL)
1152 hr = get_stgmed_for_global(h, med);
1153 else if(mask & TYMED_ISTREAM)
1154 hr = get_stgmed_for_stream(h, med);
1155 else
1157 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed);
1158 hr = E_FAIL;
1159 goto end;
1162 end:
1163 HeapFree(GetProcessHeap(), 0, enum_data);
1164 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1165 return hr;
1168 /************************************************************************
1169 * snapshot_GetDataHere
1171 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1172 STGMEDIUM *med)
1174 FIXME("(%p, %p, %p): stub\n", iface, fmt, med);
1175 return E_NOTIMPL;
1178 /************************************************************************
1179 * snapshot_QueryGetData
1181 * The OLE Clipboard's implementation of this method delegates to
1182 * a data source if there is one or wraps around the windows clipboard
1183 * function IsClipboardFormatAvailable() otherwise.
1186 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1188 FIXME("(%p, %p)\n", iface, fmt);
1190 if (!fmt) return E_INVALIDARG;
1192 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1194 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1196 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1199 /************************************************************************
1200 * snapshot_GetCanonicalFormatEtc
1202 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1203 FORMATETC *fmt_out)
1205 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1207 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1209 *fmt_out = *fmt_in;
1210 return DATA_S_SAMEFORMATETC;
1213 /************************************************************************
1214 * snapshot_SetData
1216 * The OLE Clipboard does not implement this method
1218 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1219 STGMEDIUM *med, BOOL release)
1221 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1222 return E_NOTIMPL;
1225 /************************************************************************
1226 * snapshot_EnumFormatEtc
1229 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1230 IEnumFORMATETC **enum_fmt)
1232 HRESULT hr;
1233 ole_priv_data *data = NULL;
1235 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1237 *enum_fmt = NULL;
1239 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1240 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1242 hr = get_priv_data(&data);
1244 if(FAILED(hr)) goto end;
1246 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1248 end:
1249 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1250 return hr;
1253 /************************************************************************
1254 * snapshot_DAdvise
1256 * The OLE Clipboard does not implement this method
1258 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1259 DWORD flags, IAdviseSink *sink,
1260 DWORD *conn)
1262 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1263 return E_NOTIMPL;
1266 /************************************************************************
1267 * snapshot_DUnadvise
1269 * The OLE Clipboard does not implement this method
1271 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1273 TRACE("(%p, %d): not implemented\n", iface, conn);
1274 return E_NOTIMPL;
1277 /************************************************************************
1278 * snapshot_EnumDAdvise
1280 * The OLE Clipboard does not implement this method
1282 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1283 IEnumSTATDATA** enum_advise)
1285 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1286 return E_NOTIMPL;
1289 static const IDataObjectVtbl snapshot_vtable =
1291 snapshot_QueryInterface,
1292 snapshot_AddRef,
1293 snapshot_Release,
1294 snapshot_GetData,
1295 snapshot_GetDataHere,
1296 snapshot_QueryGetData,
1297 snapshot_GetCanonicalFormatEtc,
1298 snapshot_SetData,
1299 snapshot_EnumFormatEtc,
1300 snapshot_DAdvise,
1301 snapshot_DUnadvise,
1302 snapshot_EnumDAdvise
1305 /*---------------------------------------------------------------------*
1306 * Internal implementation methods for the OLE clipboard
1307 *---------------------------------------------------------------------*/
1309 static snapshot *snapshot_construct(DWORD seq_no)
1311 snapshot *This;
1313 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1314 if (!This) return NULL;
1316 This->lpVtbl = &snapshot_vtable;
1317 This->ref = 0;
1318 This->seq_no = seq_no;
1319 This->data = NULL;
1321 return This;
1324 /*********************************************************
1325 * register_clipboard_formats
1327 static void register_clipboard_formats(void)
1329 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1330 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1331 static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1333 if(!dataobject_clipboard_format)
1334 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1335 if(!ole_priv_data_clipboard_format)
1336 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1337 if(!embed_source_clipboard_format)
1338 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1341 /***********************************************************************
1342 * OLEClipbrd_Initialize()
1343 * Initializes the OLE clipboard.
1345 void OLEClipbrd_Initialize(void)
1347 register_clipboard_formats();
1349 if ( !theOleClipboard )
1351 ole_clipbrd* clipbrd;
1352 HGLOBAL h;
1354 TRACE("()\n");
1356 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1357 if (!clipbrd) return;
1359 clipbrd->latest_snapshot = NULL;
1360 clipbrd->window = NULL;
1361 clipbrd->src_data = NULL;
1362 clipbrd->cached_enum = NULL;
1364 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1365 if(!h)
1367 HeapFree(GetProcessHeap(), 0, clipbrd);
1368 return;
1371 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1373 GlobalFree(h);
1374 HeapFree(GetProcessHeap(), 0, clipbrd);
1375 return;
1378 theOleClipboard = clipbrd;
1382 /***********************************************************************
1383 * OLEClipbrd_UnInitialize()
1384 * Un-Initializes the OLE clipboard
1386 void OLEClipbrd_UnInitialize(void)
1388 ole_clipbrd *clipbrd = theOleClipboard;
1390 TRACE("()\n");
1392 if ( clipbrd )
1394 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1395 HINSTANCE hinst = GetModuleHandleW(ole32W);
1397 if ( clipbrd->window )
1399 DestroyWindow(clipbrd->window);
1400 UnregisterClassW( clipbrd_wndclass, hinst );
1403 IStream_Release(clipbrd->marshal_data);
1404 HeapFree(GetProcessHeap(), 0, clipbrd);
1405 theOleClipboard = NULL;
1409 /*********************************************************************
1410 * set_clipboard_formats
1412 * Enumerate all formats supported by the source and make
1413 * those formats available using delayed rendering using SetClipboardData.
1414 * Cache the enumeration list and make that list visibile as the
1415 * 'Ole Private Data' format on the clipboard.
1418 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1420 HRESULT hr;
1421 FORMATETC fmt;
1422 IEnumFORMATETC *enum_fmt;
1423 HGLOBAL priv_data_handle;
1424 DWORD_PTR target_offset;
1425 ole_priv_data *priv_data;
1426 DWORD count = 0, needed = sizeof(*priv_data), idx;
1428 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1429 if(FAILED(hr)) return hr;
1431 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1433 count++;
1434 needed += sizeof(priv_data->entries[0]);
1435 if(fmt.ptd)
1437 needed += fmt.ptd->tdSize;
1438 CoTaskMemFree(fmt.ptd);
1442 /* Windows pads the list with two empty ole_priv_data_entries, one
1443 * after the entries array and one after the target device data.
1444 * Allocating with zero init to zero these pads. */
1446 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1447 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1448 priv_data = GlobalLock(priv_data_handle);
1450 priv_data->unk1 = 0;
1451 priv_data->size = needed;
1452 priv_data->unk2 = 1;
1453 priv_data->count = count;
1454 priv_data->unk3[0] = 0;
1455 priv_data->unk3[1] = 0;
1457 IEnumFORMATETC_Reset(enum_fmt);
1459 idx = 0;
1460 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1462 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1464 TRACE("%s\n", dump_fmtetc(&fmt));
1466 priv_data->entries[idx].fmtetc = fmt;
1467 if(fmt.ptd)
1469 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1470 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1471 target_offset += fmt.ptd->tdSize;
1472 CoTaskMemFree(fmt.ptd);
1475 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1476 priv_data->entries[idx].unk[0] = 0;
1477 priv_data->entries[idx].unk[1] = 0;
1479 if (priv_data->entries[idx].first_use)
1480 SetClipboardData(fmt.cfFormat, NULL);
1482 idx++;
1485 IEnumFORMATETC_Release(enum_fmt);
1487 /* Cache the list and fixup any target device offsets to ptrs */
1488 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1489 memcpy(clipbrd->cached_enum, priv_data, needed);
1490 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1491 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1492 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1494 GlobalUnlock(priv_data_handle);
1495 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1497 return S_OK;
1500 static HWND create_clipbrd_window(void);
1502 /***********************************************************************
1503 * get_clipbrd_window
1505 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1507 if ( !clipbrd->window )
1508 clipbrd->window = create_clipbrd_window();
1510 *wnd = clipbrd->window;
1511 return *wnd ? S_OK : E_FAIL;
1515 /**********************************************************************
1516 * release_marshal_data
1518 * Releases the data and sets the stream back to zero size.
1520 static inline void release_marshal_data(IStream *stm)
1522 LARGE_INTEGER pos;
1523 ULARGE_INTEGER size;
1524 pos.QuadPart = size.QuadPart = 0;
1526 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1527 CoReleaseMarshalData(stm);
1528 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1529 IStream_SetSize(stm, size);
1532 /***********************************************************************
1533 * set_src_dataobject
1535 * Clears and sets the clipboard's src IDataObject.
1537 * To marshal the source dataobject we do something rather different from Windows.
1538 * We set a window prop which contains the marshalled data.
1539 * Windows set two props one of which is an IID, the other is an endpoint number.
1541 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1543 HRESULT hr;
1544 HWND wnd;
1546 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1548 if(clipbrd->src_data)
1550 RemovePropW(wnd, wine_marshal_dataobject);
1551 release_marshal_data(clipbrd->marshal_data);
1553 IDataObject_Release(clipbrd->src_data);
1554 clipbrd->src_data = NULL;
1555 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1556 clipbrd->cached_enum = NULL;
1559 if(data)
1561 HGLOBAL h;
1562 IUnknown *unk;
1564 IDataObject_AddRef(data);
1565 clipbrd->src_data = data;
1567 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1568 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1569 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1570 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1571 if(FAILED(hr)) return hr;
1572 GetHGlobalFromStream(clipbrd->marshal_data, &h);
1573 SetPropW(wnd, wine_marshal_dataobject, h);
1574 hr = set_clipboard_formats(clipbrd, data);
1576 return hr;
1579 /***********************************************************************
1580 * clipbrd_wndproc
1582 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1584 ole_clipbrd *clipbrd;
1586 get_ole_clipbrd(&clipbrd);
1588 switch (message)
1590 case WM_RENDERFORMAT:
1592 UINT cf = wparam;
1593 ole_priv_data_entry *entry;
1595 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1596 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1598 if(entry)
1599 render_format(clipbrd->src_data, &entry->fmtetc);
1601 break;
1604 case WM_RENDERALLFORMATS:
1606 DWORD i;
1607 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1609 TRACE("(): WM_RENDERALLFORMATS\n");
1611 for(i = 0; i < clipbrd->cached_enum->count; i++)
1613 if(entries[i].first_use)
1614 render_format(clipbrd->src_data, &entries[i].fmtetc);
1616 break;
1619 case WM_DESTROYCLIPBOARD:
1621 TRACE("(): WM_DESTROYCLIPBOARD\n");
1623 set_src_dataobject(clipbrd, NULL);
1624 break;
1627 default:
1628 return DefWindowProcW(hwnd, message, wparam, lparam);
1631 return 0;
1635 /***********************************************************************
1636 * create_clipbrd_window
1638 static HWND create_clipbrd_window(void)
1640 WNDCLASSEXW class;
1641 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1642 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1643 HINSTANCE hinst = GetModuleHandleW(ole32W);
1645 class.cbSize = sizeof(class);
1646 class.style = 0;
1647 class.lpfnWndProc = clipbrd_wndproc;
1648 class.cbClsExtra = 0;
1649 class.cbWndExtra = 0;
1650 class.hInstance = hinst;
1651 class.hIcon = 0;
1652 class.hCursor = 0;
1653 class.hbrBackground = 0;
1654 class.lpszMenuName = NULL;
1655 class.lpszClassName = clipbrd_wndclass;
1656 class.hIconSm = NULL;
1658 RegisterClassExW(&class);
1660 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1661 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1662 NULL, NULL, hinst, 0);
1665 /*********************************************************************
1666 * set_dataobject_format
1668 * Windows creates a 'DataObject' clipboard format that contains the
1669 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1671 static HRESULT set_dataobject_format(HWND hwnd)
1673 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1674 HWND *data;
1676 if(!h) return E_OUTOFMEMORY;
1678 data = GlobalLock(h);
1679 *data = hwnd;
1680 GlobalUnlock(h);
1682 if(!SetClipboardData(dataobject_clipboard_format, h))
1684 GlobalFree(h);
1685 return CLIPBRD_E_CANT_SET;
1688 return S_OK;
1691 /*---------------------------------------------------------------------*
1692 * Win32 OLE clipboard API
1693 *---------------------------------------------------------------------*/
1695 /***********************************************************************
1696 * OleSetClipboard [OLE32.@]
1697 * Places a pointer to the specified data object onto the clipboard,
1698 * making the data object accessible to the OleGetClipboard function.
1700 * RETURNS
1702 * S_OK IDataObject pointer placed on the clipboard
1703 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1704 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1705 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1706 * CLIPBRD_E_CANT_SET SetClipboard failed
1709 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1711 HRESULT hr;
1712 ole_clipbrd *clipbrd;
1713 HWND wnd;
1715 TRACE("(%p)\n", data);
1717 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1719 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1721 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1723 if ( !EmptyClipboard() )
1725 hr = CLIPBRD_E_CANT_EMPTY;
1726 goto end;
1729 hr = set_src_dataobject(clipbrd, data);
1730 if(FAILED(hr)) goto end;
1732 if(data)
1733 hr = set_dataobject_format(wnd);
1735 end:
1737 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1739 if ( FAILED(hr) )
1741 set_src_dataobject(clipbrd, NULL);
1744 return hr;
1748 /***********************************************************************
1749 * OleGetClipboard [OLE32.@]
1750 * Returns a pointer to our internal IDataObject which represents the conceptual
1751 * state of the Windows clipboard. If the current clipboard already contains
1752 * an IDataObject, our internal IDataObject will delegate to this object.
1754 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1756 HRESULT hr;
1757 ole_clipbrd *clipbrd;
1758 DWORD seq_no;
1760 TRACE("(%p)\n", obj);
1762 if(!obj) return E_INVALIDARG;
1764 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1766 seq_no = GetClipboardSequenceNumber();
1767 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1768 clipbrd->latest_snapshot = NULL;
1770 if(!clipbrd->latest_snapshot)
1772 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1773 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1776 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1777 IDataObject_AddRef(*obj);
1779 return S_OK;
1782 /******************************************************************************
1783 * OleFlushClipboard [OLE32.@]
1784 * Renders the data from the source IDataObject into the windows clipboard
1786 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1787 * by copying the storage into global memory. Subsequently the default
1788 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1789 * back to TYMED_IStorage.
1791 HRESULT WINAPI OleFlushClipboard(void)
1793 HRESULT hr;
1794 ole_clipbrd *clipbrd;
1795 HWND wnd;
1797 TRACE("()\n");
1799 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1801 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1804 * Already flushed or no source DataObject? Nothing to do.
1806 if (!clipbrd->src_data) return S_OK;
1808 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1810 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1812 hr = set_dataobject_format(NULL);
1814 set_src_dataobject(clipbrd, NULL);
1816 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1818 return hr;
1822 /***********************************************************************
1823 * OleIsCurrentClipboard [OLE32.@]
1825 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1827 HRESULT hr;
1828 ole_clipbrd *clipbrd;
1829 TRACE("()\n");
1831 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1833 if (data == NULL) return S_FALSE;
1835 return (data == clipbrd->src_data) ? S_OK : S_FALSE;