ole32: Rewrite the clipboard window's wndproc to use the cached enum data.
[wine] / dlls / ole32 / clipboard.c
1 /*
2  *  OLE 2 clipboard support
3  *
4  *      Copyright 1999  Noel Borthwick <noel@macadamian.com>
5  *      Copyright 2000  Abey George <abey@macadamian.com>
6  *
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.
11  *
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.
16  *
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
20  *
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:
29  *
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.
36  *
37  *    2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38  *       IDataObject functionality wraps around the WIN32 clipboard API.
39  *
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.
43  *
44  *    Implementation references : Inside OLE 2'nd  edition by Kraig Brockschmidt
45  *
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.
58  *
59  */
60
61 #include <assert.h>
62 #include <stdarg.h>
63 #include <string.h>
64
65 #define COBJMACROS
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
68
69 #include "windef.h"
70 #include "winbase.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "winerror.h"
74 #include "winnls.h"
75 #include "ole2.h"
76 #include "wine/debug.h"
77 #include "olestd.h"
78
79 #include "storage32.h"
80
81 #include "compobj_private.h"
82
83 WINE_DEFAULT_DEBUG_CHANNEL(ole);
84
85 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
86
87 /* Structure of 'Ole Private Data' clipboard format */
88 typedef struct
89 {
90     FORMATETC fmtetc;
91     DWORD first_use;  /* Has this cf been added to the list already */
92     DWORD unk[2];
93 } ole_priv_data_entry;
94
95 typedef struct
96 {
97     DWORD unk1;
98     DWORD size; /* in bytes of the entire structure */
99     DWORD unk2;
100     DWORD count; /* no. of format entries */
101     DWORD unk3[2];
102     ole_priv_data_entry entries[1]; /* array of size count */
103     /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
104 } ole_priv_data;
105
106 /*****************************************************************************
107  *           create_empty_priv_data
108  *
109  * Create an empty data structure.  The only thing that really matters
110  * here is setting count and size members.  This is used by the enumerator as a
111  * convenience when there's an empty list.
112  */
113 static HRESULT create_empty_priv_data(ole_priv_data **data)
114 {
115     ole_priv_data *ptr;
116
117     *data = NULL;
118     ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*ptr));
119     if(!ptr) return E_OUTOFMEMORY;
120     ptr->size = sizeof(*ptr);
121     ptr->count = 0;
122     *data = ptr;
123     return S_OK;
124 }
125
126
127 /****************************************************************************
128  * ole_clipbrd
129  */
130 typedef struct ole_clipbrd
131 {
132     const IDataObjectVtbl* lpvtbl;  /* Exposed IDataObject vtable */
133
134     LONG ref;
135
136     HWND hWndClipboard;              /* Hidden clipboard window */
137     IDataObject *pIDataObjectSrc;    /* Source object passed to OleSetClipboard */
138     ole_priv_data *cached_enum;      /* Cached result from the enumeration of src data object */
139 } ole_clipbrd;
140
141 static inline ole_clipbrd *impl_from_IDataObject(IDataObject *iface)
142 {
143     return (ole_clipbrd*)((char*)iface - FIELD_OFFSET(ole_clipbrd, lpvtbl));
144 }
145
146 typedef struct PresentationDataHeader
147 {
148   BYTE unknown1[28];
149   DWORD dwObjectExtentX;
150   DWORD dwObjectExtentY;
151   DWORD dwSize;
152 } PresentationDataHeader;
153
154 /*
155  * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
156  */
157 static ole_clipbrd* theOleClipboard;
158
159
160 /*
161  * Name of our registered OLE clipboard window class
162  */
163 static const CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
164
165 static UINT dataobject_clipboard_format;
166 static UINT ole_priv_data_clipboard_format;
167 static UINT embed_source_clipboard_format;
168
169 /*---------------------------------------------------------------------*
170  *  Implementation of the internal IEnumFORMATETC interface returned by
171  *  the OLE clipboard's IDataObject.
172  *---------------------------------------------------------------------*/
173
174 typedef struct enum_fmtetc
175 {
176     const IEnumFORMATETCVtbl *lpVtbl;
177     LONG ref;
178
179     UINT pos;    /* current enumerator position */
180     ole_priv_data *data;
181 } enum_fmtetc;
182
183 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
184 {
185     return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
186 }
187
188 /************************************************************************
189  * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
190  *
191  * See Windows documentation for more details on IUnknown methods.
192  */
193 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
194   (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
195 {
196   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
197
198   TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
199
200   *ppvObj = NULL;
201
202   if(IsEqualIID(riid, &IID_IUnknown) ||
203      IsEqualIID(riid, &IID_IEnumFORMATETC))
204   {
205     *ppvObj = iface;
206   }
207
208   if(*ppvObj)
209   {
210     IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
211     TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
212     return S_OK;
213   }
214
215   TRACE("-- Interface: E_NOINTERFACE\n");
216   return E_NOINTERFACE;
217 }
218
219 /************************************************************************
220  * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
221  *
222  */
223 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
224 {
225   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
226   TRACE("(%p)->(count=%u)\n",This, This->ref);
227
228   return InterlockedIncrement(&This->ref);
229 }
230
231 /************************************************************************
232  * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
233  *
234  * See Windows documentation for more details on IUnknown methods.
235  */
236 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
237 {
238   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
239   ULONG ref;
240
241   TRACE("(%p)->(count=%u)\n",This, This->ref);
242
243   ref = InterlockedDecrement(&This->ref);
244   if (!ref)
245   {
246     TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
247     HeapFree(GetProcessHeap(), 0, This->data);
248     HeapFree(GetProcessHeap(), 0, This);
249   }
250   return ref;
251 }
252
253 /************************************************************************
254  * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
255  *
256  * Standard enumerator members for IEnumFORMATETC
257  */
258 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
259   (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
260 {
261   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
262   UINT cfetch, i;
263   HRESULT hres = S_FALSE;
264
265   TRACE("(%p)->(pos=%u)\n", This, This->pos);
266
267   if (This->pos < This->data->count)
268   {
269     cfetch = This->data->count - This->pos;
270     if (cfetch >= celt)
271     {
272       cfetch = celt;
273       hres = S_OK;
274     }
275
276     for(i = 0; i < cfetch; i++)
277     {
278       rgelt[i] = This->data->entries[This->pos++].fmtetc;
279       if(rgelt[i].ptd)
280       {
281         DVTARGETDEVICE *target = (DVTARGETDEVICE *)((char *)This->data + (DWORD)rgelt[i].ptd);
282         rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
283         if(!rgelt[i].ptd) return E_OUTOFMEMORY;
284         memcpy(rgelt[i].ptd, target, target->tdSize);
285       }
286     }
287   }
288   else
289   {
290     cfetch = 0;
291   }
292
293   if (pceltFethed)
294   {
295     *pceltFethed = cfetch;
296   }
297
298   return hres;
299 }
300
301 /************************************************************************
302  * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
303  *
304  * Standard enumerator members for IEnumFORMATETC
305  */
306 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
307 {
308   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
309   TRACE("(%p)->(num=%u)\n", This, celt);
310
311   This->pos += celt;
312   if (This->pos > This->data->count)
313   {
314     This->pos = This->data->count;
315     return S_FALSE;
316   }
317   return S_OK;
318 }
319
320 /************************************************************************
321  * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
322  *
323  * Standard enumerator members for IEnumFORMATETC
324  */
325 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
326 {
327   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
328   TRACE("(%p)->()\n", This);
329
330   This->pos = 0;
331   return S_OK;
332 }
333
334 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
335
336 /************************************************************************
337  * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
338  *
339  * Standard enumerator members for IEnumFORMATETC
340  */
341 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
342   (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
343 {
344   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
345   ole_priv_data *new_data;
346
347   TRACE("(%p)->(%p)\n", This, obj);
348
349   if ( !obj ) return E_INVALIDARG;
350   *obj = NULL;
351
352   new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
353   if(!new_data) return E_OUTOFMEMORY;
354
355   return enum_fmtetc_construct(new_data, This->pos, obj);
356 }
357
358 static const IEnumFORMATETCVtbl efvt =
359 {
360   OLEClipbrd_IEnumFORMATETC_QueryInterface,
361   OLEClipbrd_IEnumFORMATETC_AddRef,
362   OLEClipbrd_IEnumFORMATETC_Release,
363   OLEClipbrd_IEnumFORMATETC_Next,
364   OLEClipbrd_IEnumFORMATETC_Skip,
365   OLEClipbrd_IEnumFORMATETC_Reset,
366   OLEClipbrd_IEnumFORMATETC_Clone
367 };
368
369 /************************************************************************
370  * enum_fmtetc_construct
371  *
372  * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
373  */
374 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
375 {
376   enum_fmtetc* ef;
377
378   *obj = NULL;
379   ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
380   if (!ef) return E_OUTOFMEMORY;
381
382   ef->ref = 1;
383   ef->lpVtbl = &efvt;
384   ef->data = data;
385   ef->pos = pos;
386
387   TRACE("(%p)->()\n", ef);
388   *obj = (IEnumFORMATETC *)ef;
389   return S_OK;
390 }
391
392 /***********************************************************************
393  *                    dup_global_mem
394  *
395  * Helper method to duplicate an HGLOBAL chunk of memory
396  */
397 static HRESULT dup_global_mem( HGLOBAL src, HGLOBAL *dst )
398 {
399     void *src_ptr, *dst_ptr;
400     DWORD size;
401
402     *dst = NULL;
403     if ( !src ) return S_FALSE;
404
405     size = GlobalSize(src);
406
407     *dst = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, size );
408     if ( !*dst ) return E_OUTOFMEMORY;
409
410     src_ptr = GlobalLock(src);
411     dst_ptr = GlobalLock(*dst);
412
413     memcpy(dst_ptr, src_ptr, size);
414
415     GlobalUnlock(*dst);
416     GlobalUnlock(src);
417
418     return S_OK;
419 }
420
421 /************************************************************
422  *              render_embed_source_hack
423  *
424  * This is clearly a hack and has no place in the clipboard code.
425  *
426  */
427 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
428 {
429     STGMEDIUM std;
430     HGLOBAL hStorage = 0;
431     HRESULT hr = S_OK;
432     ILockBytes *ptrILockBytes;
433
434     memset(&std, 0, sizeof(STGMEDIUM));
435     std.tymed = fmt->tymed = TYMED_ISTORAGE;
436
437     hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
438     if (hStorage == NULL) return E_OUTOFMEMORY;
439     hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
440     hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
441     ILockBytes_Release(ptrILockBytes);
442
443     if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, fmt, &std)))
444     {
445         WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
446         GlobalFree(hStorage);
447         return hr;
448     }
449
450     if (1) /* check whether the presentation data is already -not- present */
451     {
452         FORMATETC fmt2;
453         STGMEDIUM std2;
454         METAFILEPICT *mfp = 0;
455
456         fmt2.cfFormat = CF_METAFILEPICT;
457         fmt2.ptd = 0;
458         fmt2.dwAspect = DVASPECT_CONTENT;
459         fmt2.lindex = -1;
460         fmt2.tymed = TYMED_MFPICT;
461
462         memset(&std2, 0, sizeof(STGMEDIUM));
463         std2.tymed = TYMED_MFPICT;
464
465         /* Get the metafile picture out of it */
466
467         if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
468         {
469             mfp = GlobalLock(std2.u.hGlobal);
470         }
471
472         if (mfp)
473         {
474             OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
475             IStream *pStream = 0;
476             void *mfBits;
477             PresentationDataHeader pdh;
478             INT nSize;
479             CLSID clsID;
480             LPOLESTR strProgID;
481             CHAR strOleTypeName[51];
482             BYTE OlePresStreamHeader [] =
483             {
484                 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
485                 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
486                 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
487                 0x00, 0x00, 0x00, 0x00
488             };
489
490             nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
491
492             memset(&pdh, 0, sizeof(PresentationDataHeader));
493             memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
494
495             pdh.dwObjectExtentX = mfp->xExt;
496             pdh.dwObjectExtentY = mfp->yExt;
497             pdh.dwSize = nSize;
498
499             hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
500
501             hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
502
503             mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
504             nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
505
506             hr = IStream_Write(pStream, mfBits, nSize, NULL);
507
508             IStream_Release(pStream);
509
510             HeapFree(GetProcessHeap(), 0, mfBits);
511
512             GlobalUnlock(std2.u.hGlobal);
513             ReleaseStgMedium(&std2);
514
515             ReadClassStg(std.u.pstg, &clsID);
516             ProgIDFromCLSID(&clsID, &strProgID);
517
518             WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
519             OLECONVERT_CreateOleStream(std.u.pstg);
520             OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
521         }
522     }
523
524     if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
525     {
526         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
527         GlobalFree(hStorage);
528         hr = CLIPBRD_E_CANT_SET;
529     }
530
531     ReleaseStgMedium(&std);
532     return hr;
533 }
534
535 /************************************************************************
536  *           find_format_in_list
537  *
538  * Returns the first entry that matches the provided clipboard format.
539  */
540 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
541 {
542     DWORD i;
543     for(i = 0; i < num; i++)
544         if(entries[i].fmtetc.cfFormat == cf)
545             return &entries[i];
546
547     return NULL;
548 }
549
550 /***********************************************************************
551  *                render_format
552  *
553  * Render the clipboard data. Note that this call will delegate to the
554  * source data object.
555  * Note: This function assumes it is passed an HGLOBAL format to render.
556  */
557 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
558 {
559     STGMEDIUM std;
560     HGLOBAL clip_data = NULL;
561     HRESULT hr;
562
563     /* Embed source hack */
564     if(fmt->cfFormat == embed_source_clipboard_format)
565     {
566         return render_embed_source_hack(data, fmt);
567     }
568
569     if (FAILED(hr = IDataObject_GetData(data, fmt, &std)))
570     {
571         WARN("() : IDataObject_GetData failed to render clipboard data! (%x)\n", hr);
572         return hr;
573     }
574
575     if(std.tymed != TYMED_HGLOBAL)
576     {
577         FIXME("got tymed %x\n", std.tymed);
578         hr = DV_E_FORMATETC;
579         goto end;
580     }
581
582     hr = dup_global_mem(std.u.hGlobal, &clip_data);
583     if(FAILED(hr)) goto end;
584
585     if ( !SetClipboardData( fmt->cfFormat, clip_data ) )
586     {
587         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
588         GlobalFree(clip_data);
589         hr = CLIPBRD_E_CANT_SET;
590     }
591
592 end:
593     ReleaseStgMedium(&std);
594     return hr;
595 }
596
597
598 /***********************************************************************
599  *                   clipbrd_wndproc
600  */
601 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
602 {
603     ole_clipbrd *clipbrd = theOleClipboard;
604
605     switch (message)
606     {
607     case WM_RENDERFORMAT:
608     {
609         UINT cf = wparam;
610         ole_priv_data_entry *entry;
611
612         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
613         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
614
615         if(entry)
616             render_format(clipbrd->pIDataObjectSrc, &entry->fmtetc);
617
618         break;
619     }
620
621     case WM_RENDERALLFORMATS:
622     {
623         DWORD i;
624         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
625
626         TRACE("(): WM_RENDERALLFORMATS\n");
627
628         for(i = 0; i < clipbrd->cached_enum->count; i++)
629         {
630             if(entries[i].first_use)
631                 render_format(clipbrd->pIDataObjectSrc, &entries[i].fmtetc);
632         }
633         break;
634     }
635
636     case WM_DESTROYCLIPBOARD:
637     {
638         TRACE("(): WM_DESTROYCLIPBOARD\n");
639
640         if ( clipbrd->pIDataObjectSrc )
641         {
642             IDataObject_Release(clipbrd->pIDataObjectSrc);
643             clipbrd->pIDataObjectSrc = NULL;
644             HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
645             clipbrd->cached_enum = NULL;
646         }
647         break;
648     }
649
650     default:
651         return DefWindowProcA(hwnd, message, wparam, lparam);
652     }
653
654     return 0;
655 }
656
657
658 /*---------------------------------------------------------------------*
659  *  Implementation of the internal IDataObject interface exposed by
660  *  the OLE clipboard.
661  *---------------------------------------------------------------------*/
662
663
664 /************************************************************************
665  * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
666  *
667  * See Windows documentation for more details on IUnknown methods.
668  */
669 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
670             IDataObject*     iface,
671             REFIID           riid,
672             void**           ppvObject)
673 {
674   ole_clipbrd *This = impl_from_IDataObject(iface);
675   TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
676
677   if ( (This==0) || (ppvObject==0) )
678     return E_INVALIDARG;
679
680   *ppvObject = 0;
681
682   if (IsEqualIID(&IID_IUnknown, riid) ||
683       IsEqualIID(&IID_IDataObject, riid))
684   {
685     *ppvObject = iface;
686   }
687   else
688   {
689     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
690     return E_NOINTERFACE;
691   }
692
693   IUnknown_AddRef((IUnknown*)*ppvObject);
694
695   return S_OK;
696 }
697
698 /************************************************************************
699  * OLEClipbrd_IDataObject_AddRef (IUnknown)
700  *
701  * See Windows documentation for more details on IUnknown methods.
702  */
703 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
704             IDataObject*     iface)
705 {
706   ole_clipbrd *This = impl_from_IDataObject(iface);
707
708   TRACE("(%p)->(count=%u)\n",This, This->ref);
709
710   return InterlockedIncrement(&This->ref);
711 }
712
713 /***********************************************************************
714  * OLEClipbrd_DestroyWindow(HWND)
715  * Destroy the clipboard window and unregister its class
716  */
717 static void OLEClipbrd_DestroyWindow(HWND hwnd)
718 {
719   DestroyWindow(hwnd);
720   UnregisterClassA( OLEClipbrd_WNDCLASS, 0 );
721 }
722
723 static void OLEClipbrd_Destroy(ole_clipbrd* This)
724 {
725     TRACE("()\n");
726
727     if (!This) return;
728
729     theOleClipboard = NULL;
730
731     if ( This->hWndClipboard )
732         OLEClipbrd_DestroyWindow(This->hWndClipboard);
733
734     HeapFree(GetProcessHeap(), 0, This);
735 }
736
737 /************************************************************************
738  * OLEClipbrd_IDataObject_Release (IUnknown)
739  *
740  * See Windows documentation for more details on IUnknown methods.
741  */
742 static ULONG WINAPI OLEClipbrd_IDataObject_Release(
743             IDataObject*     iface)
744 {
745   ole_clipbrd *This = impl_from_IDataObject(iface);
746   ULONG ref;
747
748   TRACE("(%p)->(count=%u)\n",This, This->ref);
749
750   ref = InterlockedDecrement(&This->ref);
751
752   if (ref == 0)
753   {
754     OLEClipbrd_Destroy(This);
755   }
756
757   return ref;
758 }
759
760
761 /************************************************************************
762  * OLEClipbrd_IDataObject_GetData (IDataObject)
763  *
764  * The OLE Clipboard's implementation of this method delegates to
765  * a data source if there is one or wraps around the windows clipboard
766  *
767  * See Windows documentation for more details on IDataObject methods.
768  */
769 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
770             IDataObject*     iface,
771             LPFORMATETC      pformatetcIn,
772             STGMEDIUM*       pmedium)
773 {
774   HANDLE      hData = 0;
775   LPVOID src;
776   ole_clipbrd *This = impl_from_IDataObject(iface);
777
778   TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
779
780   if ( !pformatetcIn || !pmedium )
781     return E_INVALIDARG;
782
783   /*
784    * If we have a data source placed on the clipboard (via OleSetClipboard)
785    * simply delegate to the source object's QueryGetData
786    * NOTE: This code assumes that the IDataObject is in the same address space!
787    * We will need to add marshalling support when Wine handles multiple processes.
788    */
789   if ( This->pIDataObjectSrc )
790   {
791     return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
792   }
793
794   if ( pformatetcIn->lindex != -1 )
795     return DV_E_FORMATETC;
796
797   if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
798     return DV_E_TYMED;
799 /*
800    if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
801      return DV_E_DVASPECT;
802 */
803
804   /*
805    * Otherwise, get the data from the windows clipboard using GetClipboardData
806    */
807   if ( !OpenClipboard(theOleClipboard->hWndClipboard)) return CLIPBRD_E_CANT_OPEN;
808
809   hData = GetClipboardData(pformatetcIn->cfFormat);
810
811   /* Must make a copy of global handle returned by GetClipboardData; it
812    * is not valid after we call CloseClipboard
813    * Application is responsible for freeing the memory (Forte Agent does this)
814    */
815   src = GlobalLock(hData);
816   if(src) {
817       LPVOID dest;
818       ULONG  size;
819       HANDLE hDest;
820
821       size = GlobalSize(hData);
822       hDest = GlobalAlloc(GHND, size);
823       dest  = GlobalLock(hDest);
824       memcpy(dest, src, size);
825       GlobalUnlock(hDest);
826       GlobalUnlock(hData);
827       hData = hDest;
828   }
829
830   /*
831    * Return the clipboard data in the storage medium structure
832    */
833   pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
834   pmedium->u.hGlobal = hData;
835   pmedium->pUnkForRelease = NULL;
836
837   if ( !CloseClipboard() ) return CLIPBRD_E_CANT_CLOSE;
838
839   return (hData == 0) ? DV_E_FORMATETC : S_OK;
840 }
841
842 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
843             IDataObject*     iface,
844             LPFORMATETC      pformatetc,
845             STGMEDIUM*       pmedium)
846 {
847   FIXME(": Stub\n");
848   return E_NOTIMPL;
849 }
850
851 /************************************************************************
852  * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
853  *
854  * The OLE Clipboard's implementation of this method delegates to
855  * a data source if there is one or wraps around the windows clipboard
856  * function IsClipboardFormatAvailable() otherwise.
857  *
858  * See Windows documentation for more details on IDataObject methods.
859  */
860 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
861             IDataObject*     iface,
862             LPFORMATETC      pformatetc)
863 {
864   TRACE("(%p, %p)\n", iface, pformatetc);
865
866   if (!pformatetc)
867     return E_INVALIDARG;
868
869   if ( pformatetc->dwAspect != DVASPECT_CONTENT )
870     return DV_E_FORMATETC;
871
872   if ( pformatetc->lindex != -1 )
873     return DV_E_FORMATETC;
874
875   /*
876    * Delegate to the Windows clipboard function IsClipboardFormatAvailable
877    */
878   return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
879 }
880
881 /************************************************************************
882  * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
883  *
884  * See Windows documentation for more details on IDataObject methods.
885  */
886 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
887             IDataObject*     iface,
888             LPFORMATETC      pformatectIn,
889             LPFORMATETC      pformatetcOut)
890 {
891   TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
892
893   if ( !pformatectIn || !pformatetcOut )
894     return E_INVALIDARG;
895
896   *pformatetcOut = *pformatectIn;
897   return DATA_S_SAMEFORMATETC;
898 }
899
900 /************************************************************************
901  * OLEClipbrd_IDataObject_SetData (IDataObject)
902  *
903  * The OLE Clipboard's does not implement this method
904  *
905  * See Windows documentation for more details on IDataObject methods.
906  */
907 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
908             IDataObject*     iface,
909             LPFORMATETC      pformatetc,
910             STGMEDIUM*       pmedium,
911             BOOL             fRelease)
912 {
913   TRACE("\n");
914   return E_NOTIMPL;
915 }
916
917 /************************************************************************
918  * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
919  *
920  * See Windows documentation for more details on IDataObject methods.
921  */
922 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
923             IDataObject*     iface,
924             DWORD            dwDirection,
925             IEnumFORMATETC** enum_fmt)
926 {
927     HRESULT hr = S_OK;
928     ole_clipbrd *This = impl_from_IDataObject(iface);
929     HGLOBAL handle;
930     ole_priv_data *data = NULL;
931
932     TRACE("(%p, %x, %p)\n", iface, dwDirection, enum_fmt);
933
934     *enum_fmt = NULL;
935
936     if ( dwDirection != DATADIR_GET ) return E_NOTIMPL;
937     if ( !OpenClipboard(This->hWndClipboard) ) return CLIPBRD_E_CANT_OPEN;
938
939     handle = GetClipboardData( ole_priv_data_clipboard_format );
940     if(handle)
941     {
942         ole_priv_data *src = GlobalLock(handle);
943         if(src)
944         {
945             /* FIXME: sanity check on size */
946             data = HeapAlloc(GetProcessHeap(), 0, src->size);
947             if(!data)
948             {
949                 GlobalUnlock(handle);
950                 hr = E_OUTOFMEMORY;
951                 goto end;
952             }
953             memcpy(data, src, src->size);
954             GlobalUnlock(handle);
955         }
956     }
957
958     if(!data) hr = create_empty_priv_data(&data);
959     if(FAILED(hr)) goto end;
960
961     hr = enum_fmtetc_construct( data, 0, enum_fmt );
962
963 end:
964     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
965     return hr;
966 }
967
968 /************************************************************************
969  * OLEClipbrd_IDataObject_DAdvise (IDataObject)
970  *
971  * The OLE Clipboard's does not implement this method
972  *
973  * See Windows documentation for more details on IDataObject methods.
974  */
975 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
976             IDataObject*     iface,
977             FORMATETC*       pformatetc,
978             DWORD            advf,
979             IAdviseSink*     pAdvSink,
980             DWORD*           pdwConnection)
981 {
982   TRACE("\n");
983   return E_NOTIMPL;
984 }
985
986 /************************************************************************
987  * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
988  *
989  * The OLE Clipboard's does not implement this method
990  *
991  * See Windows documentation for more details on IDataObject methods.
992  */
993 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
994             IDataObject*     iface,
995             DWORD            dwConnection)
996 {
997   TRACE("\n");
998   return E_NOTIMPL;
999 }
1000
1001 /************************************************************************
1002  * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
1003  *
1004  * The OLE Clipboard does not implement this method
1005  *
1006  * See Windows documentation for more details on IDataObject methods.
1007  */
1008 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
1009             IDataObject*     iface,
1010             IEnumSTATDATA**  ppenumAdvise)
1011 {
1012   TRACE("\n");
1013   return E_NOTIMPL;
1014 }
1015
1016 static const IDataObjectVtbl OLEClipbrd_IDataObject_VTable =
1017 {
1018   OLEClipbrd_IDataObject_QueryInterface,
1019   OLEClipbrd_IDataObject_AddRef,
1020   OLEClipbrd_IDataObject_Release,
1021   OLEClipbrd_IDataObject_GetData,
1022   OLEClipbrd_IDataObject_GetDataHere,
1023   OLEClipbrd_IDataObject_QueryGetData,
1024   OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
1025   OLEClipbrd_IDataObject_SetData,
1026   OLEClipbrd_IDataObject_EnumFormatEtc,
1027   OLEClipbrd_IDataObject_DAdvise,
1028   OLEClipbrd_IDataObject_DUnadvise,
1029   OLEClipbrd_IDataObject_EnumDAdvise
1030 };
1031
1032 /*---------------------------------------------------------------------*
1033  *           Internal implementation methods for the OLE clipboard
1034  *---------------------------------------------------------------------*/
1035
1036 /*********************************************************
1037  * Construct the OLEClipbrd class.
1038  */
1039 static ole_clipbrd* OLEClipbrd_Construct(void)
1040 {
1041     ole_clipbrd* This;
1042
1043     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1044     if (!This) return NULL;
1045
1046     This->lpvtbl = &OLEClipbrd_IDataObject_VTable;
1047     This->ref = 1;
1048
1049     This->hWndClipboard = NULL;
1050     This->pIDataObjectSrc = NULL;
1051     This->cached_enum = NULL;
1052
1053     theOleClipboard = This;
1054     return This;
1055 }
1056
1057 static void register_clipboard_formats(void)
1058 {
1059     static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1060     static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1061     static const WCHAR EmbedSourceW[] = { 'E','m','b','e','d',' ','S','o','u','r','c','e',0 };
1062
1063     if(!dataobject_clipboard_format)
1064         dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1065     if(!ole_priv_data_clipboard_format)
1066         ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1067     if(!embed_source_clipboard_format)
1068         embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSourceW);
1069 }
1070
1071 /***********************************************************************
1072  * OLEClipbrd_Initialize()
1073  * Initializes the OLE clipboard.
1074  */
1075 void OLEClipbrd_Initialize(void)
1076 {
1077   register_clipboard_formats();
1078
1079   if ( !theOleClipboard )
1080   {
1081     TRACE("()\n");
1082     theOleClipboard = OLEClipbrd_Construct();
1083   }
1084 }
1085
1086
1087 /***********************************************************************
1088  * OLEClipbrd_UnInitialize()
1089  * Un-Initializes the OLE clipboard
1090  */
1091 void OLEClipbrd_UnInitialize(void)
1092 {
1093   TRACE("()\n");
1094   /*
1095    * Destroy the clipboard if no one holds a reference to us.
1096    * Note that the clipboard was created with a reference count of 1.
1097    */
1098   if ( theOleClipboard && (theOleClipboard->ref <= 1) )
1099   {
1100     OLEClipbrd_Destroy( theOleClipboard );
1101   }
1102   else
1103   {
1104     WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");
1105   }
1106 }
1107
1108 /***********************************************************************
1109  * OLEClipbrd_CreateWindow()
1110  * Create the clipboard window
1111  */
1112 static HWND OLEClipbrd_CreateWindow(void)
1113 {
1114   HWND hwnd = 0;
1115   WNDCLASSEXA wcex;
1116
1117   /*
1118    * Register the clipboard window class if necessary
1119    */
1120     ZeroMemory( &wcex, sizeof(WNDCLASSEXA));
1121
1122     wcex.cbSize         = sizeof(WNDCLASSEXA);
1123     /* Windows creates this class with a style mask of 0
1124      * We don't bother doing this since the FindClassByAtom code
1125      * would have to be changed to deal with this idiosyncrasy. */
1126     wcex.style          = CS_GLOBALCLASS;
1127     wcex.lpfnWndProc    = clipbrd_wndproc;
1128     wcex.hInstance      = 0;
1129     wcex.lpszClassName  = OLEClipbrd_WNDCLASS;
1130
1131     RegisterClassExA(&wcex);
1132
1133   /*
1134    * Create a hidden window to receive OLE clipboard messages
1135    */
1136
1137 /*
1138  *  If we need to store state info we can store it here.
1139  *  For now we don't need this functionality.
1140  *   ClipboardWindowInfo clipboardInfo;
1141  *   ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo));
1142  */
1143
1144   hwnd = CreateWindowA(OLEClipbrd_WNDCLASS,
1145                                     "ClipboardWindow",
1146                                     WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1147                                     CW_USEDEFAULT, CW_USEDEFAULT,
1148                                     CW_USEDEFAULT, CW_USEDEFAULT,
1149                                     0,
1150                                     0,
1151                                     0,
1152                                     0 /*(LPVOID)&clipboardInfo */);
1153
1154   return hwnd;
1155 }
1156
1157 /*********************************************************************
1158  *          set_clipboard_formats
1159  *
1160  * Enumerate all HGLOBAL formats supported by the source and make
1161  * those formats available using delayed rendering using SetClipboardData.
1162  *
1163  * TODO: We need to additionally handle TYMED_IStorage and
1164  * TYMED_IStream data by copying into global memory.
1165  */
1166 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1167 {
1168     HRESULT hr;
1169     FORMATETC fmt;
1170     IEnumFORMATETC *enum_fmt;
1171     HGLOBAL priv_data_handle;
1172     DWORD target_offset;
1173     ole_priv_data *priv_data;
1174     DWORD count = 0, needed = sizeof(*priv_data), idx;
1175
1176     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1177     if(FAILED(hr)) return hr;
1178
1179     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1180     {
1181         count++;
1182         needed += sizeof(priv_data->entries[0]);
1183         if(fmt.ptd)
1184         {
1185             needed += fmt.ptd->tdSize;
1186             CoTaskMemFree(fmt.ptd);
1187         }
1188     }
1189
1190     /* Windows pads the list with two empty ole_priv_data_entries, one
1191      * after the entries array and one after the target device data.
1192      * Allocating with zero init to zero these pads. */
1193
1194     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1195     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1196     priv_data = GlobalLock(priv_data_handle);
1197
1198     priv_data->unk1 = 0;
1199     priv_data->size = needed;
1200     priv_data->unk2 = 1;
1201     priv_data->count = count;
1202     priv_data->unk3[0] = 0;
1203     priv_data->unk3[1] = 0;
1204
1205     IEnumFORMATETC_Reset(enum_fmt);
1206
1207     idx = 0;
1208     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1209
1210     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1211     {
1212         if (fmt.tymed == TYMED_HGLOBAL)
1213         {
1214             char fmt_name[80];
1215             TRACE("(cfFormat=%d:%s)\n", fmt.cfFormat,
1216                   GetClipboardFormatNameA(fmt.cfFormat, fmt_name, sizeof(fmt_name)-1) ? fmt_name : "");
1217
1218             SetClipboardData(fmt.cfFormat, NULL);
1219         }
1220
1221         priv_data->entries[idx].fmtetc = fmt;
1222         if(fmt.ptd)
1223         {
1224             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1225             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1226             target_offset += fmt.ptd->tdSize;
1227             CoTaskMemFree(fmt.ptd);
1228         }
1229
1230         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1231         priv_data->entries[idx].unk[0] = 0;
1232         priv_data->entries[idx].unk[1] = 0;
1233
1234         idx++;
1235     }
1236
1237     IEnumFORMATETC_Release(enum_fmt);
1238
1239     /* Cache the list and fixup any target device offsets to ptrs */
1240     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1241     memcpy(clipbrd->cached_enum, priv_data, needed);
1242     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1243         if(clipbrd->cached_enum->entries[idx].fmtetc.ptd)
1244             clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1245                 (DVTARGETDEVICE *)((char*)clipbrd->cached_enum + (DWORD)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1246
1247     GlobalUnlock(priv_data_handle);
1248     SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1249
1250     return S_OK;
1251 }
1252
1253 /*********************************************************************
1254  *          set_dataobject_format
1255  *
1256  * Windows creates a 'DataObject' clipboard format that contains the
1257  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1258  */
1259 static HRESULT set_dataobject_format(HWND hwnd)
1260 {
1261     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1262     HWND *data;
1263
1264     if(!h) return E_OUTOFMEMORY;
1265
1266     data = GlobalLock(h);
1267     *data = hwnd;
1268     GlobalUnlock(h);
1269
1270     if(!SetClipboardData(dataobject_clipboard_format, h))
1271     {
1272         GlobalFree(h);
1273         return CLIPBRD_E_CANT_SET;
1274     }
1275
1276     return S_OK;
1277 }
1278
1279 /*---------------------------------------------------------------------*
1280  *           Win32 OLE clipboard API
1281  *---------------------------------------------------------------------*/
1282
1283 /***********************************************************************
1284  *           OleSetClipboard     [OLE32.@]
1285  *  Places a pointer to the specified data object onto the clipboard,
1286  *  making the data object accessible to the OleGetClipboard function.
1287  *
1288  * RETURNS
1289  *
1290  *    S_OK                  IDataObject pointer placed on the clipboard
1291  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
1292  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
1293  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
1294  *    CLIPBRD_E_CANT_SET    SetClipboard failed
1295  */
1296
1297 HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)
1298 {
1299   HRESULT hr = S_OK;
1300   struct oletls *info = COM_CurrentInfo();
1301
1302   TRACE("(%p)\n", pDataObj);
1303
1304   if(!info)
1305     WARN("Could not allocate tls\n");
1306   else
1307     if(!info->ole_inits)
1308       return CO_E_NOTINITIALIZED;
1309
1310   OLEClipbrd_Initialize();
1311
1312   /*
1313    * If the Ole clipboard window hasn't been created yet, create it now.
1314    */
1315   if ( !theOleClipboard->hWndClipboard )
1316     theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
1317
1318   if ( !theOleClipboard->hWndClipboard ) return E_FAIL;
1319
1320   if ( !OpenClipboard(theOleClipboard->hWndClipboard) ) return CLIPBRD_E_CANT_OPEN;
1321
1322   /*
1323    * Empty the current clipboard and make our window the clipboard owner
1324    * NOTE: This will trigger a WM_DESTROYCLIPBOARD message
1325    */
1326   if ( !EmptyClipboard() )
1327   {
1328     hr = CLIPBRD_E_CANT_EMPTY;
1329     goto end;
1330   }
1331
1332   /*
1333    * If we are already holding on to an IDataObject first release that.
1334    */
1335   if ( theOleClipboard->pIDataObjectSrc )
1336   {
1337     IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1338     theOleClipboard->pIDataObjectSrc = NULL;
1339     HeapFree(GetProcessHeap(), 0, theOleClipboard->cached_enum);
1340     theOleClipboard->cached_enum = NULL;
1341   }
1342
1343   /* A NULL value indicates that the clipboard should be emptied. */
1344   theOleClipboard->pIDataObjectSrc = pDataObj;
1345   if ( pDataObj )
1346   {
1347     IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
1348     hr = set_clipboard_formats(theOleClipboard, pDataObj);
1349     if(FAILED(hr)) goto end;
1350   }
1351
1352   hr = set_dataobject_format(theOleClipboard->hWndClipboard);
1353
1354 end:
1355
1356   if ( !CloseClipboard() )  hr = CLIPBRD_E_CANT_CLOSE;
1357
1358   if ( FAILED(hr) )
1359   {
1360     if (theOleClipboard->pIDataObjectSrc)
1361     {
1362       IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1363       theOleClipboard->pIDataObjectSrc = NULL;
1364       HeapFree(GetProcessHeap(), 0, theOleClipboard->cached_enum);
1365       theOleClipboard->cached_enum = NULL;
1366     }
1367   }
1368
1369   return hr;
1370 }
1371
1372
1373 /***********************************************************************
1374  * OleGetClipboard [OLE32.@]
1375  * Returns a pointer to our internal IDataObject which represents the conceptual
1376  * state of the Windows clipboard. If the current clipboard already contains
1377  * an IDataObject, our internal IDataObject will delegate to this object.
1378  */
1379 HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
1380 {
1381   HRESULT hr = S_OK;
1382   TRACE("()\n");
1383
1384   /*
1385    * Make sure we have a clipboard object
1386    */
1387   OLEClipbrd_Initialize();
1388
1389   if (!theOleClipboard)
1390     return E_OUTOFMEMORY;
1391
1392   /* Return a reference counted IDataObject */
1393   hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl),
1394                                    &IID_IDataObject,  (void**)ppDataObj);
1395   return hr;
1396 }
1397
1398 /******************************************************************************
1399  *              OleFlushClipboard        [OLE32.@]
1400  *  Renders the data from the source IDataObject into the windows clipboard
1401  *
1402  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1403  *  by copying the storage into global memory. Subsequently the default
1404  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1405  *  back to TYMED_IStorage.
1406  */
1407 HRESULT WINAPI OleFlushClipboard(void)
1408 {
1409   IEnumFORMATETC* penumFormatetc = NULL;
1410   FORMATETC rgelt;
1411   HRESULT hr = S_OK;
1412
1413   TRACE("()\n");
1414
1415   OLEClipbrd_Initialize();
1416
1417   /*
1418    * Already flushed or no source DataObject? Nothing to do.
1419    */
1420   if (!theOleClipboard->pIDataObjectSrc)
1421     return S_OK;
1422
1423   if (!OpenClipboard(theOleClipboard->hWndClipboard))
1424     return CLIPBRD_E_CANT_OPEN;
1425
1426   /*
1427    * Render all HGLOBAL formats supported by the source into
1428    * the windows clipboard.
1429    */
1430   if ( FAILED( hr = IDataObject_EnumFormatEtc( theOleClipboard->pIDataObjectSrc,
1431                                                DATADIR_GET,
1432                                                &penumFormatetc) ))
1433     goto end;
1434
1435
1436   while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
1437   {
1438     if ( rgelt.tymed == TYMED_HGLOBAL )
1439     {
1440       CHAR szFmtName[80];
1441       TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
1442             GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
1443               ? szFmtName : "");
1444
1445       if ( FAILED(render_format( theOleClipboard->pIDataObjectSrc, &rgelt )) )
1446         continue;
1447     }
1448   }
1449
1450   IEnumFORMATETC_Release(penumFormatetc);
1451
1452   hr = set_dataobject_format(NULL);
1453
1454   IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1455   theOleClipboard->pIDataObjectSrc = NULL;
1456   HeapFree(GetProcessHeap(), 0, theOleClipboard->cached_enum);
1457   theOleClipboard->cached_enum = NULL;
1458
1459 end:
1460
1461   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1462
1463   return hr;
1464 }
1465
1466
1467 /***********************************************************************
1468  *           OleIsCurrentClipboard [OLE32.@]
1469  */
1470 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject)
1471 {
1472   TRACE("()\n");
1473   /*
1474    * Make sure we have a clipboard object
1475    */
1476   OLEClipbrd_Initialize();
1477
1478   if (!theOleClipboard)
1479     return E_OUTOFMEMORY;
1480
1481   if (pDataObject == NULL)
1482     return S_FALSE;
1483
1484   return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;
1485 }