ole32: Add a helper function to return the ole clipboard structure.
[wine/hacks.git] / dlls / ole32 / clipboard.c
blob2c39e4554da58ba3dd26136f23176c39f2e41a6d
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 * create_empty_priv_data
110 * Create an empty data structure. The only thing that really matters
111 * here is setting count and size members. This is used by the enumerator as a
112 * convenience when there's an empty list.
114 static HRESULT create_empty_priv_data(ole_priv_data **data)
116 ole_priv_data *ptr;
118 *data = NULL;
119 ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr));
120 if(!ptr) return E_OUTOFMEMORY;
121 ptr->size = sizeof(*ptr);
122 ptr->count = 0;
123 *data = ptr;
124 return S_OK;
128 /****************************************************************************
129 * ole_clipbrd
131 typedef struct ole_clipbrd
133 const IDataObjectVtbl* lpvtbl; /* Exposed IDataObject vtable */
135 LONG ref;
137 HWND hWndClipboard; /* Hidden clipboard window */
138 IDataObject *pIDataObjectSrc; /* Source object passed to OleSetClipboard */
139 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */
140 } ole_clipbrd;
142 static inline ole_clipbrd *impl_from_IDataObject(IDataObject *iface)
144 return (ole_clipbrd*)((char*)iface - FIELD_OFFSET(ole_clipbrd, lpvtbl));
147 typedef struct PresentationDataHeader
149 BYTE unknown1[28];
150 DWORD dwObjectExtentX;
151 DWORD dwObjectExtentY;
152 DWORD dwSize;
153 } PresentationDataHeader;
156 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
158 static ole_clipbrd* theOleClipboard;
160 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
162 struct oletls *info = COM_CurrentInfo();
163 *clipbrd = NULL;
165 if(!info->ole_inits)
166 return CO_E_NOTINITIALIZED;
167 *clipbrd = theOleClipboard;
169 return S_OK;
173 * Name of our registered OLE clipboard window class
175 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
177 static UINT dataobject_clipboard_format;
178 static UINT ole_priv_data_clipboard_format;
179 static UINT embed_source_clipboard_format;
181 static inline char *dump_fmtetc(FORMATETC *fmt)
183 static char buf[100];
185 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
186 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
187 return buf;
190 /*---------------------------------------------------------------------*
191 * Implementation of the internal IEnumFORMATETC interface returned by
192 * the OLE clipboard's IDataObject.
193 *---------------------------------------------------------------------*/
195 typedef struct enum_fmtetc
197 const IEnumFORMATETCVtbl *lpVtbl;
198 LONG ref;
200 UINT pos; /* current enumerator position */
201 ole_priv_data *data;
202 } enum_fmtetc;
204 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
206 return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
209 /************************************************************************
210 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
212 * See Windows documentation for more details on IUnknown methods.
214 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
215 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
217 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
219 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
221 *ppvObj = NULL;
223 if(IsEqualIID(riid, &IID_IUnknown) ||
224 IsEqualIID(riid, &IID_IEnumFORMATETC))
226 *ppvObj = iface;
229 if(*ppvObj)
231 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
232 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
233 return S_OK;
236 TRACE("-- Interface: E_NOINTERFACE\n");
237 return E_NOINTERFACE;
240 /************************************************************************
241 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
244 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
246 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
247 TRACE("(%p)->(count=%u)\n",This, This->ref);
249 return InterlockedIncrement(&This->ref);
252 /************************************************************************
253 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
255 * See Windows documentation for more details on IUnknown methods.
257 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
259 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
260 ULONG ref;
262 TRACE("(%p)->(count=%u)\n",This, This->ref);
264 ref = InterlockedDecrement(&This->ref);
265 if (!ref)
267 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
268 HeapFree(GetProcessHeap(), 0, This->data);
269 HeapFree(GetProcessHeap(), 0, This);
271 return ref;
274 /************************************************************************
275 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
277 * Standard enumerator members for IEnumFORMATETC
279 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
280 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
282 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
283 UINT cfetch, i;
284 HRESULT hres = S_FALSE;
286 TRACE("(%p)->(pos=%u)\n", This, This->pos);
288 if (This->pos < This->data->count)
290 cfetch = This->data->count - This->pos;
291 if (cfetch >= celt)
293 cfetch = celt;
294 hres = S_OK;
297 for(i = 0; i < cfetch; i++)
299 rgelt[i] = This->data->entries[This->pos++].fmtetc;
300 if(rgelt[i].ptd)
302 DVTARGETDEVICE *target = (DVTARGETDEVICE *)((char *)This->data + (DWORD)rgelt[i].ptd);
303 rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
304 if(!rgelt[i].ptd) return E_OUTOFMEMORY;
305 memcpy(rgelt[i].ptd, target, target->tdSize);
309 else
311 cfetch = 0;
314 if (pceltFethed)
316 *pceltFethed = cfetch;
319 return hres;
322 /************************************************************************
323 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
325 * Standard enumerator members for IEnumFORMATETC
327 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
329 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
330 TRACE("(%p)->(num=%u)\n", This, celt);
332 This->pos += celt;
333 if (This->pos > This->data->count)
335 This->pos = This->data->count;
336 return S_FALSE;
338 return S_OK;
341 /************************************************************************
342 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
344 * Standard enumerator members for IEnumFORMATETC
346 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
348 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
349 TRACE("(%p)->()\n", This);
351 This->pos = 0;
352 return S_OK;
355 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
357 /************************************************************************
358 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
360 * Standard enumerator members for IEnumFORMATETC
362 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
363 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
365 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
366 ole_priv_data *new_data;
368 TRACE("(%p)->(%p)\n", This, obj);
370 if ( !obj ) return E_INVALIDARG;
371 *obj = NULL;
373 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
374 if(!new_data) return E_OUTOFMEMORY;
376 return enum_fmtetc_construct(new_data, This->pos, obj);
379 static const IEnumFORMATETCVtbl efvt =
381 OLEClipbrd_IEnumFORMATETC_QueryInterface,
382 OLEClipbrd_IEnumFORMATETC_AddRef,
383 OLEClipbrd_IEnumFORMATETC_Release,
384 OLEClipbrd_IEnumFORMATETC_Next,
385 OLEClipbrd_IEnumFORMATETC_Skip,
386 OLEClipbrd_IEnumFORMATETC_Reset,
387 OLEClipbrd_IEnumFORMATETC_Clone
390 /************************************************************************
391 * enum_fmtetc_construct
393 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
395 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
397 enum_fmtetc* ef;
399 *obj = NULL;
400 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
401 if (!ef) return E_OUTOFMEMORY;
403 ef->ref = 1;
404 ef->lpVtbl = &efvt;
405 ef->data = data;
406 ef->pos = pos;
408 TRACE("(%p)->()\n", ef);
409 *obj = (IEnumFORMATETC *)ef;
410 return S_OK;
413 /***********************************************************************
414 * dup_global_mem
416 * Helper method to duplicate an HGLOBAL chunk of memory
418 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
420 void *src_ptr, *dst_ptr;
421 DWORD size;
423 *dst = NULL;
424 if ( !src ) return S_FALSE;
426 size = GlobalSize(src);
428 *dst = GlobalAlloc( flags, size );
429 if ( !*dst ) return E_OUTOFMEMORY;
431 src_ptr = GlobalLock(src);
432 dst_ptr = GlobalLock(*dst);
434 memcpy(dst_ptr, src_ptr, size);
436 GlobalUnlock(*dst);
437 GlobalUnlock(src);
439 return S_OK;
442 /************************************************************
443 * render_embed_source_hack
445 * This is clearly a hack and has no place in the clipboard code.
448 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
450 STGMEDIUM std;
451 HGLOBAL hStorage = 0;
452 HRESULT hr = S_OK;
453 ILockBytes *ptrILockBytes;
455 memset(&std, 0, sizeof(STGMEDIUM));
456 std.tymed = fmt->tymed = TYMED_ISTORAGE;
458 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
459 if (hStorage == NULL) return E_OUTOFMEMORY;
460 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
461 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
462 ILockBytes_Release(ptrILockBytes);
464 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, fmt, &std)))
466 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
467 GlobalFree(hStorage);
468 return hr;
471 if (1) /* check whether the presentation data is already -not- present */
473 FORMATETC fmt2;
474 STGMEDIUM std2;
475 METAFILEPICT *mfp = 0;
477 fmt2.cfFormat = CF_METAFILEPICT;
478 fmt2.ptd = 0;
479 fmt2.dwAspect = DVASPECT_CONTENT;
480 fmt2.lindex = -1;
481 fmt2.tymed = TYMED_MFPICT;
483 memset(&std2, 0, sizeof(STGMEDIUM));
484 std2.tymed = TYMED_MFPICT;
486 /* Get the metafile picture out of it */
488 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
490 mfp = GlobalLock(std2.u.hGlobal);
493 if (mfp)
495 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
496 IStream *pStream = 0;
497 void *mfBits;
498 PresentationDataHeader pdh;
499 INT nSize;
500 CLSID clsID;
501 LPOLESTR strProgID;
502 CHAR strOleTypeName[51];
503 BYTE OlePresStreamHeader [] =
505 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
506 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
507 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
508 0x00, 0x00, 0x00, 0x00
511 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
513 memset(&pdh, 0, sizeof(PresentationDataHeader));
514 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
516 pdh.dwObjectExtentX = mfp->xExt;
517 pdh.dwObjectExtentY = mfp->yExt;
518 pdh.dwSize = nSize;
520 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
522 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
524 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
525 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
527 hr = IStream_Write(pStream, mfBits, nSize, NULL);
529 IStream_Release(pStream);
531 HeapFree(GetProcessHeap(), 0, mfBits);
533 GlobalUnlock(std2.u.hGlobal);
534 ReleaseStgMedium(&std2);
536 ReadClassStg(std.u.pstg, &clsID);
537 ProgIDFromCLSID(&clsID, &strProgID);
539 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
540 OLECONVERT_CreateOleStream(std.u.pstg);
541 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
545 if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
547 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
548 GlobalFree(hStorage);
549 hr = CLIPBRD_E_CANT_SET;
552 ReleaseStgMedium(&std);
553 return hr;
556 /************************************************************************
557 * find_format_in_list
559 * Returns the first entry that matches the provided clipboard format.
561 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
563 DWORD i;
564 for(i = 0; i < num; i++)
565 if(entries[i].fmtetc.cfFormat == cf)
566 return &entries[i];
568 return NULL;
571 /***************************************************************************
572 * get_data_from_storage
574 * Returns storage data in an HGLOBAL.
576 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
578 HGLOBAL h;
579 IStorage *stg;
580 HRESULT hr;
581 FORMATETC stg_fmt;
582 STGMEDIUM med;
583 ILockBytes *lbs;
585 *mem = NULL;
587 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
588 if(!h) return E_OUTOFMEMORY;
590 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
591 if(SUCCEEDED(hr))
593 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
594 ILockBytes_Release(lbs);
596 if(FAILED(hr))
598 GlobalFree(h);
599 return hr;
602 stg_fmt = *fmt;
603 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
604 med.u.pstg = stg;
605 med.pUnkForRelease = NULL;
607 hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
608 if(FAILED(hr))
610 med.u.pstg = NULL;
611 hr = IDataObject_GetData(data, &stg_fmt, &med);
612 if(FAILED(hr)) goto end;
614 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
615 ReleaseStgMedium(&med);
616 if(FAILED(hr)) goto end;
618 *mem = h;
620 end:
621 IStorage_Release(stg);
622 if(FAILED(hr)) GlobalFree(h);
623 return hr;
626 /***************************************************************************
627 * get_data_from_stream
629 * Returns stream data in an HGLOBAL.
631 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
633 HGLOBAL h;
634 IStream *stm = NULL;
635 HRESULT hr;
636 FORMATETC stm_fmt;
637 STGMEDIUM med;
639 *mem = NULL;
641 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
642 if(!h) return E_OUTOFMEMORY;
644 hr = CreateStreamOnHGlobal(h, FALSE, &stm);
645 if(FAILED(hr)) goto error;
647 stm_fmt = *fmt;
648 med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
649 med.u.pstm = stm;
650 med.pUnkForRelease = NULL;
652 hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
653 if(FAILED(hr))
655 LARGE_INTEGER offs;
656 ULARGE_INTEGER pos;
658 med.u.pstm = NULL;
659 hr = IDataObject_GetData(data, &stm_fmt, &med);
660 if(FAILED(hr)) goto error;
662 offs.QuadPart = 0;
663 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
664 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
665 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
666 ReleaseStgMedium(&med);
667 if(FAILED(hr)) goto error;
669 *mem = h;
670 IStream_Release(stm);
671 return S_OK;
673 error:
674 if(stm) IStream_Release(stm);
675 GlobalFree(h);
676 return hr;
679 /***************************************************************************
680 * get_data_from_global
682 * Returns global data in an HGLOBAL.
684 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
686 HGLOBAL h;
687 HRESULT hr;
688 FORMATETC mem_fmt;
689 STGMEDIUM med;
691 *mem = NULL;
693 mem_fmt = *fmt;
694 mem_fmt.tymed = TYMED_HGLOBAL;
696 hr = IDataObject_GetData(data, &mem_fmt, &med);
697 if(FAILED(hr)) return hr;
699 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
701 if(SUCCEEDED(hr)) *mem = h;
703 ReleaseStgMedium(&med);
705 return hr;
708 /***********************************************************************
709 * render_format
711 * Render the clipboard data. Note that this call will delegate to the
712 * source data object.
714 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
716 HGLOBAL clip_data = NULL;
717 HRESULT hr;
719 /* Embed source hack */
720 if(fmt->cfFormat == embed_source_clipboard_format)
722 return render_embed_source_hack(data, fmt);
725 if(fmt->tymed & TYMED_ISTORAGE)
727 hr = get_data_from_storage(data, fmt, &clip_data);
729 else if(fmt->tymed & TYMED_ISTREAM)
731 hr = get_data_from_stream(data, fmt, &clip_data);
733 else if(fmt->tymed & TYMED_HGLOBAL)
735 hr = get_data_from_global(data, fmt, &clip_data);
737 else
739 FIXME("Unhandled tymed %x\n", fmt->tymed);
740 hr = DV_E_FORMATETC;
743 if(SUCCEEDED(hr))
745 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
747 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
748 GlobalFree(clip_data);
749 hr = CLIPBRD_E_CANT_SET;
753 return hr;
756 /***********************************************************************
757 * clipbrd_wndproc
759 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
761 ole_clipbrd *clipbrd;
763 get_ole_clipbrd(&clipbrd);
765 switch (message)
767 case WM_RENDERFORMAT:
769 UINT cf = wparam;
770 ole_priv_data_entry *entry;
772 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
773 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
775 if(entry)
776 render_format(clipbrd->pIDataObjectSrc, &entry->fmtetc);
778 break;
781 case WM_RENDERALLFORMATS:
783 DWORD i;
784 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
786 TRACE("(): WM_RENDERALLFORMATS\n");
788 for(i = 0; i < clipbrd->cached_enum->count; i++)
790 if(entries[i].first_use)
791 render_format(clipbrd->pIDataObjectSrc, &entries[i].fmtetc);
793 break;
796 case WM_DESTROYCLIPBOARD:
798 TRACE("(): WM_DESTROYCLIPBOARD\n");
800 if ( clipbrd->pIDataObjectSrc )
802 IDataObject_Release(clipbrd->pIDataObjectSrc);
803 clipbrd->pIDataObjectSrc = NULL;
804 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
805 clipbrd->cached_enum = NULL;
807 break;
810 default:
811 return DefWindowProcW(hwnd, message, wparam, lparam);
814 return 0;
818 /*---------------------------------------------------------------------*
819 * Implementation of the internal IDataObject interface exposed by
820 * the OLE clipboard.
821 *---------------------------------------------------------------------*/
824 /************************************************************************
825 * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
827 * See Windows documentation for more details on IUnknown methods.
829 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
830 IDataObject* iface,
831 REFIID riid,
832 void** ppvObject)
834 ole_clipbrd *This = impl_from_IDataObject(iface);
835 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
837 if ( (This==0) || (ppvObject==0) )
838 return E_INVALIDARG;
840 *ppvObject = 0;
842 if (IsEqualIID(&IID_IUnknown, riid) ||
843 IsEqualIID(&IID_IDataObject, riid))
845 *ppvObject = iface;
847 else
849 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
850 return E_NOINTERFACE;
853 IUnknown_AddRef((IUnknown*)*ppvObject);
855 return S_OK;
858 /************************************************************************
859 * OLEClipbrd_IDataObject_AddRef (IUnknown)
861 * See Windows documentation for more details on IUnknown methods.
863 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
864 IDataObject* iface)
866 ole_clipbrd *This = impl_from_IDataObject(iface);
868 TRACE("(%p)->(count=%u)\n",This, This->ref);
870 return InterlockedIncrement(&This->ref);
873 /***********************************************************************
874 * OLEClipbrd_DestroyWindow(HWND)
875 * Destroy the clipboard window and unregister its class
877 static void OLEClipbrd_DestroyWindow(HWND hwnd)
879 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
880 HINSTANCE hinst = GetModuleHandleW(ole32W);
882 DestroyWindow(hwnd);
883 UnregisterClassW( clipbrd_wndclass, hinst );
886 static void OLEClipbrd_Destroy(ole_clipbrd* This)
888 TRACE("()\n");
890 if (!This) return;
892 if ( This->hWndClipboard )
893 OLEClipbrd_DestroyWindow(This->hWndClipboard);
895 HeapFree(GetProcessHeap(), 0, This);
898 /************************************************************************
899 * OLEClipbrd_IDataObject_Release (IUnknown)
901 * See Windows documentation for more details on IUnknown methods.
903 static ULONG WINAPI OLEClipbrd_IDataObject_Release(
904 IDataObject* iface)
906 ole_clipbrd *This = impl_from_IDataObject(iface);
907 ULONG ref;
909 TRACE("(%p)->(count=%u)\n",This, This->ref);
911 ref = InterlockedDecrement(&This->ref);
913 if (ref == 0)
915 OLEClipbrd_Destroy(This);
918 return ref;
922 /************************************************************************
923 * OLEClipbrd_IDataObject_GetData (IDataObject)
925 * The OLE Clipboard's implementation of this method delegates to
926 * a data source if there is one or wraps around the windows clipboard
928 * See Windows documentation for more details on IDataObject methods.
930 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
931 IDataObject* iface,
932 LPFORMATETC pformatetcIn,
933 STGMEDIUM* pmedium)
935 HANDLE h, hData = 0;
936 ole_clipbrd *This = impl_from_IDataObject(iface);
937 HRESULT hr;
939 TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
941 if ( !pformatetcIn || !pmedium )
942 return E_INVALIDARG;
945 * If we have a data source placed on the clipboard (via OleSetClipboard)
946 * simply delegate to the source object's QueryGetData
947 * NOTE: This code assumes that the IDataObject is in the same address space!
948 * We will need to add marshalling support when Wine handles multiple processes.
950 if ( This->pIDataObjectSrc )
952 return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
955 if ( pformatetcIn->lindex != -1 )
956 return DV_E_FORMATETC;
958 if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
959 return DV_E_TYMED;
961 if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
962 return DV_E_DVASPECT;
966 * Otherwise, get the data from the windows clipboard using GetClipboardData
968 if ( !OpenClipboard(theOleClipboard->hWndClipboard)) return CLIPBRD_E_CANT_OPEN;
970 h = GetClipboardData(pformatetcIn->cfFormat);
971 hr = dup_global_mem(h, GMEM_MOVEABLE, &hData);
974 * Return the clipboard data in the storage medium structure
976 pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
977 pmedium->u.hGlobal = hData;
978 pmedium->pUnkForRelease = NULL;
980 if ( !CloseClipboard() ) return CLIPBRD_E_CANT_CLOSE;
982 if(FAILED(hr)) return hr;
983 return (hData == 0) ? DV_E_FORMATETC : S_OK;
986 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
987 IDataObject* iface,
988 LPFORMATETC pformatetc,
989 STGMEDIUM* pmedium)
991 FIXME(": Stub\n");
992 return E_NOTIMPL;
995 /************************************************************************
996 * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
998 * The OLE Clipboard's implementation of this method delegates to
999 * a data source if there is one or wraps around the windows clipboard
1000 * function IsClipboardFormatAvailable() otherwise.
1002 * See Windows documentation for more details on IDataObject methods.
1004 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
1005 IDataObject* iface,
1006 LPFORMATETC pformatetc)
1008 TRACE("(%p, %p)\n", iface, pformatetc);
1010 if (!pformatetc)
1011 return E_INVALIDARG;
1013 if ( pformatetc->dwAspect != DVASPECT_CONTENT )
1014 return DV_E_FORMATETC;
1016 if ( pformatetc->lindex != -1 )
1017 return DV_E_FORMATETC;
1020 * Delegate to the Windows clipboard function IsClipboardFormatAvailable
1022 return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1025 /************************************************************************
1026 * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
1028 * See Windows documentation for more details on IDataObject methods.
1030 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
1031 IDataObject* iface,
1032 LPFORMATETC pformatectIn,
1033 LPFORMATETC pformatetcOut)
1035 TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
1037 if ( !pformatectIn || !pformatetcOut )
1038 return E_INVALIDARG;
1040 *pformatetcOut = *pformatectIn;
1041 return DATA_S_SAMEFORMATETC;
1044 /************************************************************************
1045 * OLEClipbrd_IDataObject_SetData (IDataObject)
1047 * The OLE Clipboard's does not implement this method
1049 * See Windows documentation for more details on IDataObject methods.
1051 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
1052 IDataObject* iface,
1053 LPFORMATETC pformatetc,
1054 STGMEDIUM* pmedium,
1055 BOOL fRelease)
1057 TRACE("\n");
1058 return E_NOTIMPL;
1061 /************************************************************************
1062 * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
1064 * See Windows documentation for more details on IDataObject methods.
1066 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
1067 IDataObject* iface,
1068 DWORD dwDirection,
1069 IEnumFORMATETC** enum_fmt)
1071 HRESULT hr = S_OK;
1072 ole_clipbrd *This = impl_from_IDataObject(iface);
1073 HGLOBAL handle;
1074 ole_priv_data *data = NULL;
1076 TRACE("(%p, %x, %p)\n", iface, dwDirection, enum_fmt);
1078 *enum_fmt = NULL;
1080 if ( dwDirection != DATADIR_GET ) return E_NOTIMPL;
1081 if ( !OpenClipboard(This->hWndClipboard) ) return CLIPBRD_E_CANT_OPEN;
1083 handle = GetClipboardData( ole_priv_data_clipboard_format );
1084 if(handle)
1086 ole_priv_data *src = GlobalLock(handle);
1087 if(src)
1089 /* FIXME: sanity check on size */
1090 data = HeapAlloc(GetProcessHeap(), 0, src->size);
1091 if(!data)
1093 GlobalUnlock(handle);
1094 hr = E_OUTOFMEMORY;
1095 goto end;
1097 memcpy(data, src, src->size);
1098 GlobalUnlock(handle);
1102 if(!data) hr = create_empty_priv_data(&data);
1103 if(FAILED(hr)) goto end;
1105 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1107 end:
1108 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1109 return hr;
1112 /************************************************************************
1113 * OLEClipbrd_IDataObject_DAdvise (IDataObject)
1115 * The OLE Clipboard's does not implement this method
1117 * See Windows documentation for more details on IDataObject methods.
1119 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
1120 IDataObject* iface,
1121 FORMATETC* pformatetc,
1122 DWORD advf,
1123 IAdviseSink* pAdvSink,
1124 DWORD* pdwConnection)
1126 TRACE("\n");
1127 return E_NOTIMPL;
1130 /************************************************************************
1131 * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
1133 * The OLE Clipboard's does not implement this method
1135 * See Windows documentation for more details on IDataObject methods.
1137 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
1138 IDataObject* iface,
1139 DWORD dwConnection)
1141 TRACE("\n");
1142 return E_NOTIMPL;
1145 /************************************************************************
1146 * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
1148 * The OLE Clipboard does not implement this method
1150 * See Windows documentation for more details on IDataObject methods.
1152 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
1153 IDataObject* iface,
1154 IEnumSTATDATA** ppenumAdvise)
1156 TRACE("\n");
1157 return E_NOTIMPL;
1160 static const IDataObjectVtbl OLEClipbrd_IDataObject_VTable =
1162 OLEClipbrd_IDataObject_QueryInterface,
1163 OLEClipbrd_IDataObject_AddRef,
1164 OLEClipbrd_IDataObject_Release,
1165 OLEClipbrd_IDataObject_GetData,
1166 OLEClipbrd_IDataObject_GetDataHere,
1167 OLEClipbrd_IDataObject_QueryGetData,
1168 OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
1169 OLEClipbrd_IDataObject_SetData,
1170 OLEClipbrd_IDataObject_EnumFormatEtc,
1171 OLEClipbrd_IDataObject_DAdvise,
1172 OLEClipbrd_IDataObject_DUnadvise,
1173 OLEClipbrd_IDataObject_EnumDAdvise
1176 /*---------------------------------------------------------------------*
1177 * Internal implementation methods for the OLE clipboard
1178 *---------------------------------------------------------------------*/
1180 /*********************************************************
1181 * Construct the OLEClipbrd class.
1183 static ole_clipbrd* OLEClipbrd_Construct(void)
1185 ole_clipbrd* This;
1187 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1188 if (!This) return NULL;
1190 This->lpvtbl = &OLEClipbrd_IDataObject_VTable;
1191 This->ref = 1;
1193 This->hWndClipboard = NULL;
1194 This->pIDataObjectSrc = NULL;
1195 This->cached_enum = NULL;
1197 return This;
1200 static void register_clipboard_formats(void)
1202 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1203 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1204 static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1206 if(!dataobject_clipboard_format)
1207 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1208 if(!ole_priv_data_clipboard_format)
1209 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1210 if(!embed_source_clipboard_format)
1211 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1214 /***********************************************************************
1215 * OLEClipbrd_Initialize()
1216 * Initializes the OLE clipboard.
1218 void OLEClipbrd_Initialize(void)
1220 register_clipboard_formats();
1222 if ( !theOleClipboard )
1224 TRACE("()\n");
1225 theOleClipboard = OLEClipbrd_Construct();
1230 /***********************************************************************
1231 * OLEClipbrd_UnInitialize()
1232 * Un-Initializes the OLE clipboard
1234 void OLEClipbrd_UnInitialize(void)
1236 TRACE("()\n");
1238 * Destroy the clipboard if no one holds a reference to us.
1239 * Note that the clipboard was created with a reference count of 1.
1241 if ( theOleClipboard && (theOleClipboard->ref <= 1) )
1243 OLEClipbrd_Destroy( theOleClipboard );
1244 theOleClipboard = NULL;
1246 else
1248 WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");
1252 /***********************************************************************
1253 * OLEClipbrd_CreateWindow()
1254 * Create the clipboard window
1256 static HWND OLEClipbrd_CreateWindow(void)
1258 WNDCLASSEXW class;
1259 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1260 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1261 HINSTANCE hinst = GetModuleHandleW(ole32W);
1263 class.cbSize = sizeof(class);
1264 class.style = 0;
1265 class.lpfnWndProc = clipbrd_wndproc;
1266 class.cbClsExtra = 0;
1267 class.cbWndExtra = 0;
1268 class.hInstance = hinst;
1269 class.hIcon = 0;
1270 class.hCursor = 0;
1271 class.hbrBackground = 0;
1272 class.lpszMenuName = NULL;
1273 class.lpszClassName = clipbrd_wndclass;
1274 class.hIconSm = NULL;
1276 RegisterClassExW(&class);
1278 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1279 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1280 NULL, NULL, hinst, 0);
1283 /*********************************************************************
1284 * set_clipboard_formats
1286 * Enumerate all formats supported by the source and make
1287 * those formats available using delayed rendering using SetClipboardData.
1288 * Cache the enumeration list and make that list visibile as the
1289 * 'Ole Private Data' format on the clipboard.
1292 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1294 HRESULT hr;
1295 FORMATETC fmt;
1296 IEnumFORMATETC *enum_fmt;
1297 HGLOBAL priv_data_handle;
1298 DWORD target_offset;
1299 ole_priv_data *priv_data;
1300 DWORD count = 0, needed = sizeof(*priv_data), idx;
1302 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1303 if(FAILED(hr)) return hr;
1305 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1307 count++;
1308 needed += sizeof(priv_data->entries[0]);
1309 if(fmt.ptd)
1311 needed += fmt.ptd->tdSize;
1312 CoTaskMemFree(fmt.ptd);
1316 /* Windows pads the list with two empty ole_priv_data_entries, one
1317 * after the entries array and one after the target device data.
1318 * Allocating with zero init to zero these pads. */
1320 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1321 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1322 priv_data = GlobalLock(priv_data_handle);
1324 priv_data->unk1 = 0;
1325 priv_data->size = needed;
1326 priv_data->unk2 = 1;
1327 priv_data->count = count;
1328 priv_data->unk3[0] = 0;
1329 priv_data->unk3[1] = 0;
1331 IEnumFORMATETC_Reset(enum_fmt);
1333 idx = 0;
1334 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1336 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1338 TRACE("%s\n", dump_fmtetc(&fmt));
1340 priv_data->entries[idx].fmtetc = fmt;
1341 if(fmt.ptd)
1343 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1344 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1345 target_offset += fmt.ptd->tdSize;
1346 CoTaskMemFree(fmt.ptd);
1349 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1350 priv_data->entries[idx].unk[0] = 0;
1351 priv_data->entries[idx].unk[1] = 0;
1353 if (priv_data->entries[idx].first_use)
1354 SetClipboardData(fmt.cfFormat, NULL);
1356 idx++;
1359 IEnumFORMATETC_Release(enum_fmt);
1361 /* Cache the list and fixup any target device offsets to ptrs */
1362 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1363 memcpy(clipbrd->cached_enum, priv_data, needed);
1364 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1365 if(clipbrd->cached_enum->entries[idx].fmtetc.ptd)
1366 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1367 (DVTARGETDEVICE *)((char*)clipbrd->cached_enum + (DWORD)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1369 GlobalUnlock(priv_data_handle);
1370 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1372 return S_OK;
1375 /*********************************************************************
1376 * set_dataobject_format
1378 * Windows creates a 'DataObject' clipboard format that contains the
1379 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1381 static HRESULT set_dataobject_format(HWND hwnd)
1383 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1384 HWND *data;
1386 if(!h) return E_OUTOFMEMORY;
1388 data = GlobalLock(h);
1389 *data = hwnd;
1390 GlobalUnlock(h);
1392 if(!SetClipboardData(dataobject_clipboard_format, h))
1394 GlobalFree(h);
1395 return CLIPBRD_E_CANT_SET;
1398 return S_OK;
1401 /*---------------------------------------------------------------------*
1402 * Win32 OLE clipboard API
1403 *---------------------------------------------------------------------*/
1405 /***********************************************************************
1406 * OleSetClipboard [OLE32.@]
1407 * Places a pointer to the specified data object onto the clipboard,
1408 * making the data object accessible to the OleGetClipboard function.
1410 * RETURNS
1412 * S_OK IDataObject pointer placed on the clipboard
1413 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1414 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1415 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1416 * CLIPBRD_E_CANT_SET SetClipboard failed
1419 HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)
1421 HRESULT hr;
1422 ole_clipbrd *clipbrd;
1424 TRACE("(%p)\n", pDataObj);
1426 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1429 * If the Ole clipboard window hasn't been created yet, create it now.
1431 if ( !clipbrd->hWndClipboard )
1432 clipbrd->hWndClipboard = OLEClipbrd_CreateWindow();
1433 if ( !clipbrd->hWndClipboard ) return E_FAIL;
1435 if ( !OpenClipboard(clipbrd->hWndClipboard) ) return CLIPBRD_E_CANT_OPEN;
1438 * Empty the current clipboard and make our window the clipboard owner
1439 * NOTE: This will trigger a WM_DESTROYCLIPBOARD message
1441 if ( !EmptyClipboard() )
1443 hr = CLIPBRD_E_CANT_EMPTY;
1444 goto end;
1448 * If we are already holding on to an IDataObject first release that.
1450 if ( clipbrd->pIDataObjectSrc )
1452 IDataObject_Release(clipbrd->pIDataObjectSrc);
1453 clipbrd->pIDataObjectSrc = NULL;
1454 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1455 clipbrd->cached_enum = NULL;
1458 /* A NULL value indicates that the clipboard should be emptied. */
1459 clipbrd->pIDataObjectSrc = pDataObj;
1460 if ( pDataObj )
1462 IDataObject_AddRef(clipbrd->pIDataObjectSrc);
1463 hr = set_clipboard_formats(clipbrd, pDataObj);
1464 if(FAILED(hr)) goto end;
1467 hr = set_dataobject_format(clipbrd->hWndClipboard);
1469 end:
1471 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1473 if ( FAILED(hr) )
1475 if (clipbrd->pIDataObjectSrc)
1477 IDataObject_Release(clipbrd->pIDataObjectSrc);
1478 clipbrd->pIDataObjectSrc = NULL;
1479 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1480 clipbrd->cached_enum = NULL;
1484 return hr;
1488 /***********************************************************************
1489 * OleGetClipboard [OLE32.@]
1490 * Returns a pointer to our internal IDataObject which represents the conceptual
1491 * state of the Windows clipboard. If the current clipboard already contains
1492 * an IDataObject, our internal IDataObject will delegate to this object.
1494 HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
1496 HRESULT hr;
1497 ole_clipbrd *clipbrd;
1498 TRACE("()\n");
1500 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1502 hr = IDataObject_QueryInterface( (IDataObject*)&(clipbrd->lpvtbl),
1503 &IID_IDataObject, (void**)ppDataObj);
1504 return hr;
1507 /******************************************************************************
1508 * OleFlushClipboard [OLE32.@]
1509 * Renders the data from the source IDataObject into the windows clipboard
1511 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1512 * by copying the storage into global memory. Subsequently the default
1513 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1514 * back to TYMED_IStorage.
1516 HRESULT WINAPI OleFlushClipboard(void)
1518 IEnumFORMATETC* penumFormatetc = NULL;
1519 FORMATETC rgelt;
1520 HRESULT hr;
1521 ole_clipbrd *clipbrd;
1523 TRACE("()\n");
1525 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1528 * Already flushed or no source DataObject? Nothing to do.
1530 if (!clipbrd->pIDataObjectSrc)
1531 return S_OK;
1533 if (!OpenClipboard(clipbrd->hWndClipboard))
1534 return CLIPBRD_E_CANT_OPEN;
1537 * Render all HGLOBAL formats supported by the source into
1538 * the windows clipboard.
1540 if ( FAILED( hr = IDataObject_EnumFormatEtc( clipbrd->pIDataObjectSrc,
1541 DATADIR_GET,
1542 &penumFormatetc) ))
1543 goto end;
1546 while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
1548 if ( rgelt.tymed == TYMED_HGLOBAL )
1550 CHAR szFmtName[80];
1551 TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
1552 GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
1553 ? szFmtName : "");
1555 if ( FAILED(render_format( clipbrd->pIDataObjectSrc, &rgelt )) )
1556 continue;
1560 IEnumFORMATETC_Release(penumFormatetc);
1562 hr = set_dataobject_format(NULL);
1564 IDataObject_Release(clipbrd->pIDataObjectSrc);
1565 clipbrd->pIDataObjectSrc = NULL;
1566 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1567 clipbrd->cached_enum = NULL;
1569 end:
1571 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1573 return hr;
1577 /***********************************************************************
1578 * OleIsCurrentClipboard [OLE32.@]
1580 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject)
1582 HRESULT hr;
1583 ole_clipbrd *clipbrd;
1584 TRACE("()\n");
1586 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1588 if (pDataObject == NULL)
1589 return S_FALSE;
1591 return (pDataObject == clipbrd->pIDataObjectSrc) ? S_OK : S_FALSE;