mshtml/tests: Added more IProvideClassInfo tests.
[wine.git] / dlls / ole32 / clipboard.c
blobd48ea792d6232a65c9df2f8ef445826475dd5c7e
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
69 #include "windef.h"
70 #include "winbase.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "winerror.h"
74 #include "winnls.h"
75 #include "ole2.h"
76 #include "wine/debug.h"
77 #include "olestd.h"
79 #include "storage32.h"
81 #include "compobj_private.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(ole);
85 /* Structure of 'Ole Private Data' clipboard format */
86 typedef struct
88 FORMATETC fmtetc;
89 DWORD first_use; /* Has this cf been added to the list already */
90 DWORD unk[2];
91 } ole_priv_data_entry;
93 typedef struct
95 DWORD unk1;
96 DWORD size; /* in bytes of the entire structure */
97 DWORD unk2;
98 DWORD count; /* no. of format entries */
99 DWORD unk3[2];
100 ole_priv_data_entry entries[1]; /* array of size count */
101 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
102 } ole_priv_data;
104 /*****************************************************************************
105 * td_offs_to_ptr
107 * Returns a ptr to a target device at a given offset from the
108 * start of the ole_priv_data.
110 * Used when unpacking ole private data from the clipboard.
112 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
114 if(off == 0) return NULL;
115 return (DVTARGETDEVICE*)((char*)data + off);
118 /*****************************************************************************
119 * td_get_offs
121 * Get the offset from the start of the ole_priv_data of the idx'th
122 * target device.
124 * Used when packing ole private data to the clipboard.
126 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
128 if(data->entries[idx].fmtetc.ptd == NULL) return 0;
129 return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
132 /****************************************************************************
133 * Consumer snapshot. Represents the state of the ole clipboard
134 * returned by OleGetClipboard().
136 typedef struct snapshot
138 IDataObject IDataObject_iface;
139 LONG ref;
141 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */
143 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */
144 } snapshot;
146 /****************************************************************************
147 * ole_clipbrd
149 typedef struct ole_clipbrd
151 snapshot *latest_snapshot; /* Latest consumer snapshot */
153 HWND window; /* Hidden clipboard window */
154 IDataObject *src_data; /* Source object passed to OleSetClipboard */
155 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
156 IStream *marshal_data; /* Stream onto which to marshal src_data */
157 } ole_clipbrd;
159 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
161 return CONTAINING_RECORD(iface, snapshot, IDataObject_iface);
164 typedef struct PresentationDataHeader
166 BYTE unknown1[28];
167 DWORD dwObjectExtentX;
168 DWORD dwObjectExtentY;
169 DWORD dwSize;
170 } PresentationDataHeader;
173 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
175 static ole_clipbrd* theOleClipboard;
177 static CRITICAL_SECTION latest_snapshot_cs;
178 static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug =
180 0, 0, &latest_snapshot_cs,
181 { &latest_snapshot_cs_debug.ProcessLocksList, &latest_snapshot_cs_debug.ProcessLocksList },
182 0, 0, { (DWORD_PTR)(__FILE__ ": clipboard last snapshot") }
184 static CRITICAL_SECTION latest_snapshot_cs = { &latest_snapshot_cs_debug, -1, 0, 0, 0, 0 };
186 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
188 struct oletls *info = COM_CurrentInfo();
189 *clipbrd = NULL;
191 if(!info->ole_inits)
192 return CO_E_NOTINITIALIZED;
193 *clipbrd = theOleClipboard;
195 return S_OK;
199 * Name of our registered OLE clipboard window class
201 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
203 UINT ownerlink_clipboard_format = 0;
204 UINT filename_clipboard_format = 0;
205 UINT filenameW_clipboard_format = 0;
206 UINT dataobject_clipboard_format = 0;
207 UINT embedded_object_clipboard_format = 0;
208 UINT embed_source_clipboard_format = 0;
209 UINT custom_link_source_clipboard_format = 0;
210 UINT link_source_clipboard_format = 0;
211 UINT object_descriptor_clipboard_format = 0;
212 UINT link_source_descriptor_clipboard_format = 0;
213 UINT ole_private_data_clipboard_format = 0;
215 static UINT wine_marshal_clipboard_format;
217 static inline const char *dump_fmtetc(FORMATETC *fmt)
219 if (!fmt) return "(null)";
220 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x",
221 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
224 /*---------------------------------------------------------------------*
225 * Implementation of the internal IEnumFORMATETC interface returned by
226 * the OLE clipboard's IDataObject.
227 *---------------------------------------------------------------------*/
229 typedef struct enum_fmtetc
231 IEnumFORMATETC IEnumFORMATETC_iface;
232 LONG ref;
234 UINT pos; /* current enumerator position */
235 ole_priv_data *data;
236 } enum_fmtetc;
238 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
240 return CONTAINING_RECORD(iface, enum_fmtetc, IEnumFORMATETC_iface);
243 /************************************************************************
244 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
246 * See Windows documentation for more details on IUnknown methods.
248 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
249 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
251 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
253 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
255 *ppvObj = NULL;
257 if(IsEqualIID(riid, &IID_IUnknown) ||
258 IsEqualIID(riid, &IID_IEnumFORMATETC))
260 *ppvObj = iface;
263 if(*ppvObj)
265 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
266 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
267 return S_OK;
270 TRACE("-- Interface: E_NOINTERFACE\n");
271 return E_NOINTERFACE;
274 /************************************************************************
275 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
278 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
280 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
281 TRACE("(%p)->(count=%u)\n",This, This->ref);
283 return InterlockedIncrement(&This->ref);
286 /************************************************************************
287 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
289 * See Windows documentation for more details on IUnknown methods.
291 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
293 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
294 ULONG ref;
296 TRACE("(%p)->(count=%u)\n",This, This->ref);
298 ref = InterlockedDecrement(&This->ref);
299 if (!ref)
301 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
302 HeapFree(GetProcessHeap(), 0, This->data);
303 HeapFree(GetProcessHeap(), 0, This);
305 return ref;
308 /************************************************************************
309 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
311 * Standard enumerator members for IEnumFORMATETC
313 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
314 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
316 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
317 UINT cfetch, i;
318 HRESULT hres = S_FALSE;
320 TRACE("(%p)->(pos=%u)\n", This, This->pos);
322 if (This->pos < This->data->count)
324 cfetch = This->data->count - This->pos;
325 if (cfetch >= celt)
327 cfetch = celt;
328 hres = S_OK;
331 for(i = 0; i < cfetch; i++)
333 rgelt[i] = This->data->entries[This->pos++].fmtetc;
334 if(rgelt[i].ptd)
336 DVTARGETDEVICE *target = rgelt[i].ptd;
337 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
338 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
339 memcpy(rgelt[i].ptd, target, target->tdSize);
343 else
345 cfetch = 0;
348 if (pceltFethed)
350 *pceltFethed = cfetch;
353 return hres;
356 /************************************************************************
357 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
359 * Standard enumerator members for IEnumFORMATETC
361 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
363 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
364 TRACE("(%p)->(num=%u)\n", This, celt);
366 This->pos += celt;
367 if (This->pos > This->data->count)
369 This->pos = This->data->count;
370 return S_FALSE;
372 return S_OK;
375 /************************************************************************
376 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
378 * Standard enumerator members for IEnumFORMATETC
380 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
382 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
383 TRACE("(%p)->()\n", This);
385 This->pos = 0;
386 return S_OK;
389 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
391 /************************************************************************
392 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
394 * Standard enumerator members for IEnumFORMATETC
396 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
397 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
399 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
400 ole_priv_data *new_data;
401 DWORD i;
403 TRACE("(%p)->(%p)\n", This, obj);
405 if ( !obj ) return E_INVALIDARG;
406 *obj = NULL;
408 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
409 if(!new_data) return E_OUTOFMEMORY;
410 memcpy(new_data, This->data, This->data->size);
412 /* Fixup any target device ptrs */
413 for(i = 0; i < This->data->count; i++)
414 new_data->entries[i].fmtetc.ptd =
415 td_offs_to_ptr(new_data, td_get_offs(This->data, i));
417 return enum_fmtetc_construct(new_data, This->pos, obj);
420 static const IEnumFORMATETCVtbl efvt =
422 OLEClipbrd_IEnumFORMATETC_QueryInterface,
423 OLEClipbrd_IEnumFORMATETC_AddRef,
424 OLEClipbrd_IEnumFORMATETC_Release,
425 OLEClipbrd_IEnumFORMATETC_Next,
426 OLEClipbrd_IEnumFORMATETC_Skip,
427 OLEClipbrd_IEnumFORMATETC_Reset,
428 OLEClipbrd_IEnumFORMATETC_Clone
431 /************************************************************************
432 * enum_fmtetc_construct
434 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
436 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
438 enum_fmtetc* ef;
440 *obj = NULL;
441 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
442 if (!ef) return E_OUTOFMEMORY;
444 ef->ref = 1;
445 ef->IEnumFORMATETC_iface.lpVtbl = &efvt;
446 ef->data = data;
447 ef->pos = pos;
449 TRACE("(%p)->()\n", ef);
450 *obj = &ef->IEnumFORMATETC_iface;
451 return S_OK;
454 /***********************************************************************
455 * dup_global_mem
457 * Helper method to duplicate an HGLOBAL chunk of memory
459 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
461 void *src_ptr, *dst_ptr;
462 DWORD size;
464 *dst = NULL;
465 if ( !src ) return S_FALSE;
467 size = GlobalSize(src);
469 *dst = GlobalAlloc( flags, size );
470 if ( !*dst ) return E_OUTOFMEMORY;
472 src_ptr = GlobalLock(src);
473 dst_ptr = GlobalLock(*dst);
475 memcpy(dst_ptr, src_ptr, size);
477 GlobalUnlock(*dst);
478 GlobalUnlock(src);
480 return S_OK;
483 /***********************************************************************
484 * dup_metafilepict
486 * Helper function to duplicate a handle to a METAFILEPICT, and the
487 * contained HMETAFILE.
489 static HRESULT dup_metafilepict(HGLOBAL src, HGLOBAL *pdest)
491 HRESULT hr;
492 HGLOBAL dest;
493 METAFILEPICT *dest_ptr;
495 *pdest = NULL;
497 /* Copy the METAFILEPICT structure. */
498 hr = dup_global_mem(src, GMEM_DDESHARE|GMEM_MOVEABLE, &dest);
499 if (FAILED(hr)) return hr;
501 dest_ptr = GlobalLock(dest);
502 if (!dest_ptr) return E_FAIL;
504 /* Give the new METAFILEPICT a separate HMETAFILE. */
505 dest_ptr->hMF = CopyMetaFileW(dest_ptr->hMF, NULL);
506 if (dest_ptr->hMF)
508 GlobalUnlock(dest);
509 *pdest = dest;
510 return S_OK;
512 else
514 GlobalUnlock(dest);
515 GlobalFree(dest);
516 return E_FAIL;
520 /***********************************************************************
521 * free_metafilepict
523 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
524 * free the contained HMETAFILE.
526 static void free_metafilepict(HGLOBAL src)
528 METAFILEPICT *src_ptr;
530 src_ptr = GlobalLock(src);
531 if (src_ptr)
533 DeleteMetaFile(src_ptr->hMF);
534 GlobalUnlock(src);
536 GlobalFree(src);
539 /***********************************************************************
540 * dup_bitmap
542 * Helper function to duplicate an HBITMAP.
544 static HRESULT dup_bitmap(HBITMAP src, HBITMAP *pdest)
546 HDC src_dc;
547 HGDIOBJ orig_src_bitmap;
548 BITMAP bm;
549 HBITMAP dest;
551 src_dc = CreateCompatibleDC(NULL);
552 orig_src_bitmap = SelectObject(src_dc, src);
553 GetObjectW(src, sizeof bm, &bm);
554 dest = CreateCompatibleBitmap(src_dc, bm.bmWidth, bm.bmHeight);
555 if (dest)
557 HDC dest_dc = CreateCompatibleDC(NULL);
558 HGDIOBJ orig_dest_bitmap = SelectObject(dest_dc, dest);
559 BitBlt(dest_dc, 0, 0, bm.bmWidth, bm.bmHeight, src_dc, 0, 0, SRCCOPY);
560 SelectObject(dest_dc, orig_dest_bitmap);
561 DeleteDC(dest_dc);
563 SelectObject(src_dc, orig_src_bitmap);
564 DeleteDC(src_dc);
565 *pdest = dest;
566 return dest ? S_OK : E_FAIL;
569 /************************************************************
570 * render_embed_source_hack
572 * This is clearly a hack and has no place in the clipboard code.
575 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
577 STGMEDIUM std;
578 HGLOBAL hStorage = 0;
579 HRESULT hr = S_OK;
580 ILockBytes *ptrILockBytes;
582 memset(&std, 0, sizeof(STGMEDIUM));
583 std.tymed = fmt->tymed = TYMED_ISTORAGE;
585 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
586 if (hStorage == NULL) return E_OUTOFMEMORY;
587 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
588 if (FAILED(hr))
590 GlobalFree(hStorage);
591 return hr;
594 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
595 ILockBytes_Release(ptrILockBytes);
597 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
599 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
600 GlobalFree(hStorage);
601 return hr;
604 if (1) /* check whether the presentation data is already -not- present */
606 FORMATETC fmt2;
607 STGMEDIUM std2;
608 METAFILEPICT *mfp = 0;
610 fmt2.cfFormat = CF_METAFILEPICT;
611 fmt2.ptd = 0;
612 fmt2.dwAspect = DVASPECT_CONTENT;
613 fmt2.lindex = -1;
614 fmt2.tymed = TYMED_MFPICT;
616 memset(&std2, 0, sizeof(STGMEDIUM));
617 std2.tymed = TYMED_MFPICT;
619 /* Get the metafile picture out of it */
621 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
623 mfp = GlobalLock(std2.u.hGlobal);
626 if (mfp)
628 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
629 IStream *pStream = 0;
630 void *mfBits;
631 PresentationDataHeader pdh;
632 INT nSize;
633 CLSID clsID;
634 LPOLESTR strProgID;
635 CHAR strOleTypeName[51];
636 BYTE OlePresStreamHeader [] =
638 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
639 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
640 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
641 0x00, 0x00, 0x00, 0x00
644 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
646 memset(&pdh, 0, sizeof(PresentationDataHeader));
647 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
649 pdh.dwObjectExtentX = mfp->xExt;
650 pdh.dwObjectExtentY = mfp->yExt;
651 pdh.dwSize = nSize;
653 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
655 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
657 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
658 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
660 hr = IStream_Write(pStream, mfBits, nSize, NULL);
662 IStream_Release(pStream);
664 HeapFree(GetProcessHeap(), 0, mfBits);
666 GlobalUnlock(std2.u.hGlobal);
667 ReleaseStgMedium(&std2);
669 ReadClassStg(std.u.pstg, &clsID);
670 ProgIDFromCLSID(&clsID, &strProgID);
672 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
673 STORAGE_CreateOleStream(std.u.pstg, 0);
674 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
675 CoTaskMemFree(strProgID);
679 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
681 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
682 GlobalFree(hStorage);
683 hr = CLIPBRD_E_CANT_SET;
686 ReleaseStgMedium(&std);
687 return hr;
690 /************************************************************************
691 * find_format_in_list
693 * Returns the first entry that matches the provided clipboard format.
695 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
697 DWORD i;
698 for(i = 0; i < num; i++)
699 if(entries[i].fmtetc.cfFormat == cf)
700 return &entries[i];
702 return NULL;
705 /***************************************************************************
706 * get_data_from_storage
708 * Returns storage data in an HGLOBAL.
710 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
712 HGLOBAL h;
713 IStorage *stg;
714 HRESULT hr;
715 FORMATETC stg_fmt;
716 STGMEDIUM med;
717 ILockBytes *lbs;
719 *mem = NULL;
721 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
722 if(!h) return E_OUTOFMEMORY;
724 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
725 if(SUCCEEDED(hr))
727 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
728 ILockBytes_Release(lbs);
730 if(FAILED(hr))
732 GlobalFree(h);
733 return hr;
736 stg_fmt = *fmt;
737 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
738 med.u.pstg = stg;
739 med.pUnkForRelease = NULL;
741 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
742 if(FAILED(hr))
744 memset(&med, 0, sizeof(med));
745 hr = IDataObject_GetData(data, &stg_fmt, &med);
746 if(FAILED(hr)) goto end;
748 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
749 ReleaseStgMedium(&med);
750 if(FAILED(hr)) goto end;
752 *mem = h;
754 end:
755 IStorage_Release(stg);
756 if(FAILED(hr)) GlobalFree(h);
757 return hr;
760 /***************************************************************************
761 * get_data_from_stream
763 * Returns stream data in an HGLOBAL.
765 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
767 HGLOBAL h;
768 IStream *stm = NULL;
769 HRESULT hr;
770 FORMATETC stm_fmt;
771 STGMEDIUM med;
773 *mem = NULL;
775 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
776 if(!h) return E_OUTOFMEMORY;
778 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
779 if(FAILED(hr)) goto error;
781 stm_fmt = *fmt;
782 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
783 med.u.pstm = stm;
784 med.pUnkForRelease = NULL;
786 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
787 if(FAILED(hr))
789 LARGE_INTEGER offs;
790 ULARGE_INTEGER pos;
792 memset(&med, 0, sizeof(med));
793 hr = IDataObject_GetData(data, &stm_fmt, &med);
794 if(FAILED(hr)) goto error;
796 offs.QuadPart = 0;
797 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
798 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
799 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
800 ReleaseStgMedium(&med);
801 if(FAILED(hr)) goto error;
803 *mem = h;
804 IStream_Release(stm);
805 return S_OK;
807 error:
808 if(stm) IStream_Release(stm);
809 GlobalFree(h);
810 return hr;
813 /***************************************************************************
814 * get_data_from_global
816 * Returns global data in an HGLOBAL.
818 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
820 HGLOBAL h;
821 HRESULT hr;
822 FORMATETC mem_fmt;
823 STGMEDIUM med;
825 *mem = NULL;
827 mem_fmt = *fmt;
828 mem_fmt.tymed = TYMED_HGLOBAL;
829 memset(&med, 0, sizeof(med));
831 hr = IDataObject_GetData(data, &mem_fmt, &med);
832 if(FAILED(hr)) return hr;
834 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
836 if(SUCCEEDED(hr)) *mem = h;
838 ReleaseStgMedium(&med);
840 return hr;
843 /***************************************************************************
844 * get_data_from_enhmetafile
846 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
848 HENHMETAFILE copy;
849 HRESULT hr;
850 FORMATETC mem_fmt;
851 STGMEDIUM med;
853 *mem = NULL;
855 mem_fmt = *fmt;
856 mem_fmt.tymed = TYMED_ENHMF;
857 memset(&med, 0, sizeof(med));
859 hr = IDataObject_GetData(data, &mem_fmt, &med);
860 if(FAILED(hr)) return hr;
862 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
863 if(copy) *mem = (HGLOBAL)copy;
864 else hr = E_FAIL;
866 ReleaseStgMedium(&med);
868 return hr;
871 /***************************************************************************
872 * get_data_from_metafilepict
874 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
876 HGLOBAL copy;
877 HRESULT hr;
878 FORMATETC mem_fmt;
879 STGMEDIUM med;
881 *mem = NULL;
883 mem_fmt = *fmt;
884 mem_fmt.tymed = TYMED_MFPICT;
885 memset(&med, 0, sizeof(med));
887 hr = IDataObject_GetData(data, &mem_fmt, &med);
888 if(FAILED(hr)) return hr;
890 hr = dup_metafilepict(med.u.hMetaFilePict, &copy);
892 if(SUCCEEDED(hr)) *mem = copy;
894 ReleaseStgMedium(&med);
896 return hr;
899 /***************************************************************************
900 * get_data_from_bitmap
902 * Returns bitmap in an HBITMAP.
904 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm)
906 HBITMAP copy;
907 HRESULT hr;
908 FORMATETC mem_fmt;
909 STGMEDIUM med;
911 *hbm = NULL;
913 mem_fmt = *fmt;
914 mem_fmt.tymed = TYMED_GDI;
915 memset(&med, 0, sizeof(med));
917 hr = IDataObject_GetData(data, &mem_fmt, &med);
918 if(FAILED(hr)) return hr;
920 hr = dup_bitmap(med.u.hBitmap, &copy);
922 if(SUCCEEDED(hr)) *hbm = copy;
924 ReleaseStgMedium(&med);
926 return hr;
929 /***********************************************************************
930 * render_format
932 * Render the clipboard data. Note that this call will delegate to the
933 * source data object.
935 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
937 HANDLE clip_data = NULL; /* HGLOBAL unless otherwise specified */
938 HRESULT hr;
940 /* Embed source hack */
941 if(fmt->cfFormat == embed_source_clipboard_format)
943 return render_embed_source_hack(data, fmt);
946 if(fmt->tymed & TYMED_ISTORAGE)
948 hr = get_data_from_storage(data, fmt, &clip_data);
950 else if(fmt->tymed & TYMED_ISTREAM)
952 hr = get_data_from_stream(data, fmt, &clip_data);
954 else if(fmt->tymed & TYMED_HGLOBAL)
956 hr = get_data_from_global(data, fmt, &clip_data);
958 else if(fmt->tymed & TYMED_ENHMF)
960 hr = get_data_from_enhmetafile(data, fmt, &clip_data);
962 else if(fmt->tymed & TYMED_MFPICT)
964 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
965 hr = get_data_from_metafilepict(data, fmt, &clip_data);
967 else if(fmt->tymed & TYMED_GDI)
969 /* Returns HBITMAP not HGLOBAL */
970 hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data);
972 else
974 FIXME("Unhandled tymed %x\n", fmt->tymed);
975 hr = DV_E_FORMATETC;
978 if(SUCCEEDED(hr))
980 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
982 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
983 if(fmt->tymed & TYMED_MFPICT)
984 free_metafilepict(clip_data);
985 else if(fmt->tymed & TYMED_GDI)
986 DeleteObject(clip_data);
987 else
988 GlobalFree(clip_data);
989 hr = CLIPBRD_E_CANT_SET;
993 return hr;
996 /*---------------------------------------------------------------------*
997 * Implementation of the internal IDataObject interface exposed by
998 * the OLE clipboard.
999 *---------------------------------------------------------------------*/
1002 /************************************************************************
1003 * snapshot_QueryInterface
1005 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
1006 REFIID riid, void **ppvObject)
1008 snapshot *This = impl_from_IDataObject(iface);
1009 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1011 if ( (This==0) || (ppvObject==0) )
1012 return E_INVALIDARG;
1014 *ppvObject = 0;
1016 if (IsEqualIID(&IID_IUnknown, riid) ||
1017 IsEqualIID(&IID_IDataObject, riid))
1019 *ppvObject = iface;
1021 else
1023 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1024 return E_NOINTERFACE;
1027 IUnknown_AddRef((IUnknown*)*ppvObject);
1029 return S_OK;
1032 /************************************************************************
1033 * snapshot_AddRef
1035 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
1037 snapshot *This = impl_from_IDataObject(iface);
1039 TRACE("(%p)->(count=%u)\n", This, This->ref);
1041 return InterlockedIncrement(&This->ref);
1044 /************************************************************************
1045 * snapshot_Release
1047 static ULONG WINAPI snapshot_Release(IDataObject *iface)
1049 snapshot *This = impl_from_IDataObject(iface);
1050 ULONG ref;
1052 TRACE("(%p)->(count=%u)\n", This, This->ref);
1054 ref = InterlockedDecrement(&This->ref);
1056 if (ref == 0)
1058 EnterCriticalSection(&latest_snapshot_cs);
1059 if (This->ref)
1061 LeaveCriticalSection(&latest_snapshot_cs);
1062 return ref;
1064 if (theOleClipboard->latest_snapshot == This)
1065 theOleClipboard->latest_snapshot = NULL;
1066 LeaveCriticalSection(&latest_snapshot_cs);
1068 if(This->data) IDataObject_Release(This->data);
1069 HeapFree(GetProcessHeap(), 0, This);
1072 return ref;
1075 /************************************************************
1076 * get_current_ole_clip_window
1078 * Return the window that owns the ole clipboard.
1080 * If the clipboard is flushed or not owned by ole this will
1081 * return NULL.
1083 static HWND get_current_ole_clip_window(void)
1085 HGLOBAL h;
1086 HWND *ptr, wnd;
1088 h = GetClipboardData(dataobject_clipboard_format);
1089 if(!h) return NULL;
1090 ptr = GlobalLock(h);
1091 if(!ptr) return NULL;
1092 wnd = *ptr;
1093 GlobalUnlock(h);
1094 return wnd;
1097 /************************************************************
1098 * get_current_dataobject
1100 * Return an unmarshalled IDataObject if there is a current
1101 * (ie non-flushed) object on the ole clipboard.
1103 static HRESULT get_current_dataobject(IDataObject **data)
1105 HRESULT hr = S_FALSE;
1106 HWND wnd = get_current_ole_clip_window();
1107 HGLOBAL h;
1108 void *ptr;
1109 IStream *stm;
1110 LARGE_INTEGER pos;
1112 *data = NULL;
1113 if(!wnd) return S_FALSE;
1115 h = GetClipboardData(wine_marshal_clipboard_format);
1116 if(!h) return S_FALSE;
1117 if(GlobalSize(h) <= 1) return S_FALSE;
1118 ptr = GlobalLock(h);
1119 if(!ptr) return S_FALSE;
1121 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
1122 if(FAILED(hr)) goto end;
1124 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
1125 if(SUCCEEDED(hr))
1127 pos.QuadPart = 0;
1128 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1129 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
1131 IStream_Release(stm);
1133 end:
1134 GlobalUnlock(h);
1135 return hr;
1138 static DWORD get_tymed_from_nonole_cf(UINT cf)
1140 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
1142 switch(cf)
1144 case CF_TEXT:
1145 case CF_OEMTEXT:
1146 case CF_UNICODETEXT:
1147 return TYMED_ISTREAM | TYMED_HGLOBAL;
1148 case CF_ENHMETAFILE:
1149 return TYMED_ENHMF;
1150 case CF_METAFILEPICT:
1151 return TYMED_MFPICT;
1152 case CF_BITMAP:
1153 return TYMED_GDI;
1154 default:
1155 FIXME("returning TYMED_NULL for cf %04x\n", cf);
1156 return TYMED_NULL;
1160 /***********************************************************
1161 * get_priv_data
1163 * Returns a copy of the Ole Private Data
1165 static HRESULT get_priv_data(ole_priv_data **data)
1167 HGLOBAL handle;
1168 HRESULT hr = S_OK;
1169 ole_priv_data *ret = NULL;
1171 *data = NULL;
1173 handle = GetClipboardData( ole_private_data_clipboard_format );
1174 if(handle)
1176 ole_priv_data *src = GlobalLock(handle);
1177 if(src)
1179 DWORD i;
1181 /* FIXME: sanity check on size */
1182 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1183 if(!ret)
1185 GlobalUnlock(handle);
1186 return E_OUTOFMEMORY;
1188 memcpy(ret, src, src->size);
1189 GlobalUnlock(handle);
1191 /* Fixup any target device offsets to ptrs */
1192 for(i = 0; i < ret->count; i++)
1193 ret->entries[i].fmtetc.ptd =
1194 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1198 if(!ret) /* Non-ole data */
1200 UINT cf;
1201 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1203 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1205 WCHAR buf[256];
1206 if (GetClipboardFormatNameW(cf, buf, sizeof(buf) / sizeof(WCHAR)))
1207 TRACE("cf %04x %s\n", cf, debugstr_w(buf));
1208 else
1209 TRACE("cf %04x\n", cf);
1211 TRACE("count %d\n", count);
1212 size += count * sizeof(ret->entries[0]);
1214 /* There are holes in fmtetc so zero init */
1215 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1216 if(!ret) return E_OUTOFMEMORY;
1217 ret->size = size;
1218 ret->count = count;
1220 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1222 ret->entries[idx].fmtetc.cfFormat = cf;
1223 ret->entries[idx].fmtetc.ptd = NULL;
1224 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1225 ret->entries[idx].fmtetc.lindex = -1;
1226 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1227 ret->entries[idx].first_use = 1;
1231 *data = ret;
1232 return hr;
1235 /************************************************************************
1236 * get_stgmed_for_global
1238 * Returns a stg medium with a copy of the global handle
1240 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1242 HRESULT hr;
1244 med->pUnkForRelease = NULL;
1245 med->tymed = TYMED_NULL;
1247 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1249 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1251 return hr;
1254 /************************************************************************
1255 * get_stgmed_for_stream
1257 * Returns a stg medium with a stream based on the handle
1259 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1261 HRESULT hr;
1262 HGLOBAL dst;
1264 med->pUnkForRelease = NULL;
1265 med->tymed = TYMED_NULL;
1267 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1268 if(FAILED(hr)) return hr;
1270 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1271 if(FAILED(hr))
1273 GlobalFree(dst);
1274 return hr;
1277 med->tymed = TYMED_ISTREAM;
1278 return hr;
1281 /************************************************************************
1282 * get_stgmed_for_storage
1284 * Returns a stg medium with a storage based on the handle
1286 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1288 HRESULT hr;
1289 HGLOBAL dst;
1290 ILockBytes *lbs;
1292 med->pUnkForRelease = NULL;
1293 med->tymed = TYMED_NULL;
1295 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1296 if(FAILED(hr)) return hr;
1298 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1299 if(FAILED(hr))
1301 GlobalFree(dst);
1302 return hr;
1305 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1306 ILockBytes_Release(lbs);
1307 if(FAILED(hr))
1309 GlobalFree(dst);
1310 return hr;
1313 med->tymed = TYMED_ISTORAGE;
1314 return hr;
1317 /************************************************************************
1318 * get_stgmed_for_emf
1320 * Returns a stg medium with an enhanced metafile based on the handle
1322 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
1324 med->pUnkForRelease = NULL;
1325 med->tymed = TYMED_NULL;
1327 med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
1328 if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
1329 med->tymed = TYMED_ENHMF;
1330 return S_OK;
1333 /************************************************************************
1334 * get_stgmed_for_bitmap
1336 * Returns a stg medium with a bitmap based on the handle
1338 static HRESULT get_stgmed_for_bitmap(HBITMAP hbmp, STGMEDIUM *med)
1340 HRESULT hr;
1342 med->pUnkForRelease = NULL;
1343 med->tymed = TYMED_NULL;
1345 hr = dup_bitmap(hbmp, &med->u.hBitmap);
1347 if (FAILED(hr))
1348 return hr;
1350 med->tymed = TYMED_GDI;
1351 return S_OK;
1354 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1356 const WCHAR *str1, *str2;
1358 if(off1 == 0 && off2 == 0) return TRUE;
1359 if(off1 == 0 || off2 == 0) return FALSE;
1361 str1 = (const WCHAR*)((const char*)t1 + off1);
1362 str2 = (const WCHAR*)((const char*)t2 + off2);
1364 return !lstrcmpW(str1, str2);
1367 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1369 if(t1 == NULL && t2 == NULL) return TRUE;
1370 if(t1 == NULL || t2 == NULL) return FALSE;
1372 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1373 return FALSE;
1374 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1375 return FALSE;
1376 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1377 return FALSE;
1379 /* FIXME check devmode? */
1381 return TRUE;
1384 /************************************************************************
1385 * snapshot_GetData
1387 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1388 STGMEDIUM *med)
1390 snapshot *This = impl_from_IDataObject(iface);
1391 HANDLE h;
1392 HRESULT hr;
1393 ole_priv_data *enum_data = NULL;
1394 ole_priv_data_entry *entry;
1395 DWORD mask;
1397 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1399 if ( !fmt || !med ) return E_INVALIDARG;
1401 memset(med, 0, sizeof(*med));
1403 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1405 if(!This->data)
1406 hr = get_current_dataobject(&This->data);
1408 if(This->data)
1410 hr = IDataObject_GetData(This->data, fmt, med);
1411 CloseClipboard();
1412 return hr;
1415 h = GetClipboardData(fmt->cfFormat);
1416 if(!h)
1418 hr = DV_E_FORMATETC;
1419 goto end;
1422 hr = get_priv_data(&enum_data);
1423 if(FAILED(hr)) goto end;
1425 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1426 if(entry)
1428 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1430 hr = DV_E_FORMATETC;
1431 goto end;
1433 mask = fmt->tymed & entry->fmtetc.tymed;
1434 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1436 else /* non-Ole format */
1437 mask = fmt->tymed & TYMED_HGLOBAL;
1439 if(mask & TYMED_ISTORAGE)
1440 hr = get_stgmed_for_storage(h, med);
1441 else if(mask & TYMED_HGLOBAL)
1442 hr = get_stgmed_for_global(h, med);
1443 else if(mask & TYMED_ISTREAM)
1444 hr = get_stgmed_for_stream(h, med);
1445 else if(mask & TYMED_ENHMF)
1446 hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
1447 else if(mask & TYMED_GDI)
1448 hr = get_stgmed_for_bitmap((HBITMAP)h, med);
1449 else
1451 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1452 hr = E_FAIL;
1453 goto end;
1456 end:
1457 HeapFree(GetProcessHeap(), 0, enum_data);
1458 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1459 return hr;
1462 /************************************************************************
1463 * snapshot_GetDataHere
1465 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1466 STGMEDIUM *med)
1468 snapshot *This = impl_from_IDataObject(iface);
1469 HANDLE h;
1470 HRESULT hr;
1471 ole_priv_data *enum_data = NULL;
1472 ole_priv_data_entry *entry;
1473 TYMED supported;
1475 if ( !fmt || !med ) return E_INVALIDARG;
1477 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1479 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1481 if(!This->data)
1482 hr = get_current_dataobject(&This->data);
1484 if(This->data)
1486 hr = IDataObject_GetDataHere(This->data, fmt, med);
1487 if(SUCCEEDED(hr))
1489 CloseClipboard();
1490 return hr;
1494 h = GetClipboardData(fmt->cfFormat);
1495 if(!h)
1497 hr = DV_E_FORMATETC;
1498 goto end;
1501 hr = get_priv_data(&enum_data);
1502 if(FAILED(hr)) goto end;
1504 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1505 if(entry)
1507 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1509 hr = DV_E_FORMATETC;
1510 goto end;
1512 supported = entry->fmtetc.tymed;
1514 else /* non-Ole format */
1515 supported = TYMED_HGLOBAL;
1517 switch(med->tymed)
1519 case TYMED_HGLOBAL:
1521 DWORD src_size = GlobalSize(h);
1522 DWORD dst_size = GlobalSize(med->u.hGlobal);
1523 hr = E_FAIL;
1524 if(dst_size >= src_size)
1526 void *src = GlobalLock(h);
1527 void *dst = GlobalLock(med->u.hGlobal);
1529 memcpy(dst, src, src_size);
1530 GlobalUnlock(med->u.hGlobal);
1531 GlobalUnlock(h);
1532 hr = S_OK;
1534 break;
1536 case TYMED_ISTREAM:
1538 DWORD src_size = GlobalSize(h);
1539 void *src = GlobalLock(h);
1540 hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1541 GlobalUnlock(h);
1542 break;
1544 case TYMED_ISTORAGE:
1546 STGMEDIUM copy;
1547 if(!(supported & TYMED_ISTORAGE))
1549 hr = E_FAIL;
1550 goto end;
1552 hr = get_stgmed_for_storage(h, &copy);
1553 if(SUCCEEDED(hr))
1555 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1556 ReleaseStgMedium(&copy);
1558 break;
1560 default:
1561 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1562 hr = E_FAIL;
1563 goto end;
1566 end:
1567 HeapFree(GetProcessHeap(), 0, enum_data);
1568 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1569 return hr;
1572 /************************************************************************
1573 * snapshot_QueryGetData
1575 * The OLE Clipboard's implementation of this method delegates to
1576 * a data source if there is one or wraps around the windows clipboard
1577 * function IsClipboardFormatAvailable() otherwise.
1580 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1582 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1584 if (!fmt) return E_INVALIDARG;
1586 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1588 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1590 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1593 /************************************************************************
1594 * snapshot_GetCanonicalFormatEtc
1596 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1597 FORMATETC *fmt_out)
1599 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1601 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1603 *fmt_out = *fmt_in;
1604 return DATA_S_SAMEFORMATETC;
1607 /************************************************************************
1608 * snapshot_SetData
1610 * The OLE Clipboard does not implement this method
1612 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1613 STGMEDIUM *med, BOOL release)
1615 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1616 return E_NOTIMPL;
1619 /************************************************************************
1620 * snapshot_EnumFormatEtc
1623 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1624 IEnumFORMATETC **enum_fmt)
1626 HRESULT hr;
1627 ole_priv_data *data = NULL;
1629 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1631 *enum_fmt = NULL;
1633 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1634 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1636 hr = get_priv_data(&data);
1638 if(FAILED(hr)) goto end;
1640 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1642 end:
1643 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1644 return hr;
1647 /************************************************************************
1648 * snapshot_DAdvise
1650 * The OLE Clipboard does not implement this method
1652 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1653 DWORD flags, IAdviseSink *sink,
1654 DWORD *conn)
1656 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1657 return E_NOTIMPL;
1660 /************************************************************************
1661 * snapshot_DUnadvise
1663 * The OLE Clipboard does not implement this method
1665 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1667 TRACE("(%p, %d): not implemented\n", iface, conn);
1668 return E_NOTIMPL;
1671 /************************************************************************
1672 * snapshot_EnumDAdvise
1674 * The OLE Clipboard does not implement this method
1676 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1677 IEnumSTATDATA** enum_advise)
1679 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1680 return E_NOTIMPL;
1683 static const IDataObjectVtbl snapshot_vtable =
1685 snapshot_QueryInterface,
1686 snapshot_AddRef,
1687 snapshot_Release,
1688 snapshot_GetData,
1689 snapshot_GetDataHere,
1690 snapshot_QueryGetData,
1691 snapshot_GetCanonicalFormatEtc,
1692 snapshot_SetData,
1693 snapshot_EnumFormatEtc,
1694 snapshot_DAdvise,
1695 snapshot_DUnadvise,
1696 snapshot_EnumDAdvise
1699 /*---------------------------------------------------------------------*
1700 * Internal implementation methods for the OLE clipboard
1701 *---------------------------------------------------------------------*/
1703 static snapshot *snapshot_construct(DWORD seq_no)
1705 snapshot *This;
1707 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1708 if (!This) return NULL;
1710 This->IDataObject_iface.lpVtbl = &snapshot_vtable;
1711 This->ref = 0;
1712 This->seq_no = seq_no;
1713 This->data = NULL;
1715 return This;
1718 /*********************************************************
1719 * register_clipboard_formats
1721 static void register_clipboard_formats(void)
1723 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1724 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1725 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1726 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1727 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1728 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1729 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1730 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1731 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1732 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1733 'D','e','s','c','r','i','p','t','o','r',0};
1734 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1736 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1737 'D','a','t','a','O','b','j','e','c','t',0};
1739 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1740 filename_clipboard_format = RegisterClipboardFormatW(FileName);
1741 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1742 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1743 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1744 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1745 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1746 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1747 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1748 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1749 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1751 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1754 /***********************************************************************
1755 * OLEClipbrd_Initialize()
1756 * Initializes the OLE clipboard.
1758 void OLEClipbrd_Initialize(void)
1760 register_clipboard_formats();
1762 if ( !theOleClipboard )
1764 ole_clipbrd* clipbrd;
1765 HGLOBAL h;
1767 TRACE("()\n");
1769 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1770 if (!clipbrd) return;
1772 clipbrd->latest_snapshot = NULL;
1773 clipbrd->window = NULL;
1774 clipbrd->src_data = NULL;
1775 clipbrd->cached_enum = NULL;
1777 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1778 if(!h)
1780 HeapFree(GetProcessHeap(), 0, clipbrd);
1781 return;
1784 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1786 GlobalFree(h);
1787 HeapFree(GetProcessHeap(), 0, clipbrd);
1788 return;
1791 theOleClipboard = clipbrd;
1795 /***********************************************************************
1796 * OLEClipbrd_UnInitialize()
1797 * Un-Initializes the OLE clipboard
1799 void OLEClipbrd_UnInitialize(void)
1801 ole_clipbrd *clipbrd = theOleClipboard;
1803 TRACE("()\n");
1805 if ( clipbrd )
1807 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1808 HINSTANCE hinst = GetModuleHandleW(ole32W);
1810 if ( clipbrd->window )
1812 DestroyWindow(clipbrd->window);
1813 UnregisterClassW( clipbrd_wndclass, hinst );
1816 IStream_Release(clipbrd->marshal_data);
1817 if (clipbrd->src_data) IDataObject_Release(clipbrd->src_data);
1818 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1819 HeapFree(GetProcessHeap(), 0, clipbrd);
1820 theOleClipboard = NULL;
1824 /*********************************************************************
1825 * set_clipboard_formats
1827 * Enumerate all formats supported by the source and make
1828 * those formats available using delayed rendering using SetClipboardData.
1829 * Cache the enumeration list and make that list visible as the
1830 * 'Ole Private Data' format on the clipboard.
1833 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1835 HRESULT hr;
1836 FORMATETC fmt;
1837 IEnumFORMATETC *enum_fmt;
1838 HGLOBAL priv_data_handle;
1839 DWORD_PTR target_offset;
1840 ole_priv_data *priv_data;
1841 DWORD count = 0, needed = sizeof(*priv_data), idx;
1843 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1844 if(FAILED(hr)) return hr;
1846 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1848 count++;
1849 needed += sizeof(priv_data->entries[0]);
1850 if(fmt.ptd)
1852 needed += fmt.ptd->tdSize;
1853 CoTaskMemFree(fmt.ptd);
1857 /* Windows pads the list with two empty ole_priv_data_entries, one
1858 * after the entries array and one after the target device data.
1859 * Allocating with zero init to zero these pads. */
1861 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1862 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1863 priv_data = GlobalLock(priv_data_handle);
1865 priv_data->unk1 = 0;
1866 priv_data->size = needed;
1867 priv_data->unk2 = 1;
1868 priv_data->count = count;
1869 priv_data->unk3[0] = 0;
1870 priv_data->unk3[1] = 0;
1872 IEnumFORMATETC_Reset(enum_fmt);
1874 idx = 0;
1875 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1877 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1879 TRACE("%s\n", dump_fmtetc(&fmt));
1881 priv_data->entries[idx].fmtetc = fmt;
1882 if(fmt.ptd)
1884 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1885 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1886 target_offset += fmt.ptd->tdSize;
1887 CoTaskMemFree(fmt.ptd);
1890 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1891 priv_data->entries[idx].unk[0] = 0;
1892 priv_data->entries[idx].unk[1] = 0;
1894 if (priv_data->entries[idx].first_use)
1895 SetClipboardData(fmt.cfFormat, NULL);
1897 idx++;
1900 IEnumFORMATETC_Release(enum_fmt);
1902 /* Cache the list and fixup any target device offsets to ptrs */
1903 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1904 memcpy(clipbrd->cached_enum, priv_data, needed);
1905 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1906 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1907 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1909 GlobalUnlock(priv_data_handle);
1910 if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle))
1912 GlobalFree(priv_data_handle);
1913 return CLIPBRD_E_CANT_SET;
1916 return S_OK;
1919 static HWND create_clipbrd_window(void);
1921 /***********************************************************************
1922 * get_clipbrd_window
1924 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1926 if ( !clipbrd->window )
1927 clipbrd->window = create_clipbrd_window();
1929 *wnd = clipbrd->window;
1930 return *wnd ? S_OK : E_FAIL;
1934 /**********************************************************************
1935 * release_marshal_data
1937 * Releases the data and sets the stream back to zero size.
1939 static inline void release_marshal_data(IStream *stm)
1941 LARGE_INTEGER pos;
1942 ULARGE_INTEGER size;
1943 pos.QuadPart = size.QuadPart = 0;
1945 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1946 CoReleaseMarshalData(stm);
1947 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1948 IStream_SetSize(stm, size);
1951 /***********************************************************************
1952 * expose_marshalled_dataobject
1954 * Sets the marshalled dataobject to the clipboard. In the flushed case
1955 * we set a zero sized HGLOBAL to clear the old marshalled data.
1957 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1959 HGLOBAL h;
1961 if(data)
1963 HGLOBAL h_stm;
1964 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1965 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1967 else /* flushed */
1968 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 1);
1970 if(!h) return E_OUTOFMEMORY;
1972 if(!SetClipboardData(wine_marshal_clipboard_format, h))
1974 GlobalFree(h);
1975 return CLIPBRD_E_CANT_SET;
1977 return S_OK;
1980 /***********************************************************************
1981 * set_src_dataobject
1983 * Clears and sets the clipboard's src IDataObject.
1985 * To marshal the source dataobject we do something rather different from Windows.
1986 * We set a clipboard format which contains the marshalled data.
1987 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1989 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1991 HRESULT hr;
1992 HWND wnd;
1994 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1996 if(clipbrd->src_data)
1998 release_marshal_data(clipbrd->marshal_data);
2000 IDataObject_Release(clipbrd->src_data);
2001 clipbrd->src_data = NULL;
2002 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
2003 clipbrd->cached_enum = NULL;
2006 if(data)
2008 IUnknown *unk;
2010 IDataObject_AddRef(data);
2011 clipbrd->src_data = data;
2013 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
2014 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
2015 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
2016 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
2017 if(FAILED(hr)) return hr;
2018 hr = set_clipboard_formats(clipbrd, data);
2020 return hr;
2023 /***********************************************************************
2024 * clipbrd_wndproc
2026 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2028 ole_clipbrd *clipbrd;
2030 get_ole_clipbrd(&clipbrd);
2032 switch (message)
2034 case WM_RENDERFORMAT:
2036 UINT cf = wparam;
2037 ole_priv_data_entry *entry;
2039 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
2040 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
2042 if(entry)
2043 render_format(clipbrd->src_data, &entry->fmtetc);
2045 break;
2048 case WM_RENDERALLFORMATS:
2050 DWORD i;
2051 ole_priv_data_entry *entries;
2053 TRACE("(): WM_RENDERALLFORMATS\n");
2055 if (!clipbrd || !clipbrd->cached_enum) break;
2056 entries = clipbrd->cached_enum->entries;
2057 for(i = 0; i < clipbrd->cached_enum->count; i++)
2059 if(entries[i].first_use)
2060 render_format(clipbrd->src_data, &entries[i].fmtetc);
2062 break;
2065 case WM_DESTROYCLIPBOARD:
2067 TRACE("(): WM_DESTROYCLIPBOARD\n");
2069 set_src_dataobject(clipbrd, NULL);
2070 break;
2073 default:
2074 return DefWindowProcW(hwnd, message, wparam, lparam);
2077 return 0;
2081 /***********************************************************************
2082 * create_clipbrd_window
2084 static HWND create_clipbrd_window(void)
2086 WNDCLASSEXW class;
2087 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
2088 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2089 HINSTANCE hinst = GetModuleHandleW(ole32W);
2091 class.cbSize = sizeof(class);
2092 class.style = 0;
2093 class.lpfnWndProc = clipbrd_wndproc;
2094 class.cbClsExtra = 0;
2095 class.cbWndExtra = 0;
2096 class.hInstance = hinst;
2097 class.hIcon = 0;
2098 class.hCursor = 0;
2099 class.hbrBackground = 0;
2100 class.lpszMenuName = NULL;
2101 class.lpszClassName = clipbrd_wndclass;
2102 class.hIconSm = NULL;
2104 RegisterClassExW(&class);
2106 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
2107 0, 0, 0, 0, HWND_MESSAGE, NULL, hinst, 0);
2110 /*********************************************************************
2111 * set_dataobject_format
2113 * Windows creates a 'DataObject' clipboard format that contains the
2114 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2116 static HRESULT set_dataobject_format(HWND hwnd)
2118 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
2119 HWND *data;
2121 if(!h) return E_OUTOFMEMORY;
2123 data = GlobalLock(h);
2124 *data = hwnd;
2125 GlobalUnlock(h);
2127 if(!SetClipboardData(dataobject_clipboard_format, h))
2129 GlobalFree(h);
2130 return CLIPBRD_E_CANT_SET;
2133 return S_OK;
2136 /*---------------------------------------------------------------------*
2137 * Win32 OLE clipboard API
2138 *---------------------------------------------------------------------*/
2140 /***********************************************************************
2141 * OleSetClipboard [OLE32.@]
2142 * Places a pointer to the specified data object onto the clipboard,
2143 * making the data object accessible to the OleGetClipboard function.
2145 * RETURNS
2147 * S_OK IDataObject pointer placed on the clipboard
2148 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2149 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2150 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2151 * CLIPBRD_E_CANT_SET SetClipboard failed
2154 HRESULT WINAPI OleSetClipboard(IDataObject* data)
2156 HRESULT hr;
2157 ole_clipbrd *clipbrd;
2158 HWND wnd;
2160 TRACE("(%p)\n", data);
2162 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2164 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2166 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
2168 if ( !EmptyClipboard() )
2170 hr = CLIPBRD_E_CANT_EMPTY;
2171 goto end;
2174 hr = set_src_dataobject(clipbrd, data);
2175 if(FAILED(hr)) goto end;
2177 if(data)
2179 hr = expose_marshalled_dataobject(clipbrd, data);
2180 if(FAILED(hr)) goto end;
2181 hr = set_dataobject_format(wnd);
2184 end:
2186 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2188 if ( FAILED(hr) )
2190 expose_marshalled_dataobject(clipbrd, NULL);
2191 set_src_dataobject(clipbrd, NULL);
2194 return hr;
2198 /***********************************************************************
2199 * OleGetClipboard [OLE32.@]
2200 * Returns a pointer to our internal IDataObject which represents the conceptual
2201 * state of the Windows clipboard. If the current clipboard already contains
2202 * an IDataObject, our internal IDataObject will delegate to this object.
2204 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
2206 HRESULT hr;
2207 ole_clipbrd *clipbrd;
2208 DWORD seq_no;
2210 TRACE("(%p)\n", obj);
2212 if(!obj) return E_INVALIDARG;
2213 *obj = NULL;
2215 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2217 seq_no = GetClipboardSequenceNumber();
2218 EnterCriticalSection(&latest_snapshot_cs);
2219 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2220 clipbrd->latest_snapshot = NULL;
2222 if(!clipbrd->latest_snapshot)
2224 clipbrd->latest_snapshot = snapshot_construct(seq_no);
2225 if(!clipbrd->latest_snapshot)
2227 LeaveCriticalSection(&latest_snapshot_cs);
2228 return E_OUTOFMEMORY;
2232 *obj = &clipbrd->latest_snapshot->IDataObject_iface;
2233 IDataObject_AddRef(*obj);
2234 LeaveCriticalSection(&latest_snapshot_cs);
2236 return S_OK;
2239 /******************************************************************************
2240 * OleFlushClipboard [OLE32.@]
2241 * Renders the data from the source IDataObject into the windows clipboard
2243 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2244 * by copying the storage into global memory. Subsequently the default
2245 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2246 * back to TYMED_IStorage.
2248 HRESULT WINAPI OleFlushClipboard(void)
2250 HRESULT hr;
2251 ole_clipbrd *clipbrd;
2252 HWND wnd;
2254 TRACE("()\n");
2256 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2258 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2261 * Already flushed or no source DataObject? Nothing to do.
2263 if (!clipbrd->src_data) return S_OK;
2265 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2267 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2269 hr = set_dataobject_format(NULL);
2271 expose_marshalled_dataobject(clipbrd, NULL);
2272 set_src_dataobject(clipbrd, NULL);
2274 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2276 return hr;
2280 /***********************************************************************
2281 * OleIsCurrentClipboard [OLE32.@]
2283 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2285 HRESULT hr;
2286 ole_clipbrd *clipbrd;
2287 TRACE("()\n");
2289 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2291 if (data == NULL) return S_FALSE;
2293 return (data == clipbrd->src_data) ? S_OK : S_FALSE;