~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ole32/clipboard.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  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 #include <stdio.h>
 65 
 66 #define COBJMACROS
 67 #define NONAMELESSUNION
 68 #define NONAMELESSSTRUCT
 69 
 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"
 79 
 80 #include "storage32.h"
 81 
 82 #include "compobj_private.h"
 83 
 84 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 85 
 86 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
 87 
 88 /* Structure of 'Ole Private Data' clipboard format */
 89 typedef struct
 90 {
 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;
 95 
 96 typedef struct
 97 {
 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;
106 
107 /*****************************************************************************
108  *           td_offs_to_ptr
109  *
110  * Returns a ptr to a target device at a given offset from the
111  * start of the ole_priv_data.
112  *
113  * Used when unpacking ole private data from the clipboard.
114  */
115 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
116 {
117     if(off == 0) return NULL;
118     return (DVTARGETDEVICE*)((char*)data + off);
119 }
120 
121 /*****************************************************************************
122  *           td_get_offs
123  *
124  * Get the offset from the start of the ole_priv_data of the idx'th
125  * target device.
126  *
127  * Used when packing ole private data to the clipboard.
128  */
129 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
130 {
131     if(data->entries[idx].fmtetc.ptd == NULL) return 0;
132     return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
133 }
134 
135 /****************************************************************************
136  * Consumer snapshot.  Represents the state of the ole clipboard
137  * returned by OleGetClipboard().
138  */
139 typedef struct snapshot
140 {
141     const IDataObjectVtbl* lpVtbl;
142     LONG ref;
143 
144     DWORD seq_no;                   /* Clipboard sequence number corresponding to this snapshot */
145 
146     IDataObject *data;              /* If we unmarshal a remote data object we hold a ref here */
147 } snapshot;
148 
149 /****************************************************************************
150  * ole_clipbrd
151  */
152 typedef struct ole_clipbrd
153 {
154     snapshot *latest_snapshot;       /* Latest consumer snapshot */
155 
156     HWND window;                     /* Hidden clipboard window */
157     IDataObject *src_data;           /* Source object passed to OleSetClipboard */
158     ole_priv_data *cached_enum;      /* Cached result from the enumeration of src data object */
159     IStream *marshal_data;           /* Stream onto which to marshal src_data */
160 } ole_clipbrd;
161 
162 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
163 {
164     return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl));
165 }
166 
167 typedef struct PresentationDataHeader
168 {
169   BYTE unknown1[28];
170   DWORD dwObjectExtentX;
171   DWORD dwObjectExtentY;
172   DWORD dwSize;
173 } PresentationDataHeader;
174 
175 /*
176  * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
177  */
178 static ole_clipbrd* theOleClipboard;
179 
180 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
181 {
182     struct oletls *info = COM_CurrentInfo();
183     *clipbrd = NULL;
184 
185     if(!info->ole_inits)
186         return CO_E_NOTINITIALIZED;
187     *clipbrd = theOleClipboard;
188 
189     return S_OK;
190 }
191 
192 /*
193  * Name of our registered OLE clipboard window class
194  */
195 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
196 
197 static const WCHAR wine_marshal_dataobject[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0};
198 
199 UINT ownerlink_clipboard_format = 0;
200 UINT filename_clipboard_format = 0;
201 UINT filenameW_clipboard_format = 0;
202 UINT dataobject_clipboard_format = 0;
203 UINT embedded_object_clipboard_format = 0;
204 UINT embed_source_clipboard_format = 0;
205 UINT custom_link_source_clipboard_format = 0;
206 UINT link_source_clipboard_format = 0;
207 UINT object_descriptor_clipboard_format = 0;
208 UINT link_source_descriptor_clipboard_format = 0;
209 UINT ole_private_data_clipboard_format = 0;
210 
211 static UINT wine_marshal_clipboard_format;
212 
213 static inline char *dump_fmtetc(FORMATETC *fmt)
214 {
215     static char buf[100];
216 
217     snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
218              fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
219     return buf;
220 }
221 
222 /*---------------------------------------------------------------------*
223  *  Implementation of the internal IEnumFORMATETC interface returned by
224  *  the OLE clipboard's IDataObject.
225  *---------------------------------------------------------------------*/
226 
227 typedef struct enum_fmtetc
228 {
229     const IEnumFORMATETCVtbl *lpVtbl;
230     LONG ref;
231 
232     UINT pos;    /* current enumerator position */
233     ole_priv_data *data;
234 } enum_fmtetc;
235 
236 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
237 {
238     return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl));
239 }
240 
241 /************************************************************************
242  * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
243  *
244  * See Windows documentation for more details on IUnknown methods.
245  */
246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
247   (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
248 {
249   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
250 
251   TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
252 
253   *ppvObj = NULL;
254 
255   if(IsEqualIID(riid, &IID_IUnknown) ||
256      IsEqualIID(riid, &IID_IEnumFORMATETC))
257   {
258     *ppvObj = iface;
259   }
260 
261   if(*ppvObj)
262   {
263     IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
264     TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
265     return S_OK;
266   }
267 
268   TRACE("-- Interface: E_NOINTERFACE\n");
269   return E_NOINTERFACE;
270 }
271 
272 /************************************************************************
273  * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
274  *
275  */
276 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
277 {
278   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
279   TRACE("(%p)->(count=%u)\n",This, This->ref);
280 
281   return InterlockedIncrement(&This->ref);
282 }
283 
284 /************************************************************************
285  * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
286  *
287  * See Windows documentation for more details on IUnknown methods.
288  */
289 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
290 {
291   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
292   ULONG ref;
293 
294   TRACE("(%p)->(count=%u)\n",This, This->ref);
295 
296   ref = InterlockedDecrement(&This->ref);
297   if (!ref)
298   {
299     TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
300     HeapFree(GetProcessHeap(), 0, This->data);
301     HeapFree(GetProcessHeap(), 0, This);
302   }
303   return ref;
304 }
305 
306 /************************************************************************
307  * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
308  *
309  * Standard enumerator members for IEnumFORMATETC
310  */
311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
312   (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
313 {
314   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
315   UINT cfetch, i;
316   HRESULT hres = S_FALSE;
317 
318   TRACE("(%p)->(pos=%u)\n", This, This->pos);
319 
320   if (This->pos < This->data->count)
321   {
322     cfetch = This->data->count - This->pos;
323     if (cfetch >= celt)
324     {
325       cfetch = celt;
326       hres = S_OK;
327     }
328 
329     for(i = 0; i < cfetch; i++)
330     {
331       rgelt[i] = This->data->entries[This->pos++].fmtetc;
332       if(rgelt[i].ptd)
333       {
334         DVTARGETDEVICE *target = rgelt[i].ptd;
335         rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
336         if(!rgelt[i].ptd) return E_OUTOFMEMORY;
337         memcpy(rgelt[i].ptd, target, target->tdSize);
338       }
339     }
340   }
341   else
342   {
343     cfetch = 0;
344   }
345 
346   if (pceltFethed)
347   {
348     *pceltFethed = cfetch;
349   }
350 
351   return hres;
352 }
353 
354 /************************************************************************
355  * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
356  *
357  * Standard enumerator members for IEnumFORMATETC
358  */
359 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
360 {
361   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
362   TRACE("(%p)->(num=%u)\n", This, celt);
363 
364   This->pos += celt;
365   if (This->pos > This->data->count)
366   {
367     This->pos = This->data->count;
368     return S_FALSE;
369   }
370   return S_OK;
371 }
372 
373 /************************************************************************
374  * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
375  *
376  * Standard enumerator members for IEnumFORMATETC
377  */
378 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
379 {
380   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
381   TRACE("(%p)->()\n", This);
382 
383   This->pos = 0;
384   return S_OK;
385 }
386 
387 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
388 
389 /************************************************************************
390  * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
391  *
392  * Standard enumerator members for IEnumFORMATETC
393  */
394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
395   (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
396 {
397   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
398   ole_priv_data *new_data;
399   DWORD i;
400 
401   TRACE("(%p)->(%p)\n", This, obj);
402 
403   if ( !obj ) return E_INVALIDARG;
404   *obj = NULL;
405 
406   new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
407   if(!new_data) return E_OUTOFMEMORY;
408   memcpy(new_data, This->data, This->data->size);
409 
410   /* Fixup any target device ptrs */
411   for(i = 0; i < This->data->count; i++)
412       new_data->entries[i].fmtetc.ptd =
413           td_offs_to_ptr(new_data, td_get_offs(This->data, i));
414 
415   return enum_fmtetc_construct(new_data, This->pos, obj);
416 }
417 
418 static const IEnumFORMATETCVtbl efvt =
419 {
420   OLEClipbrd_IEnumFORMATETC_QueryInterface,
421   OLEClipbrd_IEnumFORMATETC_AddRef,
422   OLEClipbrd_IEnumFORMATETC_Release,
423   OLEClipbrd_IEnumFORMATETC_Next,
424   OLEClipbrd_IEnumFORMATETC_Skip,
425   OLEClipbrd_IEnumFORMATETC_Reset,
426   OLEClipbrd_IEnumFORMATETC_Clone
427 };
428 
429 /************************************************************************
430  * enum_fmtetc_construct
431  *
432  * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
433  */
434 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
435 {
436   enum_fmtetc* ef;
437 
438   *obj = NULL;
439   ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
440   if (!ef) return E_OUTOFMEMORY;
441 
442   ef->ref = 1;
443   ef->lpVtbl = &efvt;
444   ef->data = data;
445   ef->pos = pos;
446 
447   TRACE("(%p)->()\n", ef);
448   *obj = (IEnumFORMATETC *)ef;
449   return S_OK;
450 }
451 
452 /***********************************************************************
453  *                    dup_global_mem
454  *
455  * Helper method to duplicate an HGLOBAL chunk of memory
456  */
457 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
458 {
459     void *src_ptr, *dst_ptr;
460     DWORD size;
461 
462     *dst = NULL;
463     if ( !src ) return S_FALSE;
464 
465     size = GlobalSize(src);
466 
467     *dst = GlobalAlloc( flags, size );
468     if ( !*dst ) return E_OUTOFMEMORY;
469 
470     src_ptr = GlobalLock(src);
471     dst_ptr = GlobalLock(*dst);
472 
473     memcpy(dst_ptr, src_ptr, size);
474 
475     GlobalUnlock(*dst);
476     GlobalUnlock(src);
477 
478     return S_OK;
479 }
480 
481 /************************************************************
482  *              render_embed_source_hack
483  *
484  * This is clearly a hack and has no place in the clipboard code.
485  *
486  */
487 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
488 {
489     STGMEDIUM std;
490     HGLOBAL hStorage = 0;
491     HRESULT hr = S_OK;
492     ILockBytes *ptrILockBytes;
493 
494     memset(&std, 0, sizeof(STGMEDIUM));
495     std.tymed = fmt->tymed = TYMED_ISTORAGE;
496 
497     hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
498     if (hStorage == NULL) return E_OUTOFMEMORY;
499     hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
500     hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
501     ILockBytes_Release(ptrILockBytes);
502 
503     if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
504     {
505         WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
506         GlobalFree(hStorage);
507         return hr;
508     }
509 
510     if (1) /* check whether the presentation data is already -not- present */
511     {
512         FORMATETC fmt2;
513         STGMEDIUM std2;
514         METAFILEPICT *mfp = 0;
515 
516         fmt2.cfFormat = CF_METAFILEPICT;
517         fmt2.ptd = 0;
518         fmt2.dwAspect = DVASPECT_CONTENT;
519         fmt2.lindex = -1;
520         fmt2.tymed = TYMED_MFPICT;
521 
522         memset(&std2, 0, sizeof(STGMEDIUM));
523         std2.tymed = TYMED_MFPICT;
524 
525         /* Get the metafile picture out of it */
526 
527         if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
528         {
529             mfp = GlobalLock(std2.u.hGlobal);
530         }
531 
532         if (mfp)
533         {
534             OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '', '', '', 0};
535             IStream *pStream = 0;
536             void *mfBits;
537             PresentationDataHeader pdh;
538             INT nSize;
539             CLSID clsID;
540             LPOLESTR strProgID;
541             CHAR strOleTypeName[51];
542             BYTE OlePresStreamHeader [] =
543             {
544                 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
545                 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
546                 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
547                 0x00, 0x00, 0x00, 0x00
548             };
549 
550             nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
551 
552             memset(&pdh, 0, sizeof(PresentationDataHeader));
553             memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
554 
555             pdh.dwObjectExtentX = mfp->xExt;
556             pdh.dwObjectExtentY = mfp->yExt;
557             pdh.dwSize = nSize;
558 
559             hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
560 
561             hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
562 
563             mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
564             nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
565 
566             hr = IStream_Write(pStream, mfBits, nSize, NULL);
567 
568             IStream_Release(pStream);
569 
570             HeapFree(GetProcessHeap(), 0, mfBits);
571 
572             GlobalUnlock(std2.u.hGlobal);
573             ReleaseStgMedium(&std2);
574 
575             ReadClassStg(std.u.pstg, &clsID);
576             ProgIDFromCLSID(&clsID, &strProgID);
577 
578             WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
579             OLECONVERT_CreateOleStream(std.u.pstg);
580             OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
581         }
582     }
583 
584     if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
585     {
586         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
587         GlobalFree(hStorage);
588         hr = CLIPBRD_E_CANT_SET;
589     }
590 
591     ReleaseStgMedium(&std);
592     return hr;
593 }
594 
595 /************************************************************************
596  *           find_format_in_list
597  *
598  * Returns the first entry that matches the provided clipboard format.
599  */
600 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
601 {
602     DWORD i;
603     for(i = 0; i < num; i++)
604         if(entries[i].fmtetc.cfFormat == cf)
605             return &entries[i];
606 
607     return NULL;
608 }
609 
610 /***************************************************************************
611  *         get_data_from_storage
612  *
613  * Returns storage data in an HGLOBAL.
614  */
615 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
616 {
617     HGLOBAL h;
618     IStorage *stg;
619     HRESULT hr;
620     FORMATETC stg_fmt;
621     STGMEDIUM med;
622     ILockBytes *lbs;
623 
624     *mem = NULL;
625 
626     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
627     if(!h) return E_OUTOFMEMORY;
628 
629     hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
630     if(SUCCEEDED(hr))
631     {
632         hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
633         ILockBytes_Release(lbs);
634     }
635     if(FAILED(hr))
636     {
637         GlobalFree(h);
638         return hr;
639     }
640 
641     stg_fmt = *fmt;
642     med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
643     med.u.pstg = stg;
644     med.pUnkForRelease = NULL;
645 
646     hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
647     if(FAILED(hr))
648     {
649         med.u.pstg = NULL;
650         hr = IDataObject_GetData(data, &stg_fmt, &med);
651         if(FAILED(hr)) goto end;
652 
653         hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
654         ReleaseStgMedium(&med);
655         if(FAILED(hr)) goto end;
656     }
657     *mem = h;
658 
659 end:
660     IStorage_Release(stg);
661     if(FAILED(hr)) GlobalFree(h);
662     return hr;
663 }
664 
665 /***************************************************************************
666  *         get_data_from_stream
667  *
668  * Returns stream data in an HGLOBAL.
669  */
670 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
671 {
672     HGLOBAL h;
673     IStream *stm = NULL;
674     HRESULT hr;
675     FORMATETC stm_fmt;
676     STGMEDIUM med;
677 
678     *mem = NULL;
679 
680     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
681     if(!h) return E_OUTOFMEMORY;
682 
683     hr = CreateStreamOnHGlobal(h, FALSE, &stm);
684     if(FAILED(hr)) goto error;
685 
686     stm_fmt = *fmt;
687     med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
688     med.u.pstm = stm;
689     med.pUnkForRelease = NULL;
690 
691     hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
692     if(FAILED(hr))
693     {
694         LARGE_INTEGER offs;
695         ULARGE_INTEGER pos;
696 
697         med.u.pstm = NULL;
698         hr = IDataObject_GetData(data, &stm_fmt, &med);
699         if(FAILED(hr)) goto error;
700 
701         offs.QuadPart = 0;
702         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
703         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
704         hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
705         ReleaseStgMedium(&med);
706         if(FAILED(hr)) goto error;
707     }
708     *mem = h;
709     IStream_Release(stm);
710     return S_OK;
711 
712 error:
713     if(stm) IStream_Release(stm);
714     GlobalFree(h);
715     return hr;
716 }
717 
718 /***************************************************************************
719  *         get_data_from_global
720  *
721  * Returns global data in an HGLOBAL.
722  */
723 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
724 {
725     HGLOBAL h;
726     HRESULT hr;
727     FORMATETC mem_fmt;
728     STGMEDIUM med;
729 
730     *mem = NULL;
731 
732     mem_fmt = *fmt;
733     mem_fmt.tymed = TYMED_HGLOBAL;
734 
735     hr = IDataObject_GetData(data, &mem_fmt, &med);
736     if(FAILED(hr)) return hr;
737 
738     hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
739 
740     if(SUCCEEDED(hr)) *mem = h;
741 
742     ReleaseStgMedium(&med);
743 
744     return hr;
745 }
746 
747 /***********************************************************************
748  *                render_format
749  *
750  * Render the clipboard data. Note that this call will delegate to the
751  * source data object.
752  */
753 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
754 {
755     HGLOBAL clip_data = NULL;
756     HRESULT hr;
757 
758     /* Embed source hack */
759     if(fmt->cfFormat == embed_source_clipboard_format)
760     {
761         return render_embed_source_hack(data, fmt);
762     }
763 
764     if(fmt->tymed & TYMED_ISTORAGE)
765     {
766         hr = get_data_from_storage(data, fmt, &clip_data);
767     }
768     else if(fmt->tymed & TYMED_ISTREAM)
769     {
770         hr = get_data_from_stream(data, fmt, &clip_data);
771     }
772     else if(fmt->tymed & TYMED_HGLOBAL)
773     {
774         hr = get_data_from_global(data, fmt, &clip_data);
775     }
776     else
777     {
778         FIXME("Unhandled tymed %x\n", fmt->tymed);
779         hr = DV_E_FORMATETC;
780     }
781 
782     if(SUCCEEDED(hr))
783     {
784         if ( !SetClipboardData(fmt->cfFormat, clip_data) )
785         {
786             WARN("() : Failed to set rendered clipboard data into clipboard!\n");
787             GlobalFree(clip_data);
788             hr = CLIPBRD_E_CANT_SET;
789         }
790     }
791 
792     return hr;
793 }
794 
795 /*---------------------------------------------------------------------*
796  *  Implementation of the internal IDataObject interface exposed by
797  *  the OLE clipboard.
798  *---------------------------------------------------------------------*/
799 
800 
801 /************************************************************************
802  *           snapshot_QueryInterface
803  */
804 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
805                                               REFIID riid, void **ppvObject)
806 {
807   snapshot *This = impl_from_IDataObject(iface);
808   TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
809 
810   if ( (This==0) || (ppvObject==0) )
811     return E_INVALIDARG;
812 
813   *ppvObject = 0;
814 
815   if (IsEqualIID(&IID_IUnknown, riid) ||
816       IsEqualIID(&IID_IDataObject, riid))
817   {
818     *ppvObject = iface;
819   }
820   else
821   {
822     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
823     return E_NOINTERFACE;
824   }
825 
826   IUnknown_AddRef((IUnknown*)*ppvObject);
827 
828   return S_OK;
829 }
830 
831 /************************************************************************
832  *              snapshot_AddRef
833  */
834 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
835 {
836     snapshot *This = impl_from_IDataObject(iface);
837 
838     TRACE("(%p)->(count=%u)\n", This, This->ref);
839 
840     return InterlockedIncrement(&This->ref);
841 }
842 
843 /************************************************************************
844  *      snapshot_Release
845  */
846 static ULONG WINAPI snapshot_Release(IDataObject *iface)
847 {
848     snapshot *This = impl_from_IDataObject(iface);
849     ULONG ref;
850 
851     TRACE("(%p)->(count=%u)\n", This, This->ref);
852 
853     ref = InterlockedDecrement(&This->ref);
854 
855     if (ref == 0)
856     {
857         ole_clipbrd *clipbrd;
858         HRESULT hr = get_ole_clipbrd(&clipbrd);
859 
860         if(This->data) IDataObject_Release(This->data);
861 
862         if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
863             clipbrd->latest_snapshot = NULL;
864         HeapFree(GetProcessHeap(), 0, This);
865     }
866 
867     return ref;
868 }
869 
870 /************************************************************
871  *              get_current_ole_clip_window
872  *
873  * Return the window that owns the ole clipboard.
874  *
875  * If the clipboard is flushed or not owned by ole this will
876  * return NULL.
877  */
878 static HWND get_current_ole_clip_window(void)
879 {
880     HGLOBAL h;
881     HWND *ptr, wnd;
882 
883     h = GetClipboardData(dataobject_clipboard_format);
884     if(!h) return NULL;
885     ptr = GlobalLock(h);
886     if(!ptr) return NULL;
887     wnd = *ptr;
888     GlobalUnlock(h);
889     return wnd;
890 }
891 
892 /************************************************************
893  *              get_current_dataobject
894  *
895  * Return an unmarshalled IDataObject if there is a current
896  * (ie non-flushed) object on the ole clipboard.
897  */
898 static HRESULT get_current_dataobject(IDataObject **data)
899 {
900     HRESULT hr = S_FALSE;
901     HWND wnd = get_current_ole_clip_window();
902     HGLOBAL h;
903     void *ptr;
904     IStream *stm;
905     LARGE_INTEGER pos;
906 
907     *data = NULL;
908     if(!wnd) return S_FALSE;
909 
910     h = GetClipboardData(wine_marshal_clipboard_format);
911     if(!h) return S_FALSE;
912     if(GlobalSize(h) == 0) return S_FALSE;
913     ptr = GlobalLock(h);
914     if(!ptr) return S_FALSE;
915 
916     hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
917     if(FAILED(hr)) goto end;
918 
919     hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
920     if(SUCCEEDED(hr))
921     {
922         pos.QuadPart = 0;
923         IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
924         hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
925     }
926     IStream_Release(stm);
927 
928 end:
929     GlobalUnlock(h);
930     return hr;
931 }
932 
933 static DWORD get_tymed_from_nonole_cf(UINT cf)
934 {
935     if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
936 
937     switch(cf)
938     {
939     case CF_TEXT:
940     case CF_OEMTEXT:
941     case CF_UNICODETEXT:
942         return TYMED_ISTREAM | TYMED_HGLOBAL;
943     case CF_ENHMETAFILE:
944         return TYMED_ENHMF;
945     case CF_METAFILEPICT:
946         return TYMED_MFPICT;
947     default:
948         FIXME("returning TYMED_NULL for cf %04x\n", cf);
949         return TYMED_NULL;
950     }
951 }
952 
953 /***********************************************************
954  *     get_priv_data
955  *
956  * Returns a copy of the Ole Private Data
957  */
958 static HRESULT get_priv_data(ole_priv_data **data)
959 {
960     HGLOBAL handle;
961     HRESULT hr = S_OK;
962     ole_priv_data *ret = NULL;
963 
964     *data = NULL;
965 
966     handle = GetClipboardData( ole_private_data_clipboard_format );
967     if(handle)
968     {
969         ole_priv_data *src = GlobalLock(handle);
970         if(src)
971         {
972             DWORD i;
973 
974             /* FIXME: sanity check on size */
975             ret = HeapAlloc(GetProcessHeap(), 0, src->size);
976             if(!ret)
977             {
978                 GlobalUnlock(handle);
979                 return E_OUTOFMEMORY;
980             }
981             memcpy(ret, src, src->size);
982             GlobalUnlock(handle);
983 
984             /* Fixup any target device offsets to ptrs */
985             for(i = 0; i < ret->count; i++)
986                 ret->entries[i].fmtetc.ptd =
987                     td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
988         }
989     }
990 
991     if(!ret) /* Non-ole data */
992     {
993         UINT cf;
994         DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
995 
996         for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
997         {
998             char buf[100];
999             GetClipboardFormatNameA(cf, buf, sizeof(buf));
1000             TRACE("\tcf %04x %s\n", cf, buf);
1001             ;
1002         }
1003         TRACE("count %d\n", count);
1004         size += count * sizeof(ret->entries[0]);
1005 
1006         /* There are holes in fmtetc so zero init */
1007         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1008         if(!ret) return E_OUTOFMEMORY;
1009         ret->size = size;
1010         ret->count = count;
1011 
1012         for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1013         {
1014             ret->entries[idx].fmtetc.cfFormat = cf;
1015             ret->entries[idx].fmtetc.ptd = NULL;
1016             ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1017             ret->entries[idx].fmtetc.lindex = -1;
1018             ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1019             ret->entries[idx].first_use = 1;
1020         }
1021     }
1022 
1023     *data = ret;
1024     return hr;
1025 }
1026 
1027 /************************************************************************
1028  *                    get_stgmed_for_global
1029  *
1030  * Returns a stg medium with a copy of the global handle
1031  */
1032 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1033 {
1034     HRESULT hr;
1035 
1036     med->pUnkForRelease = NULL;
1037     med->tymed = TYMED_NULL;
1038 
1039     hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1040 
1041     if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1042 
1043     return hr;
1044 }
1045 
1046 /************************************************************************
1047  *                    get_stgmed_for_stream
1048  *
1049  * Returns a stg medium with a stream based on the handle
1050  */
1051 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1052 {
1053     HRESULT hr;
1054     HGLOBAL dst;
1055 
1056     med->pUnkForRelease = NULL;
1057     med->tymed = TYMED_NULL;
1058 
1059     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1060     if(FAILED(hr)) return hr;
1061 
1062     hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1063     if(FAILED(hr))
1064     {
1065         GlobalFree(dst);
1066         return hr;
1067     }
1068 
1069     med->tymed = TYMED_ISTREAM;
1070     return hr;
1071 }
1072 
1073 /************************************************************************
1074  *                    get_stgmed_for_storage
1075  *
1076  * Returns a stg medium with a storage based on the handle
1077  */
1078 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1079 {
1080     HRESULT hr;
1081     HGLOBAL dst;
1082     ILockBytes *lbs;
1083 
1084     med->pUnkForRelease = NULL;
1085     med->tymed = TYMED_NULL;
1086 
1087     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1088     if(FAILED(hr)) return hr;
1089 
1090     hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1091     if(FAILED(hr))
1092     {
1093         GlobalFree(dst);
1094         return hr;
1095     }
1096 
1097     hr = StgOpenStorageOnILockBytes(lbs, NULL,  STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1098     ILockBytes_Release(lbs);
1099     if(FAILED(hr))
1100     {
1101         GlobalFree(dst);
1102         return hr;
1103     }
1104 
1105     med->tymed = TYMED_ISTORAGE;
1106     return hr;
1107 }
1108 
1109 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1110 {
1111     const WCHAR *str1, *str2;
1112 
1113     if(off1 == 0 && off2 == 0) return TRUE;
1114     if(off1 == 0 || off2 == 0) return FALSE;
1115 
1116     str1 = (const WCHAR*)((const char*)t1 + off1);
1117     str2 = (const WCHAR*)((const char*)t2 + off2);
1118 
1119     return !lstrcmpW(str1, str2);
1120 }
1121 
1122 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1123 {
1124     if(t1 == NULL && t2 == NULL) return TRUE;
1125     if(t1 == NULL || t2 == NULL) return FALSE;
1126 
1127     if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1128         return FALSE;
1129     if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1130         return FALSE;
1131     if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1132         return FALSE;
1133 
1134     /* FIXME check devmode? */
1135 
1136     return TRUE;
1137 }
1138 
1139 /************************************************************************
1140  *         snapshot_GetData
1141  */
1142 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1143                                        STGMEDIUM *med)
1144 {
1145     snapshot *This = impl_from_IDataObject(iface);
1146     HANDLE h;
1147     HRESULT hr;
1148     ole_priv_data *enum_data = NULL;
1149     ole_priv_data_entry *entry;
1150     DWORD mask;
1151 
1152     TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1153 
1154     if ( !fmt || !med ) return E_INVALIDARG;
1155 
1156     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1157 
1158     if(!This->data)
1159         hr = get_current_dataobject(&This->data);
1160 
1161     if(This->data)
1162     {
1163         hr = IDataObject_GetData(This->data, fmt, med);
1164         CloseClipboard();
1165         return hr;
1166     }
1167 
1168     h = GetClipboardData(fmt->cfFormat);
1169     if(!h)
1170     {
1171         hr = DV_E_FORMATETC;
1172         goto end;
1173     }
1174 
1175     hr = get_priv_data(&enum_data);
1176     if(FAILED(hr)) goto end;
1177 
1178     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1179     if(entry)
1180     {
1181         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1182         {
1183             hr = DV_E_FORMATETC;
1184             goto end;
1185         }
1186         mask = fmt->tymed & entry->fmtetc.tymed;
1187         if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1188     }
1189     else /* non-Ole format */
1190         mask = fmt->tymed & TYMED_HGLOBAL;
1191 
1192     if(mask & TYMED_ISTORAGE)
1193         hr = get_stgmed_for_storage(h, med);
1194     else if(mask & TYMED_HGLOBAL)
1195         hr = get_stgmed_for_global(h, med);
1196     else if(mask & TYMED_ISTREAM)
1197         hr = get_stgmed_for_stream(h, med);
1198     else
1199     {
1200         FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed);
1201         hr = E_FAIL;
1202         goto end;
1203     }
1204 
1205 end:
1206     HeapFree(GetProcessHeap(), 0, enum_data);
1207     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1208     return hr;
1209 }
1210 
1211 /************************************************************************
1212  *          snapshot_GetDataHere
1213  */
1214 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1215                                            STGMEDIUM *med)
1216 {
1217     FIXME("(%p, %p {%s}, %p): stub\n", iface, fmt, dump_fmtetc(fmt), med);
1218     return E_NOTIMPL;
1219 }
1220 
1221 /************************************************************************
1222  *           snapshot_QueryGetData
1223  *
1224  * The OLE Clipboard's implementation of this method delegates to
1225  * a data source if there is one or wraps around the windows clipboard
1226  * function IsClipboardFormatAvailable() otherwise.
1227  *
1228  */
1229 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1230 {
1231     FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1232 
1233     if (!fmt) return E_INVALIDARG;
1234 
1235     if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1236 
1237     if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1238 
1239     return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1240 }
1241 
1242 /************************************************************************
1243  *              snapshot_GetCanonicalFormatEtc
1244  */
1245 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1246                                                      FORMATETC *fmt_out)
1247 {
1248     TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1249 
1250     if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1251 
1252     *fmt_out = *fmt_in;
1253     return DATA_S_SAMEFORMATETC;
1254 }
1255 
1256 /************************************************************************
1257  *              snapshot_SetData
1258  *
1259  * The OLE Clipboard does not implement this method
1260  */
1261 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1262                                        STGMEDIUM *med, BOOL release)
1263 {
1264     TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1265     return E_NOTIMPL;
1266 }
1267 
1268 /************************************************************************
1269  *             snapshot_EnumFormatEtc
1270  *
1271  */
1272 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1273                                              IEnumFORMATETC **enum_fmt)
1274 {
1275     HRESULT hr;
1276     ole_priv_data *data = NULL;
1277 
1278     TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1279 
1280     *enum_fmt = NULL;
1281 
1282     if ( dir != DATADIR_GET ) return E_NOTIMPL;
1283     if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1284 
1285     hr = get_priv_data(&data);
1286 
1287     if(FAILED(hr)) goto end;
1288 
1289     hr = enum_fmtetc_construct( data, 0, enum_fmt );
1290 
1291 end:
1292     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1293     return hr;
1294 }
1295 
1296 /************************************************************************
1297  *               snapshot_DAdvise
1298  *
1299  * The OLE Clipboard does not implement this method
1300  */
1301 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1302                                        DWORD flags, IAdviseSink *sink,
1303                                        DWORD *conn)
1304 {
1305     TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1306     return E_NOTIMPL;
1307 }
1308 
1309 /************************************************************************
1310  *              snapshot_DUnadvise
1311  *
1312  * The OLE Clipboard does not implement this method
1313  */
1314 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1315 {
1316     TRACE("(%p, %d): not implemented\n", iface, conn);
1317     return E_NOTIMPL;
1318 }
1319 
1320 /************************************************************************
1321  *             snapshot_EnumDAdvise
1322  *
1323  * The OLE Clipboard does not implement this method
1324  */
1325 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1326                                            IEnumSTATDATA** enum_advise)
1327 {
1328     TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1329     return E_NOTIMPL;
1330 }
1331 
1332 static const IDataObjectVtbl snapshot_vtable =
1333 {
1334     snapshot_QueryInterface,
1335     snapshot_AddRef,
1336     snapshot_Release,
1337     snapshot_GetData,
1338     snapshot_GetDataHere,
1339     snapshot_QueryGetData,
1340     snapshot_GetCanonicalFormatEtc,
1341     snapshot_SetData,
1342     snapshot_EnumFormatEtc,
1343     snapshot_DAdvise,
1344     snapshot_DUnadvise,
1345     snapshot_EnumDAdvise
1346 };
1347 
1348 /*---------------------------------------------------------------------*
1349  *           Internal implementation methods for the OLE clipboard
1350  *---------------------------------------------------------------------*/
1351 
1352 static snapshot *snapshot_construct(DWORD seq_no)
1353 {
1354     snapshot *This;
1355 
1356     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1357     if (!This) return NULL;
1358 
1359     This->lpVtbl = &snapshot_vtable;
1360     This->ref = 0;
1361     This->seq_no = seq_no;
1362     This->data = NULL;
1363 
1364     return This;
1365 }
1366 
1367 /*********************************************************
1368  *               register_clipboard_formats
1369  */
1370 static void register_clipboard_formats(void)
1371 {
1372     static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1373     static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1374     static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1375     static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1376     static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1377     static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1378     static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1379     static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1380     static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1381     static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1382                                                  'D','e','s','c','r','i','p','t','o','r',0};
1383     static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1384 
1385     static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1386                                                      'D','a','t','a','O','b','j','e','c','t',0};
1387 
1388     ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1389     filename_clipboard_format = RegisterClipboardFormatW(FileName);
1390     filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1391     dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1392     embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1393     embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1394     custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1395     link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1396     object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1397     link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1398     ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1399 
1400     wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1401 }
1402 
1403 /***********************************************************************
1404  * OLEClipbrd_Initialize()
1405  * Initializes the OLE clipboard.
1406  */
1407 void OLEClipbrd_Initialize(void)
1408 {
1409     register_clipboard_formats();
1410 
1411     if ( !theOleClipboard )
1412     {
1413         ole_clipbrd* clipbrd;
1414         HGLOBAL h;
1415 
1416         TRACE("()\n");
1417 
1418         clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1419         if (!clipbrd) return;
1420 
1421         clipbrd->latest_snapshot = NULL;
1422         clipbrd->window = NULL;
1423         clipbrd->src_data = NULL;
1424         clipbrd->cached_enum = NULL;
1425 
1426         h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1427         if(!h)
1428         {
1429             HeapFree(GetProcessHeap(), 0, clipbrd);
1430             return;
1431         }
1432 
1433         if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1434         {
1435             GlobalFree(h);
1436             HeapFree(GetProcessHeap(), 0, clipbrd);
1437             return;
1438         }
1439 
1440         theOleClipboard = clipbrd;
1441     }
1442 }
1443 
1444 /***********************************************************************
1445  * OLEClipbrd_UnInitialize()
1446  * Un-Initializes the OLE clipboard
1447  */
1448 void OLEClipbrd_UnInitialize(void)
1449 {
1450     ole_clipbrd *clipbrd = theOleClipboard;
1451 
1452     TRACE("()\n");
1453 
1454     if ( clipbrd )
1455     {
1456         static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1457         HINSTANCE hinst = GetModuleHandleW(ole32W);
1458 
1459         if ( clipbrd->window )
1460         {
1461             DestroyWindow(clipbrd->window);
1462             UnregisterClassW( clipbrd_wndclass, hinst );
1463         }
1464 
1465         IStream_Release(clipbrd->marshal_data);
1466         HeapFree(GetProcessHeap(), 0, clipbrd);
1467         theOleClipboard = NULL;
1468     }
1469 }
1470 
1471 /*********************************************************************
1472  *          set_clipboard_formats
1473  *
1474  * Enumerate all formats supported by the source and make
1475  * those formats available using delayed rendering using SetClipboardData.
1476  * Cache the enumeration list and make that list visibile as the
1477  * 'Ole Private Data' format on the clipboard.
1478  *
1479  */
1480 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1481 {
1482     HRESULT hr;
1483     FORMATETC fmt;
1484     IEnumFORMATETC *enum_fmt;
1485     HGLOBAL priv_data_handle;
1486     DWORD_PTR target_offset;
1487     ole_priv_data *priv_data;
1488     DWORD count = 0, needed = sizeof(*priv_data), idx;
1489 
1490     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1491     if(FAILED(hr)) return hr;
1492 
1493     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1494     {
1495         count++;
1496         needed += sizeof(priv_data->entries[0]);
1497         if(fmt.ptd)
1498         {
1499             needed += fmt.ptd->tdSize;
1500             CoTaskMemFree(fmt.ptd);
1501         }
1502     }
1503 
1504     /* Windows pads the list with two empty ole_priv_data_entries, one
1505      * after the entries array and one after the target device data.
1506      * Allocating with zero init to zero these pads. */
1507 
1508     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1509     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1510     priv_data = GlobalLock(priv_data_handle);
1511 
1512     priv_data->unk1 = 0;
1513     priv_data->size = needed;
1514     priv_data->unk2 = 1;
1515     priv_data->count = count;
1516     priv_data->unk3[0] = 0;
1517     priv_data->unk3[1] = 0;
1518 
1519     IEnumFORMATETC_Reset(enum_fmt);
1520 
1521     idx = 0;
1522     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1523 
1524     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1525     {
1526         TRACE("%s\n", dump_fmtetc(&fmt));
1527 
1528         priv_data->entries[idx].fmtetc = fmt;
1529         if(fmt.ptd)
1530         {
1531             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1532             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1533             target_offset += fmt.ptd->tdSize;
1534             CoTaskMemFree(fmt.ptd);
1535         }
1536 
1537         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1538         priv_data->entries[idx].unk[0] = 0;
1539         priv_data->entries[idx].unk[1] = 0;
1540 
1541         if (priv_data->entries[idx].first_use)
1542             SetClipboardData(fmt.cfFormat, NULL);
1543 
1544         idx++;
1545     }
1546 
1547     IEnumFORMATETC_Release(enum_fmt);
1548 
1549     /* Cache the list and fixup any target device offsets to ptrs */
1550     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1551     memcpy(clipbrd->cached_enum, priv_data, needed);
1552     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1553         clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1554             td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1555 
1556     GlobalUnlock(priv_data_handle);
1557     SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1558 
1559     return S_OK;
1560 }
1561 
1562 static HWND create_clipbrd_window(void);
1563 
1564 /***********************************************************************
1565  *                 get_clipbrd_window
1566  */
1567 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1568 {
1569     if ( !clipbrd->window )
1570         clipbrd->window = create_clipbrd_window();
1571 
1572     *wnd = clipbrd->window;
1573     return *wnd ? S_OK : E_FAIL;
1574 }
1575 
1576 
1577 /**********************************************************************
1578  *                  release_marshal_data
1579  *
1580  * Releases the data and sets the stream back to zero size.
1581  */
1582 static inline void release_marshal_data(IStream *stm)
1583 {
1584     LARGE_INTEGER pos;
1585     ULARGE_INTEGER size;
1586     pos.QuadPart = size.QuadPart = 0;
1587 
1588     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1589     CoReleaseMarshalData(stm);
1590     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1591     IStream_SetSize(stm, size);
1592 }
1593 
1594 /***********************************************************************
1595  *   expose_marshalled_dataobject
1596  *
1597  * Sets the marshalled dataobject to the clipboard.  In the flushed case
1598  * we set a zero sized HGLOBAL to clear the old marshalled data.
1599  */
1600 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1601 {
1602     HGLOBAL h;
1603 
1604     if(data)
1605     {
1606         HGLOBAL h_stm;
1607         GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1608         dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1609     }
1610     else /* flushed */
1611         h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1612 
1613     if(!h) return E_OUTOFMEMORY;
1614 
1615     SetClipboardData(wine_marshal_clipboard_format, h);
1616     return S_OK;
1617 }
1618 
1619 /***********************************************************************
1620  *                   set_src_dataobject
1621  *
1622  * Clears and sets the clipboard's src IDataObject.
1623  *
1624  * To marshal the source dataobject we do something rather different from Windows.
1625  * We set a clipboard format which contains the marshalled data.
1626  * Windows sets two window props one of which is an IID, the other is an endpoint number.
1627  */
1628 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1629 {
1630     HRESULT hr;
1631     HWND wnd;
1632 
1633     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1634 
1635     if(clipbrd->src_data)
1636     {
1637         release_marshal_data(clipbrd->marshal_data);
1638 
1639         IDataObject_Release(clipbrd->src_data);
1640         clipbrd->src_data = NULL;
1641         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1642         clipbrd->cached_enum = NULL;
1643     }
1644 
1645     if(data)
1646     {
1647         IUnknown *unk;
1648 
1649         IDataObject_AddRef(data);
1650         clipbrd->src_data = data;
1651 
1652         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1653         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1654                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1655         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1656         if(FAILED(hr)) return hr;
1657         hr = set_clipboard_formats(clipbrd, data);
1658     }
1659     return hr;
1660 }
1661 
1662 /***********************************************************************
1663  *                   clipbrd_wndproc
1664  */
1665 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1666 {
1667     ole_clipbrd *clipbrd;
1668 
1669     get_ole_clipbrd(&clipbrd);
1670 
1671     switch (message)
1672     {
1673     case WM_RENDERFORMAT:
1674     {
1675         UINT cf = wparam;
1676         ole_priv_data_entry *entry;
1677 
1678         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1679         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1680 
1681         if(entry)
1682             render_format(clipbrd->src_data, &entry->fmtetc);
1683 
1684         break;
1685     }
1686 
1687     case WM_RENDERALLFORMATS:
1688     {
1689         DWORD i;
1690         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1691 
1692         TRACE("(): WM_RENDERALLFORMATS\n");
1693 
1694         for(i = 0; i < clipbrd->cached_enum->count; i++)
1695         {
1696             if(entries[i].first_use)
1697                 render_format(clipbrd->src_data, &entries[i].fmtetc);
1698         }
1699         break;
1700     }
1701 
1702     case WM_DESTROYCLIPBOARD:
1703     {
1704         TRACE("(): WM_DESTROYCLIPBOARD\n");
1705 
1706         set_src_dataobject(clipbrd, NULL);
1707         break;
1708     }
1709 
1710     default:
1711         return DefWindowProcW(hwnd, message, wparam, lparam);
1712     }
1713 
1714     return 0;
1715 }
1716 
1717 
1718 /***********************************************************************
1719  *                 create_clipbrd_window
1720  */
1721 static HWND create_clipbrd_window(void)
1722 {
1723     WNDCLASSEXW class;
1724     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1725     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1726     HINSTANCE hinst = GetModuleHandleW(ole32W);
1727 
1728     class.cbSize         = sizeof(class);
1729     class.style          = 0;
1730     class.lpfnWndProc    = clipbrd_wndproc;
1731     class.cbClsExtra     = 0;
1732     class.cbWndExtra     = 0;
1733     class.hInstance      = hinst;
1734     class.hIcon          = 0;
1735     class.hCursor        = 0;
1736     class.hbrBackground  = 0;
1737     class.lpszMenuName   = NULL;
1738     class.lpszClassName  = clipbrd_wndclass;
1739     class.hIconSm        = NULL;
1740 
1741     RegisterClassExW(&class);
1742 
1743     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1744                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1745                          NULL, NULL, hinst, 0);
1746 }
1747 
1748 /*********************************************************************
1749  *          set_dataobject_format
1750  *
1751  * Windows creates a 'DataObject' clipboard format that contains the
1752  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1753  */
1754 static HRESULT set_dataobject_format(HWND hwnd)
1755 {
1756     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1757     HWND *data;
1758 
1759     if(!h) return E_OUTOFMEMORY;
1760 
1761     data = GlobalLock(h);
1762     *data = hwnd;
1763     GlobalUnlock(h);
1764 
1765     if(!SetClipboardData(dataobject_clipboard_format, h))
1766     {
1767         GlobalFree(h);
1768         return CLIPBRD_E_CANT_SET;
1769     }
1770 
1771     return S_OK;
1772 }
1773 
1774 /*---------------------------------------------------------------------*
1775  *           Win32 OLE clipboard API
1776  *---------------------------------------------------------------------*/
1777 
1778 /***********************************************************************
1779  *           OleSetClipboard     [OLE32.@]
1780  *  Places a pointer to the specified data object onto the clipboard,
1781  *  making the data object accessible to the OleGetClipboard function.
1782  *
1783  * RETURNS
1784  *
1785  *    S_OK                  IDataObject pointer placed on the clipboard
1786  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
1787  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
1788  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
1789  *    CLIPBRD_E_CANT_SET    SetClipboard failed
1790  */
1791 
1792 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1793 {
1794   HRESULT hr;
1795   ole_clipbrd *clipbrd;
1796   HWND wnd;
1797 
1798   TRACE("(%p)\n", data);
1799 
1800   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1801 
1802   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1803 
1804   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1805 
1806   if ( !EmptyClipboard() )
1807   {
1808     hr = CLIPBRD_E_CANT_EMPTY;
1809     goto end;
1810   }
1811 
1812   hr = set_src_dataobject(clipbrd, data);
1813   if(FAILED(hr)) goto end;
1814 
1815   if(data)
1816   {
1817     hr = expose_marshalled_dataobject(clipbrd, data);
1818     if(FAILED(hr)) goto end;
1819     hr = set_dataobject_format(wnd);
1820   }
1821 
1822 end:
1823 
1824   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1825 
1826   if ( FAILED(hr) )
1827   {
1828     expose_marshalled_dataobject(clipbrd, NULL);
1829     set_src_dataobject(clipbrd, NULL);
1830   }
1831 
1832   return hr;
1833 }
1834 
1835 
1836 /***********************************************************************
1837  * OleGetClipboard [OLE32.@]
1838  * Returns a pointer to our internal IDataObject which represents the conceptual
1839  * state of the Windows clipboard. If the current clipboard already contains
1840  * an IDataObject, our internal IDataObject will delegate to this object.
1841  */
1842 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1843 {
1844     HRESULT hr;
1845     ole_clipbrd *clipbrd;
1846     DWORD seq_no;
1847 
1848     TRACE("(%p)\n", obj);
1849 
1850     if(!obj) return E_INVALIDARG;
1851 
1852     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1853 
1854     seq_no = GetClipboardSequenceNumber();
1855     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
1856         clipbrd->latest_snapshot = NULL;
1857 
1858     if(!clipbrd->latest_snapshot)
1859     {
1860         clipbrd->latest_snapshot = snapshot_construct(seq_no);
1861         if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
1862     }
1863 
1864     *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
1865     IDataObject_AddRef(*obj);
1866 
1867     return S_OK;
1868 }
1869 
1870 /******************************************************************************
1871  *              OleFlushClipboard        [OLE32.@]
1872  *  Renders the data from the source IDataObject into the windows clipboard
1873  *
1874  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1875  *  by copying the storage into global memory. Subsequently the default
1876  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1877  *  back to TYMED_IStorage.
1878  */
1879 HRESULT WINAPI OleFlushClipboard(void)
1880 {
1881   HRESULT hr;
1882   ole_clipbrd *clipbrd;
1883   HWND wnd;
1884 
1885   TRACE("()\n");
1886 
1887   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1888 
1889   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1890 
1891   /*
1892    * Already flushed or no source DataObject? Nothing to do.
1893    */
1894   if (!clipbrd->src_data) return S_OK;
1895 
1896   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
1897 
1898   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
1899 
1900   hr = set_dataobject_format(NULL);
1901 
1902   expose_marshalled_dataobject(clipbrd, NULL);
1903   set_src_dataobject(clipbrd, NULL);
1904 
1905   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1906 
1907   return hr;
1908 }
1909 
1910 
1911 /***********************************************************************
1912  *           OleIsCurrentClipboard [OLE32.@]
1913  */
1914 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
1915 {
1916     HRESULT hr;
1917     ole_clipbrd *clipbrd;
1918     TRACE("()\n");
1919 
1920     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1921 
1922     if (data == NULL) return S_FALSE;
1923 
1924     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
1925 }
1926 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.