msctf: Spelling fix.
[wine.git] / dlls / ole32 / clipboard.c
blob2cc1cfa191e209921c20eaab1998f6b663aa00e3
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 med.u.pstg = NULL;
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 med.u.pstm = NULL;
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;
830 hr = IDataObject_GetData(data, &mem_fmt, &med);
831 if(FAILED(hr)) return hr;
833 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
835 if(SUCCEEDED(hr)) *mem = h;
837 ReleaseStgMedium(&med);
839 return hr;
842 /***************************************************************************
843 * get_data_from_enhmetafile
845 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
847 HENHMETAFILE copy;
848 HRESULT hr;
849 FORMATETC mem_fmt;
850 STGMEDIUM med;
852 *mem = NULL;
854 mem_fmt = *fmt;
855 mem_fmt.tymed = TYMED_ENHMF;
857 hr = IDataObject_GetData(data, &mem_fmt, &med);
858 if(FAILED(hr)) return hr;
860 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
861 if(copy) *mem = (HGLOBAL)copy;
862 else hr = E_FAIL;
864 ReleaseStgMedium(&med);
866 return hr;
869 /***************************************************************************
870 * get_data_from_metafilepict
872 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
874 HGLOBAL copy;
875 HRESULT hr;
876 FORMATETC mem_fmt;
877 STGMEDIUM med;
879 *mem = NULL;
881 mem_fmt = *fmt;
882 mem_fmt.tymed = TYMED_MFPICT;
884 hr = IDataObject_GetData(data, &mem_fmt, &med);
885 if(FAILED(hr)) return hr;
887 hr = dup_metafilepict(med.u.hMetaFilePict, &copy);
889 if(SUCCEEDED(hr)) *mem = copy;
891 ReleaseStgMedium(&med);
893 return hr;
896 /***************************************************************************
897 * get_data_from_bitmap
899 * Returns bitmap in an HBITMAP.
901 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm)
903 HBITMAP copy;
904 HRESULT hr;
905 FORMATETC mem_fmt;
906 STGMEDIUM med;
908 *hbm = NULL;
910 mem_fmt = *fmt;
911 mem_fmt.tymed = TYMED_GDI;
913 hr = IDataObject_GetData(data, &mem_fmt, &med);
914 if(FAILED(hr)) return hr;
916 hr = dup_bitmap(med.u.hBitmap, &copy);
918 if(SUCCEEDED(hr)) *hbm = copy;
920 ReleaseStgMedium(&med);
922 return hr;
925 /***********************************************************************
926 * render_format
928 * Render the clipboard data. Note that this call will delegate to the
929 * source data object.
931 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
933 HANDLE clip_data = NULL; /* HGLOBAL unless otherwise specified */
934 HRESULT hr;
936 /* Embed source hack */
937 if(fmt->cfFormat == embed_source_clipboard_format)
939 return render_embed_source_hack(data, fmt);
942 if(fmt->tymed & TYMED_ISTORAGE)
944 hr = get_data_from_storage(data, fmt, &clip_data);
946 else if(fmt->tymed & TYMED_ISTREAM)
948 hr = get_data_from_stream(data, fmt, &clip_data);
950 else if(fmt->tymed & TYMED_HGLOBAL)
952 hr = get_data_from_global(data, fmt, &clip_data);
954 else if(fmt->tymed & TYMED_ENHMF)
956 hr = get_data_from_enhmetafile(data, fmt, &clip_data);
958 else if(fmt->tymed & TYMED_MFPICT)
960 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
961 hr = get_data_from_metafilepict(data, fmt, &clip_data);
963 else if(fmt->tymed & TYMED_GDI)
965 /* Returns HBITMAP not HGLOBAL */
966 hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data);
968 else
970 FIXME("Unhandled tymed %x\n", fmt->tymed);
971 hr = DV_E_FORMATETC;
974 if(SUCCEEDED(hr))
976 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
978 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
979 if(fmt->tymed & TYMED_MFPICT)
980 free_metafilepict(clip_data);
981 else if(fmt->tymed & TYMED_GDI)
982 DeleteObject(clip_data);
983 else
984 GlobalFree(clip_data);
985 hr = CLIPBRD_E_CANT_SET;
989 return hr;
992 /*---------------------------------------------------------------------*
993 * Implementation of the internal IDataObject interface exposed by
994 * the OLE clipboard.
995 *---------------------------------------------------------------------*/
998 /************************************************************************
999 * snapshot_QueryInterface
1001 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
1002 REFIID riid, void **ppvObject)
1004 snapshot *This = impl_from_IDataObject(iface);
1005 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1007 if ( (This==0) || (ppvObject==0) )
1008 return E_INVALIDARG;
1010 *ppvObject = 0;
1012 if (IsEqualIID(&IID_IUnknown, riid) ||
1013 IsEqualIID(&IID_IDataObject, riid))
1015 *ppvObject = iface;
1017 else
1019 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1020 return E_NOINTERFACE;
1023 IUnknown_AddRef((IUnknown*)*ppvObject);
1025 return S_OK;
1028 /************************************************************************
1029 * snapshot_AddRef
1031 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
1033 snapshot *This = impl_from_IDataObject(iface);
1035 TRACE("(%p)->(count=%u)\n", This, This->ref);
1037 return InterlockedIncrement(&This->ref);
1040 /************************************************************************
1041 * snapshot_Release
1043 static ULONG WINAPI snapshot_Release(IDataObject *iface)
1045 snapshot *This = impl_from_IDataObject(iface);
1046 ULONG ref;
1048 TRACE("(%p)->(count=%u)\n", This, This->ref);
1050 ref = InterlockedDecrement(&This->ref);
1052 if (ref == 0)
1054 EnterCriticalSection(&latest_snapshot_cs);
1055 if (This->ref)
1057 LeaveCriticalSection(&latest_snapshot_cs);
1058 return ref;
1060 if (theOleClipboard->latest_snapshot == This)
1061 theOleClipboard->latest_snapshot = NULL;
1062 LeaveCriticalSection(&latest_snapshot_cs);
1064 if(This->data) IDataObject_Release(This->data);
1065 HeapFree(GetProcessHeap(), 0, This);
1068 return ref;
1071 /************************************************************
1072 * get_current_ole_clip_window
1074 * Return the window that owns the ole clipboard.
1076 * If the clipboard is flushed or not owned by ole this will
1077 * return NULL.
1079 static HWND get_current_ole_clip_window(void)
1081 HGLOBAL h;
1082 HWND *ptr, wnd;
1084 h = GetClipboardData(dataobject_clipboard_format);
1085 if(!h) return NULL;
1086 ptr = GlobalLock(h);
1087 if(!ptr) return NULL;
1088 wnd = *ptr;
1089 GlobalUnlock(h);
1090 return wnd;
1093 /************************************************************
1094 * get_current_dataobject
1096 * Return an unmarshalled IDataObject if there is a current
1097 * (ie non-flushed) object on the ole clipboard.
1099 static HRESULT get_current_dataobject(IDataObject **data)
1101 HRESULT hr = S_FALSE;
1102 HWND wnd = get_current_ole_clip_window();
1103 HGLOBAL h;
1104 void *ptr;
1105 IStream *stm;
1106 LARGE_INTEGER pos;
1108 *data = NULL;
1109 if(!wnd) return S_FALSE;
1111 h = GetClipboardData(wine_marshal_clipboard_format);
1112 if(!h) return S_FALSE;
1113 if(GlobalSize(h) == 0) return S_FALSE;
1114 ptr = GlobalLock(h);
1115 if(!ptr) return S_FALSE;
1117 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
1118 if(FAILED(hr)) goto end;
1120 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
1121 if(SUCCEEDED(hr))
1123 pos.QuadPart = 0;
1124 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1125 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
1127 IStream_Release(stm);
1129 end:
1130 GlobalUnlock(h);
1131 return hr;
1134 static DWORD get_tymed_from_nonole_cf(UINT cf)
1136 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
1138 switch(cf)
1140 case CF_TEXT:
1141 case CF_OEMTEXT:
1142 case CF_UNICODETEXT:
1143 return TYMED_ISTREAM | TYMED_HGLOBAL;
1144 case CF_ENHMETAFILE:
1145 return TYMED_ENHMF;
1146 case CF_METAFILEPICT:
1147 return TYMED_MFPICT;
1148 case CF_BITMAP:
1149 return TYMED_GDI;
1150 default:
1151 FIXME("returning TYMED_NULL for cf %04x\n", cf);
1152 return TYMED_NULL;
1156 /***********************************************************
1157 * get_priv_data
1159 * Returns a copy of the Ole Private Data
1161 static HRESULT get_priv_data(ole_priv_data **data)
1163 HGLOBAL handle;
1164 HRESULT hr = S_OK;
1165 ole_priv_data *ret = NULL;
1167 *data = NULL;
1169 handle = GetClipboardData( ole_private_data_clipboard_format );
1170 if(handle)
1172 ole_priv_data *src = GlobalLock(handle);
1173 if(src)
1175 DWORD i;
1177 /* FIXME: sanity check on size */
1178 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1179 if(!ret)
1181 GlobalUnlock(handle);
1182 return E_OUTOFMEMORY;
1184 memcpy(ret, src, src->size);
1185 GlobalUnlock(handle);
1187 /* Fixup any target device offsets to ptrs */
1188 for(i = 0; i < ret->count; i++)
1189 ret->entries[i].fmtetc.ptd =
1190 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1194 if(!ret) /* Non-ole data */
1196 UINT cf;
1197 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1199 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1201 char buf[100];
1202 GetClipboardFormatNameA(cf, buf, sizeof(buf));
1203 TRACE("cf %04x %s\n", cf, buf);
1205 TRACE("count %d\n", count);
1206 size += count * sizeof(ret->entries[0]);
1208 /* There are holes in fmtetc so zero init */
1209 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1210 if(!ret) return E_OUTOFMEMORY;
1211 ret->size = size;
1212 ret->count = count;
1214 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1216 ret->entries[idx].fmtetc.cfFormat = cf;
1217 ret->entries[idx].fmtetc.ptd = NULL;
1218 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1219 ret->entries[idx].fmtetc.lindex = -1;
1220 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1221 ret->entries[idx].first_use = 1;
1225 *data = ret;
1226 return hr;
1229 /************************************************************************
1230 * get_stgmed_for_global
1232 * Returns a stg medium with a copy of the global handle
1234 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1236 HRESULT hr;
1238 med->pUnkForRelease = NULL;
1239 med->tymed = TYMED_NULL;
1241 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1243 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1245 return hr;
1248 /************************************************************************
1249 * get_stgmed_for_stream
1251 * Returns a stg medium with a stream based on the handle
1253 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1255 HRESULT hr;
1256 HGLOBAL dst;
1258 med->pUnkForRelease = NULL;
1259 med->tymed = TYMED_NULL;
1261 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1262 if(FAILED(hr)) return hr;
1264 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1265 if(FAILED(hr))
1267 GlobalFree(dst);
1268 return hr;
1271 med->tymed = TYMED_ISTREAM;
1272 return hr;
1275 /************************************************************************
1276 * get_stgmed_for_storage
1278 * Returns a stg medium with a storage based on the handle
1280 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1282 HRESULT hr;
1283 HGLOBAL dst;
1284 ILockBytes *lbs;
1286 med->pUnkForRelease = NULL;
1287 med->tymed = TYMED_NULL;
1289 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1290 if(FAILED(hr)) return hr;
1292 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1293 if(FAILED(hr))
1295 GlobalFree(dst);
1296 return hr;
1299 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1300 ILockBytes_Release(lbs);
1301 if(FAILED(hr))
1303 GlobalFree(dst);
1304 return hr;
1307 med->tymed = TYMED_ISTORAGE;
1308 return hr;
1311 /************************************************************************
1312 * get_stgmed_for_emf
1314 * Returns a stg medium with an enhanced metafile based on the handle
1316 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
1318 med->pUnkForRelease = NULL;
1319 med->tymed = TYMED_NULL;
1321 med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
1322 if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
1323 med->tymed = TYMED_ENHMF;
1324 return S_OK;
1327 /************************************************************************
1328 * get_stgmed_for_bitmap
1330 * Returns a stg medium with a bitmap based on the handle
1332 static HRESULT get_stgmed_for_bitmap(HBITMAP hbmp, STGMEDIUM *med)
1334 HRESULT hr;
1336 med->pUnkForRelease = NULL;
1337 med->tymed = TYMED_NULL;
1339 hr = dup_bitmap(hbmp, &med->u.hBitmap);
1341 if (FAILED(hr))
1342 return hr;
1344 med->tymed = TYMED_GDI;
1345 return S_OK;
1348 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1350 const WCHAR *str1, *str2;
1352 if(off1 == 0 && off2 == 0) return TRUE;
1353 if(off1 == 0 || off2 == 0) return FALSE;
1355 str1 = (const WCHAR*)((const char*)t1 + off1);
1356 str2 = (const WCHAR*)((const char*)t2 + off2);
1358 return !lstrcmpW(str1, str2);
1361 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1363 if(t1 == NULL && t2 == NULL) return TRUE;
1364 if(t1 == NULL || t2 == NULL) return FALSE;
1366 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1367 return FALSE;
1368 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1369 return FALSE;
1370 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1371 return FALSE;
1373 /* FIXME check devmode? */
1375 return TRUE;
1378 /************************************************************************
1379 * snapshot_GetData
1381 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1382 STGMEDIUM *med)
1384 snapshot *This = impl_from_IDataObject(iface);
1385 HANDLE h;
1386 HRESULT hr;
1387 ole_priv_data *enum_data = NULL;
1388 ole_priv_data_entry *entry;
1389 DWORD mask;
1391 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1393 if ( !fmt || !med ) return E_INVALIDARG;
1395 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1397 if(!This->data)
1398 hr = get_current_dataobject(&This->data);
1400 if(This->data)
1402 hr = IDataObject_GetData(This->data, fmt, med);
1403 CloseClipboard();
1404 return hr;
1407 h = GetClipboardData(fmt->cfFormat);
1408 if(!h)
1410 hr = DV_E_FORMATETC;
1411 goto end;
1414 hr = get_priv_data(&enum_data);
1415 if(FAILED(hr)) goto end;
1417 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1418 if(entry)
1420 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1422 hr = DV_E_FORMATETC;
1423 goto end;
1425 mask = fmt->tymed & entry->fmtetc.tymed;
1426 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1428 else /* non-Ole format */
1429 mask = fmt->tymed & TYMED_HGLOBAL;
1431 if(mask & TYMED_ISTORAGE)
1432 hr = get_stgmed_for_storage(h, med);
1433 else if(mask & TYMED_HGLOBAL)
1434 hr = get_stgmed_for_global(h, med);
1435 else if(mask & TYMED_ISTREAM)
1436 hr = get_stgmed_for_stream(h, med);
1437 else if(mask & TYMED_ENHMF)
1438 hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
1439 else if(mask & TYMED_GDI)
1440 hr = get_stgmed_for_bitmap((HBITMAP)h, med);
1441 else
1443 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1444 hr = E_FAIL;
1445 goto end;
1448 end:
1449 HeapFree(GetProcessHeap(), 0, enum_data);
1450 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1451 return hr;
1454 /************************************************************************
1455 * snapshot_GetDataHere
1457 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1458 STGMEDIUM *med)
1460 snapshot *This = impl_from_IDataObject(iface);
1461 HANDLE h;
1462 HRESULT hr;
1463 ole_priv_data *enum_data = NULL;
1464 ole_priv_data_entry *entry;
1465 TYMED supported;
1467 if ( !fmt || !med ) return E_INVALIDARG;
1469 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1471 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1473 if(!This->data)
1474 hr = get_current_dataobject(&This->data);
1476 if(This->data)
1478 hr = IDataObject_GetDataHere(This->data, fmt, med);
1479 if(SUCCEEDED(hr))
1481 CloseClipboard();
1482 return hr;
1486 h = GetClipboardData(fmt->cfFormat);
1487 if(!h)
1489 hr = DV_E_FORMATETC;
1490 goto end;
1493 hr = get_priv_data(&enum_data);
1494 if(FAILED(hr)) goto end;
1496 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1497 if(entry)
1499 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1501 hr = DV_E_FORMATETC;
1502 goto end;
1504 supported = entry->fmtetc.tymed;
1506 else /* non-Ole format */
1507 supported = TYMED_HGLOBAL;
1509 switch(med->tymed)
1511 case TYMED_HGLOBAL:
1513 DWORD src_size = GlobalSize(h);
1514 DWORD dst_size = GlobalSize(med->u.hGlobal);
1515 hr = E_FAIL;
1516 if(dst_size >= src_size)
1518 void *src = GlobalLock(h);
1519 void *dst = GlobalLock(med->u.hGlobal);
1521 memcpy(dst, src, src_size);
1522 GlobalUnlock(med->u.hGlobal);
1523 GlobalUnlock(h);
1524 hr = S_OK;
1526 break;
1528 case TYMED_ISTREAM:
1530 DWORD src_size = GlobalSize(h);
1531 void *src = GlobalLock(h);
1532 hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1533 GlobalUnlock(h);
1534 break;
1536 case TYMED_ISTORAGE:
1538 STGMEDIUM copy;
1539 if(!(supported & TYMED_ISTORAGE))
1541 hr = E_FAIL;
1542 goto end;
1544 hr = get_stgmed_for_storage(h, &copy);
1545 if(SUCCEEDED(hr))
1547 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1548 ReleaseStgMedium(&copy);
1550 break;
1552 default:
1553 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1554 hr = E_FAIL;
1555 goto end;
1558 end:
1559 HeapFree(GetProcessHeap(), 0, enum_data);
1560 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1561 return hr;
1564 /************************************************************************
1565 * snapshot_QueryGetData
1567 * The OLE Clipboard's implementation of this method delegates to
1568 * a data source if there is one or wraps around the windows clipboard
1569 * function IsClipboardFormatAvailable() otherwise.
1572 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1574 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1576 if (!fmt) return E_INVALIDARG;
1578 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1580 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1582 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1585 /************************************************************************
1586 * snapshot_GetCanonicalFormatEtc
1588 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1589 FORMATETC *fmt_out)
1591 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1593 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1595 *fmt_out = *fmt_in;
1596 return DATA_S_SAMEFORMATETC;
1599 /************************************************************************
1600 * snapshot_SetData
1602 * The OLE Clipboard does not implement this method
1604 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1605 STGMEDIUM *med, BOOL release)
1607 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1608 return E_NOTIMPL;
1611 /************************************************************************
1612 * snapshot_EnumFormatEtc
1615 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1616 IEnumFORMATETC **enum_fmt)
1618 HRESULT hr;
1619 ole_priv_data *data = NULL;
1621 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1623 *enum_fmt = NULL;
1625 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1626 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1628 hr = get_priv_data(&data);
1630 if(FAILED(hr)) goto end;
1632 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1634 end:
1635 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1636 return hr;
1639 /************************************************************************
1640 * snapshot_DAdvise
1642 * The OLE Clipboard does not implement this method
1644 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1645 DWORD flags, IAdviseSink *sink,
1646 DWORD *conn)
1648 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1649 return E_NOTIMPL;
1652 /************************************************************************
1653 * snapshot_DUnadvise
1655 * The OLE Clipboard does not implement this method
1657 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1659 TRACE("(%p, %d): not implemented\n", iface, conn);
1660 return E_NOTIMPL;
1663 /************************************************************************
1664 * snapshot_EnumDAdvise
1666 * The OLE Clipboard does not implement this method
1668 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1669 IEnumSTATDATA** enum_advise)
1671 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1672 return E_NOTIMPL;
1675 static const IDataObjectVtbl snapshot_vtable =
1677 snapshot_QueryInterface,
1678 snapshot_AddRef,
1679 snapshot_Release,
1680 snapshot_GetData,
1681 snapshot_GetDataHere,
1682 snapshot_QueryGetData,
1683 snapshot_GetCanonicalFormatEtc,
1684 snapshot_SetData,
1685 snapshot_EnumFormatEtc,
1686 snapshot_DAdvise,
1687 snapshot_DUnadvise,
1688 snapshot_EnumDAdvise
1691 /*---------------------------------------------------------------------*
1692 * Internal implementation methods for the OLE clipboard
1693 *---------------------------------------------------------------------*/
1695 static snapshot *snapshot_construct(DWORD seq_no)
1697 snapshot *This;
1699 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1700 if (!This) return NULL;
1702 This->IDataObject_iface.lpVtbl = &snapshot_vtable;
1703 This->ref = 0;
1704 This->seq_no = seq_no;
1705 This->data = NULL;
1707 return This;
1710 /*********************************************************
1711 * register_clipboard_formats
1713 static void register_clipboard_formats(void)
1715 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1716 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1717 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1718 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1719 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1720 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1721 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1722 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1723 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1724 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1725 'D','e','s','c','r','i','p','t','o','r',0};
1726 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1728 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1729 'D','a','t','a','O','b','j','e','c','t',0};
1731 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1732 filename_clipboard_format = RegisterClipboardFormatW(FileName);
1733 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1734 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1735 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1736 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1737 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1738 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1739 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1740 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1741 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1743 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1746 /***********************************************************************
1747 * OLEClipbrd_Initialize()
1748 * Initializes the OLE clipboard.
1750 void OLEClipbrd_Initialize(void)
1752 register_clipboard_formats();
1754 if ( !theOleClipboard )
1756 ole_clipbrd* clipbrd;
1757 HGLOBAL h;
1759 TRACE("()\n");
1761 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1762 if (!clipbrd) return;
1764 clipbrd->latest_snapshot = NULL;
1765 clipbrd->window = NULL;
1766 clipbrd->src_data = NULL;
1767 clipbrd->cached_enum = NULL;
1769 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1770 if(!h)
1772 HeapFree(GetProcessHeap(), 0, clipbrd);
1773 return;
1776 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1778 GlobalFree(h);
1779 HeapFree(GetProcessHeap(), 0, clipbrd);
1780 return;
1783 theOleClipboard = clipbrd;
1787 /***********************************************************************
1788 * OLEClipbrd_UnInitialize()
1789 * Un-Initializes the OLE clipboard
1791 void OLEClipbrd_UnInitialize(void)
1793 ole_clipbrd *clipbrd = theOleClipboard;
1795 TRACE("()\n");
1797 if ( clipbrd )
1799 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1800 HINSTANCE hinst = GetModuleHandleW(ole32W);
1802 if ( clipbrd->window )
1804 DestroyWindow(clipbrd->window);
1805 UnregisterClassW( clipbrd_wndclass, hinst );
1808 IStream_Release(clipbrd->marshal_data);
1809 if (clipbrd->src_data) IDataObject_Release(clipbrd->src_data);
1810 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1811 HeapFree(GetProcessHeap(), 0, clipbrd);
1812 theOleClipboard = NULL;
1816 /*********************************************************************
1817 * set_clipboard_formats
1819 * Enumerate all formats supported by the source and make
1820 * those formats available using delayed rendering using SetClipboardData.
1821 * Cache the enumeration list and make that list visible as the
1822 * 'Ole Private Data' format on the clipboard.
1825 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1827 HRESULT hr;
1828 FORMATETC fmt;
1829 IEnumFORMATETC *enum_fmt;
1830 HGLOBAL priv_data_handle;
1831 DWORD_PTR target_offset;
1832 ole_priv_data *priv_data;
1833 DWORD count = 0, needed = sizeof(*priv_data), idx;
1835 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1836 if(FAILED(hr)) return hr;
1838 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1840 count++;
1841 needed += sizeof(priv_data->entries[0]);
1842 if(fmt.ptd)
1844 needed += fmt.ptd->tdSize;
1845 CoTaskMemFree(fmt.ptd);
1849 /* Windows pads the list with two empty ole_priv_data_entries, one
1850 * after the entries array and one after the target device data.
1851 * Allocating with zero init to zero these pads. */
1853 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1854 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1855 priv_data = GlobalLock(priv_data_handle);
1857 priv_data->unk1 = 0;
1858 priv_data->size = needed;
1859 priv_data->unk2 = 1;
1860 priv_data->count = count;
1861 priv_data->unk3[0] = 0;
1862 priv_data->unk3[1] = 0;
1864 IEnumFORMATETC_Reset(enum_fmt);
1866 idx = 0;
1867 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1869 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1871 TRACE("%s\n", dump_fmtetc(&fmt));
1873 priv_data->entries[idx].fmtetc = fmt;
1874 if(fmt.ptd)
1876 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1877 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1878 target_offset += fmt.ptd->tdSize;
1879 CoTaskMemFree(fmt.ptd);
1882 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1883 priv_data->entries[idx].unk[0] = 0;
1884 priv_data->entries[idx].unk[1] = 0;
1886 if (priv_data->entries[idx].first_use)
1887 SetClipboardData(fmt.cfFormat, NULL);
1889 idx++;
1892 IEnumFORMATETC_Release(enum_fmt);
1894 /* Cache the list and fixup any target device offsets to ptrs */
1895 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1896 memcpy(clipbrd->cached_enum, priv_data, needed);
1897 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1898 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1899 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1901 GlobalUnlock(priv_data_handle);
1902 if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle))
1904 GlobalFree(priv_data_handle);
1905 return CLIPBRD_E_CANT_SET;
1908 return S_OK;
1911 static HWND create_clipbrd_window(void);
1913 /***********************************************************************
1914 * get_clipbrd_window
1916 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1918 if ( !clipbrd->window )
1919 clipbrd->window = create_clipbrd_window();
1921 *wnd = clipbrd->window;
1922 return *wnd ? S_OK : E_FAIL;
1926 /**********************************************************************
1927 * release_marshal_data
1929 * Releases the data and sets the stream back to zero size.
1931 static inline void release_marshal_data(IStream *stm)
1933 LARGE_INTEGER pos;
1934 ULARGE_INTEGER size;
1935 pos.QuadPart = size.QuadPart = 0;
1937 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1938 CoReleaseMarshalData(stm);
1939 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1940 IStream_SetSize(stm, size);
1943 /***********************************************************************
1944 * expose_marshalled_dataobject
1946 * Sets the marshalled dataobject to the clipboard. In the flushed case
1947 * we set a zero sized HGLOBAL to clear the old marshalled data.
1949 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1951 HGLOBAL h;
1953 if(data)
1955 HGLOBAL h_stm;
1956 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1957 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1959 else /* flushed */
1960 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1962 if(!h) return E_OUTOFMEMORY;
1964 if(!SetClipboardData(wine_marshal_clipboard_format, h))
1966 GlobalFree(h);
1967 return CLIPBRD_E_CANT_SET;
1969 return S_OK;
1972 /***********************************************************************
1973 * set_src_dataobject
1975 * Clears and sets the clipboard's src IDataObject.
1977 * To marshal the source dataobject we do something rather different from Windows.
1978 * We set a clipboard format which contains the marshalled data.
1979 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1981 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1983 HRESULT hr;
1984 HWND wnd;
1986 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1988 if(clipbrd->src_data)
1990 release_marshal_data(clipbrd->marshal_data);
1992 IDataObject_Release(clipbrd->src_data);
1993 clipbrd->src_data = NULL;
1994 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1995 clipbrd->cached_enum = NULL;
1998 if(data)
2000 IUnknown *unk;
2002 IDataObject_AddRef(data);
2003 clipbrd->src_data = data;
2005 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
2006 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
2007 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
2008 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
2009 if(FAILED(hr)) return hr;
2010 hr = set_clipboard_formats(clipbrd, data);
2012 return hr;
2015 /***********************************************************************
2016 * clipbrd_wndproc
2018 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2020 ole_clipbrd *clipbrd;
2022 get_ole_clipbrd(&clipbrd);
2024 switch (message)
2026 case WM_RENDERFORMAT:
2028 UINT cf = wparam;
2029 ole_priv_data_entry *entry;
2031 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
2032 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
2034 if(entry)
2035 render_format(clipbrd->src_data, &entry->fmtetc);
2037 break;
2040 case WM_RENDERALLFORMATS:
2042 DWORD i;
2043 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
2045 TRACE("(): WM_RENDERALLFORMATS\n");
2047 for(i = 0; i < clipbrd->cached_enum->count; i++)
2049 if(entries[i].first_use)
2050 render_format(clipbrd->src_data, &entries[i].fmtetc);
2052 break;
2055 case WM_DESTROYCLIPBOARD:
2057 TRACE("(): WM_DESTROYCLIPBOARD\n");
2059 set_src_dataobject(clipbrd, NULL);
2060 break;
2063 default:
2064 return DefWindowProcW(hwnd, message, wparam, lparam);
2067 return 0;
2071 /***********************************************************************
2072 * create_clipbrd_window
2074 static HWND create_clipbrd_window(void)
2076 WNDCLASSEXW class;
2077 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
2078 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
2079 HINSTANCE hinst = GetModuleHandleW(ole32W);
2081 class.cbSize = sizeof(class);
2082 class.style = 0;
2083 class.lpfnWndProc = clipbrd_wndproc;
2084 class.cbClsExtra = 0;
2085 class.cbWndExtra = 0;
2086 class.hInstance = hinst;
2087 class.hIcon = 0;
2088 class.hCursor = 0;
2089 class.hbrBackground = 0;
2090 class.lpszMenuName = NULL;
2091 class.lpszClassName = clipbrd_wndclass;
2092 class.hIconSm = NULL;
2094 RegisterClassExW(&class);
2096 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
2097 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2098 NULL, NULL, hinst, 0);
2101 /*********************************************************************
2102 * set_dataobject_format
2104 * Windows creates a 'DataObject' clipboard format that contains the
2105 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
2107 static HRESULT set_dataobject_format(HWND hwnd)
2109 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
2110 HWND *data;
2112 if(!h) return E_OUTOFMEMORY;
2114 data = GlobalLock(h);
2115 *data = hwnd;
2116 GlobalUnlock(h);
2118 if(!SetClipboardData(dataobject_clipboard_format, h))
2120 GlobalFree(h);
2121 return CLIPBRD_E_CANT_SET;
2124 return S_OK;
2127 /*---------------------------------------------------------------------*
2128 * Win32 OLE clipboard API
2129 *---------------------------------------------------------------------*/
2131 /***********************************************************************
2132 * OleSetClipboard [OLE32.@]
2133 * Places a pointer to the specified data object onto the clipboard,
2134 * making the data object accessible to the OleGetClipboard function.
2136 * RETURNS
2138 * S_OK IDataObject pointer placed on the clipboard
2139 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
2140 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
2141 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
2142 * CLIPBRD_E_CANT_SET SetClipboard failed
2145 HRESULT WINAPI OleSetClipboard(IDataObject* data)
2147 HRESULT hr;
2148 ole_clipbrd *clipbrd;
2149 HWND wnd;
2151 TRACE("(%p)\n", data);
2153 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2155 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2157 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
2159 if ( !EmptyClipboard() )
2161 hr = CLIPBRD_E_CANT_EMPTY;
2162 goto end;
2165 hr = set_src_dataobject(clipbrd, data);
2166 if(FAILED(hr)) goto end;
2168 if(data)
2170 hr = expose_marshalled_dataobject(clipbrd, data);
2171 if(FAILED(hr)) goto end;
2172 hr = set_dataobject_format(wnd);
2175 end:
2177 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2179 if ( FAILED(hr) )
2181 expose_marshalled_dataobject(clipbrd, NULL);
2182 set_src_dataobject(clipbrd, NULL);
2185 return hr;
2189 /***********************************************************************
2190 * OleGetClipboard [OLE32.@]
2191 * Returns a pointer to our internal IDataObject which represents the conceptual
2192 * state of the Windows clipboard. If the current clipboard already contains
2193 * an IDataObject, our internal IDataObject will delegate to this object.
2195 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
2197 HRESULT hr;
2198 ole_clipbrd *clipbrd;
2199 DWORD seq_no;
2201 TRACE("(%p)\n", obj);
2203 if(!obj) return E_INVALIDARG;
2204 *obj = NULL;
2206 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2208 seq_no = GetClipboardSequenceNumber();
2209 EnterCriticalSection(&latest_snapshot_cs);
2210 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2211 clipbrd->latest_snapshot = NULL;
2213 if(!clipbrd->latest_snapshot)
2215 clipbrd->latest_snapshot = snapshot_construct(seq_no);
2216 if(!clipbrd->latest_snapshot)
2218 LeaveCriticalSection(&latest_snapshot_cs);
2219 return E_OUTOFMEMORY;
2223 *obj = &clipbrd->latest_snapshot->IDataObject_iface;
2224 IDataObject_AddRef(*obj);
2225 LeaveCriticalSection(&latest_snapshot_cs);
2227 return S_OK;
2230 /******************************************************************************
2231 * OleFlushClipboard [OLE32.@]
2232 * Renders the data from the source IDataObject into the windows clipboard
2234 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2235 * by copying the storage into global memory. Subsequently the default
2236 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2237 * back to TYMED_IStorage.
2239 HRESULT WINAPI OleFlushClipboard(void)
2241 HRESULT hr;
2242 ole_clipbrd *clipbrd;
2243 HWND wnd;
2245 TRACE("()\n");
2247 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2249 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2252 * Already flushed or no source DataObject? Nothing to do.
2254 if (!clipbrd->src_data) return S_OK;
2256 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2258 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2260 hr = set_dataobject_format(NULL);
2262 expose_marshalled_dataobject(clipbrd, NULL);
2263 set_src_dataobject(clipbrd, NULL);
2265 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2267 return hr;
2271 /***********************************************************************
2272 * OleIsCurrentClipboard [OLE32.@]
2274 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2276 HRESULT hr;
2277 ole_clipbrd *clipbrd;
2278 TRACE("()\n");
2280 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2282 if (data == NULL) return S_FALSE;
2284 return (data == clipbrd->src_data) ? S_OK : S_FALSE;