ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

clipboard.c
Go to the documentation of this file.
00001 /*
00002  *  OLE 2 clipboard support
00003  *
00004  *      Copyright 1999  Noel Borthwick <noel@macadamian.com>
00005  *      Copyright 2000  Abey George <abey@macadamian.com>
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  *
00021  * NOTES:
00022  *    This file contains the implementation for the OLE Clipboard and its
00023  *    internal interfaces. The OLE clipboard interacts with an IDataObject
00024  *    interface via the OleSetClipboard, OleGetClipboard and
00025  *    OleIsCurrentClipboard API's. An internal IDataObject delegates
00026  *    to a client supplied IDataObject or the WIN32 clipboard API depending
00027  *    on whether OleSetClipboard has been invoked.
00028  *    Here are some operating scenarios:
00029  *
00030  *    1. OleSetClipboard called: In this case the internal IDataObject
00031  *       delegates to the client supplied IDataObject. Additionally OLE takes
00032  *       ownership of the Windows clipboard and any HGLOCBAL IDataObject
00033  *       items are placed on the Windows clipboard. This allows non OLE aware
00034  *       applications to access these. A local WinProc fields WM_RENDERFORMAT
00035  *       and WM_RENDERALLFORMATS messages in this case.
00036  *
00037  *    2. OleGetClipboard called without previous OleSetClipboard. Here the internal
00038  *       IDataObject functionality wraps around the WIN32 clipboard API.
00039  *
00040  *    3. OleGetClipboard called after previous OleSetClipboard. Here the internal
00041  *       IDataObject delegates to the source IDataObjects functionality directly,
00042  *       thereby bypassing the Windows clipboard.
00043  *
00044  *    Implementation references : Inside OLE 2'nd  edition by Kraig Brockschmidt
00045  *
00046  * TODO:
00047  *    - Support for pasting between different processes. OLE clipboard support
00048  *      currently works only for in process copy and paste. Since we internally
00049  *      store a pointer to the source's IDataObject and delegate to that, this
00050  *      will fail if the IDataObject client belongs to a different process.
00051  *    - IDataObject::GetDataHere is not implemented
00052  *    - OleFlushClipboard needs to additionally handle TYMED_IStorage media
00053  *      by copying the storage into global memory. Subsequently the default
00054  *      data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
00055  *      back to TYMED_IStorage.
00056  *    - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
00057  *      clipboard in OleSetClipboard.
00058  *
00059  */
00060 
00061 #include <assert.h>
00062 #include <stdarg.h>
00063 #include <string.h>
00064 #include <stdio.h>
00065 
00066 #define COBJMACROS
00067 #define NONAMELESSUNION
00068 #define NONAMELESSSTRUCT
00069 
00070 #include "windef.h"
00071 #include "winbase.h"
00072 #include "wingdi.h"
00073 #include "winuser.h"
00074 #include "winerror.h"
00075 #include "winnls.h"
00076 #include "ole2.h"
00077 #include "wine/debug.h"
00078 #include "olestd.h"
00079 
00080 #include "storage32.h"
00081 
00082 #include "compobj_private.h"
00083 
00084 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00085 
00086 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
00087 
00088 /* Structure of 'Ole Private Data' clipboard format */
00089 typedef struct
00090 {
00091     FORMATETC fmtetc;
00092     DWORD first_use;  /* Has this cf been added to the list already */
00093     DWORD unk[2];
00094 } ole_priv_data_entry;
00095 
00096 typedef struct
00097 {
00098     DWORD unk1;
00099     DWORD size; /* in bytes of the entire structure */
00100     DWORD unk2;
00101     DWORD count; /* no. of format entries */
00102     DWORD unk3[2];
00103     ole_priv_data_entry entries[1]; /* array of size count */
00104     /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
00105 } ole_priv_data;
00106 
00107 /*****************************************************************************
00108  *           td_offs_to_ptr
00109  *
00110  * Returns a ptr to a target device at a given offset from the
00111  * start of the ole_priv_data.
00112  *
00113  * Used when unpacking ole private data from the clipboard.
00114  */
00115 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off)
00116 {
00117     if(off == 0) return NULL;
00118     return (DVTARGETDEVICE*)((char*)data + off);
00119 }
00120 
00121 /*****************************************************************************
00122  *           td_get_offs
00123  *
00124  * Get the offset from the start of the ole_priv_data of the idx'th
00125  * target device.
00126  *
00127  * Used when packing ole private data to the clipboard.
00128  */
00129 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx)
00130 {
00131     if(data->entries[idx].fmtetc.ptd == NULL) return 0;
00132     return (char*)data->entries[idx].fmtetc.ptd - (char*)data;
00133 }
00134 
00135 /****************************************************************************
00136  * Consumer snapshot.  Represents the state of the ole clipboard
00137  * returned by OleGetClipboard().
00138  */
00139 typedef struct snapshot
00140 {
00141     IDataObject IDataObject_iface;
00142     LONG ref;
00143 
00144     DWORD seq_no;                   /* Clipboard sequence number corresponding to this snapshot */
00145 
00146     IDataObject *data;              /* If we unmarshal a remote data object we hold a ref here */
00147 } snapshot;
00148 
00149 /****************************************************************************
00150  * ole_clipbrd
00151  */
00152 typedef struct ole_clipbrd
00153 {
00154     snapshot *latest_snapshot;       /* Latest consumer snapshot */
00155 
00156     HWND window;                     /* Hidden clipboard window */
00157     IDataObject *src_data;           /* Source object passed to OleSetClipboard */
00158     ole_priv_data *cached_enum;      /* Cached result from the enumeration of src data object */
00159     IStream *marshal_data;           /* Stream onto which to marshal src_data */
00160 } ole_clipbrd;
00161 
00162 static inline snapshot *impl_from_IDataObject(IDataObject *iface)
00163 {
00164     return CONTAINING_RECORD(iface, snapshot, IDataObject_iface);
00165 }
00166 
00167 typedef struct PresentationDataHeader
00168 {
00169   BYTE unknown1[28];
00170   DWORD dwObjectExtentX;
00171   DWORD dwObjectExtentY;
00172   DWORD dwSize;
00173 } PresentationDataHeader;
00174 
00175 /*
00176  * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
00177  */
00178 static ole_clipbrd* theOleClipboard;
00179 
00180 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
00181 {
00182     struct oletls *info = COM_CurrentInfo();
00183     *clipbrd = NULL;
00184 
00185     if(!info->ole_inits)
00186         return CO_E_NOTINITIALIZED;
00187     *clipbrd = theOleClipboard;
00188 
00189     return S_OK;
00190 }
00191 
00192 /*
00193  * Name of our registered OLE clipboard window class
00194  */
00195 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0};
00196 
00197 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};
00198 
00199 UINT ownerlink_clipboard_format = 0;
00200 UINT filename_clipboard_format = 0;
00201 UINT filenameW_clipboard_format = 0;
00202 UINT dataobject_clipboard_format = 0;
00203 UINT embedded_object_clipboard_format = 0;
00204 UINT embed_source_clipboard_format = 0;
00205 UINT custom_link_source_clipboard_format = 0;
00206 UINT link_source_clipboard_format = 0;
00207 UINT object_descriptor_clipboard_format = 0;
00208 UINT link_source_descriptor_clipboard_format = 0;
00209 UINT ole_private_data_clipboard_format = 0;
00210 
00211 static UINT wine_marshal_clipboard_format;
00212 
00213 static inline char *dump_fmtetc(FORMATETC *fmt)
00214 {
00215     static char buf[100];
00216 
00217     snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
00218              fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
00219     return buf;
00220 }
00221 
00222 /*---------------------------------------------------------------------*
00223  *  Implementation of the internal IEnumFORMATETC interface returned by
00224  *  the OLE clipboard's IDataObject.
00225  *---------------------------------------------------------------------*/
00226 
00227 typedef struct enum_fmtetc
00228 {
00229     IEnumFORMATETC IEnumFORMATETC_iface;
00230     LONG ref;
00231 
00232     UINT pos;    /* current enumerator position */
00233     ole_priv_data *data;
00234 } enum_fmtetc;
00235 
00236 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
00237 {
00238     return CONTAINING_RECORD(iface, enum_fmtetc, IEnumFORMATETC_iface);
00239 }
00240 
00241 /************************************************************************
00242  * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
00243  *
00244  * See Windows documentation for more details on IUnknown methods.
00245  */
00246 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
00247   (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
00248 {
00249   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
00250 
00251   TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj);
00252 
00253   *ppvObj = NULL;
00254 
00255   if(IsEqualIID(riid, &IID_IUnknown) ||
00256      IsEqualIID(riid, &IID_IEnumFORMATETC))
00257   {
00258     *ppvObj = iface;
00259   }
00260 
00261   if(*ppvObj)
00262   {
00263     IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
00264     TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
00265     return S_OK;
00266   }
00267 
00268   TRACE("-- Interface: E_NOINTERFACE\n");
00269   return E_NOINTERFACE;
00270 }
00271 
00272 /************************************************************************
00273  * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
00274  *
00275  */
00276 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
00277 {
00278   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
00279   TRACE("(%p)->(count=%u)\n",This, This->ref);
00280 
00281   return InterlockedIncrement(&This->ref);
00282 }
00283 
00284 /************************************************************************
00285  * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
00286  *
00287  * See Windows documentation for more details on IUnknown methods.
00288  */
00289 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
00290 {
00291   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
00292   ULONG ref;
00293 
00294   TRACE("(%p)->(count=%u)\n",This, This->ref);
00295 
00296   ref = InterlockedDecrement(&This->ref);
00297   if (!ref)
00298   {
00299     TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
00300     HeapFree(GetProcessHeap(), 0, This->data);
00301     HeapFree(GetProcessHeap(), 0, This);
00302   }
00303   return ref;
00304 }
00305 
00306 /************************************************************************
00307  * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
00308  *
00309  * Standard enumerator members for IEnumFORMATETC
00310  */
00311 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
00312   (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
00313 {
00314   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
00315   UINT cfetch, i;
00316   HRESULT hres = S_FALSE;
00317 
00318   TRACE("(%p)->(pos=%u)\n", This, This->pos);
00319 
00320   if (This->pos < This->data->count)
00321   {
00322     cfetch = This->data->count - This->pos;
00323     if (cfetch >= celt)
00324     {
00325       cfetch = celt;
00326       hres = S_OK;
00327     }
00328 
00329     for(i = 0; i < cfetch; i++)
00330     {
00331       rgelt[i] = This->data->entries[This->pos++].fmtetc;
00332       if(rgelt[i].ptd)
00333       {
00334         DVTARGETDEVICE *target = rgelt[i].ptd;
00335         rgelt[i].ptd = CoTaskMemAlloc(target->tdSize);
00336         if(!rgelt[i].ptd) return E_OUTOFMEMORY;
00337         memcpy(rgelt[i].ptd, target, target->tdSize);
00338       }
00339     }
00340   }
00341   else
00342   {
00343     cfetch = 0;
00344   }
00345 
00346   if (pceltFethed)
00347   {
00348     *pceltFethed = cfetch;
00349   }
00350 
00351   return hres;
00352 }
00353 
00354 /************************************************************************
00355  * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
00356  *
00357  * Standard enumerator members for IEnumFORMATETC
00358  */
00359 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
00360 {
00361   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
00362   TRACE("(%p)->(num=%u)\n", This, celt);
00363 
00364   This->pos += celt;
00365   if (This->pos > This->data->count)
00366   {
00367     This->pos = This->data->count;
00368     return S_FALSE;
00369   }
00370   return S_OK;
00371 }
00372 
00373 /************************************************************************
00374  * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
00375  *
00376  * Standard enumerator members for IEnumFORMATETC
00377  */
00378 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
00379 {
00380   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
00381   TRACE("(%p)->()\n", This);
00382 
00383   This->pos = 0;
00384   return S_OK;
00385 }
00386 
00387 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj);
00388 
00389 /************************************************************************
00390  * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
00391  *
00392  * Standard enumerator members for IEnumFORMATETC
00393  */
00394 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
00395   (LPENUMFORMATETC iface, LPENUMFORMATETC* obj)
00396 {
00397   enum_fmtetc *This = impl_from_IEnumFORMATETC(iface);
00398   ole_priv_data *new_data;
00399   DWORD i;
00400 
00401   TRACE("(%p)->(%p)\n", This, obj);
00402 
00403   if ( !obj ) return E_INVALIDARG;
00404   *obj = NULL;
00405 
00406   new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size);
00407   if(!new_data) return E_OUTOFMEMORY;
00408   memcpy(new_data, This->data, This->data->size);
00409 
00410   /* Fixup any target device ptrs */
00411   for(i = 0; i < This->data->count; i++)
00412       new_data->entries[i].fmtetc.ptd =
00413           td_offs_to_ptr(new_data, td_get_offs(This->data, i));
00414 
00415   return enum_fmtetc_construct(new_data, This->pos, obj);
00416 }
00417 
00418 static const IEnumFORMATETCVtbl efvt =
00419 {
00420   OLEClipbrd_IEnumFORMATETC_QueryInterface,
00421   OLEClipbrd_IEnumFORMATETC_AddRef,
00422   OLEClipbrd_IEnumFORMATETC_Release,
00423   OLEClipbrd_IEnumFORMATETC_Next,
00424   OLEClipbrd_IEnumFORMATETC_Skip,
00425   OLEClipbrd_IEnumFORMATETC_Reset,
00426   OLEClipbrd_IEnumFORMATETC_Clone
00427 };
00428 
00429 /************************************************************************
00430  * enum_fmtetc_construct
00431  *
00432  * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns.
00433  */
00434 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj)
00435 {
00436   enum_fmtetc* ef;
00437 
00438   *obj = NULL;
00439   ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef));
00440   if (!ef) return E_OUTOFMEMORY;
00441 
00442   ef->ref = 1;
00443   ef->IEnumFORMATETC_iface.lpVtbl = &efvt;
00444   ef->data = data;
00445   ef->pos = pos;
00446 
00447   TRACE("(%p)->()\n", ef);
00448   *obj = &ef->IEnumFORMATETC_iface;
00449   return S_OK;
00450 }
00451 
00452 /***********************************************************************
00453  *                    dup_global_mem
00454  *
00455  * Helper method to duplicate an HGLOBAL chunk of memory
00456  */
00457 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst )
00458 {
00459     void *src_ptr, *dst_ptr;
00460     DWORD size;
00461 
00462     *dst = NULL;
00463     if ( !src ) return S_FALSE;
00464 
00465     size = GlobalSize(src);
00466 
00467     *dst = GlobalAlloc( flags, size );
00468     if ( !*dst ) return E_OUTOFMEMORY;
00469 
00470     src_ptr = GlobalLock(src);
00471     dst_ptr = GlobalLock(*dst);
00472 
00473     memcpy(dst_ptr, src_ptr, size);
00474 
00475     GlobalUnlock(*dst);
00476     GlobalUnlock(src);
00477 
00478     return S_OK;
00479 }
00480 
00481 /***********************************************************************
00482  *                    dup_metafilepict
00483  *
00484  * Helper function to duplicate a handle to a METAFILEPICT, and the
00485  * contained HMETAFILE.
00486  */
00487 static HRESULT dup_metafilepict(HGLOBAL src, HGLOBAL *pdest)
00488 {
00489     HRESULT hr;
00490     HGLOBAL dest;
00491     METAFILEPICT *dest_ptr;
00492 
00493     *pdest = NULL;
00494 
00495     /* Copy the METAFILEPICT structure. */
00496     hr = dup_global_mem(src, GMEM_DDESHARE|GMEM_MOVEABLE, &dest);
00497     if (FAILED(hr)) return hr;
00498 
00499     dest_ptr = GlobalLock(dest);
00500     if (!dest_ptr) return E_FAIL;
00501 
00502     /* Give the new METAFILEPICT a separate HMETAFILE. */
00503     dest_ptr->hMF = CopyMetaFileW(dest_ptr->hMF, NULL);
00504     if (dest_ptr->hMF)
00505     {
00506        GlobalUnlock(dest);
00507        *pdest = dest;
00508        return S_OK;
00509     }
00510     else
00511     {
00512        GlobalUnlock(dest);
00513        GlobalFree(dest);
00514        return E_FAIL;
00515     }
00516 }
00517 
00518 /***********************************************************************
00519  *                    free_metafilepict
00520  *
00521  * Helper function to GlobalFree a handle to a METAFILEPICT, and also
00522  * free the contained HMETAFILE.
00523  */
00524 static void free_metafilepict(HGLOBAL src)
00525 {
00526     METAFILEPICT *src_ptr;
00527 
00528     src_ptr = GlobalLock(src);
00529     if (src_ptr)
00530     {
00531         DeleteMetaFile(src_ptr->hMF);
00532         GlobalUnlock(src);
00533     }
00534     GlobalFree(src);
00535 }
00536 
00537 /***********************************************************************
00538  *                    dup_bitmap
00539  *
00540  * Helper function to duplicate an HBITMAP.
00541  */
00542 static HRESULT dup_bitmap(HBITMAP src, HBITMAP *pdest)
00543 {
00544     HDC src_dc;
00545     HGDIOBJ orig_src_bitmap;
00546     BITMAP bm;
00547     HBITMAP dest;
00548 
00549     src_dc = CreateCompatibleDC(NULL);
00550     orig_src_bitmap = SelectObject(src_dc, src);
00551     GetObjectW(src, sizeof bm, &bm);
00552     dest = CreateCompatibleBitmap(src_dc, bm.bmWidth, bm.bmHeight);
00553     if (dest)
00554     {
00555         HDC dest_dc = CreateCompatibleDC(NULL);
00556         HGDIOBJ orig_dest_bitmap = SelectObject(dest_dc, dest);
00557         BitBlt(dest_dc, 0, 0, bm.bmWidth, bm.bmHeight, src_dc, 0, 0, SRCCOPY);
00558         SelectObject(dest_dc, orig_dest_bitmap);
00559         DeleteDC(dest_dc);
00560     }
00561     SelectObject(src_dc, orig_src_bitmap);
00562     DeleteDC(src_dc);
00563     *pdest = dest;
00564     return dest ? S_OK : E_FAIL;
00565 }
00566 
00567 /************************************************************
00568  *              render_embed_source_hack
00569  *
00570  * This is clearly a hack and has no place in the clipboard code.
00571  *
00572  */
00573 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt)
00574 {
00575     STGMEDIUM std;
00576     HGLOBAL hStorage = 0;
00577     HRESULT hr = S_OK;
00578     ILockBytes *ptrILockBytes;
00579 
00580     memset(&std, 0, sizeof(STGMEDIUM));
00581     std.tymed = fmt->tymed = TYMED_ISTORAGE;
00582 
00583     hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
00584     if (hStorage == NULL) return E_OUTOFMEMORY;
00585     hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
00586     hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
00587     ILockBytes_Release(ptrILockBytes);
00588 
00589     if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std)))
00590     {
00591         WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
00592         GlobalFree(hStorage);
00593         return hr;
00594     }
00595 
00596     if (1) /* check whether the presentation data is already -not- present */
00597     {
00598         FORMATETC fmt2;
00599         STGMEDIUM std2;
00600         METAFILEPICT *mfp = 0;
00601 
00602         fmt2.cfFormat = CF_METAFILEPICT;
00603         fmt2.ptd = 0;
00604         fmt2.dwAspect = DVASPECT_CONTENT;
00605         fmt2.lindex = -1;
00606         fmt2.tymed = TYMED_MFPICT;
00607 
00608         memset(&std2, 0, sizeof(STGMEDIUM));
00609         std2.tymed = TYMED_MFPICT;
00610 
00611         /* Get the metafile picture out of it */
00612 
00613         if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2)))
00614         {
00615             mfp = GlobalLock(std2.u.hGlobal);
00616         }
00617 
00618         if (mfp)
00619         {
00620             OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
00621             IStream *pStream = 0;
00622             void *mfBits;
00623             PresentationDataHeader pdh;
00624             INT nSize;
00625             CLSID clsID;
00626             LPOLESTR strProgID;
00627             CHAR strOleTypeName[51];
00628             BYTE OlePresStreamHeader [] =
00629             {
00630                 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
00631                 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
00632                 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
00633                 0x00, 0x00, 0x00, 0x00
00634             };
00635 
00636             nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
00637 
00638             memset(&pdh, 0, sizeof(PresentationDataHeader));
00639             memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
00640 
00641             pdh.dwObjectExtentX = mfp->xExt;
00642             pdh.dwObjectExtentY = mfp->yExt;
00643             pdh.dwSize = nSize;
00644 
00645             hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
00646 
00647             hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
00648 
00649             mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
00650             nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
00651 
00652             hr = IStream_Write(pStream, mfBits, nSize, NULL);
00653 
00654             IStream_Release(pStream);
00655 
00656             HeapFree(GetProcessHeap(), 0, mfBits);
00657 
00658             GlobalUnlock(std2.u.hGlobal);
00659             ReleaseStgMedium(&std2);
00660 
00661             ReadClassStg(std.u.pstg, &clsID);
00662             ProgIDFromCLSID(&clsID, &strProgID);
00663 
00664             WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
00665             OLECONVERT_CreateOleStream(std.u.pstg);
00666             OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
00667         }
00668     }
00669 
00670     if ( !SetClipboardData( fmt->cfFormat, hStorage ) )
00671     {
00672         WARN("() : Failed to set rendered clipboard data into clipboard!\n");
00673         GlobalFree(hStorage);
00674         hr = CLIPBRD_E_CANT_SET;
00675     }
00676 
00677     ReleaseStgMedium(&std);
00678     return hr;
00679 }
00680 
00681 /************************************************************************
00682  *           find_format_in_list
00683  *
00684  * Returns the first entry that matches the provided clipboard format.
00685  */
00686 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
00687 {
00688     DWORD i;
00689     for(i = 0; i < num; i++)
00690         if(entries[i].fmtetc.cfFormat == cf)
00691             return &entries[i];
00692 
00693     return NULL;
00694 }
00695 
00696 /***************************************************************************
00697  *         get_data_from_storage
00698  *
00699  * Returns storage data in an HGLOBAL.
00700  */
00701 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
00702 {
00703     HGLOBAL h;
00704     IStorage *stg;
00705     HRESULT hr;
00706     FORMATETC stg_fmt;
00707     STGMEDIUM med;
00708     ILockBytes *lbs;
00709 
00710     *mem = NULL;
00711 
00712     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
00713     if(!h) return E_OUTOFMEMORY;
00714 
00715     hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs);
00716     if(SUCCEEDED(hr))
00717     {
00718         hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg);
00719         ILockBytes_Release(lbs);
00720     }
00721     if(FAILED(hr))
00722     {
00723         GlobalFree(h);
00724         return hr;
00725     }
00726 
00727     stg_fmt = *fmt;
00728     med.tymed = stg_fmt.tymed = TYMED_ISTORAGE;
00729     med.u.pstg = stg;
00730     med.pUnkForRelease = NULL;
00731 
00732     hr = IDataObject_GetDataHere(data, &stg_fmt, &med);
00733     if(FAILED(hr))
00734     {
00735         med.u.pstg = NULL;
00736         hr = IDataObject_GetData(data, &stg_fmt, &med);
00737         if(FAILED(hr)) goto end;
00738 
00739         hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg);
00740         ReleaseStgMedium(&med);
00741         if(FAILED(hr)) goto end;
00742     }
00743     *mem = h;
00744 
00745 end:
00746     IStorage_Release(stg);
00747     if(FAILED(hr)) GlobalFree(h);
00748     return hr;
00749 }
00750 
00751 /***************************************************************************
00752  *         get_data_from_stream
00753  *
00754  * Returns stream data in an HGLOBAL.
00755  */
00756 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
00757 {
00758     HGLOBAL h;
00759     IStream *stm = NULL;
00760     HRESULT hr;
00761     FORMATETC stm_fmt;
00762     STGMEDIUM med;
00763 
00764     *mem = NULL;
00765 
00766     h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 );
00767     if(!h) return E_OUTOFMEMORY;
00768 
00769     hr = CreateStreamOnHGlobal(h, FALSE, &stm);
00770     if(FAILED(hr)) goto error;
00771 
00772     stm_fmt = *fmt;
00773     med.tymed = stm_fmt.tymed = TYMED_ISTREAM;
00774     med.u.pstm = stm;
00775     med.pUnkForRelease = NULL;
00776 
00777     hr = IDataObject_GetDataHere(data, &stm_fmt, &med);
00778     if(FAILED(hr))
00779     {
00780         LARGE_INTEGER offs;
00781         ULARGE_INTEGER pos;
00782 
00783         med.u.pstm = NULL;
00784         hr = IDataObject_GetData(data, &stm_fmt, &med);
00785         if(FAILED(hr)) goto error;
00786 
00787         offs.QuadPart = 0;
00788         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos);
00789         IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL);
00790         hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL);
00791         ReleaseStgMedium(&med);
00792         if(FAILED(hr)) goto error;
00793     }
00794     *mem = h;
00795     IStream_Release(stm);
00796     return S_OK;
00797 
00798 error:
00799     if(stm) IStream_Release(stm);
00800     GlobalFree(h);
00801     return hr;
00802 }
00803 
00804 /***************************************************************************
00805  *         get_data_from_global
00806  *
00807  * Returns global data in an HGLOBAL.
00808  */
00809 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
00810 {
00811     HGLOBAL h;
00812     HRESULT hr;
00813     FORMATETC mem_fmt;
00814     STGMEDIUM med;
00815 
00816     *mem = NULL;
00817 
00818     mem_fmt = *fmt;
00819     mem_fmt.tymed = TYMED_HGLOBAL;
00820 
00821     hr = IDataObject_GetData(data, &mem_fmt, &med);
00822     if(FAILED(hr)) return hr;
00823 
00824     hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
00825 
00826     if(SUCCEEDED(hr)) *mem = h;
00827 
00828     ReleaseStgMedium(&med);
00829 
00830     return hr;
00831 }
00832 
00833 /***************************************************************************
00834  *         get_data_from_enhmetafile
00835  */
00836 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
00837 {
00838     HENHMETAFILE copy;
00839     HRESULT hr;
00840     FORMATETC mem_fmt;
00841     STGMEDIUM med;
00842 
00843     *mem = NULL;
00844 
00845     mem_fmt = *fmt;
00846     mem_fmt.tymed = TYMED_ENHMF;
00847 
00848     hr = IDataObject_GetData(data, &mem_fmt, &med);
00849     if(FAILED(hr)) return hr;
00850 
00851     copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
00852     if(copy) *mem = (HGLOBAL)copy;
00853     else hr = E_FAIL;
00854 
00855     ReleaseStgMedium(&med);
00856 
00857     return hr;
00858 }
00859 
00860 /***************************************************************************
00861  *         get_data_from_metafilepict
00862  */
00863 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
00864 {
00865     HGLOBAL copy;
00866     HRESULT hr;
00867     FORMATETC mem_fmt;
00868     STGMEDIUM med;
00869 
00870     *mem = NULL;
00871 
00872     mem_fmt = *fmt;
00873     mem_fmt.tymed = TYMED_MFPICT;
00874 
00875     hr = IDataObject_GetData(data, &mem_fmt, &med);
00876     if(FAILED(hr)) return hr;
00877 
00878     hr = dup_metafilepict(med.u.hMetaFilePict, &copy);
00879 
00880     if(SUCCEEDED(hr)) *mem = copy;
00881 
00882     ReleaseStgMedium(&med);
00883 
00884     return hr;
00885 }
00886 
00887 /***************************************************************************
00888  *         get_data_from_bitmap
00889  *
00890  * Returns bitmap in an HBITMAP.
00891  */
00892 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm)
00893 {
00894     HBITMAP copy;
00895     HRESULT hr;
00896     FORMATETC mem_fmt;
00897     STGMEDIUM med;
00898 
00899     *hbm = NULL;
00900 
00901     mem_fmt = *fmt;
00902     mem_fmt.tymed = TYMED_GDI;
00903 
00904     hr = IDataObject_GetData(data, &mem_fmt, &med);
00905     if(FAILED(hr)) return hr;
00906 
00907     hr = dup_bitmap(med.u.hBitmap, &copy);
00908 
00909     if(SUCCEEDED(hr)) *hbm = copy;
00910 
00911     ReleaseStgMedium(&med);
00912 
00913     return hr;
00914 }
00915 
00916 /***********************************************************************
00917  *                render_format
00918  *
00919  * Render the clipboard data. Note that this call will delegate to the
00920  * source data object.
00921  */
00922 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
00923 {
00924     HANDLE clip_data = NULL;  /* HGLOBAL unless otherwise specified */
00925     HRESULT hr;
00926 
00927     /* Embed source hack */
00928     if(fmt->cfFormat == embed_source_clipboard_format)
00929     {
00930         return render_embed_source_hack(data, fmt);
00931     }
00932 
00933     if(fmt->tymed & TYMED_ISTORAGE)
00934     {
00935         hr = get_data_from_storage(data, fmt, &clip_data);
00936     }
00937     else if(fmt->tymed & TYMED_ISTREAM)
00938     {
00939         hr = get_data_from_stream(data, fmt, &clip_data);
00940     }
00941     else if(fmt->tymed & TYMED_HGLOBAL)
00942     {
00943         hr = get_data_from_global(data, fmt, &clip_data);
00944     }
00945     else if(fmt->tymed & TYMED_ENHMF)
00946     {
00947         hr = get_data_from_enhmetafile(data, fmt, &clip_data);
00948     }
00949     else if(fmt->tymed & TYMED_MFPICT)
00950     {
00951         /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */
00952         hr = get_data_from_metafilepict(data, fmt, &clip_data);
00953     }
00954     else if(fmt->tymed & TYMED_GDI)
00955     {
00956         /* Returns HBITMAP not HGLOBAL */
00957         hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data);
00958     }
00959     else
00960     {
00961         FIXME("Unhandled tymed %x\n", fmt->tymed);
00962         hr = DV_E_FORMATETC;
00963     }
00964 
00965     if(SUCCEEDED(hr))
00966     {
00967         if ( !SetClipboardData(fmt->cfFormat, clip_data) )
00968         {
00969             WARN("() : Failed to set rendered clipboard data into clipboard!\n");
00970             if(fmt->tymed & TYMED_MFPICT)
00971                 free_metafilepict(clip_data);
00972             else if(fmt->tymed & TYMED_GDI)
00973                 DeleteObject(clip_data);
00974             else
00975                 GlobalFree(clip_data);
00976             hr = CLIPBRD_E_CANT_SET;
00977         }
00978     }
00979 
00980     return hr;
00981 }
00982 
00983 /*---------------------------------------------------------------------*
00984  *  Implementation of the internal IDataObject interface exposed by
00985  *  the OLE clipboard.
00986  *---------------------------------------------------------------------*/
00987 
00988 
00989 /************************************************************************
00990  *           snapshot_QueryInterface
00991  */
00992 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
00993                                               REFIID riid, void **ppvObject)
00994 {
00995   snapshot *This = impl_from_IDataObject(iface);
00996   TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
00997 
00998   if ( (This==0) || (ppvObject==0) )
00999     return E_INVALIDARG;
01000 
01001   *ppvObject = 0;
01002 
01003   if (IsEqualIID(&IID_IUnknown, riid) ||
01004       IsEqualIID(&IID_IDataObject, riid))
01005   {
01006     *ppvObject = iface;
01007   }
01008   else
01009   {
01010     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
01011     return E_NOINTERFACE;
01012   }
01013 
01014   IUnknown_AddRef((IUnknown*)*ppvObject);
01015 
01016   return S_OK;
01017 }
01018 
01019 /************************************************************************
01020  *              snapshot_AddRef
01021  */
01022 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
01023 {
01024     snapshot *This = impl_from_IDataObject(iface);
01025 
01026     TRACE("(%p)->(count=%u)\n", This, This->ref);
01027 
01028     return InterlockedIncrement(&This->ref);
01029 }
01030 
01031 /************************************************************************
01032  *      snapshot_Release
01033  */
01034 static ULONG WINAPI snapshot_Release(IDataObject *iface)
01035 {
01036     snapshot *This = impl_from_IDataObject(iface);
01037     ULONG ref;
01038 
01039     TRACE("(%p)->(count=%u)\n", This, This->ref);
01040 
01041     ref = InterlockedDecrement(&This->ref);
01042 
01043     if (ref == 0)
01044     {
01045         ole_clipbrd *clipbrd;
01046         HRESULT hr = get_ole_clipbrd(&clipbrd);
01047 
01048         if(This->data) IDataObject_Release(This->data);
01049 
01050         if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
01051             clipbrd->latest_snapshot = NULL;
01052         HeapFree(GetProcessHeap(), 0, This);
01053     }
01054 
01055     return ref;
01056 }
01057 
01058 /************************************************************
01059  *              get_current_ole_clip_window
01060  *
01061  * Return the window that owns the ole clipboard.
01062  *
01063  * If the clipboard is flushed or not owned by ole this will
01064  * return NULL.
01065  */
01066 static HWND get_current_ole_clip_window(void)
01067 {
01068     HGLOBAL h;
01069     HWND *ptr, wnd;
01070 
01071     h = GetClipboardData(dataobject_clipboard_format);
01072     if(!h) return NULL;
01073     ptr = GlobalLock(h);
01074     if(!ptr) return NULL;
01075     wnd = *ptr;
01076     GlobalUnlock(h);
01077     return wnd;
01078 }
01079 
01080 /************************************************************
01081  *              get_current_dataobject
01082  *
01083  * Return an unmarshalled IDataObject if there is a current
01084  * (ie non-flushed) object on the ole clipboard.
01085  */
01086 static HRESULT get_current_dataobject(IDataObject **data)
01087 {
01088     HRESULT hr = S_FALSE;
01089     HWND wnd = get_current_ole_clip_window();
01090     HGLOBAL h;
01091     void *ptr;
01092     IStream *stm;
01093     LARGE_INTEGER pos;
01094 
01095     *data = NULL;
01096     if(!wnd) return S_FALSE;
01097 
01098     h = GetClipboardData(wine_marshal_clipboard_format);
01099     if(!h) return S_FALSE;
01100     if(GlobalSize(h) == 0) return S_FALSE;
01101     ptr = GlobalLock(h);
01102     if(!ptr) return S_FALSE;
01103 
01104     hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
01105     if(FAILED(hr)) goto end;
01106 
01107     hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
01108     if(SUCCEEDED(hr))
01109     {
01110         pos.QuadPart = 0;
01111         IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
01112         hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
01113     }
01114     IStream_Release(stm);
01115 
01116 end:
01117     GlobalUnlock(h);
01118     return hr;
01119 }
01120 
01121 static DWORD get_tymed_from_nonole_cf(UINT cf)
01122 {
01123     if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
01124 
01125     switch(cf)
01126     {
01127     case CF_TEXT:
01128     case CF_OEMTEXT:
01129     case CF_UNICODETEXT:
01130         return TYMED_ISTREAM | TYMED_HGLOBAL;
01131     case CF_ENHMETAFILE:
01132         return TYMED_ENHMF;
01133     case CF_METAFILEPICT:
01134         return TYMED_MFPICT;
01135     default:
01136         FIXME("returning TYMED_NULL for cf %04x\n", cf);
01137         return TYMED_NULL;
01138     }
01139 }
01140 
01141 /***********************************************************
01142  *     get_priv_data
01143  *
01144  * Returns a copy of the Ole Private Data
01145  */
01146 static HRESULT get_priv_data(ole_priv_data **data)
01147 {
01148     HGLOBAL handle;
01149     HRESULT hr = S_OK;
01150     ole_priv_data *ret = NULL;
01151 
01152     *data = NULL;
01153 
01154     handle = GetClipboardData( ole_private_data_clipboard_format );
01155     if(handle)
01156     {
01157         ole_priv_data *src = GlobalLock(handle);
01158         if(src)
01159         {
01160             DWORD i;
01161 
01162             /* FIXME: sanity check on size */
01163             ret = HeapAlloc(GetProcessHeap(), 0, src->size);
01164             if(!ret)
01165             {
01166                 GlobalUnlock(handle);
01167                 return E_OUTOFMEMORY;
01168             }
01169             memcpy(ret, src, src->size);
01170             GlobalUnlock(handle);
01171 
01172             /* Fixup any target device offsets to ptrs */
01173             for(i = 0; i < ret->count; i++)
01174                 ret->entries[i].fmtetc.ptd =
01175                     td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
01176         }
01177     }
01178 
01179     if(!ret) /* Non-ole data */
01180     {
01181         UINT cf;
01182         DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
01183 
01184         for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
01185         {
01186             char buf[100];
01187             GetClipboardFormatNameA(cf, buf, sizeof(buf));
01188             TRACE("cf %04x %s\n", cf, buf);
01189         }
01190         TRACE("count %d\n", count);
01191         size += count * sizeof(ret->entries[0]);
01192 
01193         /* There are holes in fmtetc so zero init */
01194         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
01195         if(!ret) return E_OUTOFMEMORY;
01196         ret->size = size;
01197         ret->count = count;
01198 
01199         for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
01200         {
01201             ret->entries[idx].fmtetc.cfFormat = cf;
01202             ret->entries[idx].fmtetc.ptd = NULL;
01203             ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
01204             ret->entries[idx].fmtetc.lindex = -1;
01205             ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
01206             ret->entries[idx].first_use = 1;
01207         }
01208     }
01209 
01210     *data = ret;
01211     return hr;
01212 }
01213 
01214 /************************************************************************
01215  *                    get_stgmed_for_global
01216  *
01217  * Returns a stg medium with a copy of the global handle
01218  */
01219 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
01220 {
01221     HRESULT hr;
01222 
01223     med->pUnkForRelease = NULL;
01224     med->tymed = TYMED_NULL;
01225 
01226     hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
01227 
01228     if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
01229 
01230     return hr;
01231 }
01232 
01233 /************************************************************************
01234  *                    get_stgmed_for_stream
01235  *
01236  * Returns a stg medium with a stream based on the handle
01237  */
01238 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
01239 {
01240     HRESULT hr;
01241     HGLOBAL dst;
01242 
01243     med->pUnkForRelease = NULL;
01244     med->tymed = TYMED_NULL;
01245 
01246     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
01247     if(FAILED(hr)) return hr;
01248 
01249     hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
01250     if(FAILED(hr))
01251     {
01252         GlobalFree(dst);
01253         return hr;
01254     }
01255 
01256     med->tymed = TYMED_ISTREAM;
01257     return hr;
01258 }
01259 
01260 /************************************************************************
01261  *                    get_stgmed_for_storage
01262  *
01263  * Returns a stg medium with a storage based on the handle
01264  */
01265 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
01266 {
01267     HRESULT hr;
01268     HGLOBAL dst;
01269     ILockBytes *lbs;
01270 
01271     med->pUnkForRelease = NULL;
01272     med->tymed = TYMED_NULL;
01273 
01274     hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
01275     if(FAILED(hr)) return hr;
01276 
01277     hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
01278     if(FAILED(hr))
01279     {
01280         GlobalFree(dst);
01281         return hr;
01282     }
01283 
01284     hr = StgOpenStorageOnILockBytes(lbs, NULL,  STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
01285     ILockBytes_Release(lbs);
01286     if(FAILED(hr))
01287     {
01288         GlobalFree(dst);
01289         return hr;
01290     }
01291 
01292     med->tymed = TYMED_ISTORAGE;
01293     return hr;
01294 }
01295 
01296 /************************************************************************
01297  *                    get_stgmed_for_emf
01298  *
01299  * Returns a stg medium with an enhanced metafile based on the handle
01300  */
01301 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
01302 {
01303     med->pUnkForRelease = NULL;
01304     med->tymed = TYMED_NULL;
01305 
01306     med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
01307     if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
01308     med->tymed = TYMED_ENHMF;
01309     return S_OK;
01310 }
01311 
01312 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
01313 {
01314     const WCHAR *str1, *str2;
01315 
01316     if(off1 == 0 && off2 == 0) return TRUE;
01317     if(off1 == 0 || off2 == 0) return FALSE;
01318 
01319     str1 = (const WCHAR*)((const char*)t1 + off1);
01320     str2 = (const WCHAR*)((const char*)t2 + off2);
01321 
01322     return !lstrcmpW(str1, str2);
01323 }
01324 
01325 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
01326 {
01327     if(t1 == NULL && t2 == NULL) return TRUE;
01328     if(t1 == NULL || t2 == NULL) return FALSE;
01329 
01330     if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
01331         return FALSE;
01332     if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
01333         return FALSE;
01334     if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
01335         return FALSE;
01336 
01337     /* FIXME check devmode? */
01338 
01339     return TRUE;
01340 }
01341 
01342 /************************************************************************
01343  *         snapshot_GetData
01344  */
01345 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
01346                                        STGMEDIUM *med)
01347 {
01348     snapshot *This = impl_from_IDataObject(iface);
01349     HANDLE h;
01350     HRESULT hr;
01351     ole_priv_data *enum_data = NULL;
01352     ole_priv_data_entry *entry;
01353     DWORD mask;
01354 
01355     TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
01356 
01357     if ( !fmt || !med ) return E_INVALIDARG;
01358 
01359     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
01360 
01361     if(!This->data)
01362         hr = get_current_dataobject(&This->data);
01363 
01364     if(This->data)
01365     {
01366         hr = IDataObject_GetData(This->data, fmt, med);
01367         CloseClipboard();
01368         return hr;
01369     }
01370 
01371     h = GetClipboardData(fmt->cfFormat);
01372     if(!h)
01373     {
01374         hr = DV_E_FORMATETC;
01375         goto end;
01376     }
01377 
01378     hr = get_priv_data(&enum_data);
01379     if(FAILED(hr)) goto end;
01380 
01381     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
01382     if(entry)
01383     {
01384         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
01385         {
01386             hr = DV_E_FORMATETC;
01387             goto end;
01388         }
01389         mask = fmt->tymed & entry->fmtetc.tymed;
01390         if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
01391     }
01392     else /* non-Ole format */
01393         mask = fmt->tymed & TYMED_HGLOBAL;
01394 
01395     if(mask & TYMED_ISTORAGE)
01396         hr = get_stgmed_for_storage(h, med);
01397     else if(mask & TYMED_HGLOBAL)
01398         hr = get_stgmed_for_global(h, med);
01399     else if(mask & TYMED_ISTREAM)
01400         hr = get_stgmed_for_stream(h, med);
01401     else if(mask & TYMED_ENHMF)
01402         hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
01403     else
01404     {
01405         FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
01406         hr = E_FAIL;
01407         goto end;
01408     }
01409 
01410 end:
01411     HeapFree(GetProcessHeap(), 0, enum_data);
01412     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
01413     return hr;
01414 }
01415 
01416 /************************************************************************
01417  *          snapshot_GetDataHere
01418  */
01419 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
01420                                            STGMEDIUM *med)
01421 {
01422     snapshot *This = impl_from_IDataObject(iface);
01423     HANDLE h;
01424     HRESULT hr;
01425     ole_priv_data *enum_data = NULL;
01426     ole_priv_data_entry *entry;
01427     TYMED supported;
01428 
01429     if ( !fmt || !med ) return E_INVALIDARG;
01430 
01431     TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
01432 
01433     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
01434 
01435     if(!This->data)
01436         hr = get_current_dataobject(&This->data);
01437 
01438     if(This->data)
01439     {
01440         hr = IDataObject_GetDataHere(This->data, fmt, med);
01441         if(SUCCEEDED(hr))
01442         {
01443             CloseClipboard();
01444             return hr;
01445         }
01446     }
01447 
01448     h = GetClipboardData(fmt->cfFormat);
01449     if(!h)
01450     {
01451         hr = DV_E_FORMATETC;
01452         goto end;
01453     }
01454 
01455     hr = get_priv_data(&enum_data);
01456     if(FAILED(hr)) goto end;
01457 
01458     entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
01459     if(entry)
01460     {
01461         if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
01462         {
01463             hr = DV_E_FORMATETC;
01464             goto end;
01465         }
01466         supported = entry->fmtetc.tymed;
01467     }
01468     else /* non-Ole format */
01469         supported = TYMED_HGLOBAL;
01470 
01471     switch(med->tymed)
01472     {
01473     case TYMED_HGLOBAL:
01474     {
01475         DWORD src_size = GlobalSize(h);
01476         DWORD dst_size = GlobalSize(med->u.hGlobal);
01477         hr = E_FAIL;
01478         if(dst_size >= src_size)
01479         {
01480             void *src = GlobalLock(h);
01481             void *dst = GlobalLock(med->u.hGlobal);
01482 
01483             memcpy(dst, src, src_size);
01484             GlobalUnlock(med->u.hGlobal);
01485             GlobalUnlock(h);
01486             hr = S_OK;
01487         }
01488         break;
01489     }
01490     case TYMED_ISTREAM:
01491     {
01492         DWORD src_size = GlobalSize(h);
01493         void *src = GlobalLock(h);
01494         hr = IStream_Write(med->u.pstm, src, src_size, NULL);
01495         GlobalUnlock(h);
01496         break;
01497     }
01498     case TYMED_ISTORAGE:
01499     {
01500         STGMEDIUM copy;
01501         if(!(supported & TYMED_ISTORAGE))
01502         {
01503             hr = E_FAIL;
01504             goto end;
01505         }
01506         hr = get_stgmed_for_storage(h, &copy);
01507         if(SUCCEEDED(hr))
01508         {
01509             hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
01510             ReleaseStgMedium(&copy);
01511         }
01512         break;
01513     }
01514     default:
01515         FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
01516         hr = E_FAIL;
01517         goto end;
01518     }
01519 
01520 end:
01521     HeapFree(GetProcessHeap(), 0, enum_data);
01522     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
01523     return hr;
01524 }
01525 
01526 /************************************************************************
01527  *           snapshot_QueryGetData
01528  *
01529  * The OLE Clipboard's implementation of this method delegates to
01530  * a data source if there is one or wraps around the windows clipboard
01531  * function IsClipboardFormatAvailable() otherwise.
01532  *
01533  */
01534 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
01535 {
01536     FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
01537 
01538     if (!fmt) return E_INVALIDARG;
01539 
01540     if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
01541 
01542     if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
01543 
01544     return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
01545 }
01546 
01547 /************************************************************************
01548  *              snapshot_GetCanonicalFormatEtc
01549  */
01550 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
01551                                                      FORMATETC *fmt_out)
01552 {
01553     TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
01554 
01555     if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
01556 
01557     *fmt_out = *fmt_in;
01558     return DATA_S_SAMEFORMATETC;
01559 }
01560 
01561 /************************************************************************
01562  *              snapshot_SetData
01563  *
01564  * The OLE Clipboard does not implement this method
01565  */
01566 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
01567                                        STGMEDIUM *med, BOOL release)
01568 {
01569     TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
01570     return E_NOTIMPL;
01571 }
01572 
01573 /************************************************************************
01574  *             snapshot_EnumFormatEtc
01575  *
01576  */
01577 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
01578                                              IEnumFORMATETC **enum_fmt)
01579 {
01580     HRESULT hr;
01581     ole_priv_data *data = NULL;
01582 
01583     TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
01584 
01585     *enum_fmt = NULL;
01586 
01587     if ( dir != DATADIR_GET ) return E_NOTIMPL;
01588     if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
01589 
01590     hr = get_priv_data(&data);
01591 
01592     if(FAILED(hr)) goto end;
01593 
01594     hr = enum_fmtetc_construct( data, 0, enum_fmt );
01595 
01596 end:
01597     if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
01598     return hr;
01599 }
01600 
01601 /************************************************************************
01602  *               snapshot_DAdvise
01603  *
01604  * The OLE Clipboard does not implement this method
01605  */
01606 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
01607                                        DWORD flags, IAdviseSink *sink,
01608                                        DWORD *conn)
01609 {
01610     TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
01611     return E_NOTIMPL;
01612 }
01613 
01614 /************************************************************************
01615  *              snapshot_DUnadvise
01616  *
01617  * The OLE Clipboard does not implement this method
01618  */
01619 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
01620 {
01621     TRACE("(%p, %d): not implemented\n", iface, conn);
01622     return E_NOTIMPL;
01623 }
01624 
01625 /************************************************************************
01626  *             snapshot_EnumDAdvise
01627  *
01628  * The OLE Clipboard does not implement this method
01629  */
01630 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
01631                                            IEnumSTATDATA** enum_advise)
01632 {
01633     TRACE("(%p, %p): not implemented\n", iface, enum_advise);
01634     return E_NOTIMPL;
01635 }
01636 
01637 static const IDataObjectVtbl snapshot_vtable =
01638 {
01639     snapshot_QueryInterface,
01640     snapshot_AddRef,
01641     snapshot_Release,
01642     snapshot_GetData,
01643     snapshot_GetDataHere,
01644     snapshot_QueryGetData,
01645     snapshot_GetCanonicalFormatEtc,
01646     snapshot_SetData,
01647     snapshot_EnumFormatEtc,
01648     snapshot_DAdvise,
01649     snapshot_DUnadvise,
01650     snapshot_EnumDAdvise
01651 };
01652 
01653 /*---------------------------------------------------------------------*
01654  *           Internal implementation methods for the OLE clipboard
01655  *---------------------------------------------------------------------*/
01656 
01657 static snapshot *snapshot_construct(DWORD seq_no)
01658 {
01659     snapshot *This;
01660 
01661     This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
01662     if (!This) return NULL;
01663 
01664     This->IDataObject_iface.lpVtbl = &snapshot_vtable;
01665     This->ref = 0;
01666     This->seq_no = seq_no;
01667     This->data = NULL;
01668 
01669     return This;
01670 }
01671 
01672 /*********************************************************
01673  *               register_clipboard_formats
01674  */
01675 static void register_clipboard_formats(void)
01676 {
01677     static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
01678     static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
01679     static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
01680     static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
01681     static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
01682     static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
01683     static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
01684     static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
01685     static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
01686     static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
01687                                                  'D','e','s','c','r','i','p','t','o','r',0};
01688     static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
01689 
01690     static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
01691                                                      'D','a','t','a','O','b','j','e','c','t',0};
01692 
01693     ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
01694     filename_clipboard_format = RegisterClipboardFormatW(FileName);
01695     filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
01696     dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
01697     embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
01698     embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
01699     custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
01700     link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
01701     object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
01702     link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
01703     ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
01704 
01705     wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
01706 }
01707 
01708 /***********************************************************************
01709  * OLEClipbrd_Initialize()
01710  * Initializes the OLE clipboard.
01711  */
01712 void OLEClipbrd_Initialize(void)
01713 {
01714     register_clipboard_formats();
01715 
01716     if ( !theOleClipboard )
01717     {
01718         ole_clipbrd* clipbrd;
01719         HGLOBAL h;
01720 
01721         TRACE("()\n");
01722 
01723         clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
01724         if (!clipbrd) return;
01725 
01726         clipbrd->latest_snapshot = NULL;
01727         clipbrd->window = NULL;
01728         clipbrd->src_data = NULL;
01729         clipbrd->cached_enum = NULL;
01730 
01731         h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
01732         if(!h)
01733         {
01734             HeapFree(GetProcessHeap(), 0, clipbrd);
01735             return;
01736         }
01737 
01738         if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
01739         {
01740             GlobalFree(h);
01741             HeapFree(GetProcessHeap(), 0, clipbrd);
01742             return;
01743         }
01744 
01745         theOleClipboard = clipbrd;
01746     }
01747 }
01748 
01749 /***********************************************************************
01750  * OLEClipbrd_UnInitialize()
01751  * Un-Initializes the OLE clipboard
01752  */
01753 void OLEClipbrd_UnInitialize(void)
01754 {
01755     ole_clipbrd *clipbrd = theOleClipboard;
01756 
01757     TRACE("()\n");
01758 
01759     if ( clipbrd )
01760     {
01761         static const WCHAR ole32W[] = {'o','l','e','3','2',0};
01762         HINSTANCE hinst = GetModuleHandleW(ole32W);
01763 
01764         if ( clipbrd->window )
01765         {
01766             DestroyWindow(clipbrd->window);
01767             UnregisterClassW( clipbrd_wndclass, hinst );
01768         }
01769 
01770         IStream_Release(clipbrd->marshal_data);
01771         if (clipbrd->src_data) IDataObject_Release(clipbrd->src_data);
01772         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
01773         HeapFree(GetProcessHeap(), 0, clipbrd);
01774         theOleClipboard = NULL;
01775     }
01776 }
01777 
01778 /*********************************************************************
01779  *          set_clipboard_formats
01780  *
01781  * Enumerate all formats supported by the source and make
01782  * those formats available using delayed rendering using SetClipboardData.
01783  * Cache the enumeration list and make that list visibile as the
01784  * 'Ole Private Data' format on the clipboard.
01785  *
01786  */
01787 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
01788 {
01789     HRESULT hr;
01790     FORMATETC fmt;
01791     IEnumFORMATETC *enum_fmt;
01792     HGLOBAL priv_data_handle;
01793     DWORD_PTR target_offset;
01794     ole_priv_data *priv_data;
01795     DWORD count = 0, needed = sizeof(*priv_data), idx;
01796 
01797     hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
01798     if(FAILED(hr)) return hr;
01799 
01800     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
01801     {
01802         count++;
01803         needed += sizeof(priv_data->entries[0]);
01804         if(fmt.ptd)
01805         {
01806             needed += fmt.ptd->tdSize;
01807             CoTaskMemFree(fmt.ptd);
01808         }
01809     }
01810 
01811     /* Windows pads the list with two empty ole_priv_data_entries, one
01812      * after the entries array and one after the target device data.
01813      * Allocating with zero init to zero these pads. */
01814 
01815     needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
01816     priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
01817     priv_data = GlobalLock(priv_data_handle);
01818 
01819     priv_data->unk1 = 0;
01820     priv_data->size = needed;
01821     priv_data->unk2 = 1;
01822     priv_data->count = count;
01823     priv_data->unk3[0] = 0;
01824     priv_data->unk3[1] = 0;
01825 
01826     IEnumFORMATETC_Reset(enum_fmt);
01827 
01828     idx = 0;
01829     target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
01830 
01831     while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
01832     {
01833         TRACE("%s\n", dump_fmtetc(&fmt));
01834 
01835         priv_data->entries[idx].fmtetc = fmt;
01836         if(fmt.ptd)
01837         {
01838             memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
01839             priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
01840             target_offset += fmt.ptd->tdSize;
01841             CoTaskMemFree(fmt.ptd);
01842         }
01843 
01844         priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
01845         priv_data->entries[idx].unk[0] = 0;
01846         priv_data->entries[idx].unk[1] = 0;
01847 
01848         if (priv_data->entries[idx].first_use)
01849             SetClipboardData(fmt.cfFormat, NULL);
01850 
01851         idx++;
01852     }
01853 
01854     IEnumFORMATETC_Release(enum_fmt);
01855 
01856     /* Cache the list and fixup any target device offsets to ptrs */
01857     clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
01858     memcpy(clipbrd->cached_enum, priv_data, needed);
01859     for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
01860         clipbrd->cached_enum->entries[idx].fmtetc.ptd =
01861             td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
01862 
01863     GlobalUnlock(priv_data_handle);
01864     if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle))
01865     {
01866         GlobalFree(priv_data_handle);
01867         return CLIPBRD_E_CANT_SET;
01868     }
01869 
01870     return S_OK;
01871 }
01872 
01873 static HWND create_clipbrd_window(void);
01874 
01875 /***********************************************************************
01876  *                 get_clipbrd_window
01877  */
01878 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
01879 {
01880     if ( !clipbrd->window )
01881         clipbrd->window = create_clipbrd_window();
01882 
01883     *wnd = clipbrd->window;
01884     return *wnd ? S_OK : E_FAIL;
01885 }
01886 
01887 
01888 /**********************************************************************
01889  *                  release_marshal_data
01890  *
01891  * Releases the data and sets the stream back to zero size.
01892  */
01893 static inline void release_marshal_data(IStream *stm)
01894 {
01895     LARGE_INTEGER pos;
01896     ULARGE_INTEGER size;
01897     pos.QuadPart = size.QuadPart = 0;
01898 
01899     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
01900     CoReleaseMarshalData(stm);
01901     IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
01902     IStream_SetSize(stm, size);
01903 }
01904 
01905 /***********************************************************************
01906  *   expose_marshalled_dataobject
01907  *
01908  * Sets the marshalled dataobject to the clipboard.  In the flushed case
01909  * we set a zero sized HGLOBAL to clear the old marshalled data.
01910  */
01911 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
01912 {
01913     HGLOBAL h;
01914 
01915     if(data)
01916     {
01917         HGLOBAL h_stm;
01918         GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
01919         dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
01920     }
01921     else /* flushed */
01922         h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
01923 
01924     if(!h) return E_OUTOFMEMORY;
01925 
01926     if(!SetClipboardData(wine_marshal_clipboard_format, h))
01927     {
01928         GlobalFree(h);
01929         return CLIPBRD_E_CANT_SET;
01930     }
01931     return S_OK;
01932 }
01933 
01934 /***********************************************************************
01935  *                   set_src_dataobject
01936  *
01937  * Clears and sets the clipboard's src IDataObject.
01938  *
01939  * To marshal the source dataobject we do something rather different from Windows.
01940  * We set a clipboard format which contains the marshalled data.
01941  * Windows sets two window props one of which is an IID, the other is an endpoint number.
01942  */
01943 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
01944 {
01945     HRESULT hr;
01946     HWND wnd;
01947 
01948     if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
01949 
01950     if(clipbrd->src_data)
01951     {
01952         release_marshal_data(clipbrd->marshal_data);
01953 
01954         IDataObject_Release(clipbrd->src_data);
01955         clipbrd->src_data = NULL;
01956         HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
01957         clipbrd->cached_enum = NULL;
01958     }
01959 
01960     if(data)
01961     {
01962         IUnknown *unk;
01963 
01964         IDataObject_AddRef(data);
01965         clipbrd->src_data = data;
01966 
01967         IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
01968         hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
01969                                 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
01970         IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
01971         if(FAILED(hr)) return hr;
01972         hr = set_clipboard_formats(clipbrd, data);
01973     }
01974     return hr;
01975 }
01976 
01977 /***********************************************************************
01978  *                   clipbrd_wndproc
01979  */
01980 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
01981 {
01982     ole_clipbrd *clipbrd;
01983 
01984     get_ole_clipbrd(&clipbrd);
01985 
01986     switch (message)
01987     {
01988     case WM_RENDERFORMAT:
01989     {
01990         UINT cf = wparam;
01991         ole_priv_data_entry *entry;
01992 
01993         TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
01994         entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
01995 
01996         if(entry)
01997             render_format(clipbrd->src_data, &entry->fmtetc);
01998 
01999         break;
02000     }
02001 
02002     case WM_RENDERALLFORMATS:
02003     {
02004         DWORD i;
02005         ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
02006 
02007         TRACE("(): WM_RENDERALLFORMATS\n");
02008 
02009         for(i = 0; i < clipbrd->cached_enum->count; i++)
02010         {
02011             if(entries[i].first_use)
02012                 render_format(clipbrd->src_data, &entries[i].fmtetc);
02013         }
02014         break;
02015     }
02016 
02017     case WM_DESTROYCLIPBOARD:
02018     {
02019         TRACE("(): WM_DESTROYCLIPBOARD\n");
02020 
02021         set_src_dataobject(clipbrd, NULL);
02022         break;
02023     }
02024 
02025     default:
02026         return DefWindowProcW(hwnd, message, wparam, lparam);
02027     }
02028 
02029     return 0;
02030 }
02031 
02032 
02033 /***********************************************************************
02034  *                 create_clipbrd_window
02035  */
02036 static HWND create_clipbrd_window(void)
02037 {
02038     WNDCLASSEXW class;
02039     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
02040     static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
02041     HINSTANCE hinst = GetModuleHandleW(ole32W);
02042 
02043     class.cbSize         = sizeof(class);
02044     class.style          = 0;
02045     class.lpfnWndProc    = clipbrd_wndproc;
02046     class.cbClsExtra     = 0;
02047     class.cbWndExtra     = 0;
02048     class.hInstance      = hinst;
02049     class.hIcon          = 0;
02050     class.hCursor        = 0;
02051     class.hbrBackground  = 0;
02052     class.lpszMenuName   = NULL;
02053     class.lpszClassName  = clipbrd_wndclass;
02054     class.hIconSm        = NULL;
02055 
02056     RegisterClassExW(&class);
02057 
02058     return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
02059                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
02060                          NULL, NULL, hinst, 0);
02061 }
02062 
02063 /*********************************************************************
02064  *          set_dataobject_format
02065  *
02066  * Windows creates a 'DataObject' clipboard format that contains the
02067  * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
02068  */
02069 static HRESULT set_dataobject_format(HWND hwnd)
02070 {
02071     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
02072     HWND *data;
02073 
02074     if(!h) return E_OUTOFMEMORY;
02075 
02076     data = GlobalLock(h);
02077     *data = hwnd;
02078     GlobalUnlock(h);
02079 
02080     if(!SetClipboardData(dataobject_clipboard_format, h))
02081     {
02082         GlobalFree(h);
02083         return CLIPBRD_E_CANT_SET;
02084     }
02085 
02086     return S_OK;
02087 }
02088 
02089 /*---------------------------------------------------------------------*
02090  *           Win32 OLE clipboard API
02091  *---------------------------------------------------------------------*/
02092 
02093 /***********************************************************************
02094  *           OleSetClipboard     [OLE32.@]
02095  *  Places a pointer to the specified data object onto the clipboard,
02096  *  making the data object accessible to the OleGetClipboard function.
02097  *
02098  * RETURNS
02099  *
02100  *    S_OK                  IDataObject pointer placed on the clipboard
02101  *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
02102  *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
02103  *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
02104  *    CLIPBRD_E_CANT_SET    SetClipboard failed
02105  */
02106 
02107 HRESULT WINAPI OleSetClipboard(IDataObject* data)
02108 {
02109   HRESULT hr;
02110   ole_clipbrd *clipbrd;
02111   HWND wnd;
02112 
02113   TRACE("(%p)\n", data);
02114 
02115   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
02116 
02117   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
02118 
02119   if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
02120 
02121   if ( !EmptyClipboard() )
02122   {
02123     hr = CLIPBRD_E_CANT_EMPTY;
02124     goto end;
02125   }
02126 
02127   hr = set_src_dataobject(clipbrd, data);
02128   if(FAILED(hr)) goto end;
02129 
02130   if(data)
02131   {
02132     hr = expose_marshalled_dataobject(clipbrd, data);
02133     if(FAILED(hr)) goto end;
02134     hr = set_dataobject_format(wnd);
02135   }
02136 
02137 end:
02138 
02139   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
02140 
02141   if ( FAILED(hr) )
02142   {
02143     expose_marshalled_dataobject(clipbrd, NULL);
02144     set_src_dataobject(clipbrd, NULL);
02145   }
02146 
02147   return hr;
02148 }
02149 
02150 
02151 /***********************************************************************
02152  * OleGetClipboard [OLE32.@]
02153  * Returns a pointer to our internal IDataObject which represents the conceptual
02154  * state of the Windows clipboard. If the current clipboard already contains
02155  * an IDataObject, our internal IDataObject will delegate to this object.
02156  */
02157 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
02158 {
02159     HRESULT hr;
02160     ole_clipbrd *clipbrd;
02161     DWORD seq_no;
02162 
02163     TRACE("(%p)\n", obj);
02164 
02165     if(!obj) return E_INVALIDARG;
02166 
02167     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
02168 
02169     seq_no = GetClipboardSequenceNumber();
02170     if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
02171         clipbrd->latest_snapshot = NULL;
02172 
02173     if(!clipbrd->latest_snapshot)
02174     {
02175         clipbrd->latest_snapshot = snapshot_construct(seq_no);
02176         if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
02177     }
02178 
02179     *obj = &clipbrd->latest_snapshot->IDataObject_iface;
02180     IDataObject_AddRef(*obj);
02181 
02182     return S_OK;
02183 }
02184 
02185 /******************************************************************************
02186  *              OleFlushClipboard        [OLE32.@]
02187  *  Renders the data from the source IDataObject into the windows clipboard
02188  *
02189  *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
02190  *  by copying the storage into global memory. Subsequently the default
02191  *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
02192  *  back to TYMED_IStorage.
02193  */
02194 HRESULT WINAPI OleFlushClipboard(void)
02195 {
02196   HRESULT hr;
02197   ole_clipbrd *clipbrd;
02198   HWND wnd;
02199 
02200   TRACE("()\n");
02201 
02202   if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
02203 
02204   if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
02205 
02206   /*
02207    * Already flushed or no source DataObject? Nothing to do.
02208    */
02209   if (!clipbrd->src_data) return S_OK;
02210 
02211   if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
02212 
02213   SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
02214 
02215   hr = set_dataobject_format(NULL);
02216 
02217   expose_marshalled_dataobject(clipbrd, NULL);
02218   set_src_dataobject(clipbrd, NULL);
02219 
02220   if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
02221 
02222   return hr;
02223 }
02224 
02225 
02226 /***********************************************************************
02227  *           OleIsCurrentClipboard [OLE32.@]
02228  */
02229 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
02230 {
02231     HRESULT hr;
02232     ole_clipbrd *clipbrd;
02233     TRACE("()\n");
02234 
02235     if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
02236 
02237     if (data == NULL) return S_FALSE;
02238 
02239     return (data == clipbrd->src_data) ? S_OK : S_FALSE;
02240 }

Generated on Sat May 26 2012 04:24:05 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.