push 45342d27cd031b08b6cfabdf8789426cb53c1c53
[wine/hacks.git] / dlls / ole32 / clipboard.c
blob1e72ec2121758cb4a8c63f9cdba673f87fbc2e1a
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 /***********************************************************************
748 * render_format
750 * Render the clipboard data. Note that this call will delegate to the
751 * source data object.
753 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
755 HGLOBAL clip_data = NULL;
756 HRESULT hr;
758 /* Embed source hack */
759 if(fmt->cfFormat == embed_source_clipboard_format)
761 return render_embed_source_hack(data, fmt);
764 if(fmt->tymed & TYMED_ISTORAGE)
766 hr = get_data_from_storage(data, fmt, &clip_data);
768 else if(fmt->tymed & TYMED_ISTREAM)
770 hr = get_data_from_stream(data, fmt, &clip_data);
772 else if(fmt->tymed & TYMED_HGLOBAL)
774 hr = get_data_from_global(data, fmt, &clip_data);
776 else
778 FIXME("Unhandled tymed %x\n", fmt->tymed);
779 hr = DV_E_FORMATETC;
782 if(SUCCEEDED(hr))
784 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
786 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
787 GlobalFree(clip_data);
788 hr = CLIPBRD_E_CANT_SET;
792 return hr;
795 /*---------------------------------------------------------------------*
796 * Implementation of the internal IDataObject interface exposed by
797 * the OLE clipboard.
798 *---------------------------------------------------------------------*/
801 /************************************************************************
802 * snapshot_QueryInterface
804 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
805 REFIID riid, void **ppvObject)
807 snapshot *This = impl_from_IDataObject(iface);
808 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
810 if ( (This==0) || (ppvObject==0) )
811 return E_INVALIDARG;
813 *ppvObject = 0;
815 if (IsEqualIID(&IID_IUnknown, riid) ||
816 IsEqualIID(&IID_IDataObject, riid))
818 *ppvObject = iface;
820 else
822 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
823 return E_NOINTERFACE;
826 IUnknown_AddRef((IUnknown*)*ppvObject);
828 return S_OK;
831 /************************************************************************
832 * snapshot_AddRef
834 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
836 snapshot *This = impl_from_IDataObject(iface);
838 TRACE("(%p)->(count=%u)\n", This, This->ref);
840 return InterlockedIncrement(&This->ref);
843 /************************************************************************
844 * snapshot_Release
846 static ULONG WINAPI snapshot_Release(IDataObject *iface)
848 snapshot *This = impl_from_IDataObject(iface);
849 ULONG ref;
851 TRACE("(%p)->(count=%u)\n", This, This->ref);
853 ref = InterlockedDecrement(&This->ref);
855 if (ref == 0)
857 ole_clipbrd *clipbrd;
858 HRESULT hr = get_ole_clipbrd(&clipbrd);
860 if(This->data) IDataObject_Release(This->data);
862 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
863 clipbrd->latest_snapshot = NULL;
864 HeapFree(GetProcessHeap(), 0, This);
867 return ref;
870 /************************************************************
871 * get_current_ole_clip_window
873 * Return the window that owns the ole clipboard.
875 * If the clipboard is flushed or not owned by ole this will
876 * return NULL.
878 static HWND get_current_ole_clip_window(void)
880 HGLOBAL h;
881 HWND *ptr, wnd;
883 h = GetClipboardData(dataobject_clipboard_format);
884 if(!h) return NULL;
885 ptr = GlobalLock(h);
886 if(!ptr) return NULL;
887 wnd = *ptr;
888 GlobalUnlock(h);
889 return wnd;
892 /************************************************************
893 * get_current_dataobject
895 * Return an unmarshalled IDataObject if there is a current
896 * (ie non-flushed) object on the ole clipboard.
898 static HRESULT get_current_dataobject(IDataObject **data)
900 HRESULT hr = S_FALSE;
901 HWND wnd = get_current_ole_clip_window();
902 HGLOBAL h;
903 void *ptr;
904 IStream *stm;
905 LARGE_INTEGER pos;
907 *data = NULL;
908 if(!wnd) return S_FALSE;
910 h = GetClipboardData(wine_marshal_clipboard_format);
911 if(!h) return S_FALSE;
912 if(GlobalSize(h) == 0) return S_FALSE;
913 ptr = GlobalLock(h);
914 if(!ptr) return S_FALSE;
916 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
917 if(FAILED(hr)) goto end;
919 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
920 if(SUCCEEDED(hr))
922 pos.QuadPart = 0;
923 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
924 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
926 IStream_Release(stm);
928 end:
929 GlobalUnlock(h);
930 return hr;
933 static DWORD get_tymed_from_nonole_cf(UINT cf)
935 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
937 switch(cf)
939 case CF_TEXT:
940 case CF_OEMTEXT:
941 case CF_UNICODETEXT:
942 return TYMED_ISTREAM | TYMED_HGLOBAL;
943 case CF_ENHMETAFILE:
944 return TYMED_ENHMF;
945 case CF_METAFILEPICT:
946 return TYMED_MFPICT;
947 default:
948 FIXME("returning TYMED_NULL for cf %04x\n", cf);
949 return TYMED_NULL;
953 /***********************************************************
954 * get_priv_data
956 * Returns a copy of the Ole Private Data
958 static HRESULT get_priv_data(ole_priv_data **data)
960 HGLOBAL handle;
961 HRESULT hr = S_OK;
962 ole_priv_data *ret = NULL;
964 *data = NULL;
966 handle = GetClipboardData( ole_private_data_clipboard_format );
967 if(handle)
969 ole_priv_data *src = GlobalLock(handle);
970 if(src)
972 DWORD i;
974 /* FIXME: sanity check on size */
975 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
976 if(!ret)
978 GlobalUnlock(handle);
979 return E_OUTOFMEMORY;
981 memcpy(ret, src, src->size);
982 GlobalUnlock(handle);
984 /* Fixup any target device offsets to ptrs */
985 for(i = 0; i < ret->count; i++)
986 ret->entries[i].fmtetc.ptd =
987 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
991 if(!ret) /* Non-ole data */
993 UINT cf;
994 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
996 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
998 char buf[100];
999 GetClipboardFormatNameA(cf, buf, sizeof(buf));
1000 TRACE("\tcf %04x %s\n", cf, buf);
1003 TRACE("count %d\n", count);
1004 size += count * sizeof(ret->entries[0]);
1006 /* There are holes in fmtetc so zero init */
1007 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1008 if(!ret) return E_OUTOFMEMORY;
1009 ret->size = size;
1010 ret->count = count;
1012 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1014 ret->entries[idx].fmtetc.cfFormat = cf;
1015 ret->entries[idx].fmtetc.ptd = NULL;
1016 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1017 ret->entries[idx].fmtetc.lindex = -1;
1018 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1019 ret->entries[idx].first_use = 1;
1023 *data = ret;
1024 return hr;
1027 /************************************************************************
1028 * get_stgmed_for_global
1030 * Returns a stg medium with a copy of the global handle
1032 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1034 HRESULT hr;
1036 med->pUnkForRelease = NULL;
1037 med->tymed = TYMED_NULL;
1039 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1041 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1043 return hr;
1046 /************************************************************************
1047 * get_stgmed_for_stream
1049 * Returns a stg medium with a stream based on the handle
1051 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1053 HRESULT hr;
1054 HGLOBAL dst;
1056 med->pUnkForRelease = NULL;
1057 med->tymed = TYMED_NULL;
1059 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1060 if(FAILED(hr)) return hr;
1062 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1063 if(FAILED(hr))
1065 GlobalFree(dst);
1066 return hr;
1069 med->tymed = TYMED_ISTREAM;
1070 return hr;
1073 /************************************************************************
1074 * get_stgmed_for_storage
1076 * Returns a stg medium with a storage based on the handle
1078 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1080 HRESULT hr;
1081 HGLOBAL dst;
1082 ILockBytes *lbs;
1084 med->pUnkForRelease = NULL;
1085 med->tymed = TYMED_NULL;
1087 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1088 if(FAILED(hr)) return hr;
1090 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1091 if(FAILED(hr))
1093 GlobalFree(dst);
1094 return hr;
1097 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1098 ILockBytes_Release(lbs);
1099 if(FAILED(hr))
1101 GlobalFree(dst);
1102 return hr;
1105 med->tymed = TYMED_ISTORAGE;
1106 return hr;
1109 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1111 const WCHAR *str1, *str2;
1113 if(off1 == 0 && off2 == 0) return TRUE;
1114 if(off1 == 0 || off2 == 0) return FALSE;
1116 str1 = (const WCHAR*)((const char*)t1 + off1);
1117 str2 = (const WCHAR*)((const char*)t2 + off2);
1119 return !lstrcmpW(str1, str2);
1122 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1124 if(t1 == NULL && t2 == NULL) return TRUE;
1125 if(t1 == NULL || t2 == NULL) return FALSE;
1127 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1128 return FALSE;
1129 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1130 return FALSE;
1131 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1132 return FALSE;
1134 /* FIXME check devmode? */
1136 return TRUE;
1139 /************************************************************************
1140 * snapshot_GetData
1142 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1143 STGMEDIUM *med)
1145 snapshot *This = impl_from_IDataObject(iface);
1146 HANDLE h;
1147 HRESULT hr;
1148 ole_priv_data *enum_data = NULL;
1149 ole_priv_data_entry *entry;
1150 DWORD mask;
1152 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1154 if ( !fmt || !med ) return E_INVALIDARG;
1156 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1158 if(!This->data)
1159 hr = get_current_dataobject(&This->data);
1161 if(This->data)
1163 hr = IDataObject_GetData(This->data, fmt, med);
1164 CloseClipboard();
1165 return hr;
1168 h = GetClipboardData(fmt->cfFormat);
1169 if(!h)
1171 hr = DV_E_FORMATETC;
1172 goto end;
1175 hr = get_priv_data(&enum_data);
1176 if(FAILED(hr)) goto end;
1178 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1179 if(entry)
1181 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1183 hr = DV_E_FORMATETC;
1184 goto end;
1186 mask = fmt->tymed & entry->fmtetc.tymed;
1187 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1189 else /* non-Ole format */
1190 mask = fmt->tymed & TYMED_HGLOBAL;
1192 if(mask & TYMED_ISTORAGE)
1193 hr = get_stgmed_for_storage(h, med);
1194 else if(mask & TYMED_HGLOBAL)
1195 hr = get_stgmed_for_global(h, med);
1196 else if(mask & TYMED_ISTREAM)
1197 hr = get_stgmed_for_stream(h, med);
1198 else
1200 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1201 hr = E_FAIL;
1202 goto end;
1205 end:
1206 HeapFree(GetProcessHeap(), 0, enum_data);
1207 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1208 return hr;
1211 /************************************************************************
1212 * snapshot_GetDataHere
1214 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1215 STGMEDIUM *med)
1217 snapshot *This = impl_from_IDataObject(iface);
1218 HANDLE h;
1219 HRESULT hr;
1220 ole_priv_data *enum_data = NULL;
1221 ole_priv_data_entry *entry;
1222 TYMED supported;
1224 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1226 if ( !fmt || !med ) return E_INVALIDARG;
1228 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1230 if(!This->data)
1231 hr = get_current_dataobject(&This->data);
1233 if(This->data)
1235 hr = IDataObject_GetDataHere(This->data, fmt, med);
1236 if(SUCCEEDED(hr))
1238 CloseClipboard();
1239 return hr;
1243 h = GetClipboardData(fmt->cfFormat);
1244 if(!h)
1246 hr = DV_E_FORMATETC;
1247 goto end;
1250 hr = get_priv_data(&enum_data);
1251 if(FAILED(hr)) goto end;
1253 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1254 if(entry)
1256 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1258 hr = DV_E_FORMATETC;
1259 goto end;
1261 supported = entry->fmtetc.tymed;
1263 else /* non-Ole format */
1264 supported = TYMED_HGLOBAL;
1266 switch(med->tymed)
1268 case TYMED_HGLOBAL:
1270 DWORD src_size = GlobalSize(h);
1271 DWORD dst_size = GlobalSize(med->u.hGlobal);
1272 hr = E_FAIL;
1273 if(dst_size >= src_size)
1275 void *src = GlobalLock(h);
1276 void *dst = GlobalLock(med->u.hGlobal);
1278 memcpy(dst, src, src_size);
1279 GlobalUnlock(med->u.hGlobal);
1280 GlobalUnlock(h);
1281 hr = S_OK;
1283 break;
1285 case TYMED_ISTREAM:
1287 DWORD src_size = GlobalSize(h);
1288 void *src = GlobalLock(h);
1289 hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1290 GlobalUnlock(h);
1291 break;
1293 case TYMED_ISTORAGE:
1295 STGMEDIUM copy;
1296 if(!(supported & TYMED_ISTORAGE))
1298 hr = E_FAIL;
1299 goto end;
1301 hr = get_stgmed_for_storage(h, &copy);
1302 if(SUCCEEDED(hr))
1304 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1305 ReleaseStgMedium(&copy);
1307 break;
1309 default:
1310 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1311 hr = E_FAIL;
1312 goto end;
1315 end:
1316 HeapFree(GetProcessHeap(), 0, enum_data);
1317 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1318 return hr;
1321 /************************************************************************
1322 * snapshot_QueryGetData
1324 * The OLE Clipboard's implementation of this method delegates to
1325 * a data source if there is one or wraps around the windows clipboard
1326 * function IsClipboardFormatAvailable() otherwise.
1329 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1331 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1333 if (!fmt) return E_INVALIDARG;
1335 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1337 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1339 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1342 /************************************************************************
1343 * snapshot_GetCanonicalFormatEtc
1345 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1346 FORMATETC *fmt_out)
1348 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1350 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1352 *fmt_out = *fmt_in;
1353 return DATA_S_SAMEFORMATETC;
1356 /************************************************************************
1357 * snapshot_SetData
1359 * The OLE Clipboard does not implement this method
1361 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1362 STGMEDIUM *med, BOOL release)
1364 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1365 return E_NOTIMPL;
1368 /************************************************************************
1369 * snapshot_EnumFormatEtc
1372 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1373 IEnumFORMATETC **enum_fmt)
1375 HRESULT hr;
1376 ole_priv_data *data = NULL;
1378 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1380 *enum_fmt = NULL;
1382 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1383 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1385 hr = get_priv_data(&data);
1387 if(FAILED(hr)) goto end;
1389 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1391 end:
1392 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1393 return hr;
1396 /************************************************************************
1397 * snapshot_DAdvise
1399 * The OLE Clipboard does not implement this method
1401 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1402 DWORD flags, IAdviseSink *sink,
1403 DWORD *conn)
1405 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1406 return E_NOTIMPL;
1409 /************************************************************************
1410 * snapshot_DUnadvise
1412 * The OLE Clipboard does not implement this method
1414 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1416 TRACE("(%p, %d): not implemented\n", iface, conn);
1417 return E_NOTIMPL;
1420 /************************************************************************
1421 * snapshot_EnumDAdvise
1423 * The OLE Clipboard does not implement this method
1425 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1426 IEnumSTATDATA** enum_advise)
1428 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1429 return E_NOTIMPL;
1432 static const IDataObjectVtbl snapshot_vtable =
1434 snapshot_QueryInterface,
1435 snapshot_AddRef,
1436 snapshot_Release,
1437 snapshot_GetData,
1438 snapshot_GetDataHere,
1439 snapshot_QueryGetData,
1440 snapshot_GetCanonicalFormatEtc,
1441 snapshot_SetData,
1442 snapshot_EnumFormatEtc,
1443 snapshot_DAdvise,
1444 snapshot_DUnadvise,
1445 snapshot_EnumDAdvise
1448 /*---------------------------------------------------------------------*
1449 * Internal implementation methods for the OLE clipboard
1450 *---------------------------------------------------------------------*/
1452 static snapshot *snapshot_construct(DWORD seq_no)
1454 snapshot *This;
1456 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1457 if (!This) return NULL;
1459 This->lpVtbl = &snapshot_vtable;
1460 This->ref = 0;
1461 This->seq_no = seq_no;
1462 This->data = NULL;
1464 return This;
1467 /*********************************************************
1468 * register_clipboard_formats
1470 static void register_clipboard_formats(void)
1472 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1473 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1474 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1475 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1476 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1477 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1478 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1479 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1480 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1481 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1482 'D','e','s','c','r','i','p','t','o','r',0};
1483 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1485 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1486 'D','a','t','a','O','b','j','e','c','t',0};
1488 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1489 filename_clipboard_format = RegisterClipboardFormatW(FileName);
1490 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1491 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1492 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1493 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1494 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1495 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1496 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1497 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1498 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1500 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1503 /***********************************************************************
1504 * OLEClipbrd_Initialize()
1505 * Initializes the OLE clipboard.
1507 void OLEClipbrd_Initialize(void)
1509 register_clipboard_formats();
1511 if ( !theOleClipboard )
1513 ole_clipbrd* clipbrd;
1514 HGLOBAL h;
1516 TRACE("()\n");
1518 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1519 if (!clipbrd) return;
1521 clipbrd->latest_snapshot = NULL;
1522 clipbrd->window = NULL;
1523 clipbrd->src_data = NULL;
1524 clipbrd->cached_enum = NULL;
1526 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1527 if(!h)
1529 HeapFree(GetProcessHeap(), 0, clipbrd);
1530 return;
1533 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1535 GlobalFree(h);
1536 HeapFree(GetProcessHeap(), 0, clipbrd);
1537 return;
1540 theOleClipboard = clipbrd;
1544 /***********************************************************************
1545 * OLEClipbrd_UnInitialize()
1546 * Un-Initializes the OLE clipboard
1548 void OLEClipbrd_UnInitialize(void)
1550 ole_clipbrd *clipbrd = theOleClipboard;
1552 TRACE("()\n");
1554 if ( clipbrd )
1556 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1557 HINSTANCE hinst = GetModuleHandleW(ole32W);
1559 if ( clipbrd->window )
1561 DestroyWindow(clipbrd->window);
1562 UnregisterClassW( clipbrd_wndclass, hinst );
1565 IStream_Release(clipbrd->marshal_data);
1566 HeapFree(GetProcessHeap(), 0, clipbrd);
1567 theOleClipboard = NULL;
1571 /*********************************************************************
1572 * set_clipboard_formats
1574 * Enumerate all formats supported by the source and make
1575 * those formats available using delayed rendering using SetClipboardData.
1576 * Cache the enumeration list and make that list visibile as the
1577 * 'Ole Private Data' format on the clipboard.
1580 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1582 HRESULT hr;
1583 FORMATETC fmt;
1584 IEnumFORMATETC *enum_fmt;
1585 HGLOBAL priv_data_handle;
1586 DWORD_PTR target_offset;
1587 ole_priv_data *priv_data;
1588 DWORD count = 0, needed = sizeof(*priv_data), idx;
1590 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1591 if(FAILED(hr)) return hr;
1593 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1595 count++;
1596 needed += sizeof(priv_data->entries[0]);
1597 if(fmt.ptd)
1599 needed += fmt.ptd->tdSize;
1600 CoTaskMemFree(fmt.ptd);
1604 /* Windows pads the list with two empty ole_priv_data_entries, one
1605 * after the entries array and one after the target device data.
1606 * Allocating with zero init to zero these pads. */
1608 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1609 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1610 priv_data = GlobalLock(priv_data_handle);
1612 priv_data->unk1 = 0;
1613 priv_data->size = needed;
1614 priv_data->unk2 = 1;
1615 priv_data->count = count;
1616 priv_data->unk3[0] = 0;
1617 priv_data->unk3[1] = 0;
1619 IEnumFORMATETC_Reset(enum_fmt);
1621 idx = 0;
1622 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1624 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1626 TRACE("%s\n", dump_fmtetc(&fmt));
1628 priv_data->entries[idx].fmtetc = fmt;
1629 if(fmt.ptd)
1631 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1632 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1633 target_offset += fmt.ptd->tdSize;
1634 CoTaskMemFree(fmt.ptd);
1637 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1638 priv_data->entries[idx].unk[0] = 0;
1639 priv_data->entries[idx].unk[1] = 0;
1641 if (priv_data->entries[idx].first_use)
1642 SetClipboardData(fmt.cfFormat, NULL);
1644 idx++;
1647 IEnumFORMATETC_Release(enum_fmt);
1649 /* Cache the list and fixup any target device offsets to ptrs */
1650 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1651 memcpy(clipbrd->cached_enum, priv_data, needed);
1652 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1653 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1654 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1656 GlobalUnlock(priv_data_handle);
1657 SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1659 return S_OK;
1662 static HWND create_clipbrd_window(void);
1664 /***********************************************************************
1665 * get_clipbrd_window
1667 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1669 if ( !clipbrd->window )
1670 clipbrd->window = create_clipbrd_window();
1672 *wnd = clipbrd->window;
1673 return *wnd ? S_OK : E_FAIL;
1677 /**********************************************************************
1678 * release_marshal_data
1680 * Releases the data and sets the stream back to zero size.
1682 static inline void release_marshal_data(IStream *stm)
1684 LARGE_INTEGER pos;
1685 ULARGE_INTEGER size;
1686 pos.QuadPart = size.QuadPart = 0;
1688 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1689 CoReleaseMarshalData(stm);
1690 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1691 IStream_SetSize(stm, size);
1694 /***********************************************************************
1695 * expose_marshalled_dataobject
1697 * Sets the marshalled dataobject to the clipboard. In the flushed case
1698 * we set a zero sized HGLOBAL to clear the old marshalled data.
1700 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1702 HGLOBAL h;
1704 if(data)
1706 HGLOBAL h_stm;
1707 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1708 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1710 else /* flushed */
1711 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1713 if(!h) return E_OUTOFMEMORY;
1715 SetClipboardData(wine_marshal_clipboard_format, h);
1716 return S_OK;
1719 /***********************************************************************
1720 * set_src_dataobject
1722 * Clears and sets the clipboard's src IDataObject.
1724 * To marshal the source dataobject we do something rather different from Windows.
1725 * We set a clipboard format which contains the marshalled data.
1726 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1728 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1730 HRESULT hr;
1731 HWND wnd;
1733 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1735 if(clipbrd->src_data)
1737 release_marshal_data(clipbrd->marshal_data);
1739 IDataObject_Release(clipbrd->src_data);
1740 clipbrd->src_data = NULL;
1741 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1742 clipbrd->cached_enum = NULL;
1745 if(data)
1747 IUnknown *unk;
1749 IDataObject_AddRef(data);
1750 clipbrd->src_data = data;
1752 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1753 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1754 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1755 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1756 if(FAILED(hr)) return hr;
1757 hr = set_clipboard_formats(clipbrd, data);
1759 return hr;
1762 /***********************************************************************
1763 * clipbrd_wndproc
1765 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1767 ole_clipbrd *clipbrd;
1769 get_ole_clipbrd(&clipbrd);
1771 switch (message)
1773 case WM_RENDERFORMAT:
1775 UINT cf = wparam;
1776 ole_priv_data_entry *entry;
1778 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1779 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1781 if(entry)
1782 render_format(clipbrd->src_data, &entry->fmtetc);
1784 break;
1787 case WM_RENDERALLFORMATS:
1789 DWORD i;
1790 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1792 TRACE("(): WM_RENDERALLFORMATS\n");
1794 for(i = 0; i < clipbrd->cached_enum->count; i++)
1796 if(entries[i].first_use)
1797 render_format(clipbrd->src_data, &entries[i].fmtetc);
1799 break;
1802 case WM_DESTROYCLIPBOARD:
1804 TRACE("(): WM_DESTROYCLIPBOARD\n");
1806 set_src_dataobject(clipbrd, NULL);
1807 break;
1810 default:
1811 return DefWindowProcW(hwnd, message, wparam, lparam);
1814 return 0;
1818 /***********************************************************************
1819 * create_clipbrd_window
1821 static HWND create_clipbrd_window(void)
1823 WNDCLASSEXW class;
1824 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1825 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1826 HINSTANCE hinst = GetModuleHandleW(ole32W);
1828 class.cbSize = sizeof(class);
1829 class.style = 0;
1830 class.lpfnWndProc = clipbrd_wndproc;
1831 class.cbClsExtra = 0;
1832 class.cbWndExtra = 0;
1833 class.hInstance = hinst;
1834 class.hIcon = 0;
1835 class.hCursor = 0;
1836 class.hbrBackground = 0;
1837 class.lpszMenuName = NULL;
1838 class.lpszClassName = clipbrd_wndclass;
1839 class.hIconSm = NULL;
1841 RegisterClassExW(&class);
1843 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1844 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1845 NULL, NULL, hinst, 0);
1848 /*********************************************************************
1849 * set_dataobject_format
1851 * Windows creates a 'DataObject' clipboard format that contains the
1852 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1854 static HRESULT set_dataobject_format(HWND hwnd)
1856 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1857 HWND *data;
1859 if(!h) return E_OUTOFMEMORY;
1861 data = GlobalLock(h);
1862 *data = hwnd;
1863 GlobalUnlock(h);
1865 if(!SetClipboardData(dataobject_clipboard_format, h))
1867 GlobalFree(h);
1868 return CLIPBRD_E_CANT_SET;
1871 return S_OK;
1874 /*---------------------------------------------------------------------*
1875 * Win32 OLE clipboard API
1876 *---------------------------------------------------------------------*/
1878 /***********************************************************************
1879 * OleSetClipboard [OLE32.@]
1880 * Places a pointer to the specified data object onto the clipboard,
1881 * making the data object accessible to the OleGetClipboard function.
1883 * RETURNS
1885 * S_OK IDataObject pointer placed on the clipboard
1886 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1887 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1888 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1889 * CLIPBRD_E_CANT_SET SetClipboard failed
1892 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1894 HRESULT hr;
1895 ole_clipbrd *clipbrd;
1896 HWND wnd;
1898 TRACE("(%p)\n", data);
1900 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1902 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1904 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1906 if ( !EmptyClipboard() )
1908 hr = CLIPBRD_E_CANT_EMPTY;
1909 goto end;
1912 hr = set_src_dataobject(clipbrd, data);
1913 if(FAILED(hr)) goto end;
1915 if(data)
1917 hr = expose_marshalled_dataobject(clipbrd, data);
1918 if(FAILED(hr)) goto end;
1919 hr = set_dataobject_format(wnd);
1922 end:
1924 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1926 if ( FAILED(hr) )
1928 expose_marshalled_dataobject(clipbrd, NULL);
1929 set_src_dataobject(clipbrd, NULL);
1932 return hr;
1936 /***********************************************************************
1937 * OleGetClipboard [OLE32.@]
1938 * Returns a pointer to our internal IDataObject which represents the conceptual
1939 * state of the Windows clipboard. If the current clipboard already contains
1940 * an IDataObject, our internal IDataObject will delegate to this object.
1942 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1944 HRESULT hr;
1945 ole_clipbrd *clipbrd;
1946 DWORD seq_no;
1948 TRACE("(%p)\n", obj);
1950 if(!obj) return E_INVALIDARG;
1952 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1954 seq_no = GetClipboardSequenceNumber();
1955 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1956 clipbrd->latest_snapshot = NULL;
1958 if(!clipbrd->latest_snapshot)
1960 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1961 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1964 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1965 IDataObject_AddRef(*obj);
1967 return S_OK;
1970 /******************************************************************************
1971 * OleFlushClipboard [OLE32.@]
1972 * Renders the data from the source IDataObject into the windows clipboard
1974 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1975 * by copying the storage into global memory. Subsequently the default
1976 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1977 * back to TYMED_IStorage.
1979 HRESULT WINAPI OleFlushClipboard(void)
1981 HRESULT hr;
1982 ole_clipbrd *clipbrd;
1983 HWND wnd;
1985 TRACE("()\n");
1987 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1989 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1992 * Already flushed or no source DataObject? Nothing to do.
1994 if (!clipbrd->src_data) return S_OK;
1996 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1998 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2000 hr = set_dataobject_format(NULL);
2002 expose_marshalled_dataobject(clipbrd, NULL);
2003 set_src_dataobject(clipbrd, NULL);
2005 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2007 return hr;
2011 /***********************************************************************
2012 * OleIsCurrentClipboard [OLE32.@]
2014 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2016 HRESULT hr;
2017 ole_clipbrd *clipbrd;
2018 TRACE("()\n");
2020 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2022 if (data == NULL) return S_FALSE;
2024 return (data == clipbrd->src_data) ? S_OK : S_FALSE;