ole32: Register a few more clipboard formats and make them have global scope.
[wine/hacks.git] / dlls / ole32 / clipboard.c
blobec114114156670a8b973266b04e0c009d95f55dc
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 inline char *dump_fmtetc(FORMATETC *fmt)
213 static char buf[100];
215 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
216 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
217 return buf;
220 /*---------------------------------------------------------------------*
221 * Implementation of the internal IEnumFORMATETC interface returned by
222 * the OLE clipboard's IDataObject.
223 *---------------------------------------------------------------------*/
225 typedef struct enum_fmtetc
227 const IEnumFORMATETCVtbl *lpVtbl;
228 LONG ref;
230 UINT pos; /* current enumerator position */
231 ole_priv_data *data;
232 } enum_fmtetc;
234 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
236 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
239 /************************************************************************
240 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
242 * See Windows documentation for more details on IUnknown methods.
244 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
245 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
247 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
249 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
251 *ppvObj = NULL;
253 if(IsEqualIID(riid, &IID_IUnknown) ||
254 IsEqualIID(riid, &IID_IEnumFORMATETC))
256 *ppvObj = iface;
259 if(*ppvObj)
261 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
262 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
263 return S_OK;
266 TRACE("-- Interface: E_NOINTERFACE\n");
267 return E_NOINTERFACE;
270 /************************************************************************
271 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
274 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
276 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
277 TRACE("(%p)->(count=%u)\n",This, This->ref);
279 return InterlockedIncrement(&This->ref);
282 /************************************************************************
283 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
285 * See Windows documentation for more details on IUnknown methods.
287 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
289 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
290 ULONG ref;
292 TRACE("(%p)->(count=%u)\n",This, This->ref);
294 ref = InterlockedDecrement(&This->ref);
295 if (!ref)
297 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
298 HeapFree(GetProcessHeap(), 0, This->data);
299 HeapFree(GetProcessHeap(), 0, This);
301 return ref;
304 /************************************************************************
305 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
307 * Standard enumerator members for IEnumFORMATETC
309 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
310 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
312 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
313 UINT cfetch, i;
314 HRESULT hres = S_FALSE;
316 TRACE("(%p)->(pos=%u)\n", This, This->pos);
318 if (This->pos < This->data->count)
320 cfetch = This->data->count - This->pos;
321 if (cfetch >= celt)
323 cfetch = celt;
324 hres = S_OK;
327 for(i = 0; i < cfetch; i++)
329 rgelt[i] = This->data->entries[This->pos++].fmtetc;
330 if(rgelt[i].ptd)
332 DVTARGETDEVICE *target = rgelt[i].ptd;
333 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
334 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
335 memcpy(rgelt[i].ptd, target, target->tdSize);
339 else
341 cfetch = 0;
344 if (pceltFethed)
346 *pceltFethed = cfetch;
349 return hres;
352 /************************************************************************
353 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
355 * Standard enumerator members for IEnumFORMATETC
357 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
359 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
360 TRACE("(%p)->(num=%u)\n", This, celt);
362 This->pos += celt;
363 if (This->pos > This->data->count)
365 This->pos = This->data->count;
366 return S_FALSE;
368 return S_OK;
371 /************************************************************************
372 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
374 * Standard enumerator members for IEnumFORMATETC
376 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
378 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
379 TRACE("(%p)->()\n", This);
381 This->pos = 0;
382 return S_OK;
385 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
387 /************************************************************************
388 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
390 * Standard enumerator members for IEnumFORMATETC
392 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
393 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
395 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
396 ole_priv_data *new_data;
397 DWORD i;
399 TRACE("(%p)->(%p)\n", This, obj);
401 if ( !obj ) return E_INVALIDARG;
402 *obj = NULL;
404 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
405 if(!new_data) return E_OUTOFMEMORY;
406 memcpy(new_data, This->data, This->data->size);
408 /* Fixup any target device ptrs */
409 for(i = 0; i < This->data->count; i++)
410 new_data->entries[i].fmtetc.ptd =
411 td_offs_to_ptr(new_data, td_get_offs(This->data, i));
413 return enum_fmtetc_construct(new_data, This->pos, obj);
416 static const IEnumFORMATETCVtbl efvt =
418 OLEClipbrd_IEnumFORMATETC_QueryInterface,
419 OLEClipbrd_IEnumFORMATETC_AddRef,
420 OLEClipbrd_IEnumFORMATETC_Release,
421 OLEClipbrd_IEnumFORMATETC_Next,
422 OLEClipbrd_IEnumFORMATETC_Skip,
423 OLEClipbrd_IEnumFORMATETC_Reset,
424 OLEClipbrd_IEnumFORMATETC_Clone
427 /************************************************************************
428 * enum_fmtetc_construct
430 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
432 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
434 enum_fmtetc* ef;
436 *obj = NULL;
437 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
438 if (!ef) return E_OUTOFMEMORY;
440 ef->ref = 1;
441 ef->lpVtbl = &efvt;
442 ef->data = data;
443 ef->pos = pos;
445 TRACE("(%p)->()\n", ef);
446 *obj = (IEnumFORMATETC *)ef;
447 return S_OK;
450 /***********************************************************************
451 * dup_global_mem
453 * Helper method to duplicate an HGLOBAL chunk of memory
455 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
457 void *src_ptr, *dst_ptr;
458 DWORD size;
460 *dst = NULL;
461 if ( !src ) return S_FALSE;
463 size = GlobalSize(src);
465 *dst = GlobalAlloc( flags, size );
466 if ( !*dst ) return E_OUTOFMEMORY;
468 src_ptr = GlobalLock(src);
469 dst_ptr = GlobalLock(*dst);
471 memcpy(dst_ptr, src_ptr, size);
473 GlobalUnlock(*dst);
474 GlobalUnlock(src);
476 return S_OK;
479 /************************************************************
480 * render_embed_source_hack
482 * This is clearly a hack and has no place in the clipboard code.
485 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
487 STGMEDIUM std;
488 HGLOBAL hStorage = 0;
489 HRESULT hr = S_OK;
490 ILockBytes *ptrILockBytes;
492 memset(&std, 0, sizeof(STGMEDIUM));
493 std.tymed = fmt->tymed = TYMED_ISTORAGE;
495 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
496 if (hStorage == NULL) return E_OUTOFMEMORY;
497 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
498 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
499 ILockBytes_Release(ptrILockBytes);
501 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
503 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
504 GlobalFree(hStorage);
505 return hr;
508 if (1) /* check whether the presentation data is already -not- present */
510 FORMATETC fmt2;
511 STGMEDIUM std2;
512 METAFILEPICT *mfp = 0;
514 fmt2.cfFormat = CF_METAFILEPICT;
515 fmt2.ptd = 0;
516 fmt2.dwAspect = DVASPECT_CONTENT;
517 fmt2.lindex = -1;
518 fmt2.tymed = TYMED_MFPICT;
520 memset(&std2, 0, sizeof(STGMEDIUM));
521 std2.tymed = TYMED_MFPICT;
523 /* Get the metafile picture out of it */
525 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
527 mfp = GlobalLock(std2.u.hGlobal);
530 if (mfp)
532 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
533 IStream *pStream = 0;
534 void *mfBits;
535 PresentationDataHeader pdh;
536 INT nSize;
537 CLSID clsID;
538 LPOLESTR strProgID;
539 CHAR strOleTypeName[51];
540 BYTE OlePresStreamHeader [] =
542 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
543 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
544 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
545 0x00, 0x00, 0x00, 0x00
548 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
550 memset(&pdh, 0, sizeof(PresentationDataHeader));
551 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
553 pdh.dwObjectExtentX = mfp->xExt;
554 pdh.dwObjectExtentY = mfp->yExt;
555 pdh.dwSize = nSize;
557 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
559 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
561 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
562 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
564 hr = IStream_Write(pStream, mfBits, nSize, NULL);
566 IStream_Release(pStream);
568 HeapFree(GetProcessHeap(), 0, mfBits);
570 GlobalUnlock(std2.u.hGlobal);
571 ReleaseStgMedium(&std2);
573 ReadClassStg(std.u.pstg, &clsID);
574 ProgIDFromCLSID(&clsID, &strProgID);
576 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
577 OLECONVERT_CreateOleStream(std.u.pstg);
578 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
582 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
584 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
585 GlobalFree(hStorage);
586 hr = CLIPBRD_E_CANT_SET;
589 ReleaseStgMedium(&std);
590 return hr;
593 /************************************************************************
594 * find_format_in_list
596 * Returns the first entry that matches the provided clipboard format.
598 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
600 DWORD i;
601 for(i = 0; i < num; i++)
602 if(entries[i].fmtetc.cfFormat == cf)
603 return &entries[i];
605 return NULL;
608 /***************************************************************************
609 * get_data_from_storage
611 * Returns storage data in an HGLOBAL.
613 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
615 HGLOBAL h;
616 IStorage *stg;
617 HRESULT hr;
618 FORMATETC stg_fmt;
619 STGMEDIUM med;
620 ILockBytes *lbs;
622 *mem = NULL;
624 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
625 if(!h) return E_OUTOFMEMORY;
627 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
628 if(SUCCEEDED(hr))
630 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
631 ILockBytes_Release(lbs);
633 if(FAILED(hr))
635 GlobalFree(h);
636 return hr;
639 stg_fmt = *fmt;
640 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
641 med.u.pstg = stg;
642 med.pUnkForRelease = NULL;
644 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
645 if(FAILED(hr))
647 med.u.pstg = NULL;
648 hr = IDataObject_GetData(data, &stg_fmt, &med);
649 if(FAILED(hr)) goto end;
651 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
652 ReleaseStgMedium(&med);
653 if(FAILED(hr)) goto end;
655 *mem = h;
657 end:
658 IStorage_Release(stg);
659 if(FAILED(hr)) GlobalFree(h);
660 return hr;
663 /***************************************************************************
664 * get_data_from_stream
666 * Returns stream data in an HGLOBAL.
668 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
670 HGLOBAL h;
671 IStream *stm = NULL;
672 HRESULT hr;
673 FORMATETC stm_fmt;
674 STGMEDIUM med;
676 *mem = NULL;
678 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
679 if(!h) return E_OUTOFMEMORY;
681 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
682 if(FAILED(hr)) goto error;
684 stm_fmt = *fmt;
685 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
686 med.u.pstm = stm;
687 med.pUnkForRelease = NULL;
689 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
690 if(FAILED(hr))
692 LARGE_INTEGER offs;
693 ULARGE_INTEGER pos;
695 med.u.pstm = NULL;
696 hr = IDataObject_GetData(data, &stm_fmt, &med);
697 if(FAILED(hr)) goto error;
699 offs.QuadPart = 0;
700 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
701 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
702 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
703 ReleaseStgMedium(&med);
704 if(FAILED(hr)) goto error;
706 *mem = h;
707 IStream_Release(stm);
708 return S_OK;
710 error:
711 if(stm) IStream_Release(stm);
712 GlobalFree(h);
713 return hr;
716 /***************************************************************************
717 * get_data_from_global
719 * Returns global data in an HGLOBAL.
721 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
723 HGLOBAL h;
724 HRESULT hr;
725 FORMATETC mem_fmt;
726 STGMEDIUM med;
728 *mem = NULL;
730 mem_fmt = *fmt;
731 mem_fmt.tymed = TYMED_HGLOBAL;
733 hr = IDataObject_GetData(data, &mem_fmt, &med);
734 if(FAILED(hr)) return hr;
736 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
738 if(SUCCEEDED(hr)) *mem = h;
740 ReleaseStgMedium(&med);
742 return hr;
745 /***********************************************************************
746 * render_format
748 * Render the clipboard data. Note that this call will delegate to the
749 * source data object.
751 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
753 HGLOBAL clip_data = NULL;
754 HRESULT hr;
756 /* Embed source hack */
757 if(fmt->cfFormat == embed_source_clipboard_format)
759 return render_embed_source_hack(data, fmt);
762 if(fmt->tymed & TYMED_ISTORAGE)
764 hr = get_data_from_storage(data, fmt, &clip_data);
766 else if(fmt->tymed & TYMED_ISTREAM)
768 hr = get_data_from_stream(data, fmt, &clip_data);
770 else if(fmt->tymed & TYMED_HGLOBAL)
772 hr = get_data_from_global(data, fmt, &clip_data);
774 else
776 FIXME("Unhandled tymed %x\n", fmt->tymed);
777 hr = DV_E_FORMATETC;
780 if(SUCCEEDED(hr))
782 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
784 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
785 GlobalFree(clip_data);
786 hr = CLIPBRD_E_CANT_SET;
790 return hr;
793 /*---------------------------------------------------------------------*
794 * Implementation of the internal IDataObject interface exposed by
795 * the OLE clipboard.
796 *---------------------------------------------------------------------*/
799 /************************************************************************
800 * snapshot_QueryInterface
802 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
803 REFIID riid, void **ppvObject)
805 snapshot *This = impl_from_IDataObject(iface);
806 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
808 if ( (This==0) || (ppvObject==0) )
809 return E_INVALIDARG;
811 *ppvObject = 0;
813 if (IsEqualIID(&IID_IUnknown, riid) ||
814 IsEqualIID(&IID_IDataObject, riid))
816 *ppvObject = iface;
818 else
820 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
821 return E_NOINTERFACE;
824 IUnknown_AddRef((IUnknown*)*ppvObject);
826 return S_OK;
829 /************************************************************************
830 * snapshot_AddRef
832 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
834 snapshot *This = impl_from_IDataObject(iface);
836 TRACE("(%p)->(count=%u)\n", This, This->ref);
838 return InterlockedIncrement(&This->ref);
841 /************************************************************************
842 * snapshot_Release
844 static ULONG WINAPI snapshot_Release(IDataObject *iface)
846 snapshot *This = impl_from_IDataObject(iface);
847 ULONG ref;
849 TRACE("(%p)->(count=%u)\n", This, This->ref);
851 ref = InterlockedDecrement(&This->ref);
853 if (ref == 0)
855 ole_clipbrd *clipbrd;
856 HRESULT hr = get_ole_clipbrd(&clipbrd);
858 if(This->data) IDataObject_Release(This->data);
860 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
861 clipbrd->latest_snapshot = NULL;
862 HeapFree(GetProcessHeap(), 0, This);
865 return ref;
868 /************************************************************
869 * get_current_ole_clip_window
871 * Return the window that owns the ole clipboard.
873 * If the clipboard is flushed or not owned by ole this will
874 * return NULL.
876 static HWND get_current_ole_clip_window(void)
878 HGLOBAL h;
879 HWND *ptr, wnd;
881 h = GetClipboardData(dataobject_clipboard_format);
882 if(!h) return NULL;
883 ptr = GlobalLock(h);
884 if(!ptr) return NULL;
885 wnd = *ptr;
886 GlobalUnlock(h);
887 return wnd;
890 /************************************************************
891 * get_current_dataobject
893 * Return an unmarshalled IDataObject if there is a current
894 * (ie non-flushed) object on the ole clipboard.
896 static HRESULT get_current_dataobject(IDataObject **data)
898 HRESULT hr = S_FALSE;
899 HWND wnd = get_current_ole_clip_window();
900 HGLOBAL h;
901 void *ptr;
902 IStream *stm;
903 LARGE_INTEGER pos;
905 *data = NULL;
906 if(!wnd) return S_FALSE;
908 h = GetPropW(wnd, wine_marshal_dataobject);
909 if(!h) return S_FALSE;
910 ptr = GlobalLock(h);
911 if(!ptr) return S_FALSE;
913 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
914 if(FAILED(hr)) goto end;
916 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
917 if(SUCCEEDED(hr))
919 pos.QuadPart = 0;
920 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
921 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
923 IStream_Release(stm);
925 end:
926 GlobalUnlock(h);
927 return hr;
930 static DWORD get_tymed_from_nonole_cf(UINT cf)
932 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
934 switch(cf)
936 case CF_TEXT:
937 case CF_OEMTEXT:
938 case CF_UNICODETEXT:
939 return TYMED_ISTREAM | TYMED_HGLOBAL;
940 case CF_ENHMETAFILE:
941 return TYMED_ENHMF;
942 case CF_METAFILEPICT:
943 return TYMED_MFPICT;
944 default:
945 FIXME("returning TYMED_NULL for cf %04x\n", cf);
946 return TYMED_NULL;
950 /***********************************************************
951 * get_priv_data
953 * Returns a copy of the Ole Private Data
955 static HRESULT get_priv_data(ole_priv_data **data)
957 HGLOBAL handle;
958 HRESULT hr = S_OK;
959 ole_priv_data *ret = NULL;
961 *data = NULL;
963 handle = GetClipboardData( ole_private_data_clipboard_format );
964 if(handle)
966 ole_priv_data *src = GlobalLock(handle);
967 if(src)
969 DWORD i;
971 /* FIXME: sanity check on size */
972 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
973 if(!ret)
975 GlobalUnlock(handle);
976 return E_OUTOFMEMORY;
978 memcpy(ret, src, src->size);
979 GlobalUnlock(handle);
981 /* Fixup any target device offsets to ptrs */
982 for(i = 0; i < ret->count; i++)
983 ret->entries[i].fmtetc.ptd =
984 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
988 if(!ret) /* Non-ole data */
990 UINT cf;
991 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
993 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
995 char buf[100];
996 GetClipboardFormatNameA(cf, buf, sizeof(buf));
997 TRACE("\tcf %04x %s\n", cf, buf);
1000 TRACE("count %d\n", count);
1001 size += count * sizeof(ret->entries[0]);
1003 /* There are holes in fmtetc so zero init */
1004 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1005 if(!ret) return E_OUTOFMEMORY;
1006 ret->size = size;
1007 ret->count = count;
1009 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1011 ret->entries[idx].fmtetc.cfFormat = cf;
1012 ret->entries[idx].fmtetc.ptd = NULL;
1013 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1014 ret->entries[idx].fmtetc.lindex = -1;
1015 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1016 ret->entries[idx].first_use = 1;
1020 *data = ret;
1021 return hr;
1024 /************************************************************************
1025 * get_stgmed_for_global
1027 * Returns a stg medium with a copy of the global handle
1029 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1031 HRESULT hr;
1033 med->pUnkForRelease = NULL;
1034 med->tymed = TYMED_NULL;
1036 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1038 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1040 return hr;
1043 /************************************************************************
1044 * get_stgmed_for_stream
1046 * Returns a stg medium with a stream based on the handle
1048 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1050 HRESULT hr;
1051 HGLOBAL dst;
1053 med->pUnkForRelease = NULL;
1054 med->tymed = TYMED_NULL;
1056 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1057 if(FAILED(hr)) return hr;
1059 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1060 if(FAILED(hr))
1062 GlobalFree(dst);
1063 return hr;
1066 med->tymed = TYMED_ISTREAM;
1067 return hr;
1070 /************************************************************************
1071 * get_stgmed_for_storage
1073 * Returns a stg medium with a storage based on the handle
1075 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1077 HRESULT hr;
1078 HGLOBAL dst;
1079 ILockBytes *lbs;
1081 med->pUnkForRelease = NULL;
1082 med->tymed = TYMED_NULL;
1084 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1085 if(FAILED(hr)) return hr;
1087 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1088 if(FAILED(hr))
1090 GlobalFree(dst);
1091 return hr;
1094 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1095 ILockBytes_Release(lbs);
1096 if(FAILED(hr))
1098 GlobalFree(dst);
1099 return hr;
1102 med->tymed = TYMED_ISTORAGE;
1103 return hr;
1106 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1108 const WCHAR *str1, *str2;
1110 if(off1 == 0 && off2 == 0) return TRUE;
1111 if(off1 == 0 || off2 == 0) return FALSE;
1113 str1 = (const WCHAR*)((const char*)t1 + off1);
1114 str2 = (const WCHAR*)((const char*)t2 + off2);
1116 return !lstrcmpW(str1, str2);
1119 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1121 if(t1 == NULL && t2 == NULL) return TRUE;
1122 if(t1 == NULL || t2 == NULL) return FALSE;
1124 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1125 return FALSE;
1126 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1127 return FALSE;
1128 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1129 return FALSE;
1131 /* FIXME check devmode? */
1133 return TRUE;
1136 /************************************************************************
1137 * snapshot_GetData
1139 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1140 STGMEDIUM *med)
1142 snapshot *This = impl_from_IDataObject(iface);
1143 HANDLE h;
1144 HRESULT hr;
1145 ole_priv_data *enum_data = NULL;
1146 ole_priv_data_entry *entry;
1147 DWORD mask;
1149 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1151 if ( !fmt || !med ) return E_INVALIDARG;
1153 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1155 if(!This->data)
1156 hr = get_current_dataobject(&This->data);
1158 if(This->data)
1160 hr = IDataObject_GetData(This->data, fmt, med);
1161 CloseClipboard();
1162 return hr;
1165 h = GetClipboardData(fmt->cfFormat);
1166 if(!h)
1168 hr = DV_E_FORMATETC;
1169 goto end;
1172 hr = get_priv_data(&enum_data);
1173 if(FAILED(hr)) goto end;
1175 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1176 if(entry)
1178 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1180 hr = DV_E_FORMATETC;
1181 goto end;
1183 mask = fmt->tymed & entry->fmtetc.tymed;
1184 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1186 else /* non-Ole format */
1187 mask = fmt->tymed & TYMED_HGLOBAL;
1189 if(mask & TYMED_ISTORAGE)
1190 hr = get_stgmed_for_storage(h, med);
1191 else if(mask & TYMED_HGLOBAL)
1192 hr = get_stgmed_for_global(h, med);
1193 else if(mask & TYMED_ISTREAM)
1194 hr = get_stgmed_for_stream(h, med);
1195 else
1197 FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed);
1198 hr = E_FAIL;
1199 goto end;
1202 end:
1203 HeapFree(GetProcessHeap(), 0, enum_data);
1204 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1205 return hr;
1208 /************************************************************************
1209 * snapshot_GetDataHere
1211 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1212 STGMEDIUM *med)
1214 FIXME("(%p, %p {%s}, %p): stub\n", iface, fmt, dump_fmtetc(fmt), med);
1215 return E_NOTIMPL;
1218 /************************************************************************
1219 * snapshot_QueryGetData
1221 * The OLE Clipboard's implementation of this method delegates to
1222 * a data source if there is one or wraps around the windows clipboard
1223 * function IsClipboardFormatAvailable() otherwise.
1226 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1228 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1230 if (!fmt) return E_INVALIDARG;
1232 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1234 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1236 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1239 /************************************************************************
1240 * snapshot_GetCanonicalFormatEtc
1242 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1243 FORMATETC *fmt_out)
1245 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1247 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1249 *fmt_out = *fmt_in;
1250 return DATA_S_SAMEFORMATETC;
1253 /************************************************************************
1254 * snapshot_SetData
1256 * The OLE Clipboard does not implement this method
1258 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1259 STGMEDIUM *med, BOOL release)
1261 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1262 return E_NOTIMPL;
1265 /************************************************************************
1266 * snapshot_EnumFormatEtc
1269 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1270 IEnumFORMATETC **enum_fmt)
1272 HRESULT hr;
1273 ole_priv_data *data = NULL;
1275 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1277 *enum_fmt = NULL;
1279 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1280 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1282 hr = get_priv_data(&data);
1284 if(FAILED(hr)) goto end;
1286 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1288 end:
1289 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1290 return hr;
1293 /************************************************************************
1294 * snapshot_DAdvise
1296 * The OLE Clipboard does not implement this method
1298 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1299 DWORD flags, IAdviseSink *sink,
1300 DWORD *conn)
1302 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1303 return E_NOTIMPL;
1306 /************************************************************************
1307 * snapshot_DUnadvise
1309 * The OLE Clipboard does not implement this method
1311 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1313 TRACE("(%p, %d): not implemented\n", iface, conn);
1314 return E_NOTIMPL;
1317 /************************************************************************
1318 * snapshot_EnumDAdvise
1320 * The OLE Clipboard does not implement this method
1322 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1323 IEnumSTATDATA** enum_advise)
1325 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1326 return E_NOTIMPL;
1329 static const IDataObjectVtbl snapshot_vtable =
1331 snapshot_QueryInterface,
1332 snapshot_AddRef,
1333 snapshot_Release,
1334 snapshot_GetData,
1335 snapshot_GetDataHere,
1336 snapshot_QueryGetData,
1337 snapshot_GetCanonicalFormatEtc,
1338 snapshot_SetData,
1339 snapshot_EnumFormatEtc,
1340 snapshot_DAdvise,
1341 snapshot_DUnadvise,
1342 snapshot_EnumDAdvise
1345 /*---------------------------------------------------------------------*
1346 * Internal implementation methods for the OLE clipboard
1347 *---------------------------------------------------------------------*/
1349 static snapshot *snapshot_construct(DWORD seq_no)
1351 snapshot *This;
1353 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1354 if (!This) return NULL;
1356 This->lpVtbl = &snapshot_vtable;
1357 This->ref = 0;
1358 This->seq_no = seq_no;
1359 This->data = NULL;
1361 return This;
1364 /*********************************************************
1365 * register_clipboard_formats
1367 static void register_clipboard_formats(void)
1369 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1370 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1371 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1372 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1373 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1374 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1375 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1376 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1377 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1378 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1379 'D','e','s','c','r','i','p','t','o','r',0};
1380 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1382 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1383 filename_clipboard_format = RegisterClipboardFormatW(FileName);
1384 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1385 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1386 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1387 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1388 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1389 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1390 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1391 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1392 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1395 /***********************************************************************
1396 * OLEClipbrd_Initialize()
1397 * Initializes the OLE clipboard.
1399 void OLEClipbrd_Initialize(void)
1401 register_clipboard_formats();
1403 if ( !theOleClipboard )
1405 ole_clipbrd* clipbrd;
1406 HGLOBAL h;
1408 TRACE("()\n");
1410 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1411 if (!clipbrd) return;
1413 clipbrd->latest_snapshot = NULL;
1414 clipbrd->window = NULL;
1415 clipbrd->src_data = NULL;
1416 clipbrd->cached_enum = NULL;
1418 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1419 if(!h)
1421 HeapFree(GetProcessHeap(), 0, clipbrd);
1422 return;
1425 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1427 GlobalFree(h);
1428 HeapFree(GetProcessHeap(), 0, clipbrd);
1429 return;
1432 theOleClipboard = clipbrd;
1436 /***********************************************************************
1437 * OLEClipbrd_UnInitialize()
1438 * Un-Initializes the OLE clipboard
1440 void OLEClipbrd_UnInitialize(void)
1442 ole_clipbrd *clipbrd = theOleClipboard;
1444 TRACE("()\n");
1446 if ( clipbrd )
1448 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1449 HINSTANCE hinst = GetModuleHandleW(ole32W);
1451 if ( clipbrd->window )
1453 DestroyWindow(clipbrd->window);
1454 UnregisterClassW( clipbrd_wndclass, hinst );
1457 IStream_Release(clipbrd->marshal_data);
1458 HeapFree(GetProcessHeap(), 0, clipbrd);
1459 theOleClipboard = NULL;
1463 /*********************************************************************
1464 * set_clipboard_formats
1466 * Enumerate all formats supported by the source and make
1467 * those formats available using delayed rendering using SetClipboardData.
1468 * Cache the enumeration list and make that list visibile as the
1469 * 'Ole Private Data' format on the clipboard.
1472 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1474 HRESULT hr;
1475 FORMATETC fmt;
1476 IEnumFORMATETC *enum_fmt;
1477 HGLOBAL priv_data_handle;
1478 DWORD_PTR target_offset;
1479 ole_priv_data *priv_data;
1480 DWORD count = 0, needed = sizeof(*priv_data), idx;
1482 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1483 if(FAILED(hr)) return hr;
1485 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1487 count++;
1488 needed += sizeof(priv_data->entries[0]);
1489 if(fmt.ptd)
1491 needed += fmt.ptd->tdSize;
1492 CoTaskMemFree(fmt.ptd);
1496 /* Windows pads the list with two empty ole_priv_data_entries, one
1497 * after the entries array and one after the target device data.
1498 * Allocating with zero init to zero these pads. */
1500 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1501 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1502 priv_data = GlobalLock(priv_data_handle);
1504 priv_data->unk1 = 0;
1505 priv_data->size = needed;
1506 priv_data->unk2 = 1;
1507 priv_data->count = count;
1508 priv_data->unk3[0] = 0;
1509 priv_data->unk3[1] = 0;
1511 IEnumFORMATETC_Reset(enum_fmt);
1513 idx = 0;
1514 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1516 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1518 TRACE("%s\n", dump_fmtetc(&fmt));
1520 priv_data->entries[idx].fmtetc = fmt;
1521 if(fmt.ptd)
1523 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1524 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1525 target_offset += fmt.ptd->tdSize;
1526 CoTaskMemFree(fmt.ptd);
1529 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1530 priv_data->entries[idx].unk[0] = 0;
1531 priv_data->entries[idx].unk[1] = 0;
1533 if (priv_data->entries[idx].first_use)
1534 SetClipboardData(fmt.cfFormat, NULL);
1536 idx++;
1539 IEnumFORMATETC_Release(enum_fmt);
1541 /* Cache the list and fixup any target device offsets to ptrs */
1542 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1543 memcpy(clipbrd->cached_enum, priv_data, needed);
1544 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1545 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1546 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1548 GlobalUnlock(priv_data_handle);
1549 SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1551 return S_OK;
1554 static HWND create_clipbrd_window(void);
1556 /***********************************************************************
1557 * get_clipbrd_window
1559 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1561 if ( !clipbrd->window )
1562 clipbrd->window = create_clipbrd_window();
1564 *wnd = clipbrd->window;
1565 return *wnd ? S_OK : E_FAIL;
1569 /**********************************************************************
1570 * release_marshal_data
1572 * Releases the data and sets the stream back to zero size.
1574 static inline void release_marshal_data(IStream *stm)
1576 LARGE_INTEGER pos;
1577 ULARGE_INTEGER size;
1578 pos.QuadPart = size.QuadPart = 0;
1580 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1581 CoReleaseMarshalData(stm);
1582 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1583 IStream_SetSize(stm, size);
1586 /***********************************************************************
1587 * set_src_dataobject
1589 * Clears and sets the clipboard's src IDataObject.
1591 * To marshal the source dataobject we do something rather different from Windows.
1592 * We set a window prop which contains the marshalled data.
1593 * Windows set two props one of which is an IID, the other is an endpoint number.
1595 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1597 HRESULT hr;
1598 HWND wnd;
1600 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1602 if(clipbrd->src_data)
1604 RemovePropW(wnd, wine_marshal_dataobject);
1605 release_marshal_data(clipbrd->marshal_data);
1607 IDataObject_Release(clipbrd->src_data);
1608 clipbrd->src_data = NULL;
1609 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1610 clipbrd->cached_enum = NULL;
1613 if(data)
1615 HGLOBAL h;
1616 IUnknown *unk;
1618 IDataObject_AddRef(data);
1619 clipbrd->src_data = data;
1621 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1622 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1623 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1624 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1625 if(FAILED(hr)) return hr;
1626 GetHGlobalFromStream(clipbrd->marshal_data, &h);
1627 SetPropW(wnd, wine_marshal_dataobject, h);
1628 hr = set_clipboard_formats(clipbrd, data);
1630 return hr;
1633 /***********************************************************************
1634 * clipbrd_wndproc
1636 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1638 ole_clipbrd *clipbrd;
1640 get_ole_clipbrd(&clipbrd);
1642 switch (message)
1644 case WM_RENDERFORMAT:
1646 UINT cf = wparam;
1647 ole_priv_data_entry *entry;
1649 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1650 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1652 if(entry)
1653 render_format(clipbrd->src_data, &entry->fmtetc);
1655 break;
1658 case WM_RENDERALLFORMATS:
1660 DWORD i;
1661 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1663 TRACE("(): WM_RENDERALLFORMATS\n");
1665 for(i = 0; i < clipbrd->cached_enum->count; i++)
1667 if(entries[i].first_use)
1668 render_format(clipbrd->src_data, &entries[i].fmtetc);
1670 break;
1673 case WM_DESTROYCLIPBOARD:
1675 TRACE("(): WM_DESTROYCLIPBOARD\n");
1677 set_src_dataobject(clipbrd, NULL);
1678 break;
1681 default:
1682 return DefWindowProcW(hwnd, message, wparam, lparam);
1685 return 0;
1689 /***********************************************************************
1690 * create_clipbrd_window
1692 static HWND create_clipbrd_window(void)
1694 WNDCLASSEXW class;
1695 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1696 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1697 HINSTANCE hinst = GetModuleHandleW(ole32W);
1699 class.cbSize = sizeof(class);
1700 class.style = 0;
1701 class.lpfnWndProc = clipbrd_wndproc;
1702 class.cbClsExtra = 0;
1703 class.cbWndExtra = 0;
1704 class.hInstance = hinst;
1705 class.hIcon = 0;
1706 class.hCursor = 0;
1707 class.hbrBackground = 0;
1708 class.lpszMenuName = NULL;
1709 class.lpszClassName = clipbrd_wndclass;
1710 class.hIconSm = NULL;
1712 RegisterClassExW(&class);
1714 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1715 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1716 NULL, NULL, hinst, 0);
1719 /*********************************************************************
1720 * set_dataobject_format
1722 * Windows creates a 'DataObject' clipboard format that contains the
1723 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1725 static HRESULT set_dataobject_format(HWND hwnd)
1727 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1728 HWND *data;
1730 if(!h) return E_OUTOFMEMORY;
1732 data = GlobalLock(h);
1733 *data = hwnd;
1734 GlobalUnlock(h);
1736 if(!SetClipboardData(dataobject_clipboard_format, h))
1738 GlobalFree(h);
1739 return CLIPBRD_E_CANT_SET;
1742 return S_OK;
1745 /*---------------------------------------------------------------------*
1746 * Win32 OLE clipboard API
1747 *---------------------------------------------------------------------*/
1749 /***********************************************************************
1750 * OleSetClipboard [OLE32.@]
1751 * Places a pointer to the specified data object onto the clipboard,
1752 * making the data object accessible to the OleGetClipboard function.
1754 * RETURNS
1756 * S_OK IDataObject pointer placed on the clipboard
1757 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1758 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1759 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1760 * CLIPBRD_E_CANT_SET SetClipboard failed
1763 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1765 HRESULT hr;
1766 ole_clipbrd *clipbrd;
1767 HWND wnd;
1769 TRACE("(%p)\n", data);
1771 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1773 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1775 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1777 if ( !EmptyClipboard() )
1779 hr = CLIPBRD_E_CANT_EMPTY;
1780 goto end;
1783 hr = set_src_dataobject(clipbrd, data);
1784 if(FAILED(hr)) goto end;
1786 if(data)
1787 hr = set_dataobject_format(wnd);
1789 end:
1791 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1793 if ( FAILED(hr) )
1795 set_src_dataobject(clipbrd, NULL);
1798 return hr;
1802 /***********************************************************************
1803 * OleGetClipboard [OLE32.@]
1804 * Returns a pointer to our internal IDataObject which represents the conceptual
1805 * state of the Windows clipboard. If the current clipboard already contains
1806 * an IDataObject, our internal IDataObject will delegate to this object.
1808 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1810 HRESULT hr;
1811 ole_clipbrd *clipbrd;
1812 DWORD seq_no;
1814 TRACE("(%p)\n", obj);
1816 if(!obj) return E_INVALIDARG;
1818 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1820 seq_no = GetClipboardSequenceNumber();
1821 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1822 clipbrd->latest_snapshot = NULL;
1824 if(!clipbrd->latest_snapshot)
1826 clipbrd->latest_snapshot = snapshot_construct(seq_no);
1827 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1830 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1831 IDataObject_AddRef(*obj);
1833 return S_OK;
1836 /******************************************************************************
1837 * OleFlushClipboard [OLE32.@]
1838 * Renders the data from the source IDataObject into the windows clipboard
1840 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1841 * by copying the storage into global memory. Subsequently the default
1842 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1843 * back to TYMED_IStorage.
1845 HRESULT WINAPI OleFlushClipboard(void)
1847 HRESULT hr;
1848 ole_clipbrd *clipbrd;
1849 HWND wnd;
1851 TRACE("()\n");
1853 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1855 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1858 * Already flushed or no source DataObject? Nothing to do.
1860 if (!clipbrd->src_data) return S_OK;
1862 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1864 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1866 hr = set_dataobject_format(NULL);
1868 set_src_dataobject(clipbrd, NULL);
1870 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1872 return hr;
1876 /***********************************************************************
1877 * OleIsCurrentClipboard [OLE32.@]
1879 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1881 HRESULT hr;
1882 ole_clipbrd *clipbrd;
1883 TRACE("()\n");
1885 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1887 if (data == NULL) return S_FALSE;
1889 return (data == clipbrd->src_data) ? S_OK : S_FALSE;