ole32: Add support for enumerating non-ole clipboard formats.
[wine/hacks.git] / dlls / ole32 / clipboard.c
blob7255323ee0da996eac70fb6f1b11987402cc4c2d
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 * Consumer snapshot. Represents the state of the ole clipboard
137 * returned by OleGetClipboard().
139 typedef struct snapshot
141 const IDataObjectVtbl* lpVtbl;
142 LONG ref;
144 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */
146 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */
147 } snapshot;
149 /****************************************************************************
150 * ole_clipbrd
152 typedef struct ole_clipbrd
154 snapshot *latest_snapshot; /* Latest consumer snapshot */
156 HWND window; /* Hidden clipboard window */
157 IDataObject *src_data; /* Source object passed to OleSetClipboard */
158 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
159 IStream *marshal_data; /* Stream onto which to marshal src_data */
160 } ole_clipbrd;
162 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
164 return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
167 typedef struct PresentationDataHeader
169 BYTE unknown1[28];
170 DWORD dwObjectExtentX;
171 DWORD dwObjectExtentY;
172 DWORD dwSize;
173 } PresentationDataHeader;
176 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
178 static ole_clipbrd* theOleClipboard;
180 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
182 struct oletls *info = COM_CurrentInfo();
183 *clipbrd = NULL;
185 if(!info->ole_inits)
186 return CO_E_NOTINITIALIZED;
187 *clipbrd = theOleClipboard;
189 return S_OK;
193 * Name of our registered OLE clipboard window class
195 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
197 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};
199 static UINT dataobject_clipboard_format;
200 static UINT ole_priv_data_clipboard_format;
201 static UINT embed_source_clipboard_format;
203 static inline char *dump_fmtetc(FORMATETC *fmt)
205 static char buf[100];
207 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
208 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
209 return buf;
212 /*---------------------------------------------------------------------*
213 * Implementation of the internal IEnumFORMATETC interface returned by
214 * the OLE clipboard's IDataObject.
215 *---------------------------------------------------------------------*/
217 typedef struct enum_fmtetc
219 const IEnumFORMATETCVtbl *lpVtbl;
220 LONG ref;
222 UINT pos; /* current enumerator position */
223 ole_priv_data *data;
224 } enum_fmtetc;
226 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
228 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
231 /************************************************************************
232 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
234 * See Windows documentation for more details on IUnknown methods.
236 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
237 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
239 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
241 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
243 *ppvObj = NULL;
245 if(IsEqualIID(riid, &IID_IUnknown) ||
246 IsEqualIID(riid, &IID_IEnumFORMATETC))
248 *ppvObj = iface;
251 if(*ppvObj)
253 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
254 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
255 return S_OK;
258 TRACE("-- Interface: E_NOINTERFACE\n");
259 return E_NOINTERFACE;
262 /************************************************************************
263 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
266 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
268 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
269 TRACE("(%p)->(count=%u)\n",This, This->ref);
271 return InterlockedIncrement(&This->ref);
274 /************************************************************************
275 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
277 * See Windows documentation for more details on IUnknown methods.
279 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
281 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
282 ULONG ref;
284 TRACE("(%p)->(count=%u)\n",This, This->ref);
286 ref = InterlockedDecrement(&This->ref);
287 if (!ref)
289 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
290 HeapFree(GetProcessHeap(), 0, This->data);
291 HeapFree(GetProcessHeap(), 0, This);
293 return ref;
296 /************************************************************************
297 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
299 * Standard enumerator members for IEnumFORMATETC
301 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
302 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
304 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
305 UINT cfetch, i;
306 HRESULT hres = S_FALSE;
308 TRACE("(%p)->(pos=%u)\n", This, This->pos);
310 if (This->pos < This->data->count)
312 cfetch = This->data->count - This->pos;
313 if (cfetch >= celt)
315 cfetch = celt;
316 hres = S_OK;
319 for(i = 0; i < cfetch; i++)
321 rgelt[i] = This->data->entries[This->pos++].fmtetc;
322 if(rgelt[i].ptd)
324 DVTARGETDEVICE *target = rgelt[i].ptd;
325 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
326 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
327 memcpy(rgelt[i].ptd, target, target->tdSize);
331 else
333 cfetch = 0;
336 if (pceltFethed)
338 *pceltFethed = cfetch;
341 return hres;
344 /************************************************************************
345 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
347 * Standard enumerator members for IEnumFORMATETC
349 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
351 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
352 TRACE("(%p)->(num=%u)\n", This, celt);
354 This->pos += celt;
355 if (This->pos > This->data->count)
357 This->pos = This->data->count;
358 return S_FALSE;
360 return S_OK;
363 /************************************************************************
364 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
366 * Standard enumerator members for IEnumFORMATETC
368 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
370 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
371 TRACE("(%p)->()\n", This);
373 This->pos = 0;
374 return S_OK;
377 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
379 /************************************************************************
380 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
382 * Standard enumerator members for IEnumFORMATETC
384 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
385 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
387 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
388 ole_priv_data *new_data;
389 DWORD i;
391 TRACE("(%p)->(%p)\n", This, obj);
393 if ( !obj ) return E_INVALIDARG;
394 *obj = NULL;
396 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
397 if(!new_data) return E_OUTOFMEMORY;
398 memcpy(new_data, This->data, This->data->size);
400 /* Fixup any target device ptrs */
401 for(i = 0; i < This->data->count; i++)
402 new_data->entries[i].fmtetc.ptd =
403 td_offs_to_ptr(new_data, td_get_offs(This->data, i));
405 return enum_fmtetc_construct(new_data, This->pos, obj);
408 static const IEnumFORMATETCVtbl efvt =
410 OLEClipbrd_IEnumFORMATETC_QueryInterface,
411 OLEClipbrd_IEnumFORMATETC_AddRef,
412 OLEClipbrd_IEnumFORMATETC_Release,
413 OLEClipbrd_IEnumFORMATETC_Next,
414 OLEClipbrd_IEnumFORMATETC_Skip,
415 OLEClipbrd_IEnumFORMATETC_Reset,
416 OLEClipbrd_IEnumFORMATETC_Clone
419 /************************************************************************
420 * enum_fmtetc_construct
422 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
424 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
426 enum_fmtetc* ef;
428 *obj = NULL;
429 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
430 if (!ef) return E_OUTOFMEMORY;
432 ef->ref = 1;
433 ef->lpVtbl = &efvt;
434 ef->data = data;
435 ef->pos = pos;
437 TRACE("(%p)->()\n", ef);
438 *obj = (IEnumFORMATETC *)ef;
439 return S_OK;
442 /***********************************************************************
443 * dup_global_mem
445 * Helper method to duplicate an HGLOBAL chunk of memory
447 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
449 void *src_ptr, *dst_ptr;
450 DWORD size;
452 *dst = NULL;
453 if ( !src ) return S_FALSE;
455 size = GlobalSize(src);
457 *dst = GlobalAlloc( flags, size );
458 if ( !*dst ) return E_OUTOFMEMORY;
460 src_ptr = GlobalLock(src);
461 dst_ptr = GlobalLock(*dst);
463 memcpy(dst_ptr, src_ptr, size);
465 GlobalUnlock(*dst);
466 GlobalUnlock(src);
468 return S_OK;
471 /************************************************************
472 * render_embed_source_hack
474 * This is clearly a hack and has no place in the clipboard code.
477 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
479 STGMEDIUM std;
480 HGLOBAL hStorage = 0;
481 HRESULT hr = S_OK;
482 ILockBytes *ptrILockBytes;
484 memset(&std, 0, sizeof(STGMEDIUM));
485 std.tymed = fmt->tymed = TYMED_ISTORAGE;
487 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
488 if (hStorage == NULL) return E_OUTOFMEMORY;
489 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
490 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
491 ILockBytes_Release(ptrILockBytes);
493 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
495 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
496 GlobalFree(hStorage);
497 return hr;
500 if (1) /* check whether the presentation data is already -not- present */
502 FORMATETC fmt2;
503 STGMEDIUM std2;
504 METAFILEPICT *mfp = 0;
506 fmt2.cfFormat = CF_METAFILEPICT;
507 fmt2.ptd = 0;
508 fmt2.dwAspect = DVASPECT_CONTENT;
509 fmt2.lindex = -1;
510 fmt2.tymed = TYMED_MFPICT;
512 memset(&std2, 0, sizeof(STGMEDIUM));
513 std2.tymed = TYMED_MFPICT;
515 /* Get the metafile picture out of it */
517 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
519 mfp = GlobalLock(std2.u.hGlobal);
522 if (mfp)
524 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
525 IStream *pStream = 0;
526 void *mfBits;
527 PresentationDataHeader pdh;
528 INT nSize;
529 CLSID clsID;
530 LPOLESTR strProgID;
531 CHAR strOleTypeName[51];
532 BYTE OlePresStreamHeader [] =
534 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
535 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
536 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x00, 0x00
540 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
542 memset(&pdh, 0, sizeof(PresentationDataHeader));
543 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
545 pdh.dwObjectExtentX = mfp->xExt;
546 pdh.dwObjectExtentY = mfp->yExt;
547 pdh.dwSize = nSize;
549 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
551 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
553 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
554 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
556 hr = IStream_Write(pStream, mfBits, nSize, NULL);
558 IStream_Release(pStream);
560 HeapFree(GetProcessHeap(), 0, mfBits);
562 GlobalUnlock(std2.u.hGlobal);
563 ReleaseStgMedium(&std2);
565 ReadClassStg(std.u.pstg, &clsID);
566 ProgIDFromCLSID(&clsID, &strProgID);
568 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
569 OLECONVERT_CreateOleStream(std.u.pstg);
570 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
574 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
576 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
577 GlobalFree(hStorage);
578 hr = CLIPBRD_E_CANT_SET;
581 ReleaseStgMedium(&std);
582 return hr;
585 /************************************************************************
586 * find_format_in_list
588 * Returns the first entry that matches the provided clipboard format.
590 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
592 DWORD i;
593 for(i = 0; i < num; i++)
594 if(entries[i].fmtetc.cfFormat == cf)
595 return &entries[i];
597 return NULL;
600 /***************************************************************************
601 * get_data_from_storage
603 * Returns storage data in an HGLOBAL.
605 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
607 HGLOBAL h;
608 IStorage *stg;
609 HRESULT hr;
610 FORMATETC stg_fmt;
611 STGMEDIUM med;
612 ILockBytes *lbs;
614 *mem = NULL;
616 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
617 if(!h) return E_OUTOFMEMORY;
619 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
620 if(SUCCEEDED(hr))
622 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
623 ILockBytes_Release(lbs);
625 if(FAILED(hr))
627 GlobalFree(h);
628 return hr;
631 stg_fmt = *fmt;
632 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
633 med.u.pstg = stg;
634 med.pUnkForRelease = NULL;
636 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
637 if(FAILED(hr))
639 med.u.pstg = NULL;
640 hr = IDataObject_GetData(data, &stg_fmt, &med);
641 if(FAILED(hr)) goto end;
643 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
644 ReleaseStgMedium(&med);
645 if(FAILED(hr)) goto end;
647 *mem = h;
649 end:
650 IStorage_Release(stg);
651 if(FAILED(hr)) GlobalFree(h);
652 return hr;
655 /***************************************************************************
656 * get_data_from_stream
658 * Returns stream data in an HGLOBAL.
660 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
662 HGLOBAL h;
663 IStream *stm = NULL;
664 HRESULT hr;
665 FORMATETC stm_fmt;
666 STGMEDIUM med;
668 *mem = NULL;
670 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
671 if(!h) return E_OUTOFMEMORY;
673 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
674 if(FAILED(hr)) goto error;
676 stm_fmt = *fmt;
677 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
678 med.u.pstm = stm;
679 med.pUnkForRelease = NULL;
681 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
682 if(FAILED(hr))
684 LARGE_INTEGER offs;
685 ULARGE_INTEGER pos;
687 med.u.pstm = NULL;
688 hr = IDataObject_GetData(data, &stm_fmt, &med);
689 if(FAILED(hr)) goto error;
691 offs.QuadPart = 0;
692 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
693 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
694 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
695 ReleaseStgMedium(&med);
696 if(FAILED(hr)) goto error;
698 *mem = h;
699 IStream_Release(stm);
700 return S_OK;
702 error:
703 if(stm) IStream_Release(stm);
704 GlobalFree(h);
705 return hr;
708 /***************************************************************************
709 * get_data_from_global
711 * Returns global data in an HGLOBAL.
713 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
715 HGLOBAL h;
716 HRESULT hr;
717 FORMATETC mem_fmt;
718 STGMEDIUM med;
720 *mem = NULL;
722 mem_fmt = *fmt;
723 mem_fmt.tymed = TYMED_HGLOBAL;
725 hr = IDataObject_GetData(data, &mem_fmt, &med);
726 if(FAILED(hr)) return hr;
728 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
730 if(SUCCEEDED(hr)) *mem = h;
732 ReleaseStgMedium(&med);
734 return hr;
737 /***********************************************************************
738 * render_format
740 * Render the clipboard data. Note that this call will delegate to the
741 * source data object.
743 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
745 HGLOBAL clip_data = NULL;
746 HRESULT hr;
748 /* Embed source hack */
749 if(fmt->cfFormat == embed_source_clipboard_format)
751 return render_embed_source_hack(data, fmt);
754 if(fmt->tymed & TYMED_ISTORAGE)
756 hr = get_data_from_storage(data, fmt, &clip_data);
758 else if(fmt->tymed & TYMED_ISTREAM)
760 hr = get_data_from_stream(data, fmt, &clip_data);
762 else if(fmt->tymed & TYMED_HGLOBAL)
764 hr = get_data_from_global(data, fmt, &clip_data);
766 else
768 FIXME("Unhandled tymed %x\n", fmt->tymed);
769 hr = DV_E_FORMATETC;
772 if(SUCCEEDED(hr))
774 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
776 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
777 GlobalFree(clip_data);
778 hr = CLIPBRD_E_CANT_SET;
782 return hr;
785 /*---------------------------------------------------------------------*
786 * Implementation of the internal IDataObject interface exposed by
787 * the OLE clipboard.
788 *---------------------------------------------------------------------*/
791 /************************************************************************
792 * snapshot_QueryInterface
794 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
795 REFIID riid, void **ppvObject)
797 snapshot *This = impl_from_IDataObject(iface);
798 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
800 if ( (This==0) || (ppvObject==0) )
801 return E_INVALIDARG;
803 *ppvObject = 0;
805 if (IsEqualIID(&IID_IUnknown, riid) ||
806 IsEqualIID(&IID_IDataObject, riid))
808 *ppvObject = iface;
810 else
812 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
813 return E_NOINTERFACE;
816 IUnknown_AddRef((IUnknown*)*ppvObject);
818 return S_OK;
821 /************************************************************************
822 * snapshot_AddRef
824 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
826 snapshot *This = impl_from_IDataObject(iface);
828 TRACE("(%p)->(count=%u)\n", This, This->ref);
830 return InterlockedIncrement(&This->ref);
833 /************************************************************************
834 * snapshot_Release
836 static ULONG WINAPI snapshot_Release(IDataObject *iface)
838 snapshot *This = impl_from_IDataObject(iface);
839 ULONG ref;
841 TRACE("(%p)->(count=%u)\n", This, This->ref);
843 ref = InterlockedDecrement(&This->ref);
845 if (ref == 0)
847 ole_clipbrd *clipbrd;
848 HRESULT hr = get_ole_clipbrd(&clipbrd);
850 if(This->data) IDataObject_Release(This->data);
852 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
853 clipbrd->latest_snapshot = NULL;
854 HeapFree(GetProcessHeap(), 0, This);
857 return ref;
860 /************************************************************
861 * get_current_ole_clip_window
863 * Return the window that owns the ole clipboard.
865 * If the clipboard is flushed or not owned by ole this will
866 * return NULL.
868 static HWND get_current_ole_clip_window(void)
870 HGLOBAL h;
871 HWND *ptr, wnd;
873 h = GetClipboardData(dataobject_clipboard_format);
874 if(!h) return NULL;
875 ptr = GlobalLock(h);
876 if(!ptr) return NULL;
877 wnd = *ptr;
878 GlobalUnlock(h);
879 return wnd;
882 /************************************************************
883 * get_current_dataobject
885 * Return an unmarshalled IDataObject if there is a current
886 * (ie non-flushed) object on the ole clipboard.
888 static HRESULT get_current_dataobject(IDataObject **data)
890 HRESULT hr = S_FALSE;
891 HWND wnd = get_current_ole_clip_window();
892 HGLOBAL h;
893 void *ptr;
894 IStream *stm;
895 LARGE_INTEGER pos;
897 *data = NULL;
898 if(!wnd) return S_FALSE;
900 h = GetPropW(wnd, wine_marshal_dataobject);
901 if(!h) return S_FALSE;
902 ptr = GlobalLock(h);
903 if(!ptr) return S_FALSE;
905 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
906 if(FAILED(hr)) goto end;
908 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
909 if(SUCCEEDED(hr))
911 pos.QuadPart = 0;
912 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
913 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
915 IStream_Release(stm);
917 end:
918 GlobalUnlock(h);
919 return hr;
922 static DWORD get_tymed_from_nonole_cf(UINT cf)
924 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
926 switch(cf)
928 case CF_TEXT:
929 case CF_OEMTEXT:
930 case CF_UNICODETEXT:
931 return TYMED_ISTREAM | TYMED_HGLOBAL;
932 case CF_ENHMETAFILE:
933 return TYMED_ENHMF;
934 case CF_METAFILEPICT:
935 return TYMED_MFPICT;
936 default:
937 FIXME("returning TYMED_NULL for cf %04x\n", cf);
938 return TYMED_NULL;
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;
951 ole_priv_data *ret = NULL;
953 *data = NULL;
955 handle = GetClipboardData( ole_priv_data_clipboard_format );
956 if(handle)
958 ole_priv_data *src = GlobalLock(handle);
959 if(src)
961 DWORD i;
963 /* FIXME: sanity check on size */
964 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
965 if(!ret)
967 GlobalUnlock(handle);
968 return E_OUTOFMEMORY;
970 memcpy(ret, src, src->size);
971 GlobalUnlock(handle);
973 /* Fixup any target device offsets to ptrs */
974 for(i = 0; i < ret->count; i++)
975 ret->entries[i].fmtetc.ptd =
976 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
980 if(!ret) /* Non-ole data */
982 UINT cf;
983 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
985 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
987 char buf[100];
988 GetClipboardFormatNameA(cf, buf, sizeof(buf));
989 TRACE("\tcf %04x %s\n", cf, buf);
992 TRACE("count %d\n", count);
993 size += count * sizeof(ret->entries[0]);
995 /* There are holes in fmtetc so zero init */
996 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
997 if(!ret) return E_OUTOFMEMORY;
998 ret->size = size;
999 ret->count = count;
1001 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1003 ret->entries[idx].fmtetc.cfFormat = cf;
1004 ret->entries[idx].fmtetc.ptd = NULL;
1005 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1006 ret->entries[idx].fmtetc.lindex = -1;
1007 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1008 ret->entries[idx].first_use = 1;
1012 *data = ret;
1013 return hr;
1016 /************************************************************************
1017 * get_stgmed_for_global
1019 * Returns a stg medium with a copy of the global handle
1021 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1023 HRESULT hr;
1025 med->pUnkForRelease = NULL;
1026 med->tymed = TYMED_NULL;
1028 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1030 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1032 return hr;
1035 /************************************************************************
1036 * get_stgmed_for_stream
1038 * Returns a stg medium with a stream based on the handle
1040 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1042 HRESULT hr;
1043 HGLOBAL dst;
1045 med->pUnkForRelease = NULL;
1046 med->tymed = TYMED_NULL;
1048 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1049 if(FAILED(hr)) return hr;
1051 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1052 if(FAILED(hr))
1054 GlobalFree(dst);
1055 return hr;
1058 med->tymed = TYMED_ISTREAM;
1059 return hr;
1062 /************************************************************************
1063 * get_stgmed_for_storage
1065 * Returns a stg medium with a storage based on the handle
1067 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1069 HRESULT hr;
1070 HGLOBAL dst;
1071 ILockBytes *lbs;
1073 med->pUnkForRelease = NULL;
1074 med->tymed = TYMED_NULL;
1076 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1077 if(FAILED(hr)) return hr;
1079 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1080 if(FAILED(hr))
1082 GlobalFree(dst);
1083 return hr;
1086 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1087 ILockBytes_Release(lbs);
1088 if(FAILED(hr))
1090 GlobalFree(dst);
1091 return hr;
1094 med->tymed = TYMED_ISTORAGE;
1095 return hr;
1098 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1100 const WCHAR *str1, *str2;
1102 if(off1 == 0 && off2 == 0) return TRUE;
1103 if(off1 == 0 || off2 == 0) return FALSE;
1105 str1 = (const WCHAR*)((const char*)t1 + off1);
1106 str2 = (const WCHAR*)((const char*)t2 + off2);
1108 return !lstrcmpW(str1, str2);
1111 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1113 if(t1 == NULL && t2 == NULL) return TRUE;
1114 if(t1 == NULL || t2 == NULL) return FALSE;
1116 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1117 return FALSE;
1118 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1119 return FALSE;
1120 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1121 return FALSE;
1123 /* FIXME check devmode? */
1125 return TRUE;
1128 /************************************************************************
1129 * snapshot_GetData
1131 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1132 STGMEDIUM *med)
1134 snapshot *This = impl_from_IDataObject(iface);
1135 HANDLE h;
1136 HRESULT hr;
1137 ole_priv_data *enum_data = NULL;
1138 ole_priv_data_entry *entry;
1139 DWORD mask;
1141 TRACE("(%p,%p,%p)\n", iface, fmt, med);
1143 if ( !fmt || !med ) return E_INVALIDARG;
1145 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1147 if(!This->data)
1148 hr = get_current_dataobject(&This->data);
1150 if(This->data)
1152 hr = IDataObject_GetData(This->data, fmt, med);
1153 CloseClipboard();
1154 return hr;
1157 h = GetClipboardData(fmt->cfFormat);
1158 if(!h)
1160 hr = DV_E_FORMATETC;
1161 goto end;
1164 hr = get_priv_data(&enum_data);
1165 if(FAILED(hr)) goto end;
1167 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1168 if(entry)
1170 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1172 hr = DV_E_FORMATETC;
1173 goto end;
1175 mask = fmt->tymed & entry->fmtetc.tymed;
1176 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1178 else /* non-Ole format */
1179 mask = fmt->tymed & TYMED_HGLOBAL;
1181 if(mask & TYMED_ISTORAGE)
1182 hr = get_stgmed_for_storage(h, med);
1183 else if(mask & TYMED_HGLOBAL)
1184 hr = get_stgmed_for_global(h, med);
1185 else if(mask & TYMED_ISTREAM)
1186 hr = get_stgmed_for_stream(h, med);
1187 else
1189 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed);
1190 hr = E_FAIL;
1191 goto end;
1194 end:
1195 HeapFree(GetProcessHeap(), 0, enum_data);
1196 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1197 return hr;
1200 /************************************************************************
1201 * snapshot_GetDataHere
1203 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1204 STGMEDIUM *med)
1206 FIXME("(%p, %p, %p): stub\n", iface, fmt, med);
1207 return E_NOTIMPL;
1210 /************************************************************************
1211 * snapshot_QueryGetData
1213 * The OLE Clipboard's implementation of this method delegates to
1214 * a data source if there is one or wraps around the windows clipboard
1215 * function IsClipboardFormatAvailable() otherwise.
1218 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1220 FIXME("(%p, %p)\n", iface, fmt);
1222 if (!fmt) return E_INVALIDARG;
1224 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1226 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1228 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1231 /************************************************************************
1232 * snapshot_GetCanonicalFormatEtc
1234 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1235 FORMATETC *fmt_out)
1237 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1239 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1241 *fmt_out = *fmt_in;
1242 return DATA_S_SAMEFORMATETC;
1245 /************************************************************************
1246 * snapshot_SetData
1248 * The OLE Clipboard does not implement this method
1250 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1251 STGMEDIUM *med, BOOL release)
1253 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1254 return E_NOTIMPL;
1257 /************************************************************************
1258 * snapshot_EnumFormatEtc
1261 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1262 IEnumFORMATETC **enum_fmt)
1264 HRESULT hr;
1265 ole_priv_data *data = NULL;
1267 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1269 *enum_fmt = NULL;
1271 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1272 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1274 hr = get_priv_data(&data);
1276 if(FAILED(hr)) goto end;
1278 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1280 end:
1281 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1282 return hr;
1285 /************************************************************************
1286 * snapshot_DAdvise
1288 * The OLE Clipboard does not implement this method
1290 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1291 DWORD flags, IAdviseSink *sink,
1292 DWORD *conn)
1294 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1295 return E_NOTIMPL;
1298 /************************************************************************
1299 * snapshot_DUnadvise
1301 * The OLE Clipboard does not implement this method
1303 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1305 TRACE("(%p, %d): not implemented\n", iface, conn);
1306 return E_NOTIMPL;
1309 /************************************************************************
1310 * snapshot_EnumDAdvise
1312 * The OLE Clipboard does not implement this method
1314 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1315 IEnumSTATDATA** enum_advise)
1317 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1318 return E_NOTIMPL;
1321 static const IDataObjectVtbl snapshot_vtable =
1323 snapshot_QueryInterface,
1324 snapshot_AddRef,
1325 snapshot_Release,
1326 snapshot_GetData,
1327 snapshot_GetDataHere,
1328 snapshot_QueryGetData,
1329 snapshot_GetCanonicalFormatEtc,
1330 snapshot_SetData,
1331 snapshot_EnumFormatEtc,
1332 snapshot_DAdvise,
1333 snapshot_DUnadvise,
1334 snapshot_EnumDAdvise
1337 /*---------------------------------------------------------------------*
1338 * Internal implementation methods for the OLE clipboard
1339 *---------------------------------------------------------------------*/
1341 static snapshot *snapshot_construct(DWORD seq_no)
1343 snapshot *This;
1345 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1346 if (!This) return NULL;
1348 This->lpVtbl = &snapshot_vtable;
1349 This->ref = 0;
1350 This->seq_no = seq_no;
1351 This->data = NULL;
1353 return This;
1356 /*********************************************************
1357 * register_clipboard_formats
1359 static void register_clipboard_formats(void)
1361 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1362 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1363 static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1365 if(!dataobject_clipboard_format)
1366 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1367 if(!ole_priv_data_clipboard_format)
1368 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1369 if(!embed_source_clipboard_format)
1370 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1373 /***********************************************************************
1374 * OLEClipbrd_Initialize()
1375 * Initializes the OLE clipboard.
1377 void OLEClipbrd_Initialize(void)
1379 register_clipboard_formats();
1381 if ( !theOleClipboard )
1383 ole_clipbrd* clipbrd;
1384 HGLOBAL h;
1386 TRACE("()\n");
1388 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1389 if (!clipbrd) return;
1391 clipbrd->latest_snapshot = NULL;
1392 clipbrd->window = NULL;
1393 clipbrd->src_data = NULL;
1394 clipbrd->cached_enum = NULL;
1396 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1397 if(!h)
1399 HeapFree(GetProcessHeap(), 0, clipbrd);
1400 return;
1403 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1405 GlobalFree(h);
1406 HeapFree(GetProcessHeap(), 0, clipbrd);
1407 return;
1410 theOleClipboard = clipbrd;
1414 /***********************************************************************
1415 * OLEClipbrd_UnInitialize()
1416 * Un-Initializes the OLE clipboard
1418 void OLEClipbrd_UnInitialize(void)
1420 ole_clipbrd *clipbrd = theOleClipboard;
1422 TRACE("()\n");
1424 if ( clipbrd )
1426 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1427 HINSTANCE hinst = GetModuleHandleW(ole32W);
1429 if ( clipbrd->window )
1431 DestroyWindow(clipbrd->window);
1432 UnregisterClassW( clipbrd_wndclass, hinst );
1435 IStream_Release(clipbrd->marshal_data);
1436 HeapFree(GetProcessHeap(), 0, clipbrd);
1437 theOleClipboard = NULL;
1441 /*********************************************************************
1442 * set_clipboard_formats
1444 * Enumerate all formats supported by the source and make
1445 * those formats available using delayed rendering using SetClipboardData.
1446 * Cache the enumeration list and make that list visibile as the
1447 * 'Ole Private Data' format on the clipboard.
1450 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1452 HRESULT hr;
1453 FORMATETC fmt;
1454 IEnumFORMATETC *enum_fmt;
1455 HGLOBAL priv_data_handle;
1456 DWORD_PTR target_offset;
1457 ole_priv_data *priv_data;
1458 DWORD count = 0, needed = sizeof(*priv_data), idx;
1460 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1461 if(FAILED(hr)) return hr;
1463 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1465 count++;
1466 needed += sizeof(priv_data->entries[0]);
1467 if(fmt.ptd)
1469 needed += fmt.ptd->tdSize;
1470 CoTaskMemFree(fmt.ptd);
1474 /* Windows pads the list with two empty ole_priv_data_entries, one
1475 * after the entries array and one after the target device data.
1476 * Allocating with zero init to zero these pads. */
1478 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1479 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1480 priv_data = GlobalLock(priv_data_handle);
1482 priv_data->unk1 = 0;
1483 priv_data->size = needed;
1484 priv_data->unk2 = 1;
1485 priv_data->count = count;
1486 priv_data->unk3[0] = 0;
1487 priv_data->unk3[1] = 0;
1489 IEnumFORMATETC_Reset(enum_fmt);
1491 idx = 0;
1492 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1494 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1496 TRACE("%s\n", dump_fmtetc(&fmt));
1498 priv_data->entries[idx].fmtetc = fmt;
1499 if(fmt.ptd)
1501 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1502 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1503 target_offset += fmt.ptd->tdSize;
1504 CoTaskMemFree(fmt.ptd);
1507 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1508 priv_data->entries[idx].unk[0] = 0;
1509 priv_data->entries[idx].unk[1] = 0;
1511 if (priv_data->entries[idx].first_use)
1512 SetClipboardData(fmt.cfFormat, NULL);
1514 idx++;
1517 IEnumFORMATETC_Release(enum_fmt);
1519 /* Cache the list and fixup any target device offsets to ptrs */
1520 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1521 memcpy(clipbrd->cached_enum, priv_data, needed);
1522 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1523 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1524 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1526 GlobalUnlock(priv_data_handle);
1527 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1529 return S_OK;
1532 static HWND create_clipbrd_window(void);
1534 /***********************************************************************
1535 * get_clipbrd_window
1537 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1539 if ( !clipbrd->window )
1540 clipbrd->window = create_clipbrd_window();
1542 *wnd = clipbrd->window;
1543 return *wnd ? S_OK : E_FAIL;
1547 /**********************************************************************
1548 * release_marshal_data
1550 * Releases the data and sets the stream back to zero size.
1552 static inline void release_marshal_data(IStream *stm)
1554 LARGE_INTEGER pos;
1555 ULARGE_INTEGER size;
1556 pos.QuadPart = size.QuadPart = 0;
1558 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1559 CoReleaseMarshalData(stm);
1560 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1561 IStream_SetSize(stm, size);
1564 /***********************************************************************
1565 * set_src_dataobject
1567 * Clears and sets the clipboard's src IDataObject.
1569 * To marshal the source dataobject we do something rather different from Windows.
1570 * We set a window prop which contains the marshalled data.
1571 * Windows set two props one of which is an IID, the other is an endpoint number.
1573 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1575 HRESULT hr;
1576 HWND wnd;
1578 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1580 if(clipbrd->src_data)
1582 RemovePropW(wnd, wine_marshal_dataobject);
1583 release_marshal_data(clipbrd->marshal_data);
1585 IDataObject_Release(clipbrd->src_data);
1586 clipbrd->src_data = NULL;
1587 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1588 clipbrd->cached_enum = NULL;
1591 if(data)
1593 HGLOBAL h;
1594 IUnknown *unk;
1596 IDataObject_AddRef(data);
1597 clipbrd->src_data = data;
1599 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1600 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1601 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1602 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1603 if(FAILED(hr)) return hr;
1604 GetHGlobalFromStream(clipbrd->marshal_data, &h);
1605 SetPropW(wnd, wine_marshal_dataobject, h);
1606 hr = set_clipboard_formats(clipbrd, data);
1608 return hr;
1611 /***********************************************************************
1612 * clipbrd_wndproc
1614 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1616 ole_clipbrd *clipbrd;
1618 get_ole_clipbrd(&clipbrd);
1620 switch (message)
1622 case WM_RENDERFORMAT:
1624 UINT cf = wparam;
1625 ole_priv_data_entry *entry;
1627 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1628 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1630 if(entry)
1631 render_format(clipbrd->src_data, &entry->fmtetc);
1633 break;
1636 case WM_RENDERALLFORMATS:
1638 DWORD i;
1639 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1641 TRACE("(): WM_RENDERALLFORMATS\n");
1643 for(i = 0; i < clipbrd->cached_enum->count; i++)
1645 if(entries[i].first_use)
1646 render_format(clipbrd->src_data, &entries[i].fmtetc);
1648 break;
1651 case WM_DESTROYCLIPBOARD:
1653 TRACE("(): WM_DESTROYCLIPBOARD\n");
1655 set_src_dataobject(clipbrd, NULL);
1656 break;
1659 default:
1660 return DefWindowProcW(hwnd, message, wparam, lparam);
1663 return 0;
1667 /***********************************************************************
1668 * create_clipbrd_window
1670 static HWND create_clipbrd_window(void)
1672 WNDCLASSEXW class;
1673 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1674 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1675 HINSTANCE hinst = GetModuleHandleW(ole32W);
1677 class.cbSize = sizeof(class);
1678 class.style = 0;
1679 class.lpfnWndProc = clipbrd_wndproc;
1680 class.cbClsExtra = 0;
1681 class.cbWndExtra = 0;
1682 class.hInstance = hinst;
1683 class.hIcon = 0;
1684 class.hCursor = 0;
1685 class.hbrBackground = 0;
1686 class.lpszMenuName = NULL;
1687 class.lpszClassName = clipbrd_wndclass;
1688 class.hIconSm = NULL;
1690 RegisterClassExW(&class);
1692 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1693 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1694 NULL, NULL, hinst, 0);
1697 /*********************************************************************
1698 * set_dataobject_format
1700 * Windows creates a 'DataObject' clipboard format that contains the
1701 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1703 static HRESULT set_dataobject_format(HWND hwnd)
1705 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1706 HWND *data;
1708 if(!h) return E_OUTOFMEMORY;
1710 data = GlobalLock(h);
1711 *data = hwnd;
1712 GlobalUnlock(h);
1714 if(!SetClipboardData(dataobject_clipboard_format, h))
1716 GlobalFree(h);
1717 return CLIPBRD_E_CANT_SET;
1720 return S_OK;
1723 /*---------------------------------------------------------------------*
1724 * Win32 OLE clipboard API
1725 *---------------------------------------------------------------------*/
1727 /***********************************************************************
1728 * OleSetClipboard [OLE32.@]
1729 * Places a pointer to the specified data object onto the clipboard,
1730 * making the data object accessible to the OleGetClipboard function.
1732 * RETURNS
1734 * S_OK IDataObject pointer placed on the clipboard
1735 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1736 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1737 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1738 * CLIPBRD_E_CANT_SET SetClipboard failed
1741 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1743 HRESULT hr;
1744 ole_clipbrd *clipbrd;
1745 HWND wnd;
1747 TRACE("(%p)\n", data);
1749 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1751 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1753 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1755 if ( !EmptyClipboard() )
1757 hr = CLIPBRD_E_CANT_EMPTY;
1758 goto end;
1761 hr = set_src_dataobject(clipbrd, data);
1762 if(FAILED(hr)) goto end;
1764 if(data)
1765 hr = set_dataobject_format(wnd);
1767 end:
1769 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1771 if ( FAILED(hr) )
1773 set_src_dataobject(clipbrd, NULL);
1776 return hr;
1780 /***********************************************************************
1781 * OleGetClipboard [OLE32.@]
1782 * Returns a pointer to our internal IDataObject which represents the conceptual
1783 * state of the Windows clipboard. If the current clipboard already contains
1784 * an IDataObject, our internal IDataObject will delegate to this object.
1786 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1788 HRESULT hr;
1789 ole_clipbrd *clipbrd;
1790 DWORD seq_no;
1792 TRACE("(%p)\n", obj);
1794 if(!obj) return E_INVALIDARG;
1796 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1798 seq_no = GetClipboardSequenceNumber();
1799 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1800 clipbrd->latest_snapshot = NULL;
1802 if(!clipbrd->latest_snapshot)
1804 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1805 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1808 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1809 IDataObject_AddRef(*obj);
1811 return S_OK;
1814 /******************************************************************************
1815 * OleFlushClipboard [OLE32.@]
1816 * Renders the data from the source IDataObject into the windows clipboard
1818 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1819 * by copying the storage into global memory. Subsequently the default
1820 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1821 * back to TYMED_IStorage.
1823 HRESULT WINAPI OleFlushClipboard(void)
1825 HRESULT hr;
1826 ole_clipbrd *clipbrd;
1827 HWND wnd;
1829 TRACE("()\n");
1831 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1833 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1836 * Already flushed or no source DataObject? Nothing to do.
1838 if (!clipbrd->src_data) return S_OK;
1840 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1842 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1844 hr = set_dataobject_format(NULL);
1846 set_src_dataobject(clipbrd, NULL);
1848 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1850 return hr;
1854 /***********************************************************************
1855 * OleIsCurrentClipboard [OLE32.@]
1857 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1859 HRESULT hr;
1860 ole_clipbrd *clipbrd;
1861 TRACE("()\n");
1863 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1865 if (data == NULL) return S_FALSE;
1867 return (data == clipbrd->src_data) ? S_OK : S_FALSE;