widl: Always check the runtimeclass interfaces presence.
[wine/zf.git] / dlls / ole32 / clipboard.c
blobe61b3076883fed635dfd7028ffb4075af4e53528
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[] = L"CLIPBRDWNDCLASS";
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 hres = copy_formatetc(rgelt + i, &This->data->entries[This->pos++].fmtetc);
334 if(FAILED(hres)) return hres;
337 else
339 cfetch = 0;
342 if (pceltFethed)
344 *pceltFethed = cfetch;
347 return hres;
350 /************************************************************************
351 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
353 * Standard enumerator members for IEnumFORMATETC
355 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
357 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
358 TRACE("(%p)->(num=%u)\n", This, celt);
360 This->pos += celt;
361 if (This->pos > This->data->count)
363 This->pos = This->data->count;
364 return S_FALSE;
366 return S_OK;
369 /************************************************************************
370 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
372 * Standard enumerator members for IEnumFORMATETC
374 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
376 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
377 TRACE("(%p)->()\n", This);
379 This->pos = 0;
380 return S_OK;
383 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
385 /************************************************************************
386 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
388 * Standard enumerator members for IEnumFORMATETC
390 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
391 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
393 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
394 ole_priv_data *new_data;
395 DWORD i;
397 TRACE("(%p)->(%p)\n", This, obj);
399 if ( !obj ) return E_INVALIDARG;
400 *obj = NULL;
402 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
403 if(!new_data) return E_OUTOFMEMORY;
404 memcpy(new_data, This->data, This->data->size);
406 /* Fixup any target device ptrs */
407 for(i = 0; i < This->data->count; i++)
408 new_data->entries[i].fmtetc.ptd =
409 td_offs_to_ptr(new_data, td_get_offs(This->data, i));
411 return enum_fmtetc_construct(new_data, This->pos, obj);
414 static const IEnumFORMATETCVtbl efvt =
416 OLEClipbrd_IEnumFORMATETC_QueryInterface,
417 OLEClipbrd_IEnumFORMATETC_AddRef,
418 OLEClipbrd_IEnumFORMATETC_Release,
419 OLEClipbrd_IEnumFORMATETC_Next,
420 OLEClipbrd_IEnumFORMATETC_Skip,
421 OLEClipbrd_IEnumFORMATETC_Reset,
422 OLEClipbrd_IEnumFORMATETC_Clone
425 /************************************************************************
426 * enum_fmtetc_construct
428 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
430 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
432 enum_fmtetc* ef;
434 *obj = NULL;
435 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
436 if (!ef) return E_OUTOFMEMORY;
438 ef->ref = 1;
439 ef->IEnumFORMATETC_iface.lpVtbl = &efvt;
440 ef->data = data;
441 ef->pos = pos;
443 TRACE("(%p)->()\n", ef);
444 *obj = &ef->IEnumFORMATETC_iface;
445 return S_OK;
448 /***********************************************************************
449 * dup_global_mem
451 * Helper method to duplicate an HGLOBAL chunk of memory
453 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
455 void *src_ptr, *dst_ptr;
456 DWORD size;
458 *dst = NULL;
459 if ( !src ) return S_FALSE;
461 size = GlobalSize(src);
463 *dst = GlobalAlloc( flags, size );
464 if ( !*dst ) return E_OUTOFMEMORY;
466 src_ptr = GlobalLock(src);
467 dst_ptr = GlobalLock(*dst);
469 memcpy(dst_ptr, src_ptr, size);
471 GlobalUnlock(*dst);
472 GlobalUnlock(src);
474 return S_OK;
477 /***********************************************************************
478 * dup_metafilepict
480 * Helper function to duplicate a handle to a METAFILEPICT, and the
481 * contained HMETAFILE.
483 static HRESULT dup_metafilepict(HGLOBAL src, HGLOBAL *pdest)
485 HRESULT hr;
486 HGLOBAL dest;
487 METAFILEPICT *dest_ptr;
489 *pdest = NULL;
491 /* Copy the METAFILEPICT structure. */
492 hr = dup_global_mem(src, GMEM_DDESHARE|GMEM_MOVEABLE, &dest);
493 if (FAILED(hr)) return hr;
495 dest_ptr = GlobalLock(dest);
496 if (!dest_ptr) return E_FAIL;
498 /* Give the new METAFILEPICT a separate HMETAFILE. */
499 dest_ptr->hMF = CopyMetaFileW(dest_ptr->hMF, NULL);
500 if (dest_ptr->hMF)
502 GlobalUnlock(dest);
503 *pdest = dest;
504 return S_OK;
506 else
508 GlobalUnlock(dest);
509 GlobalFree(dest);
510 return E_FAIL;
514 /***********************************************************************
515 * free_metafilepict
517 * Helper function to GlobalFree a handle to a METAFILEPICT, and also
518 * free the contained HMETAFILE.
520 static void free_metafilepict(HGLOBAL src)
522 METAFILEPICT *src_ptr;
524 src_ptr = GlobalLock(src);
525 if (src_ptr)
527 DeleteMetaFile(src_ptr->hMF);
528 GlobalUnlock(src);
530 GlobalFree(src);
533 /***********************************************************************
534 * dup_bitmap
536 * Helper function to duplicate an HBITMAP.
538 static HRESULT dup_bitmap(HBITMAP src, HBITMAP *pdest)
540 HDC src_dc;
541 HGDIOBJ orig_src_bitmap;
542 BITMAP bm;
543 HBITMAP dest;
545 src_dc = CreateCompatibleDC(NULL);
546 orig_src_bitmap = SelectObject(src_dc, src);
547 GetObjectW(src, sizeof bm, &bm);
548 dest = CreateCompatibleBitmap(src_dc, bm.bmWidth, bm.bmHeight);
549 if (dest)
551 HDC dest_dc = CreateCompatibleDC(NULL);
552 HGDIOBJ orig_dest_bitmap = SelectObject(dest_dc, dest);
553 BitBlt(dest_dc, 0, 0, bm.bmWidth, bm.bmHeight, src_dc, 0, 0, SRCCOPY);
554 SelectObject(dest_dc, orig_dest_bitmap);
555 DeleteDC(dest_dc);
557 SelectObject(src_dc, orig_src_bitmap);
558 DeleteDC(src_dc);
559 *pdest = dest;
560 return dest ? S_OK : E_FAIL;
563 /************************************************************
564 * render_embed_source_hack
566 * This is clearly a hack and has no place in the clipboard code.
569 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
571 STGMEDIUM std;
572 HGLOBAL hStorage = 0;
573 HRESULT hr = S_OK;
574 ILockBytes *ptrILockBytes;
576 memset(&std, 0, sizeof(STGMEDIUM));
577 std.tymed = fmt->tymed = TYMED_ISTORAGE;
579 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
580 if (hStorage == NULL) return E_OUTOFMEMORY;
581 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
582 if (FAILED(hr))
584 GlobalFree(hStorage);
585 return hr;
588 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
589 ILockBytes_Release(ptrILockBytes);
591 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
593 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
594 GlobalFree(hStorage);
595 return hr;
598 if (1) /* check whether the presentation data is already -not- present */
600 FORMATETC fmt2;
601 STGMEDIUM std2;
602 METAFILEPICT *mfp = 0;
604 fmt2.cfFormat = CF_METAFILEPICT;
605 fmt2.ptd = 0;
606 fmt2.dwAspect = DVASPECT_CONTENT;
607 fmt2.lindex = -1;
608 fmt2.tymed = TYMED_MFPICT;
610 memset(&std2, 0, sizeof(STGMEDIUM));
611 std2.tymed = TYMED_MFPICT;
613 /* Get the metafile picture out of it */
615 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
617 mfp = GlobalLock(std2.u.hGlobal);
620 if (mfp)
622 IStream *pStream = 0;
623 void *mfBits;
624 PresentationDataHeader pdh;
625 INT nSize;
626 CLSID clsID;
627 LPOLESTR strProgID;
628 CHAR strOleTypeName[51];
629 BYTE OlePresStreamHeader [] =
631 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
632 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
633 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
634 0x00, 0x00, 0x00, 0x00
637 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
639 memset(&pdh, 0, sizeof(PresentationDataHeader));
640 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
642 pdh.dwObjectExtentX = mfp->xExt;
643 pdh.dwObjectExtentY = mfp->yExt;
644 pdh.dwSize = nSize;
646 hr = IStorage_CreateStream(std.u.pstg, L"\2OlePres000",
647 STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
649 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
651 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
652 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
654 hr = IStream_Write(pStream, mfBits, nSize, NULL);
656 IStream_Release(pStream);
658 HeapFree(GetProcessHeap(), 0, mfBits);
660 GlobalUnlock(std2.u.hGlobal);
661 ReleaseStgMedium(&std2);
663 ReadClassStg(std.u.pstg, &clsID);
664 ProgIDFromCLSID(&clsID, &strProgID);
666 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
667 STORAGE_CreateOleStream(std.u.pstg, 0);
668 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
669 CoTaskMemFree(strProgID);
673 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
675 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
676 GlobalFree(hStorage);
677 hr = CLIPBRD_E_CANT_SET;
680 ReleaseStgMedium(&std);
681 return hr;
684 /************************************************************************
685 * find_format_in_list
687 * Returns the first entry that matches the provided clipboard format.
689 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
691 DWORD i;
692 for(i = 0; i < num; i++)
693 if(entries[i].fmtetc.cfFormat == cf)
694 return &entries[i];
696 return NULL;
699 /***************************************************************************
700 * get_data_from_storage
702 * Returns storage data in an HGLOBAL.
704 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
706 HGLOBAL h;
707 IStorage *stg;
708 HRESULT hr;
709 FORMATETC stg_fmt;
710 STGMEDIUM med;
711 ILockBytes *lbs;
713 *mem = NULL;
715 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
716 if(!h) return E_OUTOFMEMORY;
718 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
719 if(SUCCEEDED(hr))
721 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
722 ILockBytes_Release(lbs);
724 if(FAILED(hr))
726 GlobalFree(h);
727 return hr;
730 stg_fmt = *fmt;
731 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
732 med.u.pstg = stg;
733 med.pUnkForRelease = NULL;
735 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
736 if(FAILED(hr))
738 memset(&med, 0, sizeof(med));
739 hr = IDataObject_GetData(data, &stg_fmt, &med);
740 if(FAILED(hr)) goto end;
742 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
743 ReleaseStgMedium(&med);
744 if(FAILED(hr)) goto end;
746 *mem = h;
748 end:
749 IStorage_Release(stg);
750 if(FAILED(hr)) GlobalFree(h);
751 return hr;
754 /***************************************************************************
755 * get_data_from_stream
757 * Returns stream data in an HGLOBAL.
759 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
761 HGLOBAL h;
762 IStream *stm = NULL;
763 HRESULT hr;
764 FORMATETC stm_fmt;
765 STGMEDIUM med;
767 *mem = NULL;
769 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
770 if(!h) return E_OUTOFMEMORY;
772 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
773 if(FAILED(hr)) goto error;
775 stm_fmt = *fmt;
776 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
777 med.u.pstm = stm;
778 med.pUnkForRelease = NULL;
780 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
781 if(FAILED(hr))
783 LARGE_INTEGER offs;
784 ULARGE_INTEGER pos;
786 memset(&med, 0, sizeof(med));
787 hr = IDataObject_GetData(data, &stm_fmt, &med);
788 if(FAILED(hr)) goto error;
790 offs.QuadPart = 0;
791 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_END, &pos);
792 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
793 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
794 ReleaseStgMedium(&med);
795 if(FAILED(hr)) goto error;
797 *mem = h;
798 IStream_Release(stm);
799 return S_OK;
801 error:
802 if(stm) IStream_Release(stm);
803 GlobalFree(h);
804 return hr;
807 /***************************************************************************
808 * get_data_from_global
810 * Returns global data in an HGLOBAL.
812 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
814 HGLOBAL h;
815 HRESULT hr;
816 FORMATETC mem_fmt;
817 STGMEDIUM med;
819 *mem = NULL;
821 mem_fmt = *fmt;
822 mem_fmt.tymed = TYMED_HGLOBAL;
823 memset(&med, 0, sizeof(med));
825 hr = IDataObject_GetData(data, &mem_fmt, &med);
826 if(FAILED(hr)) return hr;
828 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
830 if(SUCCEEDED(hr)) *mem = h;
832 ReleaseStgMedium(&med);
834 return hr;
837 /***************************************************************************
838 * get_data_from_enhmetafile
840 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
842 HENHMETAFILE copy;
843 HRESULT hr;
844 FORMATETC mem_fmt;
845 STGMEDIUM med;
847 *mem = NULL;
849 mem_fmt = *fmt;
850 mem_fmt.tymed = TYMED_ENHMF;
851 memset(&med, 0, sizeof(med));
853 hr = IDataObject_GetData(data, &mem_fmt, &med);
854 if(FAILED(hr)) return hr;
856 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
857 if(copy) *mem = (HGLOBAL)copy;
858 else hr = E_FAIL;
860 ReleaseStgMedium(&med);
862 return hr;
865 /***************************************************************************
866 * get_data_from_metafilepict
868 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
870 HGLOBAL copy;
871 HRESULT hr;
872 FORMATETC mem_fmt;
873 STGMEDIUM med;
875 *mem = NULL;
877 mem_fmt = *fmt;
878 mem_fmt.tymed = TYMED_MFPICT;
879 memset(&med, 0, sizeof(med));
881 hr = IDataObject_GetData(data, &mem_fmt, &med);
882 if(FAILED(hr)) return hr;
884 hr = dup_metafilepict(med.u.hMetaFilePict, &copy);
886 if(SUCCEEDED(hr)) *mem = copy;
888 ReleaseStgMedium(&med);
890 return hr;
893 /***************************************************************************
894 * get_data_from_bitmap
896 * Returns bitmap in an HBITMAP.
898 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm)
900 HBITMAP copy;
901 HRESULT hr;
902 FORMATETC mem_fmt;
903 STGMEDIUM med;
905 *hbm = NULL;
907 mem_fmt = *fmt;
908 mem_fmt.tymed = TYMED_GDI;
909 memset(&med, 0, sizeof(med));
911 hr = IDataObject_GetData(data, &mem_fmt, &med);
912 if(FAILED(hr)) return hr;
914 hr = dup_bitmap(med.u.hBitmap, &copy);
916 if(SUCCEEDED(hr)) *hbm = copy;
918 ReleaseStgMedium(&med);
920 return hr;
923 /***********************************************************************
924 * render_format
926 * Render the clipboard data. Note that this call will delegate to the
927 * source data object.
929 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
931 HANDLE clip_data = NULL; /* HGLOBAL unless otherwise specified */
932 HRESULT hr;
934 /* Embed source hack */
935 if(fmt->cfFormat == embed_source_clipboard_format)
937 return render_embed_source_hack(data, fmt);
940 if(fmt->tymed & TYMED_ISTORAGE)
942 hr = get_data_from_storage(data, fmt, &clip_data);
944 else if(fmt->tymed & TYMED_ISTREAM)
946 hr = get_data_from_stream(data, fmt, &clip_data);
948 else if(fmt->tymed & TYMED_HGLOBAL)
950 hr = get_data_from_global(data, fmt, &clip_data);
952 else if(fmt->tymed & TYMED_ENHMF)
954 hr = get_data_from_enhmetafile(data, fmt, &clip_data);
956 else if(fmt->tymed & TYMED_MFPICT)
958 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
959 hr = get_data_from_metafilepict(data, fmt, &clip_data);
961 else if(fmt->tymed & TYMED_GDI)
963 /* Returns HBITMAP not HGLOBAL */
964 hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data);
966 else
968 FIXME("Unhandled tymed %x\n", fmt->tymed);
969 hr = DV_E_FORMATETC;
972 if(SUCCEEDED(hr))
974 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
976 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
977 if(fmt->tymed & TYMED_MFPICT)
978 free_metafilepict(clip_data);
979 else if(fmt->tymed & TYMED_GDI)
980 DeleteObject(clip_data);
981 else
982 GlobalFree(clip_data);
983 hr = CLIPBRD_E_CANT_SET;
987 return hr;
990 /*---------------------------------------------------------------------*
991 * Implementation of the internal IDataObject interface exposed by
992 * the OLE clipboard.
993 *---------------------------------------------------------------------*/
996 /************************************************************************
997 * snapshot_QueryInterface
999 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
1000 REFIID riid, void **ppvObject)
1002 snapshot *This = impl_from_IDataObject(iface);
1003 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1005 if ( (This==0) || (ppvObject==0) )
1006 return E_INVALIDARG;
1008 *ppvObject = 0;
1010 if (IsEqualIID(&IID_IUnknown, riid) ||
1011 IsEqualIID(&IID_IDataObject, riid))
1013 *ppvObject = iface;
1015 else
1017 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1018 return E_NOINTERFACE;
1021 IUnknown_AddRef((IUnknown*)*ppvObject);
1023 return S_OK;
1026 /************************************************************************
1027 * snapshot_AddRef
1029 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
1031 snapshot *This = impl_from_IDataObject(iface);
1033 TRACE("(%p)->(count=%u)\n", This, This->ref);
1035 return InterlockedIncrement(&This->ref);
1038 /************************************************************************
1039 * snapshot_Release
1041 static ULONG WINAPI snapshot_Release(IDataObject *iface)
1043 snapshot *This = impl_from_IDataObject(iface);
1044 ULONG ref;
1046 TRACE("(%p)->(count=%u)\n", This, This->ref);
1048 ref = InterlockedDecrement(&This->ref);
1050 if (ref == 0)
1052 EnterCriticalSection(&latest_snapshot_cs);
1053 if (This->ref)
1055 LeaveCriticalSection(&latest_snapshot_cs);
1056 return ref;
1058 if (theOleClipboard->latest_snapshot == This)
1059 theOleClipboard->latest_snapshot = NULL;
1060 LeaveCriticalSection(&latest_snapshot_cs);
1062 if(This->data) IDataObject_Release(This->data);
1063 HeapFree(GetProcessHeap(), 0, This);
1066 return ref;
1069 /************************************************************
1070 * get_current_ole_clip_window
1072 * Return the window that owns the ole clipboard.
1074 * If the clipboard is flushed or not owned by ole this will
1075 * return NULL.
1077 static HWND get_current_ole_clip_window(void)
1079 HGLOBAL h;
1080 HWND *ptr, wnd;
1082 h = GetClipboardData(dataobject_clipboard_format);
1083 if(!h) return NULL;
1084 ptr = GlobalLock(h);
1085 if(!ptr) return NULL;
1086 wnd = *ptr;
1087 GlobalUnlock(h);
1088 return wnd;
1091 /************************************************************
1092 * get_current_dataobject
1094 * Return an unmarshalled IDataObject if there is a current
1095 * (ie non-flushed) object on the ole clipboard.
1097 static HRESULT get_current_dataobject(IDataObject **data)
1099 HRESULT hr = S_FALSE;
1100 HWND wnd = get_current_ole_clip_window();
1101 HGLOBAL h;
1102 void *ptr;
1103 IStream *stm;
1104 LARGE_INTEGER pos;
1106 *data = NULL;
1107 if(!wnd) return S_FALSE;
1109 h = GetClipboardData(wine_marshal_clipboard_format);
1110 if(!h) return S_FALSE;
1111 if(GlobalSize(h) <= 1) return S_FALSE;
1112 ptr = GlobalLock(h);
1113 if(!ptr) return S_FALSE;
1115 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
1116 if(FAILED(hr)) goto end;
1118 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
1119 if(SUCCEEDED(hr))
1121 pos.QuadPart = 0;
1122 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1123 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
1125 IStream_Release(stm);
1127 end:
1128 GlobalUnlock(h);
1129 return hr;
1132 static DWORD get_tymed_from_nonole_cf(UINT cf)
1134 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
1136 switch(cf)
1138 case CF_TEXT:
1139 case CF_OEMTEXT:
1140 case CF_UNICODETEXT:
1141 case CF_HDROP:
1142 return TYMED_ISTREAM | TYMED_HGLOBAL;
1143 case CF_ENHMETAFILE:
1144 return TYMED_ENHMF;
1145 case CF_METAFILEPICT:
1146 return TYMED_MFPICT;
1147 case CF_BITMAP:
1148 return TYMED_GDI;
1149 default:
1150 FIXME("returning TYMED_NULL for cf %04x\n", cf);
1151 return TYMED_NULL;
1155 /***********************************************************
1156 * get_priv_data
1158 * Returns a copy of the Ole Private Data
1160 static HRESULT get_priv_data(ole_priv_data **data)
1162 HGLOBAL handle;
1163 HRESULT hr = S_OK;
1164 ole_priv_data *ret = NULL;
1166 *data = NULL;
1168 handle = GetClipboardData( ole_private_data_clipboard_format );
1169 if(handle)
1171 ole_priv_data *src = GlobalLock(handle);
1172 if(src)
1174 DWORD i;
1176 /* FIXME: sanity check on size */
1177 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1178 if(!ret)
1180 GlobalUnlock(handle);
1181 return E_OUTOFMEMORY;
1183 memcpy(ret, src, src->size);
1184 GlobalUnlock(handle);
1186 /* Fixup any target device offsets to ptrs */
1187 for(i = 0; i < ret->count; i++)
1188 ret->entries[i].fmtetc.ptd =
1189 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1193 if(!ret) /* Non-ole data */
1195 UINT cf;
1196 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1198 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1200 WCHAR buf[256];
1201 if (GetClipboardFormatNameW(cf, buf, ARRAY_SIZE(buf)))
1202 TRACE("cf %04x %s\n", cf, debugstr_w(buf));
1203 else
1204 TRACE("cf %04x\n", cf);
1206 TRACE("count %d\n", count);
1207 size += count * sizeof(ret->entries[0]);
1209 /* There are holes in fmtetc so zero init */
1210 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1211 if(!ret) return E_OUTOFMEMORY;
1212 ret->size = size;
1213 ret->count = count;
1215 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1217 ret->entries[idx].fmtetc.cfFormat = cf;
1218 ret->entries[idx].fmtetc.ptd = NULL;
1219 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1220 ret->entries[idx].fmtetc.lindex = -1;
1221 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1222 ret->entries[idx].first_use = 1;
1226 *data = ret;
1227 return hr;
1230 /************************************************************************
1231 * get_stgmed_for_global
1233 * Returns a stg medium with a copy of the global handle
1235 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1237 HRESULT hr;
1239 med->pUnkForRelease = NULL;
1240 med->tymed = TYMED_NULL;
1242 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1244 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1246 return hr;
1249 /************************************************************************
1250 * get_stgmed_for_stream
1252 * Returns a stg medium with a stream based on the handle
1254 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1256 HRESULT hr;
1257 HGLOBAL dst;
1259 med->pUnkForRelease = NULL;
1260 med->tymed = TYMED_NULL;
1262 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1263 if(FAILED(hr)) return hr;
1265 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1266 if(FAILED(hr))
1268 GlobalFree(dst);
1269 return hr;
1272 med->tymed = TYMED_ISTREAM;
1273 return hr;
1276 /************************************************************************
1277 * get_stgmed_for_storage
1279 * Returns a stg medium with a storage based on the handle
1281 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1283 HRESULT hr;
1284 HGLOBAL dst;
1285 ILockBytes *lbs;
1287 med->pUnkForRelease = NULL;
1288 med->tymed = TYMED_NULL;
1290 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1291 if(FAILED(hr)) return hr;
1293 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1294 if(FAILED(hr))
1296 GlobalFree(dst);
1297 return hr;
1300 hr = StgIsStorageILockBytes(lbs);
1301 if(hr!=S_OK)
1303 ILockBytes_Release(lbs);
1304 GlobalFree(dst);
1305 return SUCCEEDED(hr) ? E_FAIL : hr;
1308 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1309 ILockBytes_Release(lbs);
1310 if(FAILED(hr))
1312 GlobalFree(dst);
1313 return hr;
1316 med->tymed = TYMED_ISTORAGE;
1317 return hr;
1320 /************************************************************************
1321 * get_stgmed_for_emf
1323 * Returns a stg medium with an enhanced metafile based on the handle
1325 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
1327 med->pUnkForRelease = NULL;
1328 med->tymed = TYMED_NULL;
1330 med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
1331 if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
1332 med->tymed = TYMED_ENHMF;
1333 return S_OK;
1336 /************************************************************************
1337 * get_stgmed_for_bitmap
1339 * Returns a stg medium with a bitmap based on the handle
1341 static HRESULT get_stgmed_for_bitmap(HBITMAP hbmp, STGMEDIUM *med)
1343 HRESULT hr;
1345 med->pUnkForRelease = NULL;
1346 med->tymed = TYMED_NULL;
1348 hr = dup_bitmap(hbmp, &med->u.hBitmap);
1350 if (FAILED(hr))
1351 return hr;
1353 med->tymed = TYMED_GDI;
1354 return S_OK;
1357 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1359 const WCHAR *str1, *str2;
1361 if(off1 == 0 && off2 == 0) return TRUE;
1362 if(off1 == 0 || off2 == 0) return FALSE;
1364 str1 = (const WCHAR*)((const char*)t1 + off1);
1365 str2 = (const WCHAR*)((const char*)t2 + off2);
1367 return !wcscmp(str1, str2);
1370 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1372 if(t1 == NULL && t2 == NULL) return TRUE;
1373 if(t1 == NULL || t2 == NULL) return FALSE;
1375 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1376 return FALSE;
1377 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1378 return FALSE;
1379 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1380 return FALSE;
1382 /* FIXME check devmode? */
1384 return TRUE;
1387 /************************************************************************
1388 * snapshot_GetData
1390 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1391 STGMEDIUM *med)
1393 snapshot *This = impl_from_IDataObject(iface);
1394 HANDLE h;
1395 HRESULT hr;
1396 ole_priv_data *enum_data = NULL;
1397 ole_priv_data_entry *entry;
1398 DWORD mask;
1400 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1402 if ( !fmt || !med ) return E_INVALIDARG;
1404 memset(med, 0, sizeof(*med));
1406 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1408 if(!This->data)
1409 hr = get_current_dataobject(&This->data);
1411 if(This->data)
1413 hr = IDataObject_GetData(This->data, fmt, med);
1414 if(SUCCEEDED(hr))
1416 CloseClipboard();
1417 return hr;
1420 if(fmt->lindex != -1)
1422 hr = DV_E_FORMATETC;
1423 goto end;
1426 if(!IsClipboardFormatAvailable(fmt->cfFormat))
1428 hr = DV_E_FORMATETC;
1429 goto end;
1432 hr = get_priv_data(&enum_data);
1433 if(FAILED(hr)) goto end;
1435 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1436 if(entry)
1438 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1440 hr = DV_E_FORMATETC;
1441 goto end;
1443 mask = fmt->tymed & entry->fmtetc.tymed;
1444 if(!mask && (entry->fmtetc.tymed & (TYMED_ISTREAM | TYMED_HGLOBAL | TYMED_ISTORAGE)))
1445 mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL | TYMED_ISTORAGE);
1447 else /* non-Ole format */
1448 mask = fmt->tymed & get_tymed_from_nonole_cf(fmt->cfFormat);
1450 if(!mask)
1452 hr = DV_E_TYMED;
1453 goto end;
1456 h = GetClipboardData(fmt->cfFormat);
1457 if(!h)
1459 hr = DV_E_FORMATETC;
1460 goto end;
1463 if(mask & TYMED_HGLOBAL)
1464 hr = get_stgmed_for_global(h, med);
1465 else if(mask & TYMED_ISTREAM)
1466 hr = get_stgmed_for_stream(h, med);
1467 else if(mask & TYMED_ISTORAGE)
1468 hr = get_stgmed_for_storage(h, med);
1469 else if(mask & TYMED_ENHMF)
1470 hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
1471 else if(mask & TYMED_GDI)
1472 hr = get_stgmed_for_bitmap((HBITMAP)h, med);
1473 else
1475 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1476 hr = E_FAIL;
1477 goto end;
1480 end:
1481 HeapFree(GetProcessHeap(), 0, enum_data);
1482 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1483 return hr;
1486 /************************************************************************
1487 * snapshot_GetDataHere
1489 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1490 STGMEDIUM *med)
1492 snapshot *This = impl_from_IDataObject(iface);
1493 HANDLE h;
1494 HRESULT hr;
1495 ole_priv_data *enum_data = NULL;
1496 ole_priv_data_entry *entry;
1497 TYMED supported;
1499 if ( !fmt || !med ) return E_INVALIDARG;
1501 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1503 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1505 if(!This->data)
1506 hr = get_current_dataobject(&This->data);
1508 if(This->data)
1510 hr = IDataObject_GetDataHere(This->data, fmt, med);
1511 if(SUCCEEDED(hr))
1513 CloseClipboard();
1514 return hr;
1518 h = GetClipboardData(fmt->cfFormat);
1519 if(!h)
1521 hr = DV_E_FORMATETC;
1522 goto end;
1525 hr = get_priv_data(&enum_data);
1526 if(FAILED(hr)) goto end;
1528 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1529 if(entry)
1531 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1533 hr = DV_E_FORMATETC;
1534 goto end;
1536 supported = entry->fmtetc.tymed;
1538 else /* non-Ole format */
1539 supported = TYMED_HGLOBAL;
1541 switch(med->tymed)
1543 case TYMED_HGLOBAL:
1545 DWORD src_size = GlobalSize(h);
1546 DWORD dst_size = GlobalSize(med->u.hGlobal);
1547 hr = E_FAIL;
1548 if(dst_size >= src_size)
1550 void *src = GlobalLock(h);
1551 void *dst = GlobalLock(med->u.hGlobal);
1553 memcpy(dst, src, src_size);
1554 GlobalUnlock(med->u.hGlobal);
1555 GlobalUnlock(h);
1556 hr = S_OK;
1558 break;
1560 case TYMED_ISTREAM:
1562 DWORD src_size = GlobalSize(h);
1563 void *src = GlobalLock(h);
1564 hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1565 GlobalUnlock(h);
1566 break;
1568 case TYMED_ISTORAGE:
1570 STGMEDIUM copy;
1571 if(!(supported & TYMED_ISTORAGE))
1573 hr = E_FAIL;
1574 goto end;
1576 hr = get_stgmed_for_storage(h, &copy);
1577 if(SUCCEEDED(hr))
1579 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1580 ReleaseStgMedium(&copy);
1582 break;
1584 default:
1585 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1586 hr = E_FAIL;
1587 goto end;
1590 end:
1591 HeapFree(GetProcessHeap(), 0, enum_data);
1592 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1593 return hr;
1596 /************************************************************************
1597 * snapshot_QueryGetData
1599 * The OLE Clipboard's implementation of this method delegates to
1600 * a data source if there is one or wraps around the windows clipboard
1601 * function IsClipboardFormatAvailable() otherwise.
1604 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1606 TRACE("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1608 if (!fmt) return E_INVALIDARG;
1610 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1612 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1614 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1617 /************************************************************************
1618 * snapshot_GetCanonicalFormatEtc
1620 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1621 FORMATETC *fmt_out)
1623 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1625 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1627 *fmt_out = *fmt_in;
1628 return DATA_S_SAMEFORMATETC;
1631 /************************************************************************
1632 * snapshot_SetData
1634 * The OLE Clipboard does not implement this method
1636 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1637 STGMEDIUM *med, BOOL release)
1639 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1640 return E_NOTIMPL;
1643 /************************************************************************
1644 * snapshot_EnumFormatEtc
1647 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1648 IEnumFORMATETC **enum_fmt)
1650 HRESULT hr;
1651 ole_priv_data *data = NULL;
1653 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1655 *enum_fmt = NULL;
1657 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1658 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1660 hr = get_priv_data(&data);
1662 if(FAILED(hr)) goto end;
1664 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1666 end:
1667 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1668 return hr;
1671 /************************************************************************
1672 * snapshot_DAdvise
1674 * The OLE Clipboard does not implement this method
1676 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1677 DWORD flags, IAdviseSink *sink,
1678 DWORD *conn)
1680 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1681 return E_NOTIMPL;
1684 /************************************************************************
1685 * snapshot_DUnadvise
1687 * The OLE Clipboard does not implement this method
1689 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1691 TRACE("(%p, %d): not implemented\n", iface, conn);
1692 return E_NOTIMPL;
1695 /************************************************************************
1696 * snapshot_EnumDAdvise
1698 * The OLE Clipboard does not implement this method
1700 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1701 IEnumSTATDATA** enum_advise)
1703 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1704 return E_NOTIMPL;
1707 static const IDataObjectVtbl snapshot_vtable =
1709 snapshot_QueryInterface,
1710 snapshot_AddRef,
1711 snapshot_Release,
1712 snapshot_GetData,
1713 snapshot_GetDataHere,
1714 snapshot_QueryGetData,
1715 snapshot_GetCanonicalFormatEtc,
1716 snapshot_SetData,
1717 snapshot_EnumFormatEtc,
1718 snapshot_DAdvise,
1719 snapshot_DUnadvise,
1720 snapshot_EnumDAdvise
1723 /*---------------------------------------------------------------------*
1724 * Internal implementation methods for the OLE clipboard
1725 *---------------------------------------------------------------------*/
1727 static snapshot *snapshot_construct(DWORD seq_no)
1729 snapshot *This;
1731 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1732 if (!This) return NULL;
1734 This->IDataObject_iface.lpVtbl = &snapshot_vtable;
1735 This->ref = 0;
1736 This->seq_no = seq_no;
1737 This->data = NULL;
1739 return This;
1742 /*********************************************************
1743 * register_clipboard_formats
1745 static void register_clipboard_formats(void)
1747 ownerlink_clipboard_format = RegisterClipboardFormatW(L"OwnerLink");
1748 filename_clipboard_format = RegisterClipboardFormatW(L"FileName");
1749 filenameW_clipboard_format = RegisterClipboardFormatW(L"FileNameW");
1750 dataobject_clipboard_format = RegisterClipboardFormatW(L"DataObject");
1751 embedded_object_clipboard_format = RegisterClipboardFormatW(L"Embedded Object");
1752 embed_source_clipboard_format = RegisterClipboardFormatW(L"Embed Source");
1753 custom_link_source_clipboard_format = RegisterClipboardFormatW(L"Custom Link Source");
1754 link_source_clipboard_format = RegisterClipboardFormatW(L"Link Source");
1755 object_descriptor_clipboard_format = RegisterClipboardFormatW(L"Object Descriptor");
1756 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(L"Link Source Descriptor");
1757 ole_private_data_clipboard_format = RegisterClipboardFormatW(L"Ole Private Data");
1759 wine_marshal_clipboard_format = RegisterClipboardFormatW(L"Wine Marshalled DataObject");
1762 /***********************************************************************
1763 * OLEClipbrd_Initialize()
1764 * Initializes the OLE clipboard.
1766 void OLEClipbrd_Initialize(void)
1768 register_clipboard_formats();
1770 if ( !theOleClipboard )
1772 ole_clipbrd* clipbrd;
1773 HGLOBAL h;
1775 TRACE("()\n");
1777 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1778 if (!clipbrd) return;
1780 clipbrd->latest_snapshot = NULL;
1781 clipbrd->window = NULL;
1782 clipbrd->src_data = NULL;
1783 clipbrd->cached_enum = NULL;
1785 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1786 if(!h)
1788 HeapFree(GetProcessHeap(), 0, clipbrd);
1789 return;
1792 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1794 GlobalFree(h);
1795 HeapFree(GetProcessHeap(), 0, clipbrd);
1796 return;
1799 theOleClipboard = clipbrd;
1803 /*********************************************************************
1804 * set_clipboard_formats
1806 * Enumerate all formats supported by the source and make
1807 * those formats available using delayed rendering using SetClipboardData.
1808 * Cache the enumeration list and make that list visible as the
1809 * 'Ole Private Data' format on the clipboard.
1812 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1814 HRESULT hr;
1815 FORMATETC fmt;
1816 IEnumFORMATETC *enum_fmt;
1817 HGLOBAL priv_data_handle;
1818 DWORD_PTR target_offset;
1819 ole_priv_data *priv_data;
1820 DWORD count = 0, needed = sizeof(*priv_data), idx;
1822 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1823 if(FAILED(hr)) return hr;
1825 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1827 count++;
1828 needed += sizeof(priv_data->entries[0]);
1829 if(fmt.ptd)
1831 needed += fmt.ptd->tdSize;
1832 CoTaskMemFree(fmt.ptd);
1836 /* Windows pads the list with two empty ole_priv_data_entries, one
1837 * after the entries array and one after the target device data.
1838 * Allocating with zero init to zero these pads. */
1840 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1841 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1842 priv_data = GlobalLock(priv_data_handle);
1844 priv_data->unk1 = 0;
1845 priv_data->size = needed;
1846 priv_data->unk2 = 1;
1847 priv_data->count = count;
1848 priv_data->unk3[0] = 0;
1849 priv_data->unk3[1] = 0;
1851 IEnumFORMATETC_Reset(enum_fmt);
1853 idx = 0;
1854 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1856 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1858 TRACE("%s\n", dump_fmtetc(&fmt));
1860 priv_data->entries[idx].fmtetc = fmt;
1861 if(fmt.ptd)
1863 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1864 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1865 target_offset += fmt.ptd->tdSize;
1866 CoTaskMemFree(fmt.ptd);
1869 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1870 priv_data->entries[idx].unk[0] = 0;
1871 priv_data->entries[idx].unk[1] = 0;
1873 if (priv_data->entries[idx].first_use)
1874 SetClipboardData(fmt.cfFormat, NULL);
1876 idx++;
1879 IEnumFORMATETC_Release(enum_fmt);
1881 /* Cache the list and fixup any target device offsets to ptrs */
1882 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1883 memcpy(clipbrd->cached_enum, priv_data, needed);
1884 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1885 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1886 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1888 GlobalUnlock(priv_data_handle);
1889 if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle))
1891 GlobalFree(priv_data_handle);
1892 return CLIPBRD_E_CANT_SET;
1895 return S_OK;
1898 static HWND create_clipbrd_window(void);
1900 /***********************************************************************
1901 * get_clipbrd_window
1903 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1905 if ( !clipbrd->window )
1906 clipbrd->window = create_clipbrd_window();
1908 *wnd = clipbrd->window;
1909 return *wnd ? S_OK : E_FAIL;
1913 /**********************************************************************
1914 * release_marshal_data
1916 * Releases the data and sets the stream back to zero size.
1918 static inline void release_marshal_data(IStream *stm)
1920 LARGE_INTEGER pos;
1921 ULARGE_INTEGER size;
1922 pos.QuadPart = size.QuadPart = 0;
1924 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1925 CoReleaseMarshalData(stm);
1926 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1927 IStream_SetSize(stm, size);
1930 /***********************************************************************
1931 * expose_marshalled_dataobject
1933 * Sets the marshalled dataobject to the clipboard. In the flushed case
1934 * we set a zero sized HGLOBAL to clear the old marshalled data.
1936 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1938 HGLOBAL h;
1940 if(data)
1942 HGLOBAL h_stm;
1943 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1944 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1946 else /* flushed */
1947 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 1);
1949 if(!h) return E_OUTOFMEMORY;
1951 if(!SetClipboardData(wine_marshal_clipboard_format, h))
1953 GlobalFree(h);
1954 return CLIPBRD_E_CANT_SET;
1956 return S_OK;
1959 /***********************************************************************
1960 * set_src_dataobject
1962 * Clears and sets the clipboard's src IDataObject.
1964 * To marshal the source dataobject we do something rather different from Windows.
1965 * We set a clipboard format which contains the marshalled data.
1966 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1968 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1970 HRESULT hr;
1971 HWND wnd;
1973 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1975 if(clipbrd->src_data)
1977 release_marshal_data(clipbrd->marshal_data);
1979 IDataObject_Release(clipbrd->src_data);
1980 clipbrd->src_data = NULL;
1981 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1982 clipbrd->cached_enum = NULL;
1985 if(data)
1987 IUnknown *unk;
1989 IDataObject_AddRef(data);
1990 clipbrd->src_data = data;
1992 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1993 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1994 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1995 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1996 if(FAILED(hr)) return hr;
1997 hr = set_clipboard_formats(clipbrd, data);
1999 return hr;
2002 /***********************************************************************
2003 * OLEClipbrd_UnInitialize()
2004 * Un-Initializes the OLE clipboard
2006 void OLEClipbrd_UnInitialize(void)
2008 ole_clipbrd *clipbrd = theOleClipboard;
2010 TRACE("()\n");
2012 if ( clipbrd )
2014 /* OleUninitialize() does not release the reference to the dataobject, so
2015 take an additional reference here. This reference is then leaked. */
2016 if (clipbrd->src_data)
2018 IDataObject_AddRef(clipbrd->src_data);
2019 set_src_dataobject(clipbrd, NULL);
2022 if ( clipbrd->window )
2024 DestroyWindow(clipbrd->window);
2025 UnregisterClassW( clipbrd_wndclass, GetModuleHandleW(L"ole32") );
2028 IStream_Release(clipbrd->marshal_data);
2029 HeapFree(GetProcessHeap(), 0, clipbrd);
2030 theOleClipboard = NULL;
2034 /***********************************************************************
2035 * clipbrd_wndproc
2037 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2039 ole_clipbrd *clipbrd;
2041 get_ole_clipbrd(&clipbrd);
2043 switch (message)
2045 case WM_RENDERFORMAT:
2047 UINT cf = wparam;
2048 ole_priv_data_entry *entry;
2050 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
2052 if (!clipbrd || !clipbrd->cached_enum) break;
2053 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
2055 if(entry)
2056 render_format(clipbrd->src_data, &entry->fmtetc);
2058 break;
2061 case WM_RENDERALLFORMATS:
2063 DWORD i;
2064 ole_priv_data_entry *entries;
2066 TRACE("(): WM_RENDERALLFORMATS\n");
2068 if (!clipbrd || !clipbrd->cached_enum) break;
2069 entries = clipbrd->cached_enum->entries;
2070 for(i = 0; i < clipbrd->cached_enum->count; i++)
2072 if(entries[i].first_use)
2073 render_format(clipbrd->src_data, &entries[i].fmtetc);
2075 break;
2078 case WM_DESTROYCLIPBOARD:
2080 TRACE("(): WM_DESTROYCLIPBOARD\n");
2082 set_src_dataobject(clipbrd, NULL);
2083 break;
2086 default:
2087 return DefWindowProcW(hwnd, message, wparam, lparam);
2090 return 0;
2094 /***********************************************************************
2095 * create_clipbrd_window
2097 static HWND create_clipbrd_window(void)
2099 WNDCLASSEXW class;
2100 HINSTANCE hinst = GetModuleHandleW(L"ole32");
2102 class.cbSize = sizeof(class);
2103 class.style = 0;
2104 class.lpfnWndProc = clipbrd_wndproc;
2105 class.cbClsExtra = 0;
2106 class.cbWndExtra = 0;
2107 class.hInstance = hinst;
2108 class.hIcon = 0;
2109 class.hCursor = 0;
2110 class.hbrBackground = 0;
2111 class.lpszMenuName = NULL;
2112 class.lpszClassName = clipbrd_wndclass;
2113 class.hIconSm = NULL;
2115 RegisterClassExW(&class);
2117 return CreateWindowW(clipbrd_wndclass, L"ClipboardWindow", WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
2118 0, 0, 0, 0, HWND_MESSAGE, NULL, hinst, 0);
2121 /*********************************************************************
2122 * set_dataobject_format
2124 * Windows creates a 'DataObject' clipboard format that contains the
2125 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2127 static HRESULT set_dataobject_format(HWND hwnd)
2129 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
2130 HWND *data;
2132 if(!h) return E_OUTOFMEMORY;
2134 data = GlobalLock(h);
2135 *data = hwnd;
2136 GlobalUnlock(h);
2138 if(!SetClipboardData(dataobject_clipboard_format, h))
2140 GlobalFree(h);
2141 return CLIPBRD_E_CANT_SET;
2144 return S_OK;
2147 /*---------------------------------------------------------------------*
2148 * Win32 OLE clipboard API
2149 *---------------------------------------------------------------------*/
2151 /***********************************************************************
2152 * OleSetClipboard [OLE32.@]
2153 * Places a pointer to the specified data object onto the clipboard,
2154 * making the data object accessible to the OleGetClipboard function.
2156 * RETURNS
2158 * S_OK IDataObject pointer placed on the clipboard
2159 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2160 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2161 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2162 * CLIPBRD_E_CANT_SET SetClipboard failed
2165 HRESULT WINAPI OleSetClipboard(IDataObject* data)
2167 HRESULT hr;
2168 ole_clipbrd *clipbrd;
2169 HWND wnd;
2171 TRACE("(%p)\n", data);
2173 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2175 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2177 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
2179 if ( !EmptyClipboard() )
2181 hr = CLIPBRD_E_CANT_EMPTY;
2182 goto end;
2185 hr = set_src_dataobject(clipbrd, data);
2186 if(FAILED(hr)) goto end;
2188 if(data)
2190 hr = expose_marshalled_dataobject(clipbrd, data);
2191 if(FAILED(hr)) goto end;
2192 hr = set_dataobject_format(wnd);
2195 end:
2197 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2199 if ( FAILED(hr) )
2201 expose_marshalled_dataobject(clipbrd, NULL);
2202 set_src_dataobject(clipbrd, NULL);
2205 return hr;
2209 /***********************************************************************
2210 * OleGetClipboard [OLE32.@]
2211 * Returns a pointer to our internal IDataObject which represents the conceptual
2212 * state of the Windows clipboard. If the current clipboard already contains
2213 * an IDataObject, our internal IDataObject will delegate to this object.
2215 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
2217 HRESULT hr;
2218 ole_clipbrd *clipbrd;
2219 DWORD seq_no;
2221 TRACE("(%p)\n", obj);
2223 if(!obj) return E_INVALIDARG;
2224 *obj = NULL;
2226 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2228 seq_no = GetClipboardSequenceNumber();
2229 EnterCriticalSection(&latest_snapshot_cs);
2230 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2231 clipbrd->latest_snapshot = NULL;
2233 if(!clipbrd->latest_snapshot)
2235 clipbrd->latest_snapshot = snapshot_construct(seq_no);
2236 if(!clipbrd->latest_snapshot)
2238 LeaveCriticalSection(&latest_snapshot_cs);
2239 return E_OUTOFMEMORY;
2243 *obj = &clipbrd->latest_snapshot->IDataObject_iface;
2244 IDataObject_AddRef(*obj);
2245 LeaveCriticalSection(&latest_snapshot_cs);
2247 return S_OK;
2250 /******************************************************************************
2251 * OleFlushClipboard [OLE32.@]
2252 * Renders the data from the source IDataObject into the windows clipboard
2254 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2255 * by copying the storage into global memory. Subsequently the default
2256 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2257 * back to TYMED_IStorage.
2259 HRESULT WINAPI OleFlushClipboard(void)
2261 HRESULT hr;
2262 ole_clipbrd *clipbrd;
2263 HWND wnd;
2265 TRACE("()\n");
2267 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2269 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2272 * Already flushed or no source DataObject? Nothing to do.
2274 if (!clipbrd->src_data) return S_OK;
2276 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2278 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2280 hr = set_dataobject_format(NULL);
2282 expose_marshalled_dataobject(clipbrd, NULL);
2283 set_src_dataobject(clipbrd, NULL);
2285 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2287 return hr;
2291 /***********************************************************************
2292 * OleIsCurrentClipboard [OLE32.@]
2294 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2296 HRESULT hr;
2297 ole_clipbrd *clipbrd;
2298 TRACE("()\n");
2300 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2302 if (data == NULL) return S_FALSE;
2304 return (data == clipbrd->src_data) ? S_OK : S_FALSE;