diff --git a/dlls/ole32/clipboard.c b/dlls/ole32/clipboard.c index b386b1ed594..efa51525a27 100644 --- a/dlls/ole32/clipboard.c +++ b/dlls/ole32/clipboard.c @@ -145,117 +145,6 @@ typedef struct PresentationDataHeader static ole_clipbrd* theOleClipboard; -/* - * Prototypes for the methods of the OLEClipboard class. - */ -void OLEClipbrd_Initialize(void); -void OLEClipbrd_UnInitialize(void); -static ole_clipbrd* OLEClipbrd_Construct(void); -static void OLEClipbrd_Destroy(ole_clipbrd* ptrToDestroy); -static HWND OLEClipbrd_CreateWindow(void); -static void OLEClipbrd_DestroyWindow(HWND hwnd); -static 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 const 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 const 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 */ @@ -271,583 +160,287 @@ typedef struct tagClipboardWindowInfo */ /*---------------------------------------------------------------------* - * Win32 OLE clipboard API + * Implementation of the internal IEnumFORMATETC interface returned by + * the OLE clipboard's IDataObject. *---------------------------------------------------------------------*/ -/*********************************************************************** - * OleSetClipboard [OLE32.@] - * Places a pointer to the specified data object onto the clipboard, - * making the data object accessible to the OleGetClipboard function. +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown) * - * 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 + * See Windows documentation for more details on IUnknown methods. */ - -HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj) +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface + (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) { - HRESULT hr = S_OK; - IEnumFORMATETC* penumFormatetc = NULL; - FORMATETC rgelt; - BOOL bClipboardOpen = FALSE; - struct oletls *info = COM_CurrentInfo(); -/* - HGLOBAL hDataObject = 0; - OLEClipbrd **ppDataObject; -*/ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)\n", pDataObj); - - if(!info) - WARN("Could not allocate tls\n"); - else - if(!info->ole_inits) - return CO_E_NOTINITIALIZED; + TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); /* - * Make sure we have a clipboard object + * Since enumerators are separate objects from the parent data object + * we only need to support the IUnknown and IEnumFORMATETC interfaces */ - OLEClipbrd_Initialize(); - /* - * If the Ole clipboard window hasn't been created yet, create it now. - */ - if ( !theOleClipboard->hWndClipboard ) - theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow(); + *ppvObj = NULL; - 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 ) + if(IsEqualIID(riid, &IID_IUnknown)) { - IDataObject_Release(theOleClipboard->pIDataObjectSrc); - theOleClipboard->pIDataObjectSrc = NULL; + *ppvObj = This; + } + else if(IsEqualIID(riid, &IID_IEnumFORMATETC)) + { + *ppvObj = This; } - /* - * 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 ) + if(*ppvObj) { - 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 = 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->lpvtbl), - &IID_IDataObject, (void**)ppDataObj); - return hr; -} - -/****************************************************************************** - * 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(void) -{ - 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) + IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj); + TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); 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) ) + 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=%u)\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=%u)\n",This, This->ref); + + if (This->pUnkDataObj) + IUnknown_Release(This->pUnkDataObj); /* Release parent data object */ + + ref = InterlockedDecrement(&This->ref); + if (!ref) { - if ( rgelt.tymed == TYMED_HGLOBAL ) + TRACE("() - destroying IEnumFORMATETC(%p)\n",This); + if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) { - 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; + IMalloc_Free(pIMalloc, This->pFmt); + IMalloc_Release(pIMalloc); } + + HeapFree(GetProcessHeap(),0,This); } - - 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; + return ref; } - -/*********************************************************************** - * OleIsCurrentClipboard [OLE32.@] +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC) + * + * Standard enumerator members for IEnumFORMATETC */ -HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject) +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next + (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) { - TRACE("()\n"); - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + UINT cfetch; + HRESULT hres = S_FALSE; - if (!theOleClipboard) - return E_OUTOFMEMORY; + TRACE("(%p)->(pos=%u)\n", This, This->posFmt); - if (pDataObject == NULL) - return S_FALSE; - - 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 ) + if (This->posFmt < This->countFmt) { - TRACE("()\n"); - theOleClipboard = OLEClipbrd_Construct(); - } -} + cfetch = This->countFmt - This->posFmt; + if (cfetch >= celt) + { + cfetch = celt; + hres = S_OK; + } - -/*********************************************************************** - * 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 ); + memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC)); + This->posFmt += cfetch; } else { - WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n"); + cfetch = 0; } -} - -/********************************************************* - * Construct the OLEClipbrd class. - */ -static ole_clipbrd* OLEClipbrd_Construct(void) -{ - ole_clipbrd* This; - - This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) ); - if (!This) return NULL; - - This->lpvtbl = &OLEClipbrd_IDataObject_VTable; - This->ref = 1; - - This->hWndClipboard = NULL; - This->pIDataObjectSrc = NULL; - - theOleClipboard = This; - return This; -} - -static void OLEClipbrd_Destroy(ole_clipbrd* This) -{ - TRACE("()\n"); - - if (!This) return; - - theOleClipboard = NULL; - - if ( This->hWndClipboard ) - OLEClipbrd_DestroyWindow(This->hWndClipboard); - - HeapFree(GetProcessHeap(), 0, This); -} - -/*********************************************************************** - * OLEClipbrd_CreateWindow() - * Create the clipboard window - */ -static HWND OLEClipbrd_CreateWindow(void) -{ - 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. - */ -static LRESULT CALLBACK OLEClipbrd_WndProc - (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) + if (pceltFethed) { - /* - * 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->lpvtbl), &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->lpvtbl), - 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->lpvtbl), &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); + *pceltFethed = cfetch; } - return 0; + 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=%u)\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; +} + +static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], + LPUNKNOWN pUnkDataObj); + +/************************************************************************ + * 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; +} + +static const IEnumFORMATETCVtbl efvt = +{ + OLEClipbrd_IEnumFORMATETC_QueryInterface, + OLEClipbrd_IEnumFORMATETC_AddRef, + OLEClipbrd_IEnumFORMATETC_Release, + OLEClipbrd_IEnumFORMATETC_Next, + OLEClipbrd_IEnumFORMATETC_Skip, + OLEClipbrd_IEnumFORMATETC_Reset, + OLEClipbrd_IEnumFORMATETC_Clone +}; + +/************************************************************************ + * 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. + */ + +static 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 = IMalloc_Alloc(pIMalloc, size); + IMalloc_Release(pIMalloc); + + if (ef->pFmt) + memcpy(ef->pFmt, afmt, size); + + TRACE("(%p)->()\n",ef); + return (LPENUMFORMATETC)ef; +} + +/*********************************************************************** + * 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; } #define MAX_CLIPFORMAT_NAME 80 @@ -998,41 +591,136 @@ CLEANUP: /*********************************************************************** - * OLEClipbrd_GlobalDupMem( HGLOBAL ) - * Helper method to duplicate an HGLOBAL chunk of memory + * 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. */ -static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ) +static LRESULT CALLBACK OLEClipbrd_WndProc + (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - 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 ) + 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: { - GlobalFree(hGlobalDest); - return 0; + 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->lpvtbl), &rgelt ); + + break; } - memcpy(pGlobalDest, pGlobalSrc, cBytes); + /* + * 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; - GlobalUnlock(hGlobalSrc); - GlobalUnlock(hGlobalDest); + TRACE("(): WM_RENDERALLFORMATS\n"); - return hGlobalDest; + /* + * Render all HGLOBAL formats supported by the source into + * the windows clipboard. + */ + if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl), + 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->lpvtbl), &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; } @@ -1107,6 +795,30 @@ static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( return InterlockedIncrement(&This->ref); } +/*********************************************************************** + * OLEClipbrd_DestroyWindow(HWND) + * Destroy the clipboard window and unregister its class + */ +static void OLEClipbrd_DestroyWindow(HWND hwnd) +{ + DestroyWindow(hwnd); + UnregisterClassA( OLEClipbrd_WNDCLASS, 0 ); +} + +static void OLEClipbrd_Destroy(ole_clipbrd* This) +{ + TRACE("()\n"); + + if (!This) return; + + theOleClipboard = NULL; + + if ( This->hWndClipboard ) + OLEClipbrd_DestroyWindow(This->hWndClipboard); + + HeapFree(GetProcessHeap(), 0, This); +} + /************************************************************************ * OLEClipbrd_IDataObject_Release (IUnknown) * @@ -1450,236 +1162,436 @@ static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( return E_NOTIMPL; } +static const 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 +}; /*---------------------------------------------------------------------* - * Implementation of the internal IEnumFORMATETC interface returned by - * the OLE clipboard's IDataObject. + * Internal implementation methods for the OLE clipboard *---------------------------------------------------------------------*/ -/************************************************************************ - * 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. +/********************************************************* + * Construct the OLEClipbrd class. */ - -static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], - LPUNKNOWN pUnkDataObj) +static ole_clipbrd* OLEClipbrd_Construct(void) { - IEnumFORMATETCImpl* ef; - DWORD size=cfmt * sizeof(FORMATETC); - LPMALLOC pIMalloc; + ole_clipbrd* This; - ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl)); - if (!ef) - return NULL; + This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) ); + if (!This) return NULL; - ef->ref = 0; - ef->lpVtbl = &efvt; - ef->pUnkDataObj = pUnkDataObj; + This->lpvtbl = &OLEClipbrd_IDataObject_VTable; + This->ref = 1; - ef->posFmt = 0; - ef->countFmt = cfmt; - if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) { - HeapFree(GetProcessHeap(), 0, ef); - return NULL; - } - ef->pFmt = IMalloc_Alloc(pIMalloc, size); - IMalloc_Release(pIMalloc); + This->hWndClipboard = NULL; + This->pIDataObjectSrc = NULL; - if (ef->pFmt) - memcpy(ef->pFmt, afmt, size); - - TRACE("(%p)->()\n",ef); - return (LPENUMFORMATETC)ef; + theOleClipboard = This; + return This; } - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. +/*********************************************************************** + * OLEClipbrd_Initialize() + * Initializes the OLE clipboard. */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface - (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) +void OLEClipbrd_Initialize(void) { - 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 + * Create the clipboard if necessary */ - - *ppvObj = NULL; - - if(IsEqualIID(riid, &IID_IUnknown)) + if ( !theOleClipboard ) { - *ppvObj = This; + TRACE("()\n"); + theOleClipboard = OLEClipbrd_Construct(); } - else if(IsEqualIID(riid, &IID_IEnumFORMATETC)) - { - *ppvObj = 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. + +/*********************************************************************** + * OLEClipbrd_UnInitialize() + * Un-Initializes the OLE clipboard */ -static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) +void OLEClipbrd_UnInitialize(void) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->(count=%u)\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=%u)\n",This, This->ref); - - if (This->pUnkDataObj) - IUnknown_Release(This->pUnkDataObj); /* Release parent data object */ - - ref = InterlockedDecrement(&This->ref); - if (!ref) + 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) ) { - 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; + OLEClipbrd_Destroy( theOleClipboard ); } else { - cfetch = 0; + WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n"); } - - if (pceltFethed) - { - *pceltFethed = cfetch; - } - - return hres; } -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC) - * - * Standard enumerator members for IEnumFORMATETC +/*********************************************************************** + * OLEClipbrd_CreateWindow() + * Create the clipboard window */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt) +static HWND OLEClipbrd_CreateWindow(void) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->(num=%u)\n", This, celt); + HWND hwnd = 0; + WNDCLASSEXA wcex; - This->posFmt += celt; - if (This->posFmt > This->countFmt) - { - This->posFmt = This->countFmt; - return S_FALSE; - } - return S_OK; + /* + * 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_IEnumFORMATETC_Reset (IEnumFORMATETC) - * - * Standard enumerator members for IEnumFORMATETC - */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->()\n", This); +/*---------------------------------------------------------------------* + * Win32 OLE clipboard API + *---------------------------------------------------------------------*/ - This->posFmt = 0; - return S_OK; -} - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC) +/*********************************************************************** + * OleSetClipboard [OLE32.@] + * Places a pointer to the specified data object onto the clipboard, + * making the data object accessible to the OleGetClipboard function. * - * Standard enumerator members for IEnumFORMATETC + * 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 */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone - (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum) + +HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; HRESULT hr = S_OK; + IEnumFORMATETC* penumFormatetc = NULL; + FORMATETC rgelt; + BOOL bClipboardOpen = FALSE; + struct oletls *info = COM_CurrentInfo(); +/* + HGLOBAL hDataObject = 0; + OLEClipbrd **ppDataObject; +*/ - TRACE("(%p)->(ppenum=%p)\n", This, ppenum); + TRACE("(%p)\n", pDataObj); - if ( !ppenum ) - return E_INVALIDARG; + if(!info) + WARN("Could not allocate tls\n"); + else + if(!info->ole_inits) + return CO_E_NOTINITIALIZED; - *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt, - This->pFmt, - This->pUnkDataObj); + /* + * Make sure we have a clipboard object + */ + OLEClipbrd_Initialize(); - if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum))) - return ( hr ); + /* + * If the Ole clipboard window hasn't been created yet, create it now. + */ + if ( !theOleClipboard->hWndClipboard ) + theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow(); - return (*ppenum) ? S_OK : E_OUTOFMEMORY; + 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 = 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->lpvtbl), + &IID_IDataObject, (void**)ppDataObj); + return hr; +} + +/****************************************************************************** + * 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(void) +{ + 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; + + if (pDataObject == NULL) + return S_FALSE; + + return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE; }