ntdll: Fix race in NtRead/WriteFile.
[wine/testsucceed.git] / dlls / ole32 / clipboard.c
blob3064bb0415636f41779f363068ae866e3c6d1c59
1 /*
2 * OLE 2 clipboard support
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * NOTES:
22 * This file contains the implementation for the OLE Clipboard and its
23 * internal interfaces. The OLE clipboard interacts with an IDataObject
24 * interface via the OleSetClipboard, OleGetClipboard and
25 * OleIsCurrentClipboard API's. An internal IDataObject delegates
26 * to a client supplied IDataObject or the WIN32 clipboard API depending
27 * on whether OleSetClipboard has been invoked.
28 * Here are some operating scenarios:
30 * 1. OleSetClipboard called: In this case the internal IDataObject
31 * delegates to the client supplied IDataObject. Additionally OLE takes
32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject
33 * items are placed on the Windows clipboard. This allows non OLE aware
34 * applications to access these. A local WinProc fields WM_RENDERFORMAT
35 * and WM_RENDERALLFORMATS messages in this case.
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41 * IDataObject delegates to the source IDataObjects functionality directly,
42 * thereby bypassing the Windows clipboard.
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
46 * TODO:
47 * - Support for pasting between different processes. OLE clipboard support
48 * currently works only for in process copy and paste. Since we internally
49 * store a pointer to the source's IDataObject and delegate to that, this
50 * will fail if the IDataObject client belongs to a different process.
51 * - IDataObject::GetDataHere is not implemented
52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53 * by copying the storage into global memory. Subsequently the default
54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55 * back to TYMED_IStorage.
56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57 * clipboard in OleSetClipboard.
61 #include <assert.h>
62 #include <stdarg.h>
63 #include <string.h>
64 #include <stdio.h>
66 #define COBJMACROS
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
70 #include "windef.h"
71 #include "winbase.h"
72 #include "wingdi.h"
73 #include "winuser.h"
74 #include "winerror.h"
75 #include "winnls.h"
76 #include "ole2.h"
77 #include "wine/debug.h"
78 #include "olestd.h"
80 #include "storage32.h"
82 #include "compobj_private.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(ole);
86 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
88 /* Structure of 'Ole Private Data' clipboard format */
89 typedef struct
91 FORMATETC fmtetc;
92 DWORD first_use; /* Has this cf been added to the list already */
93 DWORD unk[2];
94 } ole_priv_data_entry;
96 typedef struct
98 DWORD unk1;
99 DWORD size; /* in bytes of the entire structure */
100 DWORD unk2;
101 DWORD count; /* no. of format entries */
102 DWORD unk3[2];
103 ole_priv_data_entry entries[1]; /* array of size count */
104 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
105 } ole_priv_data;
107 /*****************************************************************************
108 * td_offs_to_ptr
110 * Returns a ptr to a target device at a given offset from the
111 * start of the ole_priv_data.
113 * Used when unpacking ole private data from the clipboard.
115 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
117 if(off == 0) return NULL;
118 return (DVTARGETDEVICE*)((char*)data + off);
121 /*****************************************************************************
122 * td_get_offs
124 * Get the offset from the start of the ole_priv_data of the idx'th
125 * target device.
127 * Used when packing ole private data to the clipboard.
129 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
131 if(data->entries[idx].fmtetc.ptd == NULL) return 0;
132 return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
135 /****************************************************************************
136 * Consumer snapshot. Represents the state of the ole clipboard
137 * returned by OleGetClipboard().
139 typedef struct snapshot
141 const IDataObjectVtbl* lpVtbl;
142 LONG ref;
144 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */
146 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */
147 } snapshot;
149 /****************************************************************************
150 * ole_clipbrd
152 typedef struct ole_clipbrd
154 snapshot *latest_snapshot; /* Latest consumer snapshot */
156 HWND window; /* Hidden clipboard window */
157 IDataObject *src_data; /* Source object passed to OleSetClipboard */
158 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
159 IStream *marshal_data; /* Stream onto which to marshal src_data */
160 } ole_clipbrd;
162 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
164 return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
167 typedef struct PresentationDataHeader
169 BYTE unknown1[28];
170 DWORD dwObjectExtentX;
171 DWORD dwObjectExtentY;
172 DWORD dwSize;
173 } PresentationDataHeader;
176 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
178 static ole_clipbrd* theOleClipboard;
180 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
182 struct oletls *info = COM_CurrentInfo();
183 *clipbrd = NULL;
185 if(!info->ole_inits)
186 return CO_E_NOTINITIALIZED;
187 *clipbrd = theOleClipboard;
189 return S_OK;
193 * Name of our registered OLE clipboard window class
195 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
197 static const WCHAR wine_marshal_dataobject[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0};
199 UINT ownerlink_clipboard_format = 0;
200 UINT filename_clipboard_format = 0;
201 UINT filenameW_clipboard_format = 0;
202 UINT dataobject_clipboard_format = 0;
203 UINT embedded_object_clipboard_format = 0;
204 UINT embed_source_clipboard_format = 0;
205 UINT custom_link_source_clipboard_format = 0;
206 UINT link_source_clipboard_format = 0;
207 UINT object_descriptor_clipboard_format = 0;
208 UINT link_source_descriptor_clipboard_format = 0;
209 UINT ole_private_data_clipboard_format = 0;
211 static UINT wine_marshal_clipboard_format;
213 static inline char *dump_fmtetc(FORMATETC *fmt)
215 static char buf[100];
217 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
218 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
219 return buf;
222 /*---------------------------------------------------------------------*
223 * Implementation of the internal IEnumFORMATETC interface returned by
224 * the OLE clipboard's IDataObject.
225 *---------------------------------------------------------------------*/
227 typedef struct enum_fmtetc
229 const IEnumFORMATETCVtbl *lpVtbl;
230 LONG ref;
232 UINT pos; /* current enumerator position */
233 ole_priv_data *data;
234 } enum_fmtetc;
236 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
238 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
241 /************************************************************************
242 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
244 * See Windows documentation for more details on IUnknown methods.
246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
247 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
249 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
251 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
253 *ppvObj = NULL;
255 if(IsEqualIID(riid, &IID_IUnknown) ||
256 IsEqualIID(riid, &IID_IEnumFORMATETC))
258 *ppvObj = iface;
261 if(*ppvObj)
263 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
264 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
265 return S_OK;
268 TRACE("-- Interface: E_NOINTERFACE\n");
269 return E_NOINTERFACE;
272 /************************************************************************
273 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
276 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
278 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
279 TRACE("(%p)->(count=%u)\n",This, This->ref);
281 return InterlockedIncrement(&This->ref);
284 /************************************************************************
285 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
287 * See Windows documentation for more details on IUnknown methods.
289 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
291 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
292 ULONG ref;
294 TRACE("(%p)->(count=%u)\n",This, This->ref);
296 ref = InterlockedDecrement(&This->ref);
297 if (!ref)
299 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
300 HeapFree(GetProcessHeap(), 0, This->data);
301 HeapFree(GetProcessHeap(), 0, This);
303 return ref;
306 /************************************************************************
307 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
309 * Standard enumerator members for IEnumFORMATETC
311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
312 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
314 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
315 UINT cfetch, i;
316 HRESULT hres = S_FALSE;
318 TRACE("(%p)->(pos=%u)\n", This, This->pos);
320 if (This->pos < This->data->count)
322 cfetch = This->data->count - This->pos;
323 if (cfetch >= celt)
325 cfetch = celt;
326 hres = S_OK;
329 for(i = 0; i < cfetch; i++)
331 rgelt[i] = This->data->entries[This->pos++].fmtetc;
332 if(rgelt[i].ptd)
334 DVTARGETDEVICE *target = rgelt[i].ptd;
335 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
336 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
337 memcpy(rgelt[i].ptd, target, target->tdSize);
341 else
343 cfetch = 0;
346 if (pceltFethed)
348 *pceltFethed = cfetch;
351 return hres;
354 /************************************************************************
355 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
357 * Standard enumerator members for IEnumFORMATETC
359 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
361 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
362 TRACE("(%p)->(num=%u)\n", This, celt);
364 This->pos += celt;
365 if (This->pos > This->data->count)
367 This->pos = This->data->count;
368 return S_FALSE;
370 return S_OK;
373 /************************************************************************
374 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
376 * Standard enumerator members for IEnumFORMATETC
378 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
380 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
381 TRACE("(%p)->()\n", This);
383 This->pos = 0;
384 return S_OK;
387 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
389 /************************************************************************
390 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
392 * Standard enumerator members for IEnumFORMATETC
394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
395 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
397 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
398 ole_priv_data *new_data;
399 DWORD i;
401 TRACE("(%p)->(%p)\n", This, obj);
403 if ( !obj ) return E_INVALIDARG;
404 *obj = NULL;
406 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
407 if(!new_data) return E_OUTOFMEMORY;
408 memcpy(new_data, This->data, This->data->size);
410 /* Fixup any target device ptrs */
411 for(i = 0; i < This->data->count; i++)
412 new_data->entries[i].fmtetc.ptd =
413 td_offs_to_ptr(new_data, td_get_offs(This->data, i));
415 return enum_fmtetc_construct(new_data, This->pos, obj);
418 static const IEnumFORMATETCVtbl efvt =
420 OLEClipbrd_IEnumFORMATETC_QueryInterface,
421 OLEClipbrd_IEnumFORMATETC_AddRef,
422 OLEClipbrd_IEnumFORMATETC_Release,
423 OLEClipbrd_IEnumFORMATETC_Next,
424 OLEClipbrd_IEnumFORMATETC_Skip,
425 OLEClipbrd_IEnumFORMATETC_Reset,
426 OLEClipbrd_IEnumFORMATETC_Clone
429 /************************************************************************
430 * enum_fmtetc_construct
432 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
434 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
436 enum_fmtetc* ef;
438 *obj = NULL;
439 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
440 if (!ef) return E_OUTOFMEMORY;
442 ef->ref = 1;
443 ef->lpVtbl = &efvt;
444 ef->data = data;
445 ef->pos = pos;
447 TRACE("(%p)->()\n", ef);
448 *obj = (IEnumFORMATETC *)ef;
449 return S_OK;
452 /***********************************************************************
453 * dup_global_mem
455 * Helper method to duplicate an HGLOBAL chunk of memory
457 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
459 void *src_ptr, *dst_ptr;
460 DWORD size;
462 *dst = NULL;
463 if ( !src ) return S_FALSE;
465 size = GlobalSize(src);
467 *dst = GlobalAlloc( flags, size );
468 if ( !*dst ) return E_OUTOFMEMORY;
470 src_ptr = GlobalLock(src);
471 dst_ptr = GlobalLock(*dst);
473 memcpy(dst_ptr, src_ptr, size);
475 GlobalUnlock(*dst);
476 GlobalUnlock(src);
478 return S_OK;
481 /************************************************************
482 * render_embed_source_hack
484 * This is clearly a hack and has no place in the clipboard code.
487 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
489 STGMEDIUM std;
490 HGLOBAL hStorage = 0;
491 HRESULT hr = S_OK;
492 ILockBytes *ptrILockBytes;
494 memset(&std, 0, sizeof(STGMEDIUM));
495 std.tymed = fmt->tymed = TYMED_ISTORAGE;
497 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
498 if (hStorage == NULL) return E_OUTOFMEMORY;
499 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
500 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
501 ILockBytes_Release(ptrILockBytes);
503 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
505 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
506 GlobalFree(hStorage);
507 return hr;
510 if (1) /* check whether the presentation data is already -not- present */
512 FORMATETC fmt2;
513 STGMEDIUM std2;
514 METAFILEPICT *mfp = 0;
516 fmt2.cfFormat = CF_METAFILEPICT;
517 fmt2.ptd = 0;
518 fmt2.dwAspect = DVASPECT_CONTENT;
519 fmt2.lindex = -1;
520 fmt2.tymed = TYMED_MFPICT;
522 memset(&std2, 0, sizeof(STGMEDIUM));
523 std2.tymed = TYMED_MFPICT;
525 /* Get the metafile picture out of it */
527 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
529 mfp = GlobalLock(std2.u.hGlobal);
532 if (mfp)
534 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
535 IStream *pStream = 0;
536 void *mfBits;
537 PresentationDataHeader pdh;
538 INT nSize;
539 CLSID clsID;
540 LPOLESTR strProgID;
541 CHAR strOleTypeName[51];
542 BYTE OlePresStreamHeader [] =
544 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
545 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
546 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00
550 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
552 memset(&pdh, 0, sizeof(PresentationDataHeader));
553 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
555 pdh.dwObjectExtentX = mfp->xExt;
556 pdh.dwObjectExtentY = mfp->yExt;
557 pdh.dwSize = nSize;
559 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
561 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
563 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
564 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
566 hr = IStream_Write(pStream, mfBits, nSize, NULL);
568 IStream_Release(pStream);
570 HeapFree(GetProcessHeap(), 0, mfBits);
572 GlobalUnlock(std2.u.hGlobal);
573 ReleaseStgMedium(&std2);
575 ReadClassStg(std.u.pstg, &clsID);
576 ProgIDFromCLSID(&clsID, &strProgID);
578 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
579 OLECONVERT_CreateOleStream(std.u.pstg);
580 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
584 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
586 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
587 GlobalFree(hStorage);
588 hr = CLIPBRD_E_CANT_SET;
591 ReleaseStgMedium(&std);
592 return hr;
595 /************************************************************************
596 * find_format_in_list
598 * Returns the first entry that matches the provided clipboard format.
600 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
602 DWORD i;
603 for(i = 0; i < num; i++)
604 if(entries[i].fmtetc.cfFormat == cf)
605 return &entries[i];
607 return NULL;
610 /***************************************************************************
611 * get_data_from_storage
613 * Returns storage data in an HGLOBAL.
615 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
617 HGLOBAL h;
618 IStorage *stg;
619 HRESULT hr;
620 FORMATETC stg_fmt;
621 STGMEDIUM med;
622 ILockBytes *lbs;
624 *mem = NULL;
626 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
627 if(!h) return E_OUTOFMEMORY;
629 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
630 if(SUCCEEDED(hr))
632 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
633 ILockBytes_Release(lbs);
635 if(FAILED(hr))
637 GlobalFree(h);
638 return hr;
641 stg_fmt = *fmt;
642 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
643 med.u.pstg = stg;
644 med.pUnkForRelease = NULL;
646 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
647 if(FAILED(hr))
649 med.u.pstg = NULL;
650 hr = IDataObject_GetData(data, &stg_fmt, &med);
651 if(FAILED(hr)) goto end;
653 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
654 ReleaseStgMedium(&med);
655 if(FAILED(hr)) goto end;
657 *mem = h;
659 end:
660 IStorage_Release(stg);
661 if(FAILED(hr)) GlobalFree(h);
662 return hr;
665 /***************************************************************************
666 * get_data_from_stream
668 * Returns stream data in an HGLOBAL.
670 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
672 HGLOBAL h;
673 IStream *stm = NULL;
674 HRESULT hr;
675 FORMATETC stm_fmt;
676 STGMEDIUM med;
678 *mem = NULL;
680 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
681 if(!h) return E_OUTOFMEMORY;
683 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
684 if(FAILED(hr)) goto error;
686 stm_fmt = *fmt;
687 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
688 med.u.pstm = stm;
689 med.pUnkForRelease = NULL;
691 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
692 if(FAILED(hr))
694 LARGE_INTEGER offs;
695 ULARGE_INTEGER pos;
697 med.u.pstm = NULL;
698 hr = IDataObject_GetData(data, &stm_fmt, &med);
699 if(FAILED(hr)) goto error;
701 offs.QuadPart = 0;
702 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
703 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
704 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
705 ReleaseStgMedium(&med);
706 if(FAILED(hr)) goto error;
708 *mem = h;
709 IStream_Release(stm);
710 return S_OK;
712 error:
713 if(stm) IStream_Release(stm);
714 GlobalFree(h);
715 return hr;
718 /***************************************************************************
719 * get_data_from_global
721 * Returns global data in an HGLOBAL.
723 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
725 HGLOBAL h;
726 HRESULT hr;
727 FORMATETC mem_fmt;
728 STGMEDIUM med;
730 *mem = NULL;
732 mem_fmt = *fmt;
733 mem_fmt.tymed = TYMED_HGLOBAL;
735 hr = IDataObject_GetData(data, &mem_fmt, &med);
736 if(FAILED(hr)) return hr;
738 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
740 if(SUCCEEDED(hr)) *mem = h;
742 ReleaseStgMedium(&med);
744 return hr;
747 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
749 HENHMETAFILE copy;
750 HRESULT hr;
751 FORMATETC mem_fmt;
752 STGMEDIUM med;
754 *mem = NULL;
756 mem_fmt = *fmt;
757 mem_fmt.tymed = TYMED_ENHMF;
759 hr = IDataObject_GetData(data, &mem_fmt, &med);
760 if(FAILED(hr)) return hr;
762 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
763 if(copy) *mem = (HGLOBAL)copy;
764 else hr = E_FAIL;
766 ReleaseStgMedium(&med);
768 return hr;
771 /***********************************************************************
772 * render_format
774 * Render the clipboard data. Note that this call will delegate to the
775 * source data object.
777 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
779 HGLOBAL clip_data = NULL;
780 HRESULT hr;
782 /* Embed source hack */
783 if(fmt->cfFormat == embed_source_clipboard_format)
785 return render_embed_source_hack(data, fmt);
788 if(fmt->tymed & TYMED_ISTORAGE)
790 hr = get_data_from_storage(data, fmt, &clip_data);
792 else if(fmt->tymed & TYMED_ISTREAM)
794 hr = get_data_from_stream(data, fmt, &clip_data);
796 else if(fmt->tymed & TYMED_HGLOBAL)
798 hr = get_data_from_global(data, fmt, &clip_data);
800 else if(fmt->tymed & TYMED_ENHMF)
802 hr = get_data_from_enhmetafile(data, fmt, &clip_data);
804 else
806 FIXME("Unhandled tymed %x\n", fmt->tymed);
807 hr = DV_E_FORMATETC;
810 if(SUCCEEDED(hr))
812 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
814 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
815 GlobalFree(clip_data);
816 hr = CLIPBRD_E_CANT_SET;
820 return hr;
823 /*---------------------------------------------------------------------*
824 * Implementation of the internal IDataObject interface exposed by
825 * the OLE clipboard.
826 *---------------------------------------------------------------------*/
829 /************************************************************************
830 * snapshot_QueryInterface
832 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
833 REFIID riid, void **ppvObject)
835 snapshot *This = impl_from_IDataObject(iface);
836 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
838 if ( (This==0) || (ppvObject==0) )
839 return E_INVALIDARG;
841 *ppvObject = 0;
843 if (IsEqualIID(&IID_IUnknown, riid) ||
844 IsEqualIID(&IID_IDataObject, riid))
846 *ppvObject = iface;
848 else
850 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
851 return E_NOINTERFACE;
854 IUnknown_AddRef((IUnknown*)*ppvObject);
856 return S_OK;
859 /************************************************************************
860 * snapshot_AddRef
862 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
864 snapshot *This = impl_from_IDataObject(iface);
866 TRACE("(%p)->(count=%u)\n", This, This->ref);
868 return InterlockedIncrement(&This->ref);
871 /************************************************************************
872 * snapshot_Release
874 static ULONG WINAPI snapshot_Release(IDataObject *iface)
876 snapshot *This = impl_from_IDataObject(iface);
877 ULONG ref;
879 TRACE("(%p)->(count=%u)\n", This, This->ref);
881 ref = InterlockedDecrement(&This->ref);
883 if (ref == 0)
885 ole_clipbrd *clipbrd;
886 HRESULT hr = get_ole_clipbrd(&clipbrd);
888 if(This->data) IDataObject_Release(This->data);
890 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
891 clipbrd->latest_snapshot = NULL;
892 HeapFree(GetProcessHeap(), 0, This);
895 return ref;
898 /************************************************************
899 * get_current_ole_clip_window
901 * Return the window that owns the ole clipboard.
903 * If the clipboard is flushed or not owned by ole this will
904 * return NULL.
906 static HWND get_current_ole_clip_window(void)
908 HGLOBAL h;
909 HWND *ptr, wnd;
911 h = GetClipboardData(dataobject_clipboard_format);
912 if(!h) return NULL;
913 ptr = GlobalLock(h);
914 if(!ptr) return NULL;
915 wnd = *ptr;
916 GlobalUnlock(h);
917 return wnd;
920 /************************************************************
921 * get_current_dataobject
923 * Return an unmarshalled IDataObject if there is a current
924 * (ie non-flushed) object on the ole clipboard.
926 static HRESULT get_current_dataobject(IDataObject **data)
928 HRESULT hr = S_FALSE;
929 HWND wnd = get_current_ole_clip_window();
930 HGLOBAL h;
931 void *ptr;
932 IStream *stm;
933 LARGE_INTEGER pos;
935 *data = NULL;
936 if(!wnd) return S_FALSE;
938 h = GetClipboardData(wine_marshal_clipboard_format);
939 if(!h) return S_FALSE;
940 if(GlobalSize(h) == 0) return S_FALSE;
941 ptr = GlobalLock(h);
942 if(!ptr) return S_FALSE;
944 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
945 if(FAILED(hr)) goto end;
947 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
948 if(SUCCEEDED(hr))
950 pos.QuadPart = 0;
951 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
952 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
954 IStream_Release(stm);
956 end:
957 GlobalUnlock(h);
958 return hr;
961 static DWORD get_tymed_from_nonole_cf(UINT cf)
963 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
965 switch(cf)
967 case CF_TEXT:
968 case CF_OEMTEXT:
969 case CF_UNICODETEXT:
970 return TYMED_ISTREAM | TYMED_HGLOBAL;
971 case CF_ENHMETAFILE:
972 return TYMED_ENHMF;
973 case CF_METAFILEPICT:
974 return TYMED_MFPICT;
975 default:
976 FIXME("returning TYMED_NULL for cf %04x\n", cf);
977 return TYMED_NULL;
981 /***********************************************************
982 * get_priv_data
984 * Returns a copy of the Ole Private Data
986 static HRESULT get_priv_data(ole_priv_data **data)
988 HGLOBAL handle;
989 HRESULT hr = S_OK;
990 ole_priv_data *ret = NULL;
992 *data = NULL;
994 handle = GetClipboardData( ole_private_data_clipboard_format );
995 if(handle)
997 ole_priv_data *src = GlobalLock(handle);
998 if(src)
1000 DWORD i;
1002 /* FIXME: sanity check on size */
1003 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1004 if(!ret)
1006 GlobalUnlock(handle);
1007 return E_OUTOFMEMORY;
1009 memcpy(ret, src, src->size);
1010 GlobalUnlock(handle);
1012 /* Fixup any target device offsets to ptrs */
1013 for(i = 0; i < ret->count; i++)
1014 ret->entries[i].fmtetc.ptd =
1015 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1019 if(!ret) /* Non-ole data */
1021 UINT cf;
1022 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1024 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1026 char buf[100];
1027 GetClipboardFormatNameA(cf, buf, sizeof(buf));
1028 TRACE("cf %04x %s\n", cf, buf);
1030 TRACE("count %d\n", count);
1031 size += count * sizeof(ret->entries[0]);
1033 /* There are holes in fmtetc so zero init */
1034 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1035 if(!ret) return E_OUTOFMEMORY;
1036 ret->size = size;
1037 ret->count = count;
1039 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1041 ret->entries[idx].fmtetc.cfFormat = cf;
1042 ret->entries[idx].fmtetc.ptd = NULL;
1043 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1044 ret->entries[idx].fmtetc.lindex = -1;
1045 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1046 ret->entries[idx].first_use = 1;
1050 *data = ret;
1051 return hr;
1054 /************************************************************************
1055 * get_stgmed_for_global
1057 * Returns a stg medium with a copy of the global handle
1059 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1061 HRESULT hr;
1063 med->pUnkForRelease = NULL;
1064 med->tymed = TYMED_NULL;
1066 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1068 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1070 return hr;
1073 /************************************************************************
1074 * get_stgmed_for_stream
1076 * Returns a stg medium with a stream based on the handle
1078 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1080 HRESULT hr;
1081 HGLOBAL dst;
1083 med->pUnkForRelease = NULL;
1084 med->tymed = TYMED_NULL;
1086 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1087 if(FAILED(hr)) return hr;
1089 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1090 if(FAILED(hr))
1092 GlobalFree(dst);
1093 return hr;
1096 med->tymed = TYMED_ISTREAM;
1097 return hr;
1100 /************************************************************************
1101 * get_stgmed_for_storage
1103 * Returns a stg medium with a storage based on the handle
1105 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1107 HRESULT hr;
1108 HGLOBAL dst;
1109 ILockBytes *lbs;
1111 med->pUnkForRelease = NULL;
1112 med->tymed = TYMED_NULL;
1114 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1115 if(FAILED(hr)) return hr;
1117 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1118 if(FAILED(hr))
1120 GlobalFree(dst);
1121 return hr;
1124 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1125 ILockBytes_Release(lbs);
1126 if(FAILED(hr))
1128 GlobalFree(dst);
1129 return hr;
1132 med->tymed = TYMED_ISTORAGE;
1133 return hr;
1136 /************************************************************************
1137 * get_stgmed_for_emf
1139 * Returns a stg medium with an enhanced metafile based on the handle
1141 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
1143 med->pUnkForRelease = NULL;
1144 med->tymed = TYMED_NULL;
1146 med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
1147 if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
1148 med->tymed = TYMED_ENHMF;
1149 return S_OK;
1152 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1154 const WCHAR *str1, *str2;
1156 if(off1 == 0 && off2 == 0) return TRUE;
1157 if(off1 == 0 || off2 == 0) return FALSE;
1159 str1 = (const WCHAR*)((const char*)t1 + off1);
1160 str2 = (const WCHAR*)((const char*)t2 + off2);
1162 return !lstrcmpW(str1, str2);
1165 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1167 if(t1 == NULL && t2 == NULL) return TRUE;
1168 if(t1 == NULL || t2 == NULL) return FALSE;
1170 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1171 return FALSE;
1172 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1173 return FALSE;
1174 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1175 return FALSE;
1177 /* FIXME check devmode? */
1179 return TRUE;
1182 /************************************************************************
1183 * snapshot_GetData
1185 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1186 STGMEDIUM *med)
1188 snapshot *This = impl_from_IDataObject(iface);
1189 HANDLE h;
1190 HRESULT hr;
1191 ole_priv_data *enum_data = NULL;
1192 ole_priv_data_entry *entry;
1193 DWORD mask;
1195 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1197 if ( !fmt || !med ) return E_INVALIDARG;
1199 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1201 if(!This->data)
1202 hr = get_current_dataobject(&This->data);
1204 if(This->data)
1206 hr = IDataObject_GetData(This->data, fmt, med);
1207 CloseClipboard();
1208 return hr;
1211 h = GetClipboardData(fmt->cfFormat);
1212 if(!h)
1214 hr = DV_E_FORMATETC;
1215 goto end;
1218 hr = get_priv_data(&enum_data);
1219 if(FAILED(hr)) goto end;
1221 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1222 if(entry)
1224 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1226 hr = DV_E_FORMATETC;
1227 goto end;
1229 mask = fmt->tymed & entry->fmtetc.tymed;
1230 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1232 else /* non-Ole format */
1233 mask = fmt->tymed & TYMED_HGLOBAL;
1235 if(mask & TYMED_ISTORAGE)
1236 hr = get_stgmed_for_storage(h, med);
1237 else if(mask & TYMED_HGLOBAL)
1238 hr = get_stgmed_for_global(h, med);
1239 else if(mask & TYMED_ISTREAM)
1240 hr = get_stgmed_for_stream(h, med);
1241 else if(mask & TYMED_ENHMF)
1242 hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
1243 else
1245 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1246 hr = E_FAIL;
1247 goto end;
1250 end:
1251 HeapFree(GetProcessHeap(), 0, enum_data);
1252 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1253 return hr;
1256 /************************************************************************
1257 * snapshot_GetDataHere
1259 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1260 STGMEDIUM *med)
1262 snapshot *This = impl_from_IDataObject(iface);
1263 HANDLE h;
1264 HRESULT hr;
1265 ole_priv_data *enum_data = NULL;
1266 ole_priv_data_entry *entry;
1267 TYMED supported;
1269 if ( !fmt || !med ) return E_INVALIDARG;
1271 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1273 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1275 if(!This->data)
1276 hr = get_current_dataobject(&This->data);
1278 if(This->data)
1280 hr = IDataObject_GetDataHere(This->data, fmt, med);
1281 if(SUCCEEDED(hr))
1283 CloseClipboard();
1284 return hr;
1288 h = GetClipboardData(fmt->cfFormat);
1289 if(!h)
1291 hr = DV_E_FORMATETC;
1292 goto end;
1295 hr = get_priv_data(&enum_data);
1296 if(FAILED(hr)) goto end;
1298 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1299 if(entry)
1301 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1303 hr = DV_E_FORMATETC;
1304 goto end;
1306 supported = entry->fmtetc.tymed;
1308 else /* non-Ole format */
1309 supported = TYMED_HGLOBAL;
1311 switch(med->tymed)
1313 case TYMED_HGLOBAL:
1315 DWORD src_size = GlobalSize(h);
1316 DWORD dst_size = GlobalSize(med->u.hGlobal);
1317 hr = E_FAIL;
1318 if(dst_size >= src_size)
1320 void *src = GlobalLock(h);
1321 void *dst = GlobalLock(med->u.hGlobal);
1323 memcpy(dst, src, src_size);
1324 GlobalUnlock(med->u.hGlobal);
1325 GlobalUnlock(h);
1326 hr = S_OK;
1328 break;
1330 case TYMED_ISTREAM:
1332 DWORD src_size = GlobalSize(h);
1333 void *src = GlobalLock(h);
1334 hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1335 GlobalUnlock(h);
1336 break;
1338 case TYMED_ISTORAGE:
1340 STGMEDIUM copy;
1341 if(!(supported & TYMED_ISTORAGE))
1343 hr = E_FAIL;
1344 goto end;
1346 hr = get_stgmed_for_storage(h, &copy);
1347 if(SUCCEEDED(hr))
1349 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1350 ReleaseStgMedium(&copy);
1352 break;
1354 default:
1355 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1356 hr = E_FAIL;
1357 goto end;
1360 end:
1361 HeapFree(GetProcessHeap(), 0, enum_data);
1362 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1363 return hr;
1366 /************************************************************************
1367 * snapshot_QueryGetData
1369 * The OLE Clipboard's implementation of this method delegates to
1370 * a data source if there is one or wraps around the windows clipboard
1371 * function IsClipboardFormatAvailable() otherwise.
1374 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1376 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1378 if (!fmt) return E_INVALIDARG;
1380 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1382 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1384 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1387 /************************************************************************
1388 * snapshot_GetCanonicalFormatEtc
1390 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1391 FORMATETC *fmt_out)
1393 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1395 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1397 *fmt_out = *fmt_in;
1398 return DATA_S_SAMEFORMATETC;
1401 /************************************************************************
1402 * snapshot_SetData
1404 * The OLE Clipboard does not implement this method
1406 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1407 STGMEDIUM *med, BOOL release)
1409 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1410 return E_NOTIMPL;
1413 /************************************************************************
1414 * snapshot_EnumFormatEtc
1417 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1418 IEnumFORMATETC **enum_fmt)
1420 HRESULT hr;
1421 ole_priv_data *data = NULL;
1423 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1425 *enum_fmt = NULL;
1427 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1428 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1430 hr = get_priv_data(&data);
1432 if(FAILED(hr)) goto end;
1434 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1436 end:
1437 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1438 return hr;
1441 /************************************************************************
1442 * snapshot_DAdvise
1444 * The OLE Clipboard does not implement this method
1446 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1447 DWORD flags, IAdviseSink *sink,
1448 DWORD *conn)
1450 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1451 return E_NOTIMPL;
1454 /************************************************************************
1455 * snapshot_DUnadvise
1457 * The OLE Clipboard does not implement this method
1459 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1461 TRACE("(%p, %d): not implemented\n", iface, conn);
1462 return E_NOTIMPL;
1465 /************************************************************************
1466 * snapshot_EnumDAdvise
1468 * The OLE Clipboard does not implement this method
1470 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1471 IEnumSTATDATA** enum_advise)
1473 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1474 return E_NOTIMPL;
1477 static const IDataObjectVtbl snapshot_vtable =
1479 snapshot_QueryInterface,
1480 snapshot_AddRef,
1481 snapshot_Release,
1482 snapshot_GetData,
1483 snapshot_GetDataHere,
1484 snapshot_QueryGetData,
1485 snapshot_GetCanonicalFormatEtc,
1486 snapshot_SetData,
1487 snapshot_EnumFormatEtc,
1488 snapshot_DAdvise,
1489 snapshot_DUnadvise,
1490 snapshot_EnumDAdvise
1493 /*---------------------------------------------------------------------*
1494 * Internal implementation methods for the OLE clipboard
1495 *---------------------------------------------------------------------*/
1497 static snapshot *snapshot_construct(DWORD seq_no)
1499 snapshot *This;
1501 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1502 if (!This) return NULL;
1504 This->lpVtbl = &snapshot_vtable;
1505 This->ref = 0;
1506 This->seq_no = seq_no;
1507 This->data = NULL;
1509 return This;
1512 /*********************************************************
1513 * register_clipboard_formats
1515 static void register_clipboard_formats(void)
1517 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1518 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1519 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1520 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1521 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1522 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1523 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1524 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1525 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1526 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1527 'D','e','s','c','r','i','p','t','o','r',0};
1528 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1530 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1531 'D','a','t','a','O','b','j','e','c','t',0};
1533 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1534 filename_clipboard_format = RegisterClipboardFormatW(FileName);
1535 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1536 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1537 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1538 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1539 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1540 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1541 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1542 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1543 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1545 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1548 /***********************************************************************
1549 * OLEClipbrd_Initialize()
1550 * Initializes the OLE clipboard.
1552 void OLEClipbrd_Initialize(void)
1554 register_clipboard_formats();
1556 if ( !theOleClipboard )
1558 ole_clipbrd* clipbrd;
1559 HGLOBAL h;
1561 TRACE("()\n");
1563 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1564 if (!clipbrd) return;
1566 clipbrd->latest_snapshot = NULL;
1567 clipbrd->window = NULL;
1568 clipbrd->src_data = NULL;
1569 clipbrd->cached_enum = NULL;
1571 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1572 if(!h)
1574 HeapFree(GetProcessHeap(), 0, clipbrd);
1575 return;
1578 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1580 GlobalFree(h);
1581 HeapFree(GetProcessHeap(), 0, clipbrd);
1582 return;
1585 theOleClipboard = clipbrd;
1589 /***********************************************************************
1590 * OLEClipbrd_UnInitialize()
1591 * Un-Initializes the OLE clipboard
1593 void OLEClipbrd_UnInitialize(void)
1595 ole_clipbrd *clipbrd = theOleClipboard;
1597 TRACE("()\n");
1599 if ( clipbrd )
1601 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1602 HINSTANCE hinst = GetModuleHandleW(ole32W);
1604 if ( clipbrd->window )
1606 DestroyWindow(clipbrd->window);
1607 UnregisterClassW( clipbrd_wndclass, hinst );
1610 IStream_Release(clipbrd->marshal_data);
1611 if (clipbrd->src_data) IDataObject_Release(clipbrd->src_data);
1612 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1613 HeapFree(GetProcessHeap(), 0, clipbrd);
1614 theOleClipboard = NULL;
1618 /*********************************************************************
1619 * set_clipboard_formats
1621 * Enumerate all formats supported by the source and make
1622 * those formats available using delayed rendering using SetClipboardData.
1623 * Cache the enumeration list and make that list visibile as the
1624 * 'Ole Private Data' format on the clipboard.
1627 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1629 HRESULT hr;
1630 FORMATETC fmt;
1631 IEnumFORMATETC *enum_fmt;
1632 HGLOBAL priv_data_handle;
1633 DWORD_PTR target_offset;
1634 ole_priv_data *priv_data;
1635 DWORD count = 0, needed = sizeof(*priv_data), idx;
1637 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1638 if(FAILED(hr)) return hr;
1640 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1642 count++;
1643 needed += sizeof(priv_data->entries[0]);
1644 if(fmt.ptd)
1646 needed += fmt.ptd->tdSize;
1647 CoTaskMemFree(fmt.ptd);
1651 /* Windows pads the list with two empty ole_priv_data_entries, one
1652 * after the entries array and one after the target device data.
1653 * Allocating with zero init to zero these pads. */
1655 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1656 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1657 priv_data = GlobalLock(priv_data_handle);
1659 priv_data->unk1 = 0;
1660 priv_data->size = needed;
1661 priv_data->unk2 = 1;
1662 priv_data->count = count;
1663 priv_data->unk3[0] = 0;
1664 priv_data->unk3[1] = 0;
1666 IEnumFORMATETC_Reset(enum_fmt);
1668 idx = 0;
1669 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1671 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1673 TRACE("%s\n", dump_fmtetc(&fmt));
1675 priv_data->entries[idx].fmtetc = fmt;
1676 if(fmt.ptd)
1678 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1679 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1680 target_offset += fmt.ptd->tdSize;
1681 CoTaskMemFree(fmt.ptd);
1684 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1685 priv_data->entries[idx].unk[0] = 0;
1686 priv_data->entries[idx].unk[1] = 0;
1688 if (priv_data->entries[idx].first_use)
1689 SetClipboardData(fmt.cfFormat, NULL);
1691 idx++;
1694 IEnumFORMATETC_Release(enum_fmt);
1696 /* Cache the list and fixup any target device offsets to ptrs */
1697 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1698 memcpy(clipbrd->cached_enum, priv_data, needed);
1699 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1700 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1701 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1703 GlobalUnlock(priv_data_handle);
1704 if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle))
1706 GlobalFree(priv_data_handle);
1707 return CLIPBRD_E_CANT_SET;
1710 return S_OK;
1713 static HWND create_clipbrd_window(void);
1715 /***********************************************************************
1716 * get_clipbrd_window
1718 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1720 if ( !clipbrd->window )
1721 clipbrd->window = create_clipbrd_window();
1723 *wnd = clipbrd->window;
1724 return *wnd ? S_OK : E_FAIL;
1728 /**********************************************************************
1729 * release_marshal_data
1731 * Releases the data and sets the stream back to zero size.
1733 static inline void release_marshal_data(IStream *stm)
1735 LARGE_INTEGER pos;
1736 ULARGE_INTEGER size;
1737 pos.QuadPart = size.QuadPart = 0;
1739 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1740 CoReleaseMarshalData(stm);
1741 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1742 IStream_SetSize(stm, size);
1745 /***********************************************************************
1746 * expose_marshalled_dataobject
1748 * Sets the marshalled dataobject to the clipboard. In the flushed case
1749 * we set a zero sized HGLOBAL to clear the old marshalled data.
1751 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1753 HGLOBAL h;
1755 if(data)
1757 HGLOBAL h_stm;
1758 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1759 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1761 else /* flushed */
1762 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1764 if(!h) return E_OUTOFMEMORY;
1766 if(!SetClipboardData(wine_marshal_clipboard_format, h))
1768 GlobalFree(h);
1769 return CLIPBRD_E_CANT_SET;
1771 return S_OK;
1774 /***********************************************************************
1775 * set_src_dataobject
1777 * Clears and sets the clipboard's src IDataObject.
1779 * To marshal the source dataobject we do something rather different from Windows.
1780 * We set a clipboard format which contains the marshalled data.
1781 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1783 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1785 HRESULT hr;
1786 HWND wnd;
1788 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1790 if(clipbrd->src_data)
1792 release_marshal_data(clipbrd->marshal_data);
1794 IDataObject_Release(clipbrd->src_data);
1795 clipbrd->src_data = NULL;
1796 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1797 clipbrd->cached_enum = NULL;
1800 if(data)
1802 IUnknown *unk;
1804 IDataObject_AddRef(data);
1805 clipbrd->src_data = data;
1807 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1808 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1809 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1810 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1811 if(FAILED(hr)) return hr;
1812 hr = set_clipboard_formats(clipbrd, data);
1814 return hr;
1817 /***********************************************************************
1818 * clipbrd_wndproc
1820 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1822 ole_clipbrd *clipbrd;
1824 get_ole_clipbrd(&clipbrd);
1826 switch (message)
1828 case WM_RENDERFORMAT:
1830 UINT cf = wparam;
1831 ole_priv_data_entry *entry;
1833 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1834 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1836 if(entry)
1837 render_format(clipbrd->src_data, &entry->fmtetc);
1839 break;
1842 case WM_RENDERALLFORMATS:
1844 DWORD i;
1845 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1847 TRACE("(): WM_RENDERALLFORMATS\n");
1849 for(i = 0; i < clipbrd->cached_enum->count; i++)
1851 if(entries[i].first_use)
1852 render_format(clipbrd->src_data, &entries[i].fmtetc);
1854 break;
1857 case WM_DESTROYCLIPBOARD:
1859 TRACE("(): WM_DESTROYCLIPBOARD\n");
1861 set_src_dataobject(clipbrd, NULL);
1862 break;
1865 default:
1866 return DefWindowProcW(hwnd, message, wparam, lparam);
1869 return 0;
1873 /***********************************************************************
1874 * create_clipbrd_window
1876 static HWND create_clipbrd_window(void)
1878 WNDCLASSEXW class;
1879 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1880 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1881 HINSTANCE hinst = GetModuleHandleW(ole32W);
1883 class.cbSize = sizeof(class);
1884 class.style = 0;
1885 class.lpfnWndProc = clipbrd_wndproc;
1886 class.cbClsExtra = 0;
1887 class.cbWndExtra = 0;
1888 class.hInstance = hinst;
1889 class.hIcon = 0;
1890 class.hCursor = 0;
1891 class.hbrBackground = 0;
1892 class.lpszMenuName = NULL;
1893 class.lpszClassName = clipbrd_wndclass;
1894 class.hIconSm = NULL;
1896 RegisterClassExW(&class);
1898 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1899 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1900 NULL, NULL, hinst, 0);
1903 /*********************************************************************
1904 * set_dataobject_format
1906 * Windows creates a 'DataObject' clipboard format that contains the
1907 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1909 static HRESULT set_dataobject_format(HWND hwnd)
1911 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1912 HWND *data;
1914 if(!h) return E_OUTOFMEMORY;
1916 data = GlobalLock(h);
1917 *data = hwnd;
1918 GlobalUnlock(h);
1920 if(!SetClipboardData(dataobject_clipboard_format, h))
1922 GlobalFree(h);
1923 return CLIPBRD_E_CANT_SET;
1926 return S_OK;
1929 /*---------------------------------------------------------------------*
1930 * Win32 OLE clipboard API
1931 *---------------------------------------------------------------------*/
1933 /***********************************************************************
1934 * OleSetClipboard [OLE32.@]
1935 * Places a pointer to the specified data object onto the clipboard,
1936 * making the data object accessible to the OleGetClipboard function.
1938 * RETURNS
1940 * S_OK IDataObject pointer placed on the clipboard
1941 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1942 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1943 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1944 * CLIPBRD_E_CANT_SET SetClipboard failed
1947 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1949 HRESULT hr;
1950 ole_clipbrd *clipbrd;
1951 HWND wnd;
1953 TRACE("(%p)\n", data);
1955 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1957 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1959 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1961 if ( !EmptyClipboard() )
1963 hr = CLIPBRD_E_CANT_EMPTY;
1964 goto end;
1967 hr = set_src_dataobject(clipbrd, data);
1968 if(FAILED(hr)) goto end;
1970 if(data)
1972 hr = expose_marshalled_dataobject(clipbrd, data);
1973 if(FAILED(hr)) goto end;
1974 hr = set_dataobject_format(wnd);
1977 end:
1979 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1981 if ( FAILED(hr) )
1983 expose_marshalled_dataobject(clipbrd, NULL);
1984 set_src_dataobject(clipbrd, NULL);
1987 return hr;
1991 /***********************************************************************
1992 * OleGetClipboard [OLE32.@]
1993 * Returns a pointer to our internal IDataObject which represents the conceptual
1994 * state of the Windows clipboard. If the current clipboard already contains
1995 * an IDataObject, our internal IDataObject will delegate to this object.
1997 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1999 HRESULT hr;
2000 ole_clipbrd *clipbrd;
2001 DWORD seq_no;
2003 TRACE("(%p)\n", obj);
2005 if(!obj) return E_INVALIDARG;
2007 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2009 seq_no = GetClipboardSequenceNumber();
2010 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2011 clipbrd->latest_snapshot = NULL;
2013 if(!clipbrd->latest_snapshot)
2015 clipbrd->latest_snapshot = snapshot_construct(seq_no);
2016 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
2019 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
2020 IDataObject_AddRef(*obj);
2022 return S_OK;
2025 /******************************************************************************
2026 * OleFlushClipboard [OLE32.@]
2027 * Renders the data from the source IDataObject into the windows clipboard
2029 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2030 * by copying the storage into global memory. Subsequently the default
2031 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2032 * back to TYMED_IStorage.
2034 HRESULT WINAPI OleFlushClipboard(void)
2036 HRESULT hr;
2037 ole_clipbrd *clipbrd;
2038 HWND wnd;
2040 TRACE("()\n");
2042 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2044 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2047 * Already flushed or no source DataObject? Nothing to do.
2049 if (!clipbrd->src_data) return S_OK;
2051 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2053 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2055 hr = set_dataobject_format(NULL);
2057 expose_marshalled_dataobject(clipbrd, NULL);
2058 set_src_dataobject(clipbrd, NULL);
2060 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2062 return hr;
2066 /***********************************************************************
2067 * OleIsCurrentClipboard [OLE32.@]
2069 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2071 HRESULT hr;
2072 ole_clipbrd *clipbrd;
2073 TRACE("()\n");
2075 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2077 if (data == NULL) return S_FALSE;
2079 return (data == clipbrd->src_data) ? S_OK : S_FALSE;