ole32: Make get_priv_data return target device ptrs (rather than offsets) and add...
[wine/hacks.git] / dlls / ole32 / clipboard.c
blob8aa14dc0174d08bb520c78af4a5cde6becd3db1c
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 /************************************************************************
1067 * snapshot_GetData
1069 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1070 STGMEDIUM *med)
1072 snapshot *This = impl_from_IDataObject(iface);
1073 HANDLE h;
1074 HRESULT hr;
1075 ole_priv_data *enum_data = NULL;
1076 ole_priv_data_entry *entry;
1077 DWORD mask;
1079 TRACE("(%p,%p,%p)\n", iface, fmt, med);
1081 if ( !fmt || !med ) return E_INVALIDARG;
1083 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1085 if(!This->data)
1086 hr = get_current_dataobject(&This->data);
1088 if(This->data)
1090 hr = IDataObject_GetData(This->data, fmt, med);
1091 CloseClipboard();
1092 return hr;
1095 h = GetClipboardData(fmt->cfFormat);
1096 if(!h)
1098 hr = DV_E_FORMATETC;
1099 goto end;
1102 hr = get_priv_data(&enum_data);
1103 if(FAILED(hr)) goto end;
1105 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1106 if(entry)
1108 mask = fmt->tymed & entry->fmtetc.tymed;
1109 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1111 else /* non-Ole format */
1112 mask = fmt->tymed & TYMED_HGLOBAL;
1114 if(mask & TYMED_ISTORAGE)
1115 hr = get_stgmed_for_storage(h, med);
1116 else if(mask & TYMED_HGLOBAL)
1117 hr = get_stgmed_for_global(h, med);
1118 else if(mask & TYMED_ISTREAM)
1119 hr = get_stgmed_for_stream(h, med);
1120 else
1122 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed);
1123 hr = E_FAIL;
1124 goto end;
1127 end:
1128 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1129 return hr;
1132 /************************************************************************
1133 * snapshot_GetDataHere
1135 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1136 STGMEDIUM *med)
1138 FIXME("(%p, %p, %p): stub\n", iface, fmt, med);
1139 return E_NOTIMPL;
1142 /************************************************************************
1143 * snapshot_QueryGetData
1145 * The OLE Clipboard's implementation of this method delegates to
1146 * a data source if there is one or wraps around the windows clipboard
1147 * function IsClipboardFormatAvailable() otherwise.
1150 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1152 FIXME("(%p, %p)\n", iface, fmt);
1154 if (!fmt) return E_INVALIDARG;
1156 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1158 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1160 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1163 /************************************************************************
1164 * snapshot_GetCanonicalFormatEtc
1166 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1167 FORMATETC *fmt_out)
1169 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1171 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1173 *fmt_out = *fmt_in;
1174 return DATA_S_SAMEFORMATETC;
1177 /************************************************************************
1178 * snapshot_SetData
1180 * The OLE Clipboard does not implement this method
1182 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1183 STGMEDIUM *med, BOOL release)
1185 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1186 return E_NOTIMPL;
1189 /************************************************************************
1190 * snapshot_EnumFormatEtc
1193 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1194 IEnumFORMATETC **enum_fmt)
1196 HRESULT hr;
1197 ole_priv_data *data = NULL;
1199 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1201 *enum_fmt = NULL;
1203 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1204 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1206 hr = get_priv_data(&data);
1208 if(FAILED(hr)) goto end;
1210 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1212 end:
1213 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1214 return hr;
1217 /************************************************************************
1218 * snapshot_DAdvise
1220 * The OLE Clipboard does not implement this method
1222 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1223 DWORD flags, IAdviseSink *sink,
1224 DWORD *conn)
1226 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1227 return E_NOTIMPL;
1230 /************************************************************************
1231 * snapshot_DUnadvise
1233 * The OLE Clipboard does not implement this method
1235 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1237 TRACE("(%p, %d): not implemented\n", iface, conn);
1238 return E_NOTIMPL;
1241 /************************************************************************
1242 * snapshot_EnumDAdvise
1244 * The OLE Clipboard does not implement this method
1246 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1247 IEnumSTATDATA** enum_advise)
1249 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1250 return E_NOTIMPL;
1253 static const IDataObjectVtbl snapshot_vtable =
1255 snapshot_QueryInterface,
1256 snapshot_AddRef,
1257 snapshot_Release,
1258 snapshot_GetData,
1259 snapshot_GetDataHere,
1260 snapshot_QueryGetData,
1261 snapshot_GetCanonicalFormatEtc,
1262 snapshot_SetData,
1263 snapshot_EnumFormatEtc,
1264 snapshot_DAdvise,
1265 snapshot_DUnadvise,
1266 snapshot_EnumDAdvise
1269 /*---------------------------------------------------------------------*
1270 * Internal implementation methods for the OLE clipboard
1271 *---------------------------------------------------------------------*/
1273 static snapshot *snapshot_construct(DWORD seq_no)
1275 snapshot *This;
1277 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1278 if (!This) return NULL;
1280 This->lpVtbl = &snapshot_vtable;
1281 This->ref = 0;
1282 This->seq_no = seq_no;
1283 This->data = NULL;
1285 return This;
1288 /*********************************************************
1289 * register_clipboard_formats
1291 static void register_clipboard_formats(void)
1293 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1294 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1295 static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1297 if(!dataobject_clipboard_format)
1298 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1299 if(!ole_priv_data_clipboard_format)
1300 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1301 if(!embed_source_clipboard_format)
1302 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1305 /***********************************************************************
1306 * OLEClipbrd_Initialize()
1307 * Initializes the OLE clipboard.
1309 void OLEClipbrd_Initialize(void)
1311 register_clipboard_formats();
1313 if ( !theOleClipboard )
1315 ole_clipbrd* clipbrd;
1316 HGLOBAL h;
1318 TRACE("()\n");
1320 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1321 if (!clipbrd) return;
1323 clipbrd->latest_snapshot = NULL;
1324 clipbrd->window = NULL;
1325 clipbrd->src_data = NULL;
1326 clipbrd->cached_enum = NULL;
1328 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1329 if(!h)
1331 HeapFree(GetProcessHeap(), 0, clipbrd);
1332 return;
1335 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1337 GlobalFree(h);
1338 HeapFree(GetProcessHeap(), 0, clipbrd);
1339 return;
1342 theOleClipboard = clipbrd;
1346 /***********************************************************************
1347 * OLEClipbrd_UnInitialize()
1348 * Un-Initializes the OLE clipboard
1350 void OLEClipbrd_UnInitialize(void)
1352 ole_clipbrd *clipbrd = theOleClipboard;
1354 TRACE("()\n");
1356 if ( clipbrd )
1358 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1359 HINSTANCE hinst = GetModuleHandleW(ole32W);
1361 if ( clipbrd->window )
1363 DestroyWindow(clipbrd->window);
1364 UnregisterClassW( clipbrd_wndclass, hinst );
1367 IStream_Release(clipbrd->marshal_data);
1368 HeapFree(GetProcessHeap(), 0, clipbrd);
1369 theOleClipboard = NULL;
1373 /*********************************************************************
1374 * set_clipboard_formats
1376 * Enumerate all formats supported by the source and make
1377 * those formats available using delayed rendering using SetClipboardData.
1378 * Cache the enumeration list and make that list visibile as the
1379 * 'Ole Private Data' format on the clipboard.
1382 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1384 HRESULT hr;
1385 FORMATETC fmt;
1386 IEnumFORMATETC *enum_fmt;
1387 HGLOBAL priv_data_handle;
1388 DWORD_PTR target_offset;
1389 ole_priv_data *priv_data;
1390 DWORD count = 0, needed = sizeof(*priv_data), idx;
1392 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1393 if(FAILED(hr)) return hr;
1395 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1397 count++;
1398 needed += sizeof(priv_data->entries[0]);
1399 if(fmt.ptd)
1401 needed += fmt.ptd->tdSize;
1402 CoTaskMemFree(fmt.ptd);
1406 /* Windows pads the list with two empty ole_priv_data_entries, one
1407 * after the entries array and one after the target device data.
1408 * Allocating with zero init to zero these pads. */
1410 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1411 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1412 priv_data = GlobalLock(priv_data_handle);
1414 priv_data->unk1 = 0;
1415 priv_data->size = needed;
1416 priv_data->unk2 = 1;
1417 priv_data->count = count;
1418 priv_data->unk3[0] = 0;
1419 priv_data->unk3[1] = 0;
1421 IEnumFORMATETC_Reset(enum_fmt);
1423 idx = 0;
1424 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1426 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1428 TRACE("%s\n", dump_fmtetc(&fmt));
1430 priv_data->entries[idx].fmtetc = fmt;
1431 if(fmt.ptd)
1433 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1434 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1435 target_offset += fmt.ptd->tdSize;
1436 CoTaskMemFree(fmt.ptd);
1439 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1440 priv_data->entries[idx].unk[0] = 0;
1441 priv_data->entries[idx].unk[1] = 0;
1443 if (priv_data->entries[idx].first_use)
1444 SetClipboardData(fmt.cfFormat, NULL);
1446 idx++;
1449 IEnumFORMATETC_Release(enum_fmt);
1451 /* Cache the list and fixup any target device offsets to ptrs */
1452 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1453 memcpy(clipbrd->cached_enum, priv_data, needed);
1454 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1455 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1456 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1458 GlobalUnlock(priv_data_handle);
1459 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1461 return S_OK;
1464 static HWND create_clipbrd_window(void);
1466 /***********************************************************************
1467 * get_clipbrd_window
1469 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1471 if ( !clipbrd->window )
1472 clipbrd->window = create_clipbrd_window();
1474 *wnd = clipbrd->window;
1475 return *wnd ? S_OK : E_FAIL;
1479 /**********************************************************************
1480 * release_marshal_data
1482 * Releases the data and sets the stream back to zero size.
1484 static inline void release_marshal_data(IStream *stm)
1486 LARGE_INTEGER pos;
1487 ULARGE_INTEGER size;
1488 pos.QuadPart = size.QuadPart = 0;
1490 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1491 CoReleaseMarshalData(stm);
1492 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1493 IStream_SetSize(stm, size);
1496 /***********************************************************************
1497 * set_src_dataobject
1499 * Clears and sets the clipboard's src IDataObject.
1501 * To marshal the source dataobject we do something rather different from Windows.
1502 * We set a window prop which contains the marshalled data.
1503 * Windows set two props one of which is an IID, the other is an endpoint number.
1505 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1507 HRESULT hr;
1508 HWND wnd;
1510 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1512 if(clipbrd->src_data)
1514 RemovePropW(wnd, wine_marshal_dataobject);
1515 release_marshal_data(clipbrd->marshal_data);
1517 IDataObject_Release(clipbrd->src_data);
1518 clipbrd->src_data = NULL;
1519 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1520 clipbrd->cached_enum = NULL;
1523 if(data)
1525 HGLOBAL h;
1526 IUnknown *unk;
1528 IDataObject_AddRef(data);
1529 clipbrd->src_data = data;
1531 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1532 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1533 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1534 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1535 if(FAILED(hr)) return hr;
1536 GetHGlobalFromStream(clipbrd->marshal_data, &h);
1537 SetPropW(wnd, wine_marshal_dataobject, h);
1538 hr = set_clipboard_formats(clipbrd, data);
1540 return hr;
1543 /***********************************************************************
1544 * clipbrd_wndproc
1546 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1548 ole_clipbrd *clipbrd;
1550 get_ole_clipbrd(&clipbrd);
1552 switch (message)
1554 case WM_RENDERFORMAT:
1556 UINT cf = wparam;
1557 ole_priv_data_entry *entry;
1559 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1560 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1562 if(entry)
1563 render_format(clipbrd->src_data, &entry->fmtetc);
1565 break;
1568 case WM_RENDERALLFORMATS:
1570 DWORD i;
1571 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1573 TRACE("(): WM_RENDERALLFORMATS\n");
1575 for(i = 0; i < clipbrd->cached_enum->count; i++)
1577 if(entries[i].first_use)
1578 render_format(clipbrd->src_data, &entries[i].fmtetc);
1580 break;
1583 case WM_DESTROYCLIPBOARD:
1585 TRACE("(): WM_DESTROYCLIPBOARD\n");
1587 set_src_dataobject(clipbrd, NULL);
1588 break;
1591 default:
1592 return DefWindowProcW(hwnd, message, wparam, lparam);
1595 return 0;
1599 /***********************************************************************
1600 * create_clipbrd_window
1602 static HWND create_clipbrd_window(void)
1604 WNDCLASSEXW class;
1605 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1606 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1607 HINSTANCE hinst = GetModuleHandleW(ole32W);
1609 class.cbSize = sizeof(class);
1610 class.style = 0;
1611 class.lpfnWndProc = clipbrd_wndproc;
1612 class.cbClsExtra = 0;
1613 class.cbWndExtra = 0;
1614 class.hInstance = hinst;
1615 class.hIcon = 0;
1616 class.hCursor = 0;
1617 class.hbrBackground = 0;
1618 class.lpszMenuName = NULL;
1619 class.lpszClassName = clipbrd_wndclass;
1620 class.hIconSm = NULL;
1622 RegisterClassExW(&class);
1624 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1625 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1626 NULL, NULL, hinst, 0);
1629 /*********************************************************************
1630 * set_dataobject_format
1632 * Windows creates a 'DataObject' clipboard format that contains the
1633 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1635 static HRESULT set_dataobject_format(HWND hwnd)
1637 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1638 HWND *data;
1640 if(!h) return E_OUTOFMEMORY;
1642 data = GlobalLock(h);
1643 *data = hwnd;
1644 GlobalUnlock(h);
1646 if(!SetClipboardData(dataobject_clipboard_format, h))
1648 GlobalFree(h);
1649 return CLIPBRD_E_CANT_SET;
1652 return S_OK;
1655 /*---------------------------------------------------------------------*
1656 * Win32 OLE clipboard API
1657 *---------------------------------------------------------------------*/
1659 /***********************************************************************
1660 * OleSetClipboard [OLE32.@]
1661 * Places a pointer to the specified data object onto the clipboard,
1662 * making the data object accessible to the OleGetClipboard function.
1664 * RETURNS
1666 * S_OK IDataObject pointer placed on the clipboard
1667 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1668 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1669 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1670 * CLIPBRD_E_CANT_SET SetClipboard failed
1673 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1675 HRESULT hr;
1676 ole_clipbrd *clipbrd;
1677 HWND wnd;
1679 TRACE("(%p)\n", data);
1681 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1683 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1685 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1687 if ( !EmptyClipboard() )
1689 hr = CLIPBRD_E_CANT_EMPTY;
1690 goto end;
1693 hr = set_src_dataobject(clipbrd, data);
1694 if(FAILED(hr)) goto end;
1696 hr = set_dataobject_format(wnd);
1698 end:
1700 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1702 if ( FAILED(hr) )
1704 set_src_dataobject(clipbrd, NULL);
1707 return hr;
1711 /***********************************************************************
1712 * OleGetClipboard [OLE32.@]
1713 * Returns a pointer to our internal IDataObject which represents the conceptual
1714 * state of the Windows clipboard. If the current clipboard already contains
1715 * an IDataObject, our internal IDataObject will delegate to this object.
1717 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1719 HRESULT hr;
1720 ole_clipbrd *clipbrd;
1721 DWORD seq_no;
1723 TRACE("(%p)\n", obj);
1725 if(!obj) return E_INVALIDARG;
1727 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1729 seq_no = GetClipboardSequenceNumber();
1730 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1731 clipbrd->latest_snapshot = NULL;
1733 if(!clipbrd->latest_snapshot)
1735 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1736 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1739 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1740 IDataObject_AddRef(*obj);
1742 return S_OK;
1745 /******************************************************************************
1746 * OleFlushClipboard [OLE32.@]
1747 * Renders the data from the source IDataObject into the windows clipboard
1749 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1750 * by copying the storage into global memory. Subsequently the default
1751 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1752 * back to TYMED_IStorage.
1754 HRESULT WINAPI OleFlushClipboard(void)
1756 HRESULT hr;
1757 ole_clipbrd *clipbrd;
1758 HWND wnd;
1760 TRACE("()\n");
1762 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1764 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1767 * Already flushed or no source DataObject? Nothing to do.
1769 if (!clipbrd->src_data) return S_OK;
1771 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1773 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1775 hr = set_dataobject_format(NULL);
1777 set_src_dataobject(clipbrd, NULL);
1779 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1781 return hr;
1785 /***********************************************************************
1786 * OleIsCurrentClipboard [OLE32.@]
1788 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1790 HRESULT hr;
1791 ole_clipbrd *clipbrd;
1792 TRACE("()\n");
1794 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1796 if (data == NULL) return S_FALSE;
1798 return (data == clipbrd->src_data) ? S_OK : S_FALSE;