set svn:eol-style to native
[reactos.git] / reactos / lib / ole32 / clipboard.c
index 3d50057..236416e 100644 (file)
-/*\r
- *  OLE 2 clipboard support\r
- *\r
- *      Copyright 1999  Noel Borthwick <noel@macadamian.com>\r
- *      Copyright 2000  Abey George <abey@macadamian.com>\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- *\r
- * NOTES:\r
- *    This file contains the implementation for the OLE Clipboard and its\r
- *    internal interfaces. The OLE clipboard interacts with an IDataObject\r
- *    interface via the OleSetClipboard, OleGetClipboard and\r
- *    OleIsCurrentClipboard API's. An internal IDataObject delegates\r
- *    to a client supplied IDataObject or the WIN32 clipboard API depending\r
- *    on whether OleSetClipboard has been invoked.\r
- *    Here are some operating scenarios:\r
- *\r
- *    1. OleSetClipboard called: In this case the internal IDataObject\r
- *       delegates to the client supplied IDataObject. Additionally OLE takes\r
- *       ownership of the Windows clipboard and any HGLOCBAL IDataObject\r
- *       items are placed on the Windows clipboard. This allows non OLE aware\r
- *       applications to access these. A local WinProc fields WM_RENDERFORMAT\r
- *       and WM_RENDERALLFORMATS messages in this case.\r
- *\r
- *    2. OleGetClipboard called without previous OleSetClipboard. Here the internal\r
- *       IDataObject functionality wraps around the WIN32 clipboard API.\r
- *\r
- *    3. OleGetClipboard called after previous OleSetClipboard. Here the internal\r
- *       IDataObject delegates to the source IDataObjects functionality directly,\r
- *       thereby bypassing the Windows clipboard.\r
- *\r
- *    Implementation references : Inside OLE 2'nd  edition by Kraig Brockschmidt\r
- *\r
- * TODO:\r
- *    - Support for pasting between different processes. OLE clipboard support\r
- *      currently works only for in process copy and paste. Since we internally\r
- *      store a pointer to the source's IDataObject and delegate to that, this\r
- *      will fail if the IDataObject client belongs to a different process.\r
- *    - IDataObject::GetDataHere is not implemented\r
- *    - OleFlushClipboard needs to additionally handle TYMED_IStorage media\r
- *      by copying the storage into global memory. Subsequently the default\r
- *      data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL\r
- *      back to TYMED_IStorage.\r
- *    - OLE1 compatibility formats to be synthesized from OLE2 formats and put on\r
- *      clipboard in OleSetClipboard.\r
- *\r
- */\r
-\r
-#include <assert.h>\r
-#include <stdarg.h>\r
-#include <string.h>\r
-\r
-#define COBJMACROS\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "winerror.h"\r
-#include "winnls.h"\r
-#include "ole2.h"\r
-#include "wine/debug.h"\r
-#include "olestd.h"\r
-\r
-#include "storage32.h"\r
-\r
-#define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%lx)\n", (HRESULT)err); goto CLEANUP; }\r
-\r
-/* For CoGetMalloc (MEMCTX_TASK is currently ignored) */\r
-#ifndef MEMCTX_TASK\r
-# define MEMCTX_TASK -1\r
-#endif\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(ole);\r
-\r
-/****************************************************************************\r
- * OLEClipbrd\r
- * DO NOT add any members before the VTables declaration!\r
- */\r
-struct OLEClipbrd\r
-{\r
-  /*\r
-   * List all interface VTables here\r
-   */\r
-  IDataObjectVtbl*  lpvtbl1;  /* IDataObject VTable */\r
-\r
-  /*\r
-   * The hidden OLE clipboard window. This window is used as the bridge between the\r
-   * the OLE and windows clipboard API. (Windows creates one such window per process)\r
-   */\r
-  HWND                       hWndClipboard;\r
-\r
-  /*\r
-   * Pointer to the source data object (via OleSetClipboard)\r
-   */\r
-  IDataObject*               pIDataObjectSrc;\r
-\r
-  /*\r
-   * The registered DataObject clipboard format\r
-   */\r
-  UINT                       cfDataObj;\r
-\r
-  /*\r
-   * The handle to ourself\r
-   */\r
-  HGLOBAL                    hSelf;\r
-\r
-  /*\r
-   * Reference count of this object\r
-   */\r
-  ULONG                      ref;\r
-};\r
-\r
-typedef struct OLEClipbrd OLEClipbrd;\r
-\r
-\r
-/****************************************************************************\r
-*   IEnumFORMATETC implementation\r
-*   DO NOT add any members before the VTables declaration!\r
-*/\r
-typedef struct\r
-{\r
-  /* IEnumFORMATETC VTable */\r
-  IEnumFORMATETCVtbl          *lpVtbl;\r
-\r
-  /* IEnumFORMATETC fields */\r
-  UINT                         posFmt;    /* current enumerator position */\r
-  UINT                         countFmt;  /* number of EnumFORMATETC's in array */\r
-  LPFORMATETC                  pFmt;      /* array of EnumFORMATETC's */\r
-\r
-  /*\r
-   * Reference count of this object\r
-   */\r
-  DWORD                        ref;\r
-\r
-  /*\r
-   * IUnknown implementation of the parent data object.\r
-   */\r
-  IUnknown*                    pUnkDataObj;\r
-\r
-} IEnumFORMATETCImpl;\r
-\r
-typedef struct PresentationDataHeader\r
-{\r
-  BYTE unknown1[28];\r
-  DWORD dwObjectExtentX;\r
-  DWORD dwObjectExtentY;\r
-  DWORD dwSize;\r
-} PresentationDataHeader;\r
-\r
-/*\r
- * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize()\r
- */\r
-static HGLOBAL hTheOleClipboard = 0;\r
-static OLEClipbrd* theOleClipboard = NULL;\r
-\r
-\r
-/*\r
- * Prototypes for the methods of the OLEClipboard class.\r
- */\r
-void OLEClipbrd_Initialize(void);\r
-void OLEClipbrd_UnInitialize(void);\r
-static OLEClipbrd* OLEClipbrd_Construct(void);\r
-static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy);\r
-static HWND OLEClipbrd_CreateWindow(void);\r
-static void OLEClipbrd_DestroyWindow(HWND hwnd);\r
-LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);\r
-static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc );\r
-static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc );\r
-\r
-/*\r
- * Prototypes for the methods of the OLEClipboard class\r
- * that implement IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(\r
-            IDataObject*     iface,\r
-            REFIID           riid,\r
-            void**           ppvObject);\r
-static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(\r
-            IDataObject*     iface);\r
-static ULONG WINAPI OLEClipbrd_IDataObject_Release(\r
-            IDataObject*     iface);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetcIn,\r
-           STGMEDIUM*       pmedium);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetc,\r
-           STGMEDIUM*       pmedium);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetc);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatectIn,\r
-           LPFORMATETC      pformatetcOut);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetc,\r
-           STGMEDIUM*       pmedium,\r
-           BOOL             fRelease);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(\r
-           IDataObject*     iface,\r
-           DWORD            dwDirection,\r
-           IEnumFORMATETC** ppenumFormatEtc);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(\r
-           IDataObject*     iface,\r
-           FORMATETC*       pformatetc,\r
-           DWORD            advf,\r
-           IAdviseSink*     pAdvSink,\r
-           DWORD*           pdwConnection);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(\r
-           IDataObject*     iface,\r
-           DWORD            dwConnection);\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(\r
-           IDataObject*     iface,\r
-           IEnumSTATDATA**  ppenumAdvise);\r
-\r
-/*\r
- * Prototypes for the IEnumFORMATETC methods.\r
- */\r
-static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],\r
-                                                           LPUNKNOWN pUnkDataObj);\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid,\r
-                                                               LPVOID* ppvObj);\r
-static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface);\r
-static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface);\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt,\r
-                                                     FORMATETC* rgelt, ULONG* pceltFethed);\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt);\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface);\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);\r
-\r
-\r
-/*\r
- * Virtual function table for the OLEClipbrd's exposed IDataObject interface\r
- */\r
-static IDataObjectVtbl OLEClipbrd_IDataObject_VTable =\r
-{\r
-  OLEClipbrd_IDataObject_QueryInterface,\r
-  OLEClipbrd_IDataObject_AddRef,\r
-  OLEClipbrd_IDataObject_Release,\r
-  OLEClipbrd_IDataObject_GetData,\r
-  OLEClipbrd_IDataObject_GetDataHere,\r
-  OLEClipbrd_IDataObject_QueryGetData,\r
-  OLEClipbrd_IDataObject_GetCanonicalFormatEtc,\r
-  OLEClipbrd_IDataObject_SetData,\r
-  OLEClipbrd_IDataObject_EnumFormatEtc,\r
-  OLEClipbrd_IDataObject_DAdvise,\r
-  OLEClipbrd_IDataObject_DUnadvise,\r
-  OLEClipbrd_IDataObject_EnumDAdvise\r
-};\r
-\r
-/*\r
- * Virtual function table for IEnumFORMATETC interface\r
- */\r
-static struct IEnumFORMATETCVtbl efvt =\r
-{\r
-  OLEClipbrd_IEnumFORMATETC_QueryInterface,\r
-  OLEClipbrd_IEnumFORMATETC_AddRef,\r
-  OLEClipbrd_IEnumFORMATETC_Release,\r
-  OLEClipbrd_IEnumFORMATETC_Next,\r
-  OLEClipbrd_IEnumFORMATETC_Skip,\r
-  OLEClipbrd_IEnumFORMATETC_Reset,\r
-  OLEClipbrd_IEnumFORMATETC_Clone\r
-};\r
-\r
-/*\r
- * Name of our registered OLE clipboard window class\r
- */\r
-CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";\r
-\r
-/*\r
- *  If we need to store state info we can store it here.\r
- *  For now we don't need this functionality.\r
- *\r
-typedef struct tagClipboardWindowInfo\r
-{\r
-} ClipboardWindowInfo;\r
- */\r
-\r
-/*---------------------------------------------------------------------*\r
- *           Win32 OLE clipboard API\r
- *---------------------------------------------------------------------*/\r
-\r
-/***********************************************************************\r
- *           OleSetClipboard     [OLE32.@]\r
- *  Places a pointer to the specified data object onto the clipboard,\r
- *  making the data object accessible to the OleGetClipboard function.\r
- *\r
- * RETURNS:\r
- *\r
- *    S_OK                  IDataObject pointer placed on the clipboard\r
- *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed\r
- *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed\r
- *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed\r
- *    CLIPBRD_E_CANT_SET    SetClipboard failed\r
- */\r
-\r
-HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)\r
-{\r
-  HRESULT hr = S_OK;\r
-  IEnumFORMATETC* penumFormatetc = NULL;\r
-  FORMATETC rgelt;\r
-  BOOL bClipboardOpen = FALSE;\r
-/*\r
-  HGLOBAL hDataObject = 0;\r
-  OLEClipbrd **ppDataObject;\r
-*/\r
-\r
-  TRACE("(%p)\n", pDataObj);\r
-\r
-  /*\r
-   * Make sure we have a clipboard object\r
-   */\r
-  OLEClipbrd_Initialize();\r
-\r
-  /*\r
-   * If the Ole clipboard window hasn't been created yet, create it now.\r
-   */\r
-  if ( !theOleClipboard->hWndClipboard )\r
-    theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();\r
-\r
-  if ( !theOleClipboard->hWndClipboard ) /* sanity check */\r
-    HANDLE_ERROR( E_FAIL );\r
-\r
-  /*\r
-   * Open the Windows clipboard, associating it with our hidden window\r
-   */\r
-  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )\r
-    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );\r
-\r
-  /*\r
-   * Empty the current clipboard and make our window the clipboard owner\r
-   * NOTE: This will trigger a WM_DESTROYCLIPBOARD message\r
-   */\r
-  if ( !EmptyClipboard() )\r
-    HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );\r
-\r
-  /*\r
-   * If we are already holding on to an IDataObject first release that.\r
-   */\r
-  if ( theOleClipboard->pIDataObjectSrc )\r
-  {\r
-    IDataObject_Release(theOleClipboard->pIDataObjectSrc);\r
-    theOleClipboard->pIDataObjectSrc = NULL;\r
-  }\r
-\r
-  /*\r
-   * AddRef the data object passed in and save its pointer.\r
-   * A NULL value indicates that the clipboard should be emptied.\r
-   */\r
-  theOleClipboard->pIDataObjectSrc = pDataObj;\r
-  if ( pDataObj )\r
-  {\r
-    IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);\r
-  }\r
-\r
-  /*\r
-   * Enumerate all HGLOBAL formats supported by the source and make\r
-   * those formats available using delayed rendering using SetClipboardData.\r
-   * Only global memory based data items may be made available to non-OLE\r
-   * applications via the standard Windows clipboard API. Data based on other\r
-   * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API.\r
-   *\r
-   * TODO: Do we need to additionally handle TYMED_IStorage media by copying\r
-   * the storage into global memory?\r
-   */\r
-  if ( pDataObj )\r
-  {\r
-    if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj,\r
-                                                DATADIR_GET,\r
-                                                &penumFormatetc )))\r
-    {\r
-      HANDLE_ERROR( hr );\r
-    }\r
-\r
-    while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )\r
-    {\r
-      if ( rgelt.tymed == TYMED_HGLOBAL )\r
-      {\r
-        CHAR szFmtName[80];\r
-        TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,\r
-              GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)\r
-                ? szFmtName : "");\r
-\r
-        SetClipboardData( rgelt.cfFormat, NULL);\r
-      }\r
-    }\r
-    IEnumFORMATETC_Release(penumFormatetc);\r
-  }\r
-\r
-  /*\r
-   * Windows additionally creates a new "DataObject" clipboard format\r
-   * and stores in on the clipboard. We could possibly store a pointer\r
-   * to our internal IDataObject interface on the clipboard. I'm not\r
-   * sure what the use of this is though.\r
-   * Enable the code below for this functionality.\r
-   */\r
-/*\r
-   theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject");\r
-   hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,\r
-                             sizeof(OLEClipbrd *));\r
-   if (hDataObject==0)\r
-     HANDLE_ERROR( E_OUTOFMEMORY );\r
-\r
-   ppDataObject = (OLEClipbrd**)GlobalLock(hDataObject);\r
-   *ppDataObject = theOleClipboard;\r
-   GlobalUnlock(hDataObject);\r
-\r
-   if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) )\r
-     HANDLE_ERROR( CLIPBRD_E_CANT_SET );\r
-*/\r
-\r
-  hr = S_OK;\r
-\r
-CLEANUP:\r
-\r
-  /*\r
-   * Close Windows clipboard (It remains associated with our window)\r
-   */\r
-  if ( bClipboardOpen && !CloseClipboard() )\r
-    hr = CLIPBRD_E_CANT_CLOSE;\r
-\r
-  /*\r
-   * Release the source IDataObject if something failed\r
-   */\r
-  if ( FAILED(hr) )\r
-  {\r
-    if (theOleClipboard->pIDataObjectSrc)\r
-    {\r
-      IDataObject_Release(theOleClipboard->pIDataObjectSrc);\r
-      theOleClipboard->pIDataObjectSrc = NULL;\r
-    }\r
-  }\r
-\r
-  return hr;\r
-}\r
-\r
-\r
-/***********************************************************************\r
- * OleGetClipboard [OLE32.@]\r
- * Returns a pointer to our internal IDataObject which represents the conceptual\r
- * state of the Windows clipboard. If the current clipboard already contains\r
- * an IDataObject, our internal IDataObject will delegate to this object.\r
- */\r
-HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)\r
-{\r
-  HRESULT hr = S_OK;\r
-  TRACE("()\n");\r
-\r
-  /*\r
-   * Make sure we have a clipboard object\r
-   */\r
-  OLEClipbrd_Initialize();\r
-\r
-  if (!theOleClipboard)\r
-    return E_OUTOFMEMORY;\r
-\r
-  /* Return a reference counted IDataObject */\r
-  hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1),\r
-                                   &IID_IDataObject,  (void**)ppDataObj);\r
-  return hr;\r
-}\r
-\r
-/***********************************************************************\r
- *           OleFlushClipboard   [OLE2.76]\r
- */\r
-\r
-HRESULT WINAPI OleFlushClipboard16(void)\r
-{\r
-  return OleFlushClipboard();\r
-}\r
-\r
-\r
-/******************************************************************************\r
- *              OleFlushClipboard        [OLE32.@]\r
- *  Renders the data from the source IDataObject into the windows clipboard\r
- *\r
- *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media\r
- *  by copying the storage into global memory. Subsequently the default\r
- *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL\r
- *  back to TYMED_IStorage.\r
- */\r
-HRESULT WINAPI OleFlushClipboard()\r
-{\r
-  IEnumFORMATETC* penumFormatetc = NULL;\r
-  FORMATETC rgelt;\r
-  HRESULT hr = S_OK;\r
-  BOOL bClipboardOpen = FALSE;\r
-  IDataObject* pIDataObjectSrc = NULL;\r
-\r
-  TRACE("()\n");\r
-\r
-  /*\r
-   * Make sure we have a clipboard object\r
-   */\r
-  OLEClipbrd_Initialize();\r
-\r
-  /*\r
-   * Already flushed or no source DataObject? Nothing to do.\r
-   */\r
-  if (!theOleClipboard->pIDataObjectSrc)\r
-    return S_OK;\r
-\r
-  /*\r
-   * Addref and save the source data object we are holding on to temporarily,\r
-   * since it will be released when we empty the clipboard.\r
-   */\r
-  pIDataObjectSrc = theOleClipboard->pIDataObjectSrc;\r
-  IDataObject_AddRef(pIDataObjectSrc);\r
-\r
-  /*\r
-   * Open the Windows clipboard\r
-   */\r
-  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )\r
-    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );\r
-\r
-  /*\r
-   * Empty the current clipboard\r
-   */\r
-  if ( !EmptyClipboard() )\r
-    HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );\r
-\r
-  /*\r
-   * Render all HGLOBAL formats supported by the source into\r
-   * the windows clipboard.\r
-   */\r
-  if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc,\r
-                                               DATADIR_GET,\r
-                                               &penumFormatetc) ))\r
-  {\r
-    HANDLE_ERROR( hr );\r
-  }\r
-\r
-  while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )\r
-  {\r
-    if ( rgelt.tymed == TYMED_HGLOBAL )\r
-    {\r
-      CHAR szFmtName[80];\r
-      TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,\r
-            GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)\r
-              ? szFmtName : "");\r
-\r
-      /*\r
-       * Render the clipboard data\r
-       */\r
-      if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) )\r
-        continue;\r
-    }\r
-  }\r
-\r
-  IEnumFORMATETC_Release(penumFormatetc);\r
-\r
-  /*\r
-   * Release the source data object we are holding on to\r
-   */\r
-  IDataObject_Release(pIDataObjectSrc);\r
-\r
-CLEANUP:\r
-\r
-  /*\r
-   * Close Windows clipboard (It remains associated with our window)\r
-   */\r
-  if ( bClipboardOpen && !CloseClipboard() )\r
-    hr = CLIPBRD_E_CANT_CLOSE;\r
-\r
-  return hr;\r
-}\r
-\r
-\r
-/***********************************************************************\r
- *           OleIsCurrentClipboard [OLE32.@]\r
- */\r
-HRESULT WINAPI OleIsCurrentClipboard (  IDataObject *pDataObject)\r
-{\r
-  TRACE("()\n");\r
-  /*\r
-   * Make sure we have a clipboard object\r
-   */\r
-  OLEClipbrd_Initialize();\r
-\r
-  if (!theOleClipboard)\r
-    return E_OUTOFMEMORY;\r
-\r
-  return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;\r
-}\r
-\r
-\r
-/*---------------------------------------------------------------------*\r
- *           Internal implementation methods for the OLE clipboard\r
- *---------------------------------------------------------------------*/\r
-\r
-/***********************************************************************\r
- * OLEClipbrd_Initialize()\r
- * Initializes the OLE clipboard.\r
- */\r
-void OLEClipbrd_Initialize(void)\r
-{\r
-  /*\r
-   * Create the clipboard if necessary\r
-   */\r
-  if ( !theOleClipboard )\r
-  {\r
-    TRACE("()\n");\r
-    theOleClipboard = OLEClipbrd_Construct();\r
-  }\r
-}\r
-\r
-\r
-/***********************************************************************\r
- * OLEClipbrd_UnInitialize()\r
- * Un-Initializes the OLE clipboard\r
- */\r
-void OLEClipbrd_UnInitialize(void)\r
-{\r
-  TRACE("()\n");\r
-  /*\r
-   * Destroy the clipboard if no one holds a reference to us.\r
-   * Note that the clipboard was created with a reference count of 1.\r
-   */\r
-  if ( theOleClipboard && (theOleClipboard->ref <= 1) )\r
-  {\r
-    OLEClipbrd_Destroy( theOleClipboard );\r
-  }\r
-  else\r
-  {\r
-    WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");\r
-  }\r
-}\r
-\r
-\r
-/*********************************************************\r
- * Construct the OLEClipbrd class.\r
- */\r
-static OLEClipbrd* OLEClipbrd_Construct()\r
-{\r
-  OLEClipbrd* newObject = NULL;\r
-  HGLOBAL hNewObject = 0;\r
-\r
-  /*\r
-   * Allocate space for the object. We use GlobalAlloc since we need\r
-   * an HGLOBAL to expose our DataObject as a registered clipboard type.\r
-   */\r
-  hNewObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,\r
-                           sizeof(OLEClipbrd));\r
-  if (hNewObject==0)\r
-    return NULL;\r
-\r
-  /*\r
-   * Lock the handle for the entire lifetime of the clipboard.\r
-   */\r
-  newObject = GlobalLock(hNewObject);\r
-\r
-  /*\r
-   * Initialize the virtual function table.\r
-   */\r
-  newObject->lpvtbl1 = &OLEClipbrd_IDataObject_VTable;\r
-\r
-  /*\r
-   * Start with one reference count. The caller of this function\r
-   * must release the interface pointer when it is done.\r
-   */\r
-  newObject->ref = 1;\r
-\r
-  newObject->hSelf = hNewObject;\r
-\r
-  /*\r
-   * The Ole clipboard is a singleton - save the global handle and pointer\r
-   */\r
-  theOleClipboard = newObject;\r
-  hTheOleClipboard = hNewObject;\r
-\r
-  return theOleClipboard;\r
-}\r
-\r
-static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy)\r
-{\r
-  TRACE("()\n");\r
-\r
-  if ( !ptrToDestroy )\r
-    return;\r
-\r
-  /*\r
-   * Destroy the Ole clipboard window\r
-   */\r
-  if ( ptrToDestroy->hWndClipboard )\r
-    OLEClipbrd_DestroyWindow(ptrToDestroy->hWndClipboard);\r
-\r
-  /*\r
-   * Free the actual OLE Clipboard structure.\r
-   */\r
-  TRACE("() - Destroying clipboard data object.\n");\r
-  GlobalUnlock(ptrToDestroy->hSelf);\r
-  GlobalFree(ptrToDestroy->hSelf);\r
-\r
-  /*\r
-   * The Ole clipboard is a singleton (ptrToDestroy == theOleClipboard)\r
-   */\r
-  theOleClipboard = NULL;\r
-  hTheOleClipboard = 0;\r
-}\r
-\r
-\r
-/***********************************************************************\r
- * OLEClipbrd_CreateWindow()\r
- * Create the clipboard window\r
- */\r
-static HWND OLEClipbrd_CreateWindow()\r
-{\r
-  HWND hwnd = 0;\r
-  WNDCLASSEXA wcex;\r
-\r
-  /*\r
-   * Register the clipboard window class if necessary\r
-   */\r
-    ZeroMemory( &wcex, sizeof(WNDCLASSEXA));\r
-\r
-    wcex.cbSize         = sizeof(WNDCLASSEXA);\r
-    /* Windows creates this class with a style mask of 0\r
-     * We don't bother doing this since the FindClassByAtom code\r
-     * would have to be changed to deal with this idiosyncrasy. */\r
-    wcex.style          = CS_GLOBALCLASS;\r
-    wcex.lpfnWndProc    = OLEClipbrd_WndProc;\r
-    wcex.hInstance      = 0;\r
-    wcex.lpszClassName  = OLEClipbrd_WNDCLASS;\r
-\r
-    RegisterClassExA(&wcex);\r
-\r
-  /*\r
-   * Create a hidden window to receive OLE clipboard messages\r
-   */\r
-\r
-/*\r
- *  If we need to store state info we can store it here.\r
- *  For now we don't need this functionality.\r
- *   ClipboardWindowInfo clipboardInfo;\r
- *   ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo));\r
- */\r
-\r
-  hwnd = CreateWindowA(OLEClipbrd_WNDCLASS,\r
-                                   "ClipboardWindow",\r
-                                   WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,\r
-                                   CW_USEDEFAULT, CW_USEDEFAULT,\r
-                                   CW_USEDEFAULT, CW_USEDEFAULT,\r
-                                   0,\r
-                                   0,\r
-                                   0,\r
-                                   0 /*(LPVOID)&clipboardInfo */);\r
-\r
-  return hwnd;\r
-}\r
-\r
-/***********************************************************************\r
- * OLEClipbrd_DestroyWindow(HWND)\r
- * Destroy the clipboard window and unregister its class\r
- */\r
-static void OLEClipbrd_DestroyWindow(HWND hwnd)\r
-{\r
-  /*\r
-   * Destroy clipboard window and unregister its WNDCLASS\r
-   */\r
-  DestroyWindow(hwnd);\r
-  UnregisterClassA( OLEClipbrd_WNDCLASS, 0 );\r
-}\r
-\r
-/***********************************************************************\r
- * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG)\r
- * Processes messages sent to the OLE clipboard window.\r
- * Note that we will intercept messages in our WndProc only when data\r
- * has been placed in the clipboard via OleSetClipboard().\r
- * i.e. Only when OLE owns the windows clipboard.\r
- */\r
-LRESULT CALLBACK OLEClipbrd_WndProc\r
-  (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\r
-{\r
-  switch (message)\r
-  {\r
-    /*\r
-     * WM_RENDERFORMAT\r
-     * We receive this message to allow us to handle delayed rendering of\r
-     * a specific clipboard format when an application requests data in\r
-     * that format by calling GetClipboardData.\r
-     * (Recall that in OleSetClipboard, we used SetClipboardData to\r
-     * make all HGLOBAL formats supported by the source IDataObject\r
-     * available using delayed rendering)\r
-     * On receiving this message we must actually render the data in the\r
-     * specified format and place it on the clipboard by calling the\r
-     * SetClipboardData function.\r
-     */\r
-    case WM_RENDERFORMAT:\r
-    {\r
-      FORMATETC rgelt;\r
-\r
-      ZeroMemory( &rgelt, sizeof(FORMATETC));\r
-\r
-      /*\r
-       * Initialize FORMATETC to a Windows clipboard friendly format\r
-       */\r
-      rgelt.cfFormat = (UINT) wParam;\r
-      rgelt.dwAspect = DVASPECT_CONTENT;\r
-      rgelt.lindex = -1;\r
-      rgelt.tymed = TYMED_HGLOBAL;\r
-\r
-      TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat);\r
-\r
-      /*\r
-       * Render the clipboard data.\r
-       * (We must have a source data object or we wouldn't be in this WndProc)\r
-       */\r
-      OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt );\r
-\r
-      break;\r
-    }\r
-\r
-    /*\r
-     * WM_RENDERALLFORMATS\r
-     * Sent before the clipboard owner window is destroyed.\r
-     * We should receive this message only when OleUninitialize is called\r
-     * while we have an IDataObject in the clipboard.\r
-     * For the content of the clipboard to remain available to other\r
-     * applications, we must render data in all the formats the source IDataObject\r
-     * is capable of generating, and place the data on the clipboard by calling\r
-     * SetClipboardData.\r
-     */\r
-    case WM_RENDERALLFORMATS:\r
-    {\r
-      IEnumFORMATETC* penumFormatetc = NULL;\r
-      FORMATETC rgelt;\r
-\r
-      TRACE("(): WM_RENDERALLFORMATS\n");\r
-\r
-      /*\r
-       * Render all HGLOBAL formats supported by the source into\r
-       * the windows clipboard.\r
-       */\r
-      if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1),\r
-                                 DATADIR_GET, &penumFormatetc) ) )\r
-      {\r
-        WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n");\r
-        return 0;\r
-      }\r
-\r
-      while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )\r
-      {\r
-        if ( rgelt.tymed == TYMED_HGLOBAL )\r
-        {\r
-          /*\r
-           * Render the clipboard data.\r
-           */\r
-          if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) )\r
-            continue;\r
-\r
-          TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat);\r
-        }\r
-      }\r
-\r
-      IEnumFORMATETC_Release(penumFormatetc);\r
-\r
-      break;\r
-    }\r
-\r
-    /*\r
-     * WM_DESTROYCLIPBOARD\r
-     * This is sent by EmptyClipboard before the clipboard is emptied.\r
-     * We should release any IDataObject we are holding onto when we receive\r
-     * this message, since it indicates that the OLE clipboard should be empty\r
-     * from this point on.\r
-     */\r
-    case WM_DESTROYCLIPBOARD:\r
-    {\r
-      TRACE("(): WM_DESTROYCLIPBOARD\n");\r
-      /*\r
-       * Release the data object we are holding on to\r
-       */\r
-      if ( theOleClipboard->pIDataObjectSrc )\r
-      {\r
-        IDataObject_Release(theOleClipboard->pIDataObjectSrc);\r
-        theOleClipboard->pIDataObjectSrc = NULL;\r
-      }\r
-      break;\r
-    }\r
-\r
-/*\r
-    case WM_ASKCBFORMATNAME:\r
-    case WM_CHANGECBCHAIN:\r
-    case WM_DRAWCLIPBOARD:\r
-    case WM_SIZECLIPBOARD:\r
-    case WM_HSCROLLCLIPBOARD:\r
-    case WM_VSCROLLCLIPBOARD:\r
-    case WM_PAINTCLIPBOARD:\r
-*/\r
-    default:\r
-      return DefWindowProcA(hWnd, message, wParam, lParam);\r
-  }\r
-\r
-  return 0;\r
-}\r
-\r
-#define MAX_CLIPFORMAT_NAME   80\r
-\r
-/***********************************************************************\r
- * OLEClipbrd_RenderFormat(LPFORMATETC)\r
- * Render the clipboard data. Note that this call will delegate to the\r
- * source data object.\r
- * Note: This function assumes it is passed an HGLOBAL format to render.\r
- */\r
-static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc)\r
-{\r
-  STGMEDIUM std;\r
-  HGLOBAL hDup;\r
-  HRESULT hr = S_OK;\r
-  char szFmtName[MAX_CLIPFORMAT_NAME];\r
-  ILockBytes *ptrILockBytes = 0;\r
-  HGLOBAL hStorage = 0;\r
-\r
-  GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME);\r
-\r
-  /* If embed source */\r
-  if (!strcmp(szFmtName, CF_EMBEDSOURCE))\r
-  {\r
-    memset(&std, 0, sizeof(STGMEDIUM));\r
-    std.tymed = pFormatetc->tymed = TYMED_ISTORAGE;\r
-\r
-    hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);\r
-    if (hStorage == NULL)\r
-      HANDLE_ERROR( E_OUTOFMEMORY );\r
-    hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);\r
-    hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);\r
-\r
-    if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, pFormatetc, &std)))\r
-    {\r
-      WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%lx)\n", hr);\r
-      GlobalFree(hStorage);\r
-      return hr;\r
-    }\r
-\r
-    if (1) /* check whether the presentation data is already -not- present */\r
-    {\r
-      FORMATETC fmt2;\r
-      STGMEDIUM std2;\r
-      METAFILEPICT *mfp = 0;\r
-\r
-      fmt2.cfFormat = CF_METAFILEPICT;\r
-      fmt2.ptd = 0;\r
-      fmt2.dwAspect = DVASPECT_CONTENT;\r
-      fmt2.lindex = -1;\r
-      fmt2.tymed = TYMED_MFPICT;\r
-\r
-      memset(&std2, 0, sizeof(STGMEDIUM));\r
-      std2.tymed = TYMED_MFPICT;\r
-\r
-      /* Get the metafile picture out of it */\r
-\r
-      if (!FAILED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))\r
-      {\r
-        mfp = (METAFILEPICT *)GlobalLock(std2.u.hGlobal);\r
-      }\r
-\r
-      if (mfp)\r
-      {\r
-        OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};\r
-        IStream *pStream = 0;\r
-        void *mfBits;\r
-        PresentationDataHeader pdh;\r
-        INT nSize;\r
-        CLSID clsID;\r
-        LPOLESTR strProgID;\r
-        CHAR strOleTypeName[51];\r
-        BYTE OlePresStreamHeader [] =\r
-        {\r
-            0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,\r
-            0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\r
-            0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,\r
-            0x00, 0x00, 0x00, 0x00\r
-        };\r
-\r
-        nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);\r
-\r
-        memset(&pdh, 0, sizeof(PresentationDataHeader));\r
-        memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));\r
-\r
-        pdh.dwObjectExtentX = mfp->xExt;\r
-        pdh.dwObjectExtentY = mfp->yExt;\r
-        pdh.dwSize = nSize;\r
-\r
-        hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);\r
-\r
-        hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);\r
-\r
-        mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);\r
-        nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);\r
-\r
-        hr = IStream_Write(pStream, mfBits, nSize, NULL);\r
-\r
-        IStream_Release(pStream);\r
-\r
-        HeapFree(GetProcessHeap(), 0, mfBits);\r
-\r
-        GlobalUnlock(std2.u.hGlobal);\r
-\r
-        ReadClassStg(std.u.pstg, &clsID);\r
-        ProgIDFromCLSID(&clsID, &strProgID);\r
-\r
-        WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );\r
-        OLECONVERT_CreateOleStream(std.u.pstg);\r
-        OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);\r
-      }\r
-    }\r
-  }\r
-  else\r
-  {\r
-    if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std)))\r
-    {\r
-        WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr);\r
-        GlobalFree(hStorage);\r
-        return hr;\r
-    }\r
-\r
-    /* To put a copy back on the clipboard */\r
-\r
-    hStorage = std.u.hGlobal;\r
-  }\r
-\r
-  /*\r
-   *  Put a copy of the rendered data back on the clipboard\r
-   */\r
-\r
-  if ( !(hDup = OLEClipbrd_GlobalDupMem(hStorage)) )\r
-    HANDLE_ERROR( E_OUTOFMEMORY );\r
-\r
-  if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) )\r
-  {\r
-    GlobalFree(hDup);\r
-    WARN("() : Failed to set rendered clipboard data into clipboard!\n");\r
-  }\r
-\r
-CLEANUP:\r
-\r
-  ReleaseStgMedium(&std);\r
-\r
-  return hr;\r
-}\r
-\r
-\r
-/***********************************************************************\r
- * OLEClipbrd_GlobalDupMem( HGLOBAL )\r
- * Helper method to duplicate an HGLOBAL chunk of memory\r
- */\r
-static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc )\r
-{\r
-    HGLOBAL hGlobalDest;\r
-    PVOID pGlobalSrc, pGlobalDest;\r
-    DWORD cBytes;\r
-\r
-    if ( !hGlobalSrc )\r
-      return 0;\r
-\r
-    cBytes = GlobalSize(hGlobalSrc);\r
-    if ( 0 == cBytes )\r
-      return 0;\r
-\r
-    hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE,\r
-                               cBytes );\r
-    if ( !hGlobalDest )\r
-      return 0;\r
-\r
-    pGlobalSrc = GlobalLock(hGlobalSrc);\r
-    pGlobalDest = GlobalLock(hGlobalDest);\r
-    if ( !pGlobalSrc || !pGlobalDest )\r
-    {\r
-      GlobalFree(hGlobalDest);\r
-      return 0;\r
-    }\r
-\r
-    memcpy(pGlobalDest, pGlobalSrc, cBytes);\r
-\r
-    GlobalUnlock(hGlobalSrc);\r
-    GlobalUnlock(hGlobalDest);\r
-\r
-    return hGlobalDest;\r
-}\r
-\r
-\r
-/*---------------------------------------------------------------------*\r
- *  Implementation of the internal IDataObject interface exposed by\r
- *  the OLE clipboard.\r
- *---------------------------------------------------------------------*/\r
-\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_QueryInterface (IUnknown)\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(\r
-            IDataObject*     iface,\r
-            REFIID           riid,\r
-            void**           ppvObject)\r
-{\r
-  /*\r
-   * Declare "This" pointer\r
-   */\r
-  OLEClipbrd *This = (OLEClipbrd *)iface;\r
-  TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObject);\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if ( (This==0) || (ppvObject==0) )\r
-    return E_INVALIDARG;\r
-\r
-  /*\r
-   * Initialize the return parameter.\r
-   */\r
-  *ppvObject = 0;\r
-\r
-  /*\r
-   * Compare the riid with the interface IDs implemented by this object.\r
-   */\r
-  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)\r
-  {\r
-    *ppvObject = iface;\r
-  }\r
-  else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)\r
-  {\r
-    *ppvObject = (IDataObject*)&(This->lpvtbl1);\r
-  }\r
-  else  /* We only support IUnknown and IDataObject */\r
-  {\r
-    WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));\r
-    return E_NOINTERFACE;\r
-  }\r
-\r
-  /*\r
-   * Query Interface always increases the reference count by one when it is\r
-   * successful.\r
-   */\r
-  IUnknown_AddRef((IUnknown*)*ppvObject);\r
-\r
-  return S_OK;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_AddRef (IUnknown)\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(\r
-            IDataObject*     iface)\r
-{\r
-  /*\r
-   * Declare "This" pointer\r
-   */\r
-  OLEClipbrd *This = (OLEClipbrd *)iface;\r
-\r
-  TRACE("(%p)->(count=%lu)\n",This, This->ref);\r
-\r
-  return InterlockedIncrement(&This->ref);\r
-\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_Release (IUnknown)\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-static ULONG WINAPI OLEClipbrd_IDataObject_Release(\r
-            IDataObject*     iface)\r
-{\r
-  /*\r
-   * Declare "This" pointer\r
-   */\r
-  OLEClipbrd *This = (OLEClipbrd *)iface;\r
-  ULONG ref;\r
-\r
-  TRACE("(%p)->(count=%lu)\n",This, This->ref);\r
-\r
-  /*\r
-   * Decrease the reference count on this object.\r
-   */\r
-  ref = InterlockedDecrement(&This->ref);\r
-\r
-  /*\r
-   * If the reference count goes down to 0, perform suicide.\r
-   */\r
-  if (ref == 0)\r
-  {\r
-    OLEClipbrd_Destroy(This);\r
-  }\r
-\r
-  return ref;\r
-}\r
-\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_GetData (IDataObject)\r
- *\r
- * The OLE Clipboard's implementation of this method delegates to\r
- * a data source if there is one or wraps around the windows clipboard\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetcIn,\r
-           STGMEDIUM*       pmedium)\r
-{\r
-  HANDLE      hData = 0;\r
-  BOOL bClipboardOpen = FALSE;\r
-  HRESULT hr = S_OK;\r
-  LPVOID src;\r
-\r
-  /*\r
-   * Declare "This" pointer\r
-   */\r
-  OLEClipbrd *This = (OLEClipbrd *)iface;\r
-\r
-  TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);\r
-\r
-  if ( !pformatetcIn || !pmedium )\r
-    return E_INVALIDARG;\r
-\r
-  /*\r
-   * If we have a data source placed on the clipboard (via OleSetClipboard)\r
-   * simply delegate to the source object's QueryGetData\r
-   * NOTE: This code assumes that the IDataObject is in the same address space!\r
-   * We will need to add marshalling support when Wine handles multiple processes.\r
-   */\r
-  if ( This->pIDataObjectSrc )\r
-  {\r
-    return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);\r
-  }\r
-\r
-  if ( pformatetcIn->lindex != -1 )\r
-    return DV_E_LINDEX;\r
-  if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )\r
-    return DV_E_TYMED;\r
-/*\r
-   if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )\r
-     return DV_E_DVASPECT;\r
-*/\r
-\r
-  /*\r
-   * Otherwise, get the data from the windows clipboard using GetClipboardData\r
-   */\r
-  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )\r
-    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );\r
-\r
-  hData = GetClipboardData(pformatetcIn->cfFormat);\r
-\r
-  /* Must make a copy of global handle returned by GetClipboardData; it\r
-   * is not valid after we call CloseClipboard\r
-   * Application is responsible for freeing the memory (Forte Agent does this)\r
-   */\r
-  src = GlobalLock(hData);\r
-  if(src) {\r
-      LPVOID dest;\r
-      ULONG  size;\r
-      HANDLE hDest;\r
-\r
-      size = GlobalSize(hData);\r
-      hDest = GlobalAlloc(GHND, size);\r
-      dest  = GlobalLock(hDest);\r
-      memcpy(dest, src, size);\r
-      GlobalUnlock(hDest);\r
-      GlobalUnlock(hData);\r
-      hData = hDest;\r
-  }\r
-\r
-  /*\r
-   * Return the clipboard data in the storage medium structure\r
-   */\r
-  pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;\r
-  pmedium->u.hGlobal = (HGLOBAL)hData;\r
-  pmedium->pUnkForRelease = NULL;\r
-\r
-  hr = S_OK;\r
-\r
-CLEANUP:\r
-  /*\r
-   * Close Windows clipboard\r
-   */\r
-  if ( bClipboardOpen && !CloseClipboard() )\r
-     hr = CLIPBRD_E_CANT_CLOSE;\r
-\r
-  if ( FAILED(hr) )\r
-      return hr;\r
-  return (hData == 0) ? DV_E_FORMATETC : S_OK;\r
-}\r
-\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetc,\r
-           STGMEDIUM*       pmedium)\r
-{\r
-  FIXME(": Stub\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_QueryGetData (IDataObject)\r
- *\r
- * The OLE Clipboard's implementation of this method delegates to\r
- * a data source if there is one or wraps around the windows clipboard\r
- * function IsClipboardFormatAvailable() otherwise.\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetc)\r
-{\r
-  /*\r
-   * Declare "This" pointer\r
-   */\r
-  OLEClipbrd *This = (OLEClipbrd *)iface;\r
-\r
-  TRACE("(%p, %p)\n", iface, pformatetc);\r
-\r
-  /*\r
-   * If we have a data source placed on the clipboard (via OleSetClipboard)\r
-   * simply delegate to the source object's QueryGetData\r
-   */\r
-  if ( This->pIDataObjectSrc )\r
-  {\r
-    return IDataObject_QueryGetData(This->pIDataObjectSrc, pformatetc);\r
-  }\r
-\r
-  if (!pformatetc)\r
-    return E_INVALIDARG;\r
-/*\r
-   if ( pformatetc->dwAspect != DVASPECT_CONTENT )\r
-     return DV_E_DVASPECT;\r
-*/\r
-  if ( pformatetc->lindex != -1 )\r
-    return DV_E_LINDEX;\r
-\r
-  /* TODO: Handle TYMED_IStorage media which were put on the clipboard\r
-   * by copying the storage into global memory. We must convert this\r
-   * TYMED_HGLOBAL back to TYMED_IStorage.\r
-   */\r
-  if ( pformatetc->tymed != TYMED_HGLOBAL )\r
-    return DV_E_TYMED;\r
-\r
-  /*\r
-   * Delegate to the Windows clipboard function IsClipboardFormatAvailable\r
-   */\r
-  return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_FORMATETC;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatectIn,\r
-           LPFORMATETC      pformatetcOut)\r
-{\r
-  TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);\r
-\r
-  if ( !pformatectIn || !pformatetcOut )\r
-    return E_INVALIDARG;\r
-\r
-  memcpy(pformatetcOut, pformatectIn, sizeof(FORMATETC));\r
-  return DATA_S_SAMEFORMATETC;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_SetData (IDataObject)\r
- *\r
- * The OLE Clipboard's does not implement this method\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(\r
-           IDataObject*     iface,\r
-           LPFORMATETC      pformatetc,\r
-           STGMEDIUM*       pmedium,\r
-           BOOL             fRelease)\r
-{\r
-  TRACE("\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(\r
-           IDataObject*     iface,\r
-           DWORD            dwDirection,\r
-           IEnumFORMATETC** ppenumFormatEtc)\r
-{\r
-  HRESULT hr = S_OK;\r
-  FORMATETC *afmt = NULL;\r
-  int cfmt, i;\r
-  UINT format;\r
-  BOOL bClipboardOpen;\r
-\r
-  /*\r
-   * Declare "This" pointer\r
-   */\r
-  OLEClipbrd *This = (OLEClipbrd *)iface;\r
-\r
-  TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc);\r
-\r
-  /*\r
-   * If we have a data source placed on the clipboard (via OleSetClipboard)\r
-   * simply delegate to the source object's EnumFormatEtc\r
-   */\r
-  if ( This->pIDataObjectSrc )\r
-  {\r
-    return IDataObject_EnumFormatEtc(This->pIDataObjectSrc,\r
-                                     dwDirection, ppenumFormatEtc);\r
-  }\r
-\r
-  /*\r
-   * Otherwise we must provide our own enumerator which wraps around the\r
-   * Windows clipboard function EnumClipboardFormats\r
-   */\r
-  if ( !ppenumFormatEtc )\r
-    return E_INVALIDARG;\r
-\r
-  if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */\r
-    return E_NOTIMPL;\r
-\r
-  /*\r
-   * Store all current clipboard formats in an array of FORMATETC's,\r
-   * and create an IEnumFORMATETC enumerator from this list.\r
-   */\r
-  cfmt = CountClipboardFormats();\r
-  afmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
-                                sizeof(FORMATETC) * cfmt);\r
-  /*\r
-   * Open the Windows clipboard, associating it with our hidden window\r
-   */\r
-  if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) )\r
-    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );\r
-\r
-  /*\r
-   * Store all current clipboard formats in an array of FORMATETC's\r
-   * TODO: Handle TYMED_IStorage media which were put on the clipboard\r
-   * by copying the storage into global memory. We must convert this\r
-   * TYMED_HGLOBAL back to TYMED_IStorage.\r
-   */\r
-  for (i = 0, format = 0; i < cfmt; i++)\r
-  {\r
-    format = EnumClipboardFormats(format);\r
-    if (!format)  /* Failed! */\r
-    {\r
-      ERR("EnumClipboardFormats failed to return format!\n");\r
-      HANDLE_ERROR( E_FAIL );\r
-    }\r
-\r
-    /* Init the FORMATETC struct */\r
-    afmt[i].cfFormat = format;\r
-    afmt[i].ptd = NULL;\r
-    afmt[i].dwAspect = DVASPECT_CONTENT;\r
-    afmt[i].lindex = -1;\r
-    afmt[i].tymed = TYMED_HGLOBAL;\r
-  }\r
-\r
-  /*\r
-   * Create an EnumFORMATETC enumerator and return an\r
-   * EnumFORMATETC after bumping up its ref count\r
-   */\r
-  *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface);\r
-  if (!(*ppenumFormatEtc))\r
-    HANDLE_ERROR( E_OUTOFMEMORY );\r
-\r
-  if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc)))\r
-    HANDLE_ERROR( hr );\r
-\r
-  hr = S_OK;\r
-\r
-CLEANUP:\r
-  /*\r
-   * Free the array of FORMATETC's\r
-   */\r
-  HeapFree(GetProcessHeap(), 0, afmt);\r
-\r
-  /*\r
-   * Close Windows clipboard\r
-   */\r
-  if ( bClipboardOpen && !CloseClipboard() )\r
-    hr = CLIPBRD_E_CANT_CLOSE;\r
-\r
-  return hr;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_DAdvise (IDataObject)\r
- *\r
- * The OLE Clipboard's does not implement this method\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(\r
-           IDataObject*     iface,\r
-           FORMATETC*       pformatetc,\r
-           DWORD            advf,\r
-           IAdviseSink*     pAdvSink,\r
-           DWORD*           pdwConnection)\r
-{\r
-  TRACE("\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_DUnadvise (IDataObject)\r
- *\r
- * The OLE Clipboard's does not implement this method\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(\r
-           IDataObject*     iface,\r
-           DWORD            dwConnection)\r
-{\r
-  TRACE("\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)\r
- *\r
- * The OLE Clipboard does not implement this method\r
- *\r
- * See Windows documentation for more details on IDataObject methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(\r
-           IDataObject*     iface,\r
-           IEnumSTATDATA**  ppenumAdvise)\r
-{\r
-  TRACE("\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-\r
-/*---------------------------------------------------------------------*\r
- *  Implementation of the internal IEnumFORMATETC interface returned by\r
- *  the OLE clipboard's IDataObject.\r
- *---------------------------------------------------------------------*/\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN)\r
- *\r
- * Creates an IEnumFORMATETC enumerator from an array of FORMATETC\r
- * Structures. pUnkOuter is the outer unknown for reference counting only.\r
- * NOTE: this does not AddRef the interface.\r
- */\r
-\r
-LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],\r
-                                                    LPUNKNOWN pUnkDataObj)\r
-{\r
-  IEnumFORMATETCImpl* ef;\r
-  DWORD size=cfmt * sizeof(FORMATETC);\r
-  LPMALLOC pIMalloc;\r
-\r
-  ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl));\r
-  if (!ef)\r
-    return NULL;\r
-\r
-  ef->ref = 0;\r
-  ef->lpVtbl = &efvt;\r
-  ef->pUnkDataObj = pUnkDataObj;\r
-\r
-  ef->posFmt = 0;\r
-  ef->countFmt = cfmt;\r
-  if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) {\r
-    HeapFree(GetProcessHeap(), 0, ef);\r
-    return NULL;\r
-  }\r
-  ef->pFmt = (LPFORMATETC)IMalloc_Alloc(pIMalloc, size);\r
-  IMalloc_Release(pIMalloc);\r
-\r
-  if (ef->pFmt)\r
-    memcpy(ef->pFmt, afmt, size);\r
-\r
-  TRACE("(%p)->()\n",ef);\r
-  return (LPENUMFORMATETC)ef;\r
-}\r
-\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface\r
-  (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)\r
-{\r
-  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;\r
-\r
-  TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);\r
-\r
-  /*\r
-   * Since enumerators are separate objects from the parent data object\r
-   * we only need to support the IUnknown and IEnumFORMATETC interfaces\r
-   */\r
-\r
-  *ppvObj = NULL;\r
-\r
-  if(IsEqualIID(riid, &IID_IUnknown))\r
-  {\r
-    *ppvObj = This;\r
-  }\r
-  else if(IsEqualIID(riid, &IID_IEnumFORMATETC))\r
-  {\r
-    *ppvObj = (IDataObject*)This;\r
-  }\r
-\r
-  if(*ppvObj)\r
-  {\r
-    IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);\r
-    TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);\r
-    return S_OK;\r
-  }\r
-\r
-  TRACE("-- Interface: E_NOINTERFACE\n");\r
-  return E_NOINTERFACE;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)\r
- *\r
- * Since enumerating formats only makes sense when our data object is around,\r
- * we insure that it stays as long as we stay by calling our parents IUnknown\r
- * for AddRef and Release. But since we are not controlled by the lifetime of\r
- * the outer object, we still keep our own reference count in order to\r
- * free ourselves.\r
- */\r
-static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)\r
-{\r
-  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;\r
-  TRACE("(%p)->(count=%lu)\n",This, This->ref);\r
-\r
-  if (This->pUnkDataObj)\r
-    IUnknown_AddRef(This->pUnkDataObj);\r
-\r
-  return InterlockedIncrement(&This->ref);\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)\r
-{\r
-  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;\r
-  LPMALLOC pIMalloc;\r
-  ULONG ref;\r
-\r
-  TRACE("(%p)->(count=%lu)\n",This, This->ref);\r
-\r
-  if (This->pUnkDataObj)\r
-    IUnknown_Release(This->pUnkDataObj);  /* Release parent data object */\r
-\r
-  ref = InterlockedDecrement(&This->ref);\r
-  if (!ref)\r
-  {\r
-    TRACE("() - destroying IEnumFORMATETC(%p)\n",This);\r
-    if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))\r
-    {\r
-      IMalloc_Free(pIMalloc, This->pFmt);\r
-      IMalloc_Release(pIMalloc);\r
-    }\r
-\r
-    HeapFree(GetProcessHeap(),0,This);\r
-  }\r
-  return ref;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)\r
- *\r
- * Standard enumerator members for IEnumFORMATETC\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next\r
-  (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)\r
-{\r
-  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;\r
-  UINT cfetch;\r
-  HRESULT hres = S_FALSE;\r
-\r
-  TRACE("(%p)->(pos=%u)\n", This, This->posFmt);\r
-\r
-  if (This->posFmt < This->countFmt)\r
-  {\r
-    cfetch = This->countFmt - This->posFmt;\r
-    if (cfetch >= celt)\r
-    {\r
-      cfetch = celt;\r
-      hres = S_OK;\r
-    }\r
-\r
-    memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));\r
-    This->posFmt += cfetch;\r
-  }\r
-  else\r
-  {\r
-    cfetch = 0;\r
-  }\r
-\r
-  if (pceltFethed)\r
-  {\r
-    *pceltFethed = cfetch;\r
-  }\r
-\r
-  return hres;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)\r
- *\r
- * Standard enumerator members for IEnumFORMATETC\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)\r
-{\r
-  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;\r
-  TRACE("(%p)->(num=%lu)\n", This, celt);\r
-\r
-  This->posFmt += celt;\r
-  if (This->posFmt > This->countFmt)\r
-  {\r
-    This->posFmt = This->countFmt;\r
-    return S_FALSE;\r
-  }\r
-  return S_OK;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)\r
- *\r
- * Standard enumerator members for IEnumFORMATETC\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)\r
-{\r
-  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;\r
-  TRACE("(%p)->()\n", This);\r
-\r
-  This->posFmt = 0;\r
-  return S_OK;\r
-}\r
-\r
-/************************************************************************\r
- * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)\r
- *\r
- * Standard enumerator members for IEnumFORMATETC\r
- */\r
-static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone\r
-  (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)\r
-{\r
-  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;\r
-  HRESULT hr = S_OK;\r
-\r
-  TRACE("(%p)->(ppenum=%p)\n", This, ppenum);\r
-\r
-  if ( !ppenum )\r
-    return E_INVALIDARG;\r
-\r
-  *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt,\r
-                                                This->pFmt,\r
-                                                This->pUnkDataObj);\r
-\r
-  if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum)))\r
-    return ( hr );\r
-\r
-  return (*ppenum) ? S_OK : E_OUTOFMEMORY;\r
-}\r
+/*
+ *  OLE 2 clipboard support
+ *
+ *      Copyright 1999  Noel Borthwick <noel@macadamian.com>
+ *      Copyright 2000  Abey George <abey@macadamian.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * NOTES:
+ *    This file contains the implementation for the OLE Clipboard and its
+ *    internal interfaces. The OLE clipboard interacts with an IDataObject
+ *    interface via the OleSetClipboard, OleGetClipboard and
+ *    OleIsCurrentClipboard API's. An internal IDataObject delegates
+ *    to a client supplied IDataObject or the WIN32 clipboard API depending
+ *    on whether OleSetClipboard has been invoked.
+ *    Here are some operating scenarios:
+ *
+ *    1. OleSetClipboard called: In this case the internal IDataObject
+ *       delegates to the client supplied IDataObject. Additionally OLE takes
+ *       ownership of the Windows clipboard and any HGLOCBAL IDataObject
+ *       items are placed on the Windows clipboard. This allows non OLE aware
+ *       applications to access these. A local WinProc fields WM_RENDERFORMAT
+ *       and WM_RENDERALLFORMATS messages in this case.
+ *
+ *    2. OleGetClipboard called without previous OleSetClipboard. Here the internal
+ *       IDataObject functionality wraps around the WIN32 clipboard API.
+ *
+ *    3. OleGetClipboard called after previous OleSetClipboard. Here the internal
+ *       IDataObject delegates to the source IDataObjects functionality directly,
+ *       thereby bypassing the Windows clipboard.
+ *
+ *    Implementation references : Inside OLE 2'nd  edition by Kraig Brockschmidt
+ *
+ * TODO:
+ *    - Support for pasting between different processes. OLE clipboard support
+ *      currently works only for in process copy and paste. Since we internally
+ *      store a pointer to the source's IDataObject and delegate to that, this
+ *      will fail if the IDataObject client belongs to a different process.
+ *    - IDataObject::GetDataHere is not implemented
+ *    - OleFlushClipboard needs to additionally handle TYMED_IStorage media
+ *      by copying the storage into global memory. Subsequently the default
+ *      data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
+ *      back to TYMED_IStorage.
+ *    - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
+ *      clipboard in OleSetClipboard.
+ *
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "winnls.h"
+#include "ole2.h"
+#include "wine/debug.h"
+#include "olestd.h"
+
+#include "storage32.h"
+
+#define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%lx)\n", (HRESULT)err); goto CLEANUP; }
+
+/* For CoGetMalloc (MEMCTX_TASK is currently ignored) */
+#ifndef MEMCTX_TASK
+# define MEMCTX_TASK -1
+#endif
+
+WINE_DEFAULT_DEBUG_CHANNEL(ole);
+
+/****************************************************************************
+ * OLEClipbrd
+ * DO NOT add any members before the VTables declaration!
+ */
+struct OLEClipbrd
+{
+  /*
+   * List all interface VTables here
+   */
+  IDataObjectVtbl*  lpvtbl1;  /* IDataObject VTable */
+
+  /*
+   * The hidden OLE clipboard window. This window is used as the bridge between the
+   * the OLE and windows clipboard API. (Windows creates one such window per process)
+   */
+  HWND                       hWndClipboard;
+
+  /*
+   * Pointer to the source data object (via OleSetClipboard)
+   */
+  IDataObject*               pIDataObjectSrc;
+
+  /*
+   * The registered DataObject clipboard format
+   */
+  UINT                       cfDataObj;
+
+  /*
+   * The handle to ourself
+   */
+  HGLOBAL                    hSelf;
+
+  /*
+   * Reference count of this object
+   */
+  ULONG                      ref;
+};
+
+typedef struct OLEClipbrd OLEClipbrd;
+
+
+/****************************************************************************
+*   IEnumFORMATETC implementation
+*   DO NOT add any members before the VTables declaration!
+*/
+typedef struct
+{
+  /* IEnumFORMATETC VTable */
+  IEnumFORMATETCVtbl          *lpVtbl;
+
+  /* IEnumFORMATETC fields */
+  UINT                         posFmt;    /* current enumerator position */
+  UINT                         countFmt;  /* number of EnumFORMATETC's in array */
+  LPFORMATETC                  pFmt;      /* array of EnumFORMATETC's */
+
+  /*
+   * Reference count of this object
+   */
+  DWORD                        ref;
+
+  /*
+   * IUnknown implementation of the parent data object.
+   */
+  IUnknown*                    pUnkDataObj;
+
+} IEnumFORMATETCImpl;
+
+typedef struct PresentationDataHeader
+{
+  BYTE unknown1[28];
+  DWORD dwObjectExtentX;
+  DWORD dwObjectExtentY;
+  DWORD dwSize;
+} PresentationDataHeader;
+
+/*
+ * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize()
+ */
+static HGLOBAL hTheOleClipboard = 0;
+static OLEClipbrd* theOleClipboard = NULL;
+
+
+/*
+ * Prototypes for the methods of the OLEClipboard class.
+ */
+void OLEClipbrd_Initialize(void);
+void OLEClipbrd_UnInitialize(void);
+static OLEClipbrd* OLEClipbrd_Construct(void);
+static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy);
+static HWND OLEClipbrd_CreateWindow(void);
+static void OLEClipbrd_DestroyWindow(HWND hwnd);
+LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc );
+static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc );
+
+/*
+ * Prototypes for the methods of the OLEClipboard class
+ * that implement IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
+            IDataObject*     iface,
+            REFIID           riid,
+            void**           ppvObject);
+static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
+            IDataObject*     iface);
+static ULONG WINAPI OLEClipbrd_IDataObject_Release(
+            IDataObject*     iface);
+static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetcIn,
+           STGMEDIUM*       pmedium);
+static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetc,
+           STGMEDIUM*       pmedium);
+static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetc);
+static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
+           IDataObject*     iface,
+           LPFORMATETC      pformatectIn,
+           LPFORMATETC      pformatetcOut);
+static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetc,
+           STGMEDIUM*       pmedium,
+           BOOL             fRelease);
+static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
+           IDataObject*     iface,
+           DWORD            dwDirection,
+           IEnumFORMATETC** ppenumFormatEtc);
+static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
+           IDataObject*     iface,
+           FORMATETC*       pformatetc,
+           DWORD            advf,
+           IAdviseSink*     pAdvSink,
+           DWORD*           pdwConnection);
+static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
+           IDataObject*     iface,
+           DWORD            dwConnection);
+static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
+           IDataObject*     iface,
+           IEnumSTATDATA**  ppenumAdvise);
+
+/*
+ * Prototypes for the IEnumFORMATETC methods.
+ */
+static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
+                                                           LPUNKNOWN pUnkDataObj);
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid,
+                                                               LPVOID* ppvObj);
+static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface);
+static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface);
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt,
+                                                     FORMATETC* rgelt, ULONG* pceltFethed);
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt);
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface);
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);
+
+
+/*
+ * Virtual function table for the OLEClipbrd's exposed IDataObject interface
+ */
+static IDataObjectVtbl OLEClipbrd_IDataObject_VTable =
+{
+  OLEClipbrd_IDataObject_QueryInterface,
+  OLEClipbrd_IDataObject_AddRef,
+  OLEClipbrd_IDataObject_Release,
+  OLEClipbrd_IDataObject_GetData,
+  OLEClipbrd_IDataObject_GetDataHere,
+  OLEClipbrd_IDataObject_QueryGetData,
+  OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
+  OLEClipbrd_IDataObject_SetData,
+  OLEClipbrd_IDataObject_EnumFormatEtc,
+  OLEClipbrd_IDataObject_DAdvise,
+  OLEClipbrd_IDataObject_DUnadvise,
+  OLEClipbrd_IDataObject_EnumDAdvise
+};
+
+/*
+ * Virtual function table for IEnumFORMATETC interface
+ */
+static struct IEnumFORMATETCVtbl efvt =
+{
+  OLEClipbrd_IEnumFORMATETC_QueryInterface,
+  OLEClipbrd_IEnumFORMATETC_AddRef,
+  OLEClipbrd_IEnumFORMATETC_Release,
+  OLEClipbrd_IEnumFORMATETC_Next,
+  OLEClipbrd_IEnumFORMATETC_Skip,
+  OLEClipbrd_IEnumFORMATETC_Reset,
+  OLEClipbrd_IEnumFORMATETC_Clone
+};
+
+/*
+ * Name of our registered OLE clipboard window class
+ */
+CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
+
+/*
+ *  If we need to store state info we can store it here.
+ *  For now we don't need this functionality.
+ *
+typedef struct tagClipboardWindowInfo
+{
+} ClipboardWindowInfo;
+ */
+
+/*---------------------------------------------------------------------*
+ *           Win32 OLE clipboard API
+ *---------------------------------------------------------------------*/
+
+/***********************************************************************
+ *           OleSetClipboard     [OLE32.@]
+ *  Places a pointer to the specified data object onto the clipboard,
+ *  making the data object accessible to the OleGetClipboard function.
+ *
+ * RETURNS:
+ *
+ *    S_OK                  IDataObject pointer placed on the clipboard
+ *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed
+ *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed
+ *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
+ *    CLIPBRD_E_CANT_SET    SetClipboard failed
+ */
+
+HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)
+{
+  HRESULT hr = S_OK;
+  IEnumFORMATETC* penumFormatetc = NULL;
+  FORMATETC rgelt;
+  BOOL bClipboardOpen = FALSE;
+/*
+  HGLOBAL hDataObject = 0;
+  OLEClipbrd **ppDataObject;
+*/
+
+  TRACE("(%p)\n", pDataObj);
+
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  /*
+   * If the Ole clipboard window hasn't been created yet, create it now.
+   */
+  if ( !theOleClipboard->hWndClipboard )
+    theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
+
+  if ( !theOleClipboard->hWndClipboard ) /* sanity check */
+    HANDLE_ERROR( E_FAIL );
+
+  /*
+   * Open the Windows clipboard, associating it with our hidden window
+   */
+  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
+  /*
+   * Empty the current clipboard and make our window the clipboard owner
+   * NOTE: This will trigger a WM_DESTROYCLIPBOARD message
+   */
+  if ( !EmptyClipboard() )
+    HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
+
+  /*
+   * If we are already holding on to an IDataObject first release that.
+   */
+  if ( theOleClipboard->pIDataObjectSrc )
+  {
+    IDataObject_Release(theOleClipboard->pIDataObjectSrc);
+    theOleClipboard->pIDataObjectSrc = NULL;
+  }
+
+  /*
+   * AddRef the data object passed in and save its pointer.
+   * A NULL value indicates that the clipboard should be emptied.
+   */
+  theOleClipboard->pIDataObjectSrc = pDataObj;
+  if ( pDataObj )
+  {
+    IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
+  }
+
+  /*
+   * Enumerate all HGLOBAL formats supported by the source and make
+   * those formats available using delayed rendering using SetClipboardData.
+   * Only global memory based data items may be made available to non-OLE
+   * applications via the standard Windows clipboard API. Data based on other
+   * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API.
+   *
+   * TODO: Do we need to additionally handle TYMED_IStorage media by copying
+   * the storage into global memory?
+   */
+  if ( pDataObj )
+  {
+    if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj,
+                                                DATADIR_GET,
+                                                &penumFormatetc )))
+    {
+      HANDLE_ERROR( hr );
+    }
+
+    while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
+    {
+      if ( rgelt.tymed == TYMED_HGLOBAL )
+      {
+        CHAR szFmtName[80];
+        TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
+              GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
+                ? szFmtName : "");
+
+        SetClipboardData( rgelt.cfFormat, NULL);
+      }
+    }
+    IEnumFORMATETC_Release(penumFormatetc);
+  }
+
+  /*
+   * Windows additionally creates a new "DataObject" clipboard format
+   * and stores in on the clipboard. We could possibly store a pointer
+   * to our internal IDataObject interface on the clipboard. I'm not
+   * sure what the use of this is though.
+   * Enable the code below for this functionality.
+   */
+/*
+   theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject");
+   hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
+                             sizeof(OLEClipbrd *));
+   if (hDataObject==0)
+     HANDLE_ERROR( E_OUTOFMEMORY );
+
+   ppDataObject = (OLEClipbrd**)GlobalLock(hDataObject);
+   *ppDataObject = theOleClipboard;
+   GlobalUnlock(hDataObject);
+
+   if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) )
+     HANDLE_ERROR( CLIPBRD_E_CANT_SET );
+*/
+
+  hr = S_OK;
+
+CLEANUP:
+
+  /*
+   * Close Windows clipboard (It remains associated with our window)
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+    hr = CLIPBRD_E_CANT_CLOSE;
+
+  /*
+   * Release the source IDataObject if something failed
+   */
+  if ( FAILED(hr) )
+  {
+    if (theOleClipboard->pIDataObjectSrc)
+    {
+      IDataObject_Release(theOleClipboard->pIDataObjectSrc);
+      theOleClipboard->pIDataObjectSrc = NULL;
+    }
+  }
+
+  return hr;
+}
+
+
+/***********************************************************************
+ * OleGetClipboard [OLE32.@]
+ * Returns a pointer to our internal IDataObject which represents the conceptual
+ * state of the Windows clipboard. If the current clipboard already contains
+ * an IDataObject, our internal IDataObject will delegate to this object.
+ */
+HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
+{
+  HRESULT hr = S_OK;
+  TRACE("()\n");
+
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  if (!theOleClipboard)
+    return E_OUTOFMEMORY;
+
+  /* Return a reference counted IDataObject */
+  hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1),
+                                   &IID_IDataObject,  (void**)ppDataObj);
+  return hr;
+}
+
+/***********************************************************************
+ *           OleFlushClipboard   [OLE2.76]
+ */
+
+HRESULT WINAPI OleFlushClipboard16(void)
+{
+  return OleFlushClipboard();
+}
+
+
+/******************************************************************************
+ *              OleFlushClipboard        [OLE32.@]
+ *  Renders the data from the source IDataObject into the windows clipboard
+ *
+ *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
+ *  by copying the storage into global memory. Subsequently the default
+ *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
+ *  back to TYMED_IStorage.
+ */
+HRESULT WINAPI OleFlushClipboard()
+{
+  IEnumFORMATETC* penumFormatetc = NULL;
+  FORMATETC rgelt;
+  HRESULT hr = S_OK;
+  BOOL bClipboardOpen = FALSE;
+  IDataObject* pIDataObjectSrc = NULL;
+
+  TRACE("()\n");
+
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  /*
+   * Already flushed or no source DataObject? Nothing to do.
+   */
+  if (!theOleClipboard->pIDataObjectSrc)
+    return S_OK;
+
+  /*
+   * Addref and save the source data object we are holding on to temporarily,
+   * since it will be released when we empty the clipboard.
+   */
+  pIDataObjectSrc = theOleClipboard->pIDataObjectSrc;
+  IDataObject_AddRef(pIDataObjectSrc);
+
+  /*
+   * Open the Windows clipboard
+   */
+  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
+  /*
+   * Empty the current clipboard
+   */
+  if ( !EmptyClipboard() )
+    HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
+
+  /*
+   * Render all HGLOBAL formats supported by the source into
+   * the windows clipboard.
+   */
+  if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc,
+                                               DATADIR_GET,
+                                               &penumFormatetc) ))
+  {
+    HANDLE_ERROR( hr );
+  }
+
+  while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
+  {
+    if ( rgelt.tymed == TYMED_HGLOBAL )
+    {
+      CHAR szFmtName[80];
+      TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
+            GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
+              ? szFmtName : "");
+
+      /*
+       * Render the clipboard data
+       */
+      if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) )
+        continue;
+    }
+  }
+
+  IEnumFORMATETC_Release(penumFormatetc);
+
+  /*
+   * Release the source data object we are holding on to
+   */
+  IDataObject_Release(pIDataObjectSrc);
+
+CLEANUP:
+
+  /*
+   * Close Windows clipboard (It remains associated with our window)
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+    hr = CLIPBRD_E_CANT_CLOSE;
+
+  return hr;
+}
+
+
+/***********************************************************************
+ *           OleIsCurrentClipboard [OLE32.@]
+ */
+HRESULT WINAPI OleIsCurrentClipboard (  IDataObject *pDataObject)
+{
+  TRACE("()\n");
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  if (!theOleClipboard)
+    return E_OUTOFMEMORY;
+
+  return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;
+}
+
+
+/*---------------------------------------------------------------------*
+ *           Internal implementation methods for the OLE clipboard
+ *---------------------------------------------------------------------*/
+
+/***********************************************************************
+ * OLEClipbrd_Initialize()
+ * Initializes the OLE clipboard.
+ */
+void OLEClipbrd_Initialize(void)
+{
+  /*
+   * Create the clipboard if necessary
+   */
+  if ( !theOleClipboard )
+  {
+    TRACE("()\n");
+    theOleClipboard = OLEClipbrd_Construct();
+  }
+}
+
+
+/***********************************************************************
+ * OLEClipbrd_UnInitialize()
+ * Un-Initializes the OLE clipboard
+ */
+void OLEClipbrd_UnInitialize(void)
+{
+  TRACE("()\n");
+  /*
+   * Destroy the clipboard if no one holds a reference to us.
+   * Note that the clipboard was created with a reference count of 1.
+   */
+  if ( theOleClipboard && (theOleClipboard->ref <= 1) )
+  {
+    OLEClipbrd_Destroy( theOleClipboard );
+  }
+  else
+  {
+    WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");
+  }
+}
+
+
+/*********************************************************
+ * Construct the OLEClipbrd class.
+ */
+static OLEClipbrd* OLEClipbrd_Construct()
+{
+  OLEClipbrd* newObject = NULL;
+  HGLOBAL hNewObject = 0;
+
+  /*
+   * Allocate space for the object. We use GlobalAlloc since we need
+   * an HGLOBAL to expose our DataObject as a registered clipboard type.
+   */
+  hNewObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
+                           sizeof(OLEClipbrd));
+  if (hNewObject==0)
+    return NULL;
+
+  /*
+   * Lock the handle for the entire lifetime of the clipboard.
+   */
+  newObject = GlobalLock(hNewObject);
+
+  /*
+   * Initialize the virtual function table.
+   */
+  newObject->lpvtbl1 = &OLEClipbrd_IDataObject_VTable;
+
+  /*
+   * Start with one reference count. The caller of this function
+   * must release the interface pointer when it is done.
+   */
+  newObject->ref = 1;
+
+  newObject->hSelf = hNewObject;
+
+  /*
+   * The Ole clipboard is a singleton - save the global handle and pointer
+   */
+  theOleClipboard = newObject;
+  hTheOleClipboard = hNewObject;
+
+  return theOleClipboard;
+}
+
+static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy)
+{
+  TRACE("()\n");
+
+  if ( !ptrToDestroy )
+    return;
+
+  /*
+   * Destroy the Ole clipboard window
+   */
+  if ( ptrToDestroy->hWndClipboard )
+    OLEClipbrd_DestroyWindow(ptrToDestroy->hWndClipboard);
+
+  /*
+   * Free the actual OLE Clipboard structure.
+   */
+  TRACE("() - Destroying clipboard data object.\n");
+  GlobalUnlock(ptrToDestroy->hSelf);
+  GlobalFree(ptrToDestroy->hSelf);
+
+  /*
+   * The Ole clipboard is a singleton (ptrToDestroy == theOleClipboard)
+   */
+  theOleClipboard = NULL;
+  hTheOleClipboard = 0;
+}
+
+
+/***********************************************************************
+ * OLEClipbrd_CreateWindow()
+ * Create the clipboard window
+ */
+static HWND OLEClipbrd_CreateWindow()
+{
+  HWND hwnd = 0;
+  WNDCLASSEXA wcex;
+
+  /*
+   * Register the clipboard window class if necessary
+   */
+    ZeroMemory( &wcex, sizeof(WNDCLASSEXA));
+
+    wcex.cbSize         = sizeof(WNDCLASSEXA);
+    /* Windows creates this class with a style mask of 0
+     * We don't bother doing this since the FindClassByAtom code
+     * would have to be changed to deal with this idiosyncrasy. */
+    wcex.style          = CS_GLOBALCLASS;
+    wcex.lpfnWndProc    = OLEClipbrd_WndProc;
+    wcex.hInstance      = 0;
+    wcex.lpszClassName  = OLEClipbrd_WNDCLASS;
+
+    RegisterClassExA(&wcex);
+
+  /*
+   * Create a hidden window to receive OLE clipboard messages
+   */
+
+/*
+ *  If we need to store state info we can store it here.
+ *  For now we don't need this functionality.
+ *   ClipboardWindowInfo clipboardInfo;
+ *   ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo));
+ */
+
+  hwnd = CreateWindowA(OLEClipbrd_WNDCLASS,
+                                   "ClipboardWindow",
+                                   WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
+                                   CW_USEDEFAULT, CW_USEDEFAULT,
+                                   CW_USEDEFAULT, CW_USEDEFAULT,
+                                   0,
+                                   0,
+                                   0,
+                                   0 /*(LPVOID)&clipboardInfo */);
+
+  return hwnd;
+}
+
+/***********************************************************************
+ * OLEClipbrd_DestroyWindow(HWND)
+ * Destroy the clipboard window and unregister its class
+ */
+static void OLEClipbrd_DestroyWindow(HWND hwnd)
+{
+  /*
+   * Destroy clipboard window and unregister its WNDCLASS
+   */
+  DestroyWindow(hwnd);
+  UnregisterClassA( OLEClipbrd_WNDCLASS, 0 );
+}
+
+/***********************************************************************
+ * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG)
+ * Processes messages sent to the OLE clipboard window.
+ * Note that we will intercept messages in our WndProc only when data
+ * has been placed in the clipboard via OleSetClipboard().
+ * i.e. Only when OLE owns the windows clipboard.
+ */
+LRESULT CALLBACK OLEClipbrd_WndProc
+  (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+  switch (message)
+  {
+    /*
+     * WM_RENDERFORMAT
+     * We receive this message to allow us to handle delayed rendering of
+     * a specific clipboard format when an application requests data in
+     * that format by calling GetClipboardData.
+     * (Recall that in OleSetClipboard, we used SetClipboardData to
+     * make all HGLOBAL formats supported by the source IDataObject
+     * available using delayed rendering)
+     * On receiving this message we must actually render the data in the
+     * specified format and place it on the clipboard by calling the
+     * SetClipboardData function.
+     */
+    case WM_RENDERFORMAT:
+    {
+      FORMATETC rgelt;
+
+      ZeroMemory( &rgelt, sizeof(FORMATETC));
+
+      /*
+       * Initialize FORMATETC to a Windows clipboard friendly format
+       */
+      rgelt.cfFormat = (UINT) wParam;
+      rgelt.dwAspect = DVASPECT_CONTENT;
+      rgelt.lindex = -1;
+      rgelt.tymed = TYMED_HGLOBAL;
+
+      TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat);
+
+      /*
+       * Render the clipboard data.
+       * (We must have a source data object or we wouldn't be in this WndProc)
+       */
+      OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt );
+
+      break;
+    }
+
+    /*
+     * WM_RENDERALLFORMATS
+     * Sent before the clipboard owner window is destroyed.
+     * We should receive this message only when OleUninitialize is called
+     * while we have an IDataObject in the clipboard.
+     * For the content of the clipboard to remain available to other
+     * applications, we must render data in all the formats the source IDataObject
+     * is capable of generating, and place the data on the clipboard by calling
+     * SetClipboardData.
+     */
+    case WM_RENDERALLFORMATS:
+    {
+      IEnumFORMATETC* penumFormatetc = NULL;
+      FORMATETC rgelt;
+
+      TRACE("(): WM_RENDERALLFORMATS\n");
+
+      /*
+       * Render all HGLOBAL formats supported by the source into
+       * the windows clipboard.
+       */
+      if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1),
+                                 DATADIR_GET, &penumFormatetc) ) )
+      {
+        WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n");
+        return 0;
+      }
+
+      while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
+      {
+        if ( rgelt.tymed == TYMED_HGLOBAL )
+        {
+          /*
+           * Render the clipboard data.
+           */
+          if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) )
+            continue;
+
+          TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat);
+        }
+      }
+
+      IEnumFORMATETC_Release(penumFormatetc);
+
+      break;
+    }
+
+    /*
+     * WM_DESTROYCLIPBOARD
+     * This is sent by EmptyClipboard before the clipboard is emptied.
+     * We should release any IDataObject we are holding onto when we receive
+     * this message, since it indicates that the OLE clipboard should be empty
+     * from this point on.
+     */
+    case WM_DESTROYCLIPBOARD:
+    {
+      TRACE("(): WM_DESTROYCLIPBOARD\n");
+      /*
+       * Release the data object we are holding on to
+       */
+      if ( theOleClipboard->pIDataObjectSrc )
+      {
+        IDataObject_Release(theOleClipboard->pIDataObjectSrc);
+        theOleClipboard->pIDataObjectSrc = NULL;
+      }
+      break;
+    }
+
+/*
+    case WM_ASKCBFORMATNAME:
+    case WM_CHANGECBCHAIN:
+    case WM_DRAWCLIPBOARD:
+    case WM_SIZECLIPBOARD:
+    case WM_HSCROLLCLIPBOARD:
+    case WM_VSCROLLCLIPBOARD:
+    case WM_PAINTCLIPBOARD:
+*/
+    default:
+      return DefWindowProcA(hWnd, message, wParam, lParam);
+  }
+
+  return 0;
+}
+
+#define MAX_CLIPFORMAT_NAME   80
+
+/***********************************************************************
+ * OLEClipbrd_RenderFormat(LPFORMATETC)
+ * Render the clipboard data. Note that this call will delegate to the
+ * source data object.
+ * Note: This function assumes it is passed an HGLOBAL format to render.
+ */
+static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc)
+{
+  STGMEDIUM std;
+  HGLOBAL hDup;
+  HRESULT hr = S_OK;
+  char szFmtName[MAX_CLIPFORMAT_NAME];
+  ILockBytes *ptrILockBytes = 0;
+  HGLOBAL hStorage = 0;
+
+  GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME);
+
+  /* If embed source */
+  if (!strcmp(szFmtName, CF_EMBEDSOURCE))
+  {
+    memset(&std, 0, sizeof(STGMEDIUM));
+    std.tymed = pFormatetc->tymed = TYMED_ISTORAGE;
+
+    hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
+    if (hStorage == NULL)
+      HANDLE_ERROR( E_OUTOFMEMORY );
+    hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
+    hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
+
+    if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, pFormatetc, &std)))
+    {
+      WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%lx)\n", hr);
+      GlobalFree(hStorage);
+      return hr;
+    }
+
+    if (1) /* check whether the presentation data is already -not- present */
+    {
+      FORMATETC fmt2;
+      STGMEDIUM std2;
+      METAFILEPICT *mfp = 0;
+
+      fmt2.cfFormat = CF_METAFILEPICT;
+      fmt2.ptd = 0;
+      fmt2.dwAspect = DVASPECT_CONTENT;
+      fmt2.lindex = -1;
+      fmt2.tymed = TYMED_MFPICT;
+
+      memset(&std2, 0, sizeof(STGMEDIUM));
+      std2.tymed = TYMED_MFPICT;
+
+      /* Get the metafile picture out of it */
+
+      if (!FAILED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
+      {
+        mfp = (METAFILEPICT *)GlobalLock(std2.u.hGlobal);
+      }
+
+      if (mfp)
+      {
+        OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+        IStream *pStream = 0;
+        void *mfBits;
+        PresentationDataHeader pdh;
+        INT nSize;
+        CLSID clsID;
+        LPOLESTR strProgID;
+        CHAR strOleTypeName[51];
+        BYTE OlePresStreamHeader [] =
+        {
+            0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
+            0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00
+        };
+
+        nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
+
+        memset(&pdh, 0, sizeof(PresentationDataHeader));
+        memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
+
+        pdh.dwObjectExtentX = mfp->xExt;
+        pdh.dwObjectExtentY = mfp->yExt;
+        pdh.dwSize = nSize;
+
+        hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
+
+        hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
+
+        mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
+        nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
+
+        hr = IStream_Write(pStream, mfBits, nSize, NULL);
+
+        IStream_Release(pStream);
+
+        HeapFree(GetProcessHeap(), 0, mfBits);
+
+        GlobalUnlock(std2.u.hGlobal);
+
+        ReadClassStg(std.u.pstg, &clsID);
+        ProgIDFromCLSID(&clsID, &strProgID);
+
+        WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
+        OLECONVERT_CreateOleStream(std.u.pstg);
+        OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
+      }
+    }
+  }
+  else
+  {
+    if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std)))
+    {
+        WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr);
+        GlobalFree(hStorage);
+        return hr;
+    }
+
+    /* To put a copy back on the clipboard */
+
+    hStorage = std.u.hGlobal;
+  }
+
+  /*
+   *  Put a copy of the rendered data back on the clipboard
+   */
+
+  if ( !(hDup = OLEClipbrd_GlobalDupMem(hStorage)) )
+    HANDLE_ERROR( E_OUTOFMEMORY );
+
+  if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) )
+  {
+    GlobalFree(hDup);
+    WARN("() : Failed to set rendered clipboard data into clipboard!\n");
+  }
+
+CLEANUP:
+
+  ReleaseStgMedium(&std);
+
+  return hr;
+}
+
+
+/***********************************************************************
+ * OLEClipbrd_GlobalDupMem( HGLOBAL )
+ * Helper method to duplicate an HGLOBAL chunk of memory
+ */
+static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc )
+{
+    HGLOBAL hGlobalDest;
+    PVOID pGlobalSrc, pGlobalDest;
+    DWORD cBytes;
+
+    if ( !hGlobalSrc )
+      return 0;
+
+    cBytes = GlobalSize(hGlobalSrc);
+    if ( 0 == cBytes )
+      return 0;
+
+    hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE,
+                               cBytes );
+    if ( !hGlobalDest )
+      return 0;
+
+    pGlobalSrc = GlobalLock(hGlobalSrc);
+    pGlobalDest = GlobalLock(hGlobalDest);
+    if ( !pGlobalSrc || !pGlobalDest )
+    {
+      GlobalFree(hGlobalDest);
+      return 0;
+    }
+
+    memcpy(pGlobalDest, pGlobalSrc, cBytes);
+
+    GlobalUnlock(hGlobalSrc);
+    GlobalUnlock(hGlobalDest);
+
+    return hGlobalDest;
+}
+
+
+/*---------------------------------------------------------------------*
+ *  Implementation of the internal IDataObject interface exposed by
+ *  the OLE clipboard.
+ *---------------------------------------------------------------------*/
+
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
+            IDataObject*     iface,
+            REFIID           riid,
+            void**           ppvObject)
+{
+  /*
+   * Declare "This" pointer
+   */
+  OLEClipbrd *This = (OLEClipbrd *)iface;
+  TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObject);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
+  {
+    *ppvObject = iface;
+  }
+  else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
+  {
+    *ppvObject = (IDataObject*)&(This->lpvtbl1);
+  }
+  else  /* We only support IUnknown and IDataObject */
+  {
+    WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+  }
+
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful.
+   */
+  IUnknown_AddRef((IUnknown*)*ppvObject);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
+            IDataObject*     iface)
+{
+  /*
+   * Declare "This" pointer
+   */
+  OLEClipbrd *This = (OLEClipbrd *)iface;
+
+  TRACE("(%p)->(count=%lu)\n",This, This->ref);
+
+  return InterlockedIncrement(&This->ref);
+
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEClipbrd_IDataObject_Release(
+            IDataObject*     iface)
+{
+  /*
+   * Declare "This" pointer
+   */
+  OLEClipbrd *This = (OLEClipbrd *)iface;
+  ULONG ref;
+
+  TRACE("(%p)->(count=%lu)\n",This, This->ref);
+
+  /*
+   * Decrease the reference count on this object.
+   */
+  ref = InterlockedDecrement(&This->ref);
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (ref == 0)
+  {
+    OLEClipbrd_Destroy(This);
+  }
+
+  return ref;
+}
+
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_GetData (IDataObject)
+ *
+ * The OLE Clipboard's implementation of this method delegates to
+ * a data source if there is one or wraps around the windows clipboard
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetcIn,
+           STGMEDIUM*       pmedium)
+{
+  HANDLE      hData = 0;
+  BOOL bClipboardOpen = FALSE;
+  HRESULT hr = S_OK;
+  LPVOID src;
+
+  /*
+   * Declare "This" pointer
+   */
+  OLEClipbrd *This = (OLEClipbrd *)iface;
+
+  TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
+
+  if ( !pformatetcIn || !pmedium )
+    return E_INVALIDARG;
+
+  /*
+   * If we have a data source placed on the clipboard (via OleSetClipboard)
+   * simply delegate to the source object's QueryGetData
+   * NOTE: This code assumes that the IDataObject is in the same address space!
+   * We will need to add marshalling support when Wine handles multiple processes.
+   */
+  if ( This->pIDataObjectSrc )
+  {
+    return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
+  }
+
+  if ( pformatetcIn->lindex != -1 )
+    return DV_E_LINDEX;
+  if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
+    return DV_E_TYMED;
+/*
+   if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
+     return DV_E_DVASPECT;
+*/
+
+  /*
+   * Otherwise, get the data from the windows clipboard using GetClipboardData
+   */
+  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
+  hData = GetClipboardData(pformatetcIn->cfFormat);
+
+  /* Must make a copy of global handle returned by GetClipboardData; it
+   * is not valid after we call CloseClipboard
+   * Application is responsible for freeing the memory (Forte Agent does this)
+   */
+  src = GlobalLock(hData);
+  if(src) {
+      LPVOID dest;
+      ULONG  size;
+      HANDLE hDest;
+
+      size = GlobalSize(hData);
+      hDest = GlobalAlloc(GHND, size);
+      dest  = GlobalLock(hDest);
+      memcpy(dest, src, size);
+      GlobalUnlock(hDest);
+      GlobalUnlock(hData);
+      hData = hDest;
+  }
+
+  /*
+   * Return the clipboard data in the storage medium structure
+   */
+  pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
+  pmedium->u.hGlobal = (HGLOBAL)hData;
+  pmedium->pUnkForRelease = NULL;
+
+  hr = S_OK;
+
+CLEANUP:
+  /*
+   * Close Windows clipboard
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+     hr = CLIPBRD_E_CANT_CLOSE;
+
+  if ( FAILED(hr) )
+      return hr;
+  return (hData == 0) ? DV_E_FORMATETC : S_OK;
+}
+
+static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetc,
+           STGMEDIUM*       pmedium)
+{
+  FIXME(": Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
+ *
+ * The OLE Clipboard's implementation of this method delegates to
+ * a data source if there is one or wraps around the windows clipboard
+ * function IsClipboardFormatAvailable() otherwise.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetc)
+{
+  /*
+   * Declare "This" pointer
+   */
+  OLEClipbrd *This = (OLEClipbrd *)iface;
+
+  TRACE("(%p, %p)\n", iface, pformatetc);
+
+  /*
+   * If we have a data source placed on the clipboard (via OleSetClipboard)
+   * simply delegate to the source object's QueryGetData
+   */
+  if ( This->pIDataObjectSrc )
+  {
+    return IDataObject_QueryGetData(This->pIDataObjectSrc, pformatetc);
+  }
+
+  if (!pformatetc)
+    return E_INVALIDARG;
+/*
+   if ( pformatetc->dwAspect != DVASPECT_CONTENT )
+     return DV_E_DVASPECT;
+*/
+  if ( pformatetc->lindex != -1 )
+    return DV_E_LINDEX;
+
+  /* TODO: Handle TYMED_IStorage media which were put on the clipboard
+   * by copying the storage into global memory. We must convert this
+   * TYMED_HGLOBAL back to TYMED_IStorage.
+   */
+  if ( pformatetc->tymed != TYMED_HGLOBAL )
+    return DV_E_TYMED;
+
+  /*
+   * Delegate to the Windows clipboard function IsClipboardFormatAvailable
+   */
+  return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_FORMATETC;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
+           IDataObject*     iface,
+           LPFORMATETC      pformatectIn,
+           LPFORMATETC      pformatetcOut)
+{
+  TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
+
+  if ( !pformatectIn || !pformatetcOut )
+    return E_INVALIDARG;
+
+  memcpy(pformatetcOut, pformatectIn, sizeof(FORMATETC));
+  return DATA_S_SAMEFORMATETC;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_SetData (IDataObject)
+ *
+ * The OLE Clipboard's does not implement this method
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
+           IDataObject*     iface,
+           LPFORMATETC      pformatetc,
+           STGMEDIUM*       pmedium,
+           BOOL             fRelease)
+{
+  TRACE("\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
+           IDataObject*     iface,
+           DWORD            dwDirection,
+           IEnumFORMATETC** ppenumFormatEtc)
+{
+  HRESULT hr = S_OK;
+  FORMATETC *afmt = NULL;
+  int cfmt, i;
+  UINT format;
+  BOOL bClipboardOpen;
+
+  /*
+   * Declare "This" pointer
+   */
+  OLEClipbrd *This = (OLEClipbrd *)iface;
+
+  TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc);
+
+  /*
+   * If we have a data source placed on the clipboard (via OleSetClipboard)
+   * simply delegate to the source object's EnumFormatEtc
+   */
+  if ( This->pIDataObjectSrc )
+  {
+    return IDataObject_EnumFormatEtc(This->pIDataObjectSrc,
+                                     dwDirection, ppenumFormatEtc);
+  }
+
+  /*
+   * Otherwise we must provide our own enumerator which wraps around the
+   * Windows clipboard function EnumClipboardFormats
+   */
+  if ( !ppenumFormatEtc )
+    return E_INVALIDARG;
+
+  if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */
+    return E_NOTIMPL;
+
+  /*
+   * Store all current clipboard formats in an array of FORMATETC's,
+   * and create an IEnumFORMATETC enumerator from this list.
+   */
+  cfmt = CountClipboardFormats();
+  afmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                sizeof(FORMATETC) * cfmt);
+  /*
+   * Open the Windows clipboard, associating it with our hidden window
+   */
+  if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
+  /*
+   * Store all current clipboard formats in an array of FORMATETC's
+   * TODO: Handle TYMED_IStorage media which were put on the clipboard
+   * by copying the storage into global memory. We must convert this
+   * TYMED_HGLOBAL back to TYMED_IStorage.
+   */
+  for (i = 0, format = 0; i < cfmt; i++)
+  {
+    format = EnumClipboardFormats(format);
+    if (!format)  /* Failed! */
+    {
+      ERR("EnumClipboardFormats failed to return format!\n");
+      HANDLE_ERROR( E_FAIL );
+    }
+
+    /* Init the FORMATETC struct */
+    afmt[i].cfFormat = format;
+    afmt[i].ptd = NULL;
+    afmt[i].dwAspect = DVASPECT_CONTENT;
+    afmt[i].lindex = -1;
+    afmt[i].tymed = TYMED_HGLOBAL;
+  }
+
+  /*
+   * Create an EnumFORMATETC enumerator and return an
+   * EnumFORMATETC after bumping up its ref count
+   */
+  *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface);
+  if (!(*ppenumFormatEtc))
+    HANDLE_ERROR( E_OUTOFMEMORY );
+
+  if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc)))
+    HANDLE_ERROR( hr );
+
+  hr = S_OK;
+
+CLEANUP:
+  /*
+   * Free the array of FORMATETC's
+   */
+  HeapFree(GetProcessHeap(), 0, afmt);
+
+  /*
+   * Close Windows clipboard
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+    hr = CLIPBRD_E_CANT_CLOSE;
+
+  return hr;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_DAdvise (IDataObject)
+ *
+ * The OLE Clipboard's does not implement this method
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
+           IDataObject*     iface,
+           FORMATETC*       pformatetc,
+           DWORD            advf,
+           IAdviseSink*     pAdvSink,
+           DWORD*           pdwConnection)
+{
+  TRACE("\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
+ *
+ * The OLE Clipboard's does not implement this method
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
+           IDataObject*     iface,
+           DWORD            dwConnection)
+{
+  TRACE("\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
+ *
+ * The OLE Clipboard does not implement this method
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
+           IDataObject*     iface,
+           IEnumSTATDATA**  ppenumAdvise)
+{
+  TRACE("\n");
+  return E_NOTIMPL;
+}
+
+
+/*---------------------------------------------------------------------*
+ *  Implementation of the internal IEnumFORMATETC interface returned by
+ *  the OLE clipboard's IDataObject.
+ *---------------------------------------------------------------------*/
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN)
+ *
+ * Creates an IEnumFORMATETC enumerator from an array of FORMATETC
+ * Structures. pUnkOuter is the outer unknown for reference counting only.
+ * NOTE: this does not AddRef the interface.
+ */
+
+LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
+                                                    LPUNKNOWN pUnkDataObj)
+{
+  IEnumFORMATETCImpl* ef;
+  DWORD size=cfmt * sizeof(FORMATETC);
+  LPMALLOC pIMalloc;
+
+  ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl));
+  if (!ef)
+    return NULL;
+
+  ef->ref = 0;
+  ef->lpVtbl = &efvt;
+  ef->pUnkDataObj = pUnkDataObj;
+
+  ef->posFmt = 0;
+  ef->countFmt = cfmt;
+  if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) {
+    HeapFree(GetProcessHeap(), 0, ef);
+    return NULL;
+  }
+  ef->pFmt = (LPFORMATETC)IMalloc_Alloc(pIMalloc, size);
+  IMalloc_Release(pIMalloc);
+
+  if (ef->pFmt)
+    memcpy(ef->pFmt, afmt, size);
+
+  TRACE("(%p)->()\n",ef);
+  return (LPENUMFORMATETC)ef;
+}
+
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
+  (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
+{
+  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
+
+  TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
+
+  /*
+   * Since enumerators are separate objects from the parent data object
+   * we only need to support the IUnknown and IEnumFORMATETC interfaces
+   */
+
+  *ppvObj = NULL;
+
+  if(IsEqualIID(riid, &IID_IUnknown))
+  {
+    *ppvObj = This;
+  }
+  else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
+  {
+    *ppvObj = (IDataObject*)This;
+  }
+
+  if(*ppvObj)
+  {
+    IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
+    TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
+    return S_OK;
+  }
+
+  TRACE("-- Interface: E_NOINTERFACE\n");
+  return E_NOINTERFACE;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
+ *
+ * Since enumerating formats only makes sense when our data object is around,
+ * we insure that it stays as long as we stay by calling our parents IUnknown
+ * for AddRef and Release. But since we are not controlled by the lifetime of
+ * the outer object, we still keep our own reference count in order to
+ * free ourselves.
+ */
+static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
+{
+  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
+  TRACE("(%p)->(count=%lu)\n",This, This->ref);
+
+  if (This->pUnkDataObj)
+    IUnknown_AddRef(This->pUnkDataObj);
+
+  return InterlockedIncrement(&This->ref);
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
+{
+  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
+  LPMALLOC pIMalloc;
+  ULONG ref;
+
+  TRACE("(%p)->(count=%lu)\n",This, This->ref);
+
+  if (This->pUnkDataObj)
+    IUnknown_Release(This->pUnkDataObj);  /* Release parent data object */
+
+  ref = InterlockedDecrement(&This->ref);
+  if (!ref)
+  {
+    TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
+    if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
+    {
+      IMalloc_Free(pIMalloc, This->pFmt);
+      IMalloc_Release(pIMalloc);
+    }
+
+    HeapFree(GetProcessHeap(),0,This);
+  }
+  return ref;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
+  (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
+{
+  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
+  UINT cfetch;
+  HRESULT hres = S_FALSE;
+
+  TRACE("(%p)->(pos=%u)\n", This, This->posFmt);
+
+  if (This->posFmt < This->countFmt)
+  {
+    cfetch = This->countFmt - This->posFmt;
+    if (cfetch >= celt)
+    {
+      cfetch = celt;
+      hres = S_OK;
+    }
+
+    memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));
+    This->posFmt += cfetch;
+  }
+  else
+  {
+    cfetch = 0;
+  }
+
+  if (pceltFethed)
+  {
+    *pceltFethed = cfetch;
+  }
+
+  return hres;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
+{
+  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
+  TRACE("(%p)->(num=%lu)\n", This, celt);
+
+  This->posFmt += celt;
+  if (This->posFmt > This->countFmt)
+  {
+    This->posFmt = This->countFmt;
+    return S_FALSE;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
+{
+  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
+  TRACE("(%p)->()\n", This);
+
+  This->posFmt = 0;
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
+  (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
+{
+  IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
+  HRESULT hr = S_OK;
+
+  TRACE("(%p)->(ppenum=%p)\n", This, ppenum);
+
+  if ( !ppenum )
+    return E_INVALIDARG;
+
+  *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt,
+                                                This->pFmt,
+                                                This->pUnkDataObj);
+
+  if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum)))
+    return ( hr );
+
+  return (*ppenum) ? S_OK : E_OUTOFMEMORY;
+}