-/*\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;
+}