From 557ff419bea378d9736aafa6c5c1c1caf955ae22 Mon Sep 17 00:00:00 2001 From: Noel Borthwick Date: Sun, 18 Jul 1999 15:43:45 +0000 Subject: [PATCH] Implemented the OLE Clipboard API. --- include/ole2.h | 1 + include/winerror.h | 12 + ole/Makefile.in | 1 + ole/clipboard.c | 1623 ++++++++++++++++++++++++++++++++++++++++++++ ole/ole2.c | 48 +- ole/ole2stubs.c | 13 +- ole/olecli.c | 10 - 7 files changed, 1655 insertions(+), 53 deletions(-) create mode 100644 ole/clipboard.c diff --git a/include/ole2.h b/include/ole2.h index af0851e4edd..fdf821c1a81 100644 --- a/include/ole2.h +++ b/include/ole2.h @@ -62,6 +62,7 @@ HRESULT WINAPI OleSetContainedObject(LPUNKNOWN pUnknown, BOOL fContained); HRESULT WINAPI OleQueryLinkFromData(IDataObject* pSrcDataObject); HRESULT WINAPI OleQueryCreateFromData(LPDATAOBJECT pSrcDataObject); HRESULT WINAPI OleRun(LPUNKNOWN pUnknown); +VOID WINAPI ReleaseStgMedium(LPSTGMEDIUM); HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj); HRESULT WINAPI OleCreateStaticFromData(LPDATAOBJECT pSrcDataObj, REFIID iid, DWORD renderopt, LPFORMATETC pFormatEtc, LPOLECLIENTSITE pClientSite, diff --git a/include/winerror.h b/include/winerror.h index d232779b94a..1039a233c22 100644 --- a/include/winerror.h +++ b/include/winerror.h @@ -296,6 +296,16 @@ extern int WIN32_LastError; #define TYPE_E_ELEMENTNOTFOUND 0x8002802BL #define TYPE_E_CANTLOADLIBRARY 0x80029C4AL +/* OLE Clipboard */ +#define CLIPBRD_E_FIRST 0x800401D0L +#define CLIPBRD_E_LAST 0x800401DFL +#define CLIPBRD_S_FIRST 0x000401D0L +#define CLIPBRD_S_LAST 0x000401DFL +#define CLIPBRD_E_CANT_OPEN 0x800401D0L +#define CLIPBRD_E_CANT_EMPTY 0x800401D1L +#define CLIPBRD_E_CANT_SET 0x800401D2L +#define CLIPBRD_E_BAD_DATA 0x800401D3L +#define CLIPBRD_E_CANT_CLOSE 0x800401D4L /* Drag and Drop */ #define DRAGDROP_S_DROP 0x00040100L @@ -350,6 +360,8 @@ extern int WIN32_LastError; #define DV_E_FORMATETC 0x80040064 #define DV_E_DVASPECT 0x8004006B +#define DV_E_LINDEX 0x80040068 +#define DV_E_TYMED 0x80040069 #define CLASS_E_NOAGGREGATION 0x80040110 #define CLASS_E_CLASSNOTAVAILABLE 0x80040111 diff --git a/ole/Makefile.in b/ole/Makefile.in index 831d3b56002..30dbe424fa7 100644 --- a/ole/Makefile.in +++ b/ole/Makefile.in @@ -8,6 +8,7 @@ MODULE = ole C_SRCS = \ antimoniker.c \ bindctx.c \ + clipboard.c\ compobj.c \ compositemoniker.c \ datacache.c \ diff --git a/ole/clipboard.c b/ole/clipboard.c new file mode 100644 index 00000000000..5ebe2cc03fa --- /dev/null +++ b/ole/clipboard.c @@ -0,0 +1,1623 @@ +/* + * OLE 2 clipboard support + * + * Copyright 1999 Noel Borthwick + * + * 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 +#include "winuser.h" +#include "winerror.h" +#include "ole2.h" +#include "class.h" +#include "debugtools.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 + +DEFAULT_DEBUG_CHANNEL(ole) + +/**************************************************************************** + * OLEClipbrd + * DO NOT add any members before the VTables declaration! + */ +struct OLEClipbrd +{ + /* + * List all interface VTables here + */ + ICOM_VTABLE(IDataObject)* 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 our ourself + */ + UINT 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 */ + ICOM_VTABLE(IEnumFORMATETC)* 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; + + +/* + * 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. + */ +extern void OLEClipbrd_Initialize(); +extern void OLEClipbrd_UnInitialize(); +static OLEClipbrd* OLEClipbrd_Construct(); +static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy); +static HWND OLEClipbrd_CreateWindow(); +static void OLEClipbrd_DestroyWindow(HWND hwnd); +LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +static HRESULT OLEClipbrd_RenderFormat(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 ICOM_VTABLE(IDataObject) OLEClipbrd_IDataObject_VTable = +{ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + 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 ICOM_VTABLE(IEnumFORMATETC) efvt = +{ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + 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 dont need this functionality. + * +typedef struct tagClipboardWindowInfo +{ +} ClipboardWindowInfo; + */ + +/*---------------------------------------------------------------------* + * Win32 OLE clipboard API + *---------------------------------------------------------------------*/ + +/*********************************************************************** + * OleSetClipboard [OLE32.127] + * 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, (HANDLE)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; +} + + +/*********************************************************************** + * OleGetClipboard32 [OLE32.105] + * 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.103] + * 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; + + 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; + + /* + * 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( (IDataObject*)&(theOleClipboard->lpvtbl1), + 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( &rgelt )) ) + continue; + } + } + + IEnumFORMATETC_Release(penumFormatetc); + + /* + * Release the data object we are holding on to + */ + if ( theOleClipboard->pIDataObjectSrc ) + { + IDataObject_Release(theOleClipboard->pIDataObjectSrc); + theOleClipboard->pIDataObjectSrc = NULL; + } + +CLEANUP: + + /* + * Close Windows clipboard (It remains associated with our window) + */ + if ( bClipboardOpen && !CloseClipboard() ) + hr = CLIPBRD_E_CANT_CLOSE; + + return hr; +} + + +/*********************************************************************** + * OleIsCurrentClipboard32 [OLE32.110] + */ +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() +{ + /* + * Create the clipboard if necesary + */ + if ( !theOleClipboard ) + { + TRACE("()\n"); + theOleClipboard = OLEClipbrd_Construct(); + } +} + + +/*********************************************************************** + * OLEClipbrd_UnInitialize() + * Un-Initializes the OLE clipboard + */ +void OLEClipbrd_UnInitialize() +{ + 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; + ATOM atom; + + /* + * Register the clipboard window class if necessary + */ + + if ( !( atom = GlobalFindAtomA(OLEClipbrd_WNDCLASS) ) || + !( CLASS_FindClassByAtom(atom, 0) ) ) + { + ZeroMemory( &wcex, sizeof(WNDCLASSEXA)); + + wcex.cbSize = sizeof(WNDCLASSEXA); + /* Windows creates this class with a style mask of 0 + * We dont bother doing this since the FindClassByAtom code + * would have to be changed to deal with this idiosyncracy. */ + wcex.style = CS_GLOBALCLASS; + wcex.lpfnWndProc = (WNDPROC)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 dont 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 mesage 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( &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( &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; +} + + +/*********************************************************************** + * 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(LPFORMATETC pFormatetc) +{ + STGMEDIUM medium; + HGLOBAL hDup; + HRESULT hr = S_OK; + + if ( FAILED(hr = IDataObject_GetData((IDataObject*)&(theOleClipboard->lpvtbl1), + pFormatetc, &medium)) ) + { + WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr); + return hr; + } + + /* + * Put a copy of the rendered data back on the clipboard + */ + + if ( !(hDup = OLEClipbrd_GlobalDupMem(medium.u.hGlobal)) ) + HANDLE_ERROR( E_OUTOFMEMORY ); + + if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) ) + { + GlobalFree(hDup); + WARN("() : Failed to set rendered clipboard data into clipboard!\n"); + } + +CLEANUP: + + ReleaseStgMedium(&medium); + + 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 ) + 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 + */ + ICOM_THIS(OLEClipbrd, iface); + char xriid[50]; + + WINE_StringFromCLSID((LPCLSID)riid,xriid); + TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,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 */ + { + char clsid[50]; + + WINE_StringFromCLSID((LPCLSID)riid,clsid); + WARN( "() : asking for unsupported interface %s\n", clsid); + + 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 + */ + ICOM_THIS(OLEClipbrd, iface); + + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + This->ref++; + + return 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 + */ + ICOM_THIS(OLEClipbrd, iface); + + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + /* + * Decrease the reference count on this object. + */ + This->ref--; + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (This->ref==0) + { + OLEClipbrd_Destroy(This); + } + + return This->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; + /* + * Declare "This" pointer + */ + ICOM_THIS(OLEClipbrd, iface); + + if ( !pformatetcIn || !pformatetcIn || !pmedium ) + return E_INVALIDARG; + + TRACE("(%p, %p)\n", iface, pformatetcIn); + + /* + * 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, delegate to the Windows clipboard function GetClipboardData + */ + hData = GetClipboardData(pformatetcIn->cfFormat); + + /* + * 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; + + 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 + */ + ICOM_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) +{ + 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 + */ + ICOM_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 = (FORMATETC *)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 + */ + if (afmt) + 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) +{ + 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) +{ + 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) +{ + 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 = (IEnumFORMATETCImpl*)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))) + 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) +{ + ICOM_THIS(IEnumFORMATETCImpl,iface); + char xriid[50]; + + WINE_StringFromCLSID((LPCLSID)riid,xriid); + TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj); + + /* + * Since enumerators are seperate 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) +{ + ICOM_THIS(IEnumFORMATETCImpl,iface); + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + if (This->pUnkDataObj) + IUnknown_AddRef(This->pUnkDataObj); + + return ++(This->ref); +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) +{ + ICOM_THIS(IEnumFORMATETCImpl,iface); + LPMALLOC pIMalloc; + + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + if (This->pUnkDataObj) + IUnknown_Release(This->pUnkDataObj); /* Release parent data object */ + + if (!--(This->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 0; + } + + return This->ref; +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC) + * + * Standard enumerator members for IEnumFORMATETC + */ +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next + (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) +{ + ICOM_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) +{ + ICOM_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) +{ + ICOM_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) +{ + ICOM_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; +} + diff --git a/ole/ole2.c b/ole/ole2.c index 3d0aee0e476..216ce4d37bc 100644 --- a/ole/ole2.c +++ b/ole/ole2.c @@ -106,6 +106,12 @@ BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); +/****************************************************************************** + * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c) + */ +void OLEClipbrd_UnInitialize(); +void OLEClipbrd_Initialize(); + /****************************************************************************** * These are the prototypes of the utility methods used for OLE Drag n Drop */ @@ -178,6 +184,11 @@ HRESULT WINAPI OleInitialize(LPVOID reserved) */ TRACE("() - Initializing the OLE libraries\n"); + /* + * OLE Clipboard + */ + OLEClipbrd_Initialize(); + /* * Drag and Drop */ @@ -229,6 +240,11 @@ void WINAPI OleUninitialize(void) */ TRACE("() - Freeing the last reference count\n"); + /* + * OLE Clipboard + */ + OLEClipbrd_UnInitialize(); + /* * Drag and Drop */ @@ -246,23 +262,6 @@ void WINAPI OleUninitialize(void) CoUninitialize(); } -/*********************************************************************** - * OleFlushClipboard [OLE2.76] - */ -HRESULT WINAPI OleFlushClipboard16(void) -{ - return S_OK; -} - -/*********************************************************************** - * OleSetClipboard [OLE32.127] - */ -HRESULT WINAPI OleSetClipboard(LPVOID pDataObj) -{ - FIXME("(%p), stub!\n", pDataObj); - return S_OK; -} - /****************************************************************************** * CoRegisterMessageFilter32 [OLE32.38] */ @@ -812,21 +811,6 @@ HRESULT WINAPI OleSave( } -/*********************************************************************** - * OleGetClipboard32 [OLE32.105] - */ -HRESULT WINAPI OleGetClipboard( - IDataObject** ppDataObj) -{ - FIXME("(%p),stub!\n", ppDataObj); - - if (ppDataObj) - *ppDataObj=0; - - return E_FAIL; -} - - /************************************************************************** * Internal methods to manage the shared OLE menu in response to the * OLE***MenuDescriptor API diff --git a/ole/ole2stubs.c b/ole/ole2stubs.c index f855d49c248..96ee447e3fd 100644 --- a/ole/ole2stubs.c +++ b/ole/ole2stubs.c @@ -18,7 +18,7 @@ HRESULT WINAPI OleCreateFromData(LPDATAOBJECT pSrcDataObj, REFIID riid, LPVOID* ppvObj) { FIXME("(%p,%p,%li,%p,%p,%p,%p), stub!\n", pSrcDataObj,riid,renderopt,pFormatEtc,pClientSite,pStg,ppvObj); - return S_OK; + return DV_E_FORMATETC; } @@ -93,15 +93,6 @@ HRESULT WINAPI SetConvertStg(LPSTORAGE pStg, BOOL fConvert) return S_OK; } -/****************************************************************************** - * OleFlushClipboard [OLE32.103] - */ -HRESULT WINAPI OleFlushClipboard() -{ - FIXME("(), stub!\n"); - return S_OK; -} - /****************************************************************************** * OleCreate [OLE32.80] */ @@ -156,7 +147,7 @@ HGLOBAL WINAPI OleGetIconOfClass(REFCLSID rclsid, LPOLESTR lpszLabel, BOOL fUseT HRESULT WINAPI OleQueryCreateFromData(LPDATAOBJECT pSrcDataObject) { FIXME("(%p), stub!\n", pSrcDataObject); - return S_OK; + return S_FALSE; } /****************************************************************************** diff --git a/ole/olecli.c b/ole/olecli.c index b4992c986bf..2e1b0fa25bb 100644 --- a/ole/olecli.c +++ b/ole/olecli.c @@ -239,13 +239,3 @@ OLESTATUS WINAPI OleCreateFromClip( return OLE_OK; } -/*********************************************************************** - * OleIsCurrentClipboard32 [OLE32.110] - */ -HRESULT WINAPI OleIsCurrentClipboard ( - IDataObject *pDataObject) /* ptr to the data obj previously copied or cut */ -{ - FIXME("(DataObject %p): stub!\n", pDataObject); - return S_FALSE; -} -