📄 clipboard.c
字号:
/*
* OLE 2 clipboard support
*
* Copyright 1999 Noel Borthwick <noel@macadamian.com>
* Copyright 2000 Abey George <abey@macadamian.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTES:
* This file contains the implementation for the OLE Clipboard and its
* internal interfaces. The OLE clipboard interacts with an IDataObject
* interface via the OleSetClipboard, OleGetClipboard and
* OleIsCurrentClipboard API's. An internal IDataObject delegates
* to a client supplied IDataObject or the WIN32 clipboard API depending
* on whether OleSetClipboard has been invoked.
* Here are some operating scenarios:
*
* 1. OleSetClipboard called: In this case the internal IDataObject
* delegates to the client supplied IDataObject. Additionally OLE takes
* ownership of the Windows clipboard and any HGLOCBAL IDataObject
* items are placed on the Windows clipboard. This allows non OLE aware
* applications to access these. A local WinProc fields WM_RENDERFORMAT
* and WM_RENDERALLFORMATS messages in this case.
*
* 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
* IDataObject functionality wraps around the WIN32 clipboard API.
*
* 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
* IDataObject delegates to the source IDataObjects functionality directly,
* thereby bypassing the Windows clipboard.
*
* Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
*
* TODO:
* - Support for pasting between different processes. OLE clipboard support
* currently works only for in process copy and paste. Since we internally
* store a pointer to the source's IDataObject and delegate to that, this
* will fail if the IDataObject client belongs to a different process.
* - IDataObject::GetDataHere is not implemented
* - OleFlushClipboard needs to additionally handle TYMED_IStorage media
* by copying the storage into global memory. Subsequently the default
* data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
* back to TYMED_IStorage.
* - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
* clipboard in OleSetClipboard.
*
*/
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "winnls.h"
#include "ole2.h"
#include "wine/debug.h"
#include "olestd.h"
#include "storage32.h"
#define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; }
WINE_DEFAULT_DEBUG_CHANNEL(ole);
/****************************************************************************
* OLEClipbrd
* DO NOT add any members before the VTables declaration!
*/
struct OLEClipbrd
{
/*
* List all interface VTables here
*/
const IDataObjectVtbl* lpvtbl1; /* IDataObject VTable */
/*
* The hidden OLE clipboard window. This window is used as the bridge between the
* the OLE and windows clipboard API. (Windows creates one such window per process)
*/
HWND hWndClipboard;
/*
* Pointer to the source data object (via OleSetClipboard)
*/
IDataObject* pIDataObjectSrc;
/*
* The registered DataObject clipboard format
*/
UINT cfDataObj;
/*
* The handle to ourself
*/
HGLOBAL hSelf;
/*
* Reference count of this object
*/
LONG ref;
};
typedef struct OLEClipbrd OLEClipbrd;
/****************************************************************************
* IEnumFORMATETC implementation
* DO NOT add any members before the VTables declaration!
*/
typedef struct
{
/* IEnumFORMATETC VTable */
const IEnumFORMATETCVtbl *lpVtbl;
/* IEnumFORMATETC fields */
UINT posFmt; /* current enumerator position */
UINT countFmt; /* number of EnumFORMATETC's in array */
LPFORMATETC pFmt; /* array of EnumFORMATETC's */
/*
* Reference count of this object
*/
LONG ref;
/*
* IUnknown implementation of the parent data object.
*/
IUnknown* pUnkDataObj;
} IEnumFORMATETCImpl;
typedef struct PresentationDataHeader
{
BYTE unknown1[28];
DWORD dwObjectExtentX;
DWORD dwObjectExtentY;
DWORD dwSize;
} PresentationDataHeader;
/*
* The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize()
*/
static HGLOBAL hTheOleClipboard = 0;
static OLEClipbrd* theOleClipboard = NULL;
/*
* Prototypes for the methods of the OLEClipboard class.
*/
void OLEClipbrd_Initialize(void);
void OLEClipbrd_UnInitialize(void);
static OLEClipbrd* OLEClipbrd_Construct(void);
static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy);
static HWND OLEClipbrd_CreateWindow(void);
static void OLEClipbrd_DestroyWindow(HWND hwnd);
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
*/
static const CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
/*
* If we need to store state info we can store it here.
* For now we don't need this functionality.
*
typedef struct tagClipboardWindowInfo
{
} ClipboardWindowInfo;
*/
/*---------------------------------------------------------------------*
* Win32 OLE clipboard API
*---------------------------------------------------------------------*/
/***********************************************************************
* OleSetClipboard [OLE32.@]
* Places a pointer to the specified data object onto the clipboard,
* making the data object accessible to the OleGetClipboard function.
*
* RETURNS
*
* S_OK IDataObject pointer placed on the clipboard
* CLIPBRD_E_CANT_OPEN OpenClipboard failed
* CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
* CLIPBRD_E_CANT_CLOSE CloseClipboard failed
* CLIPBRD_E_CANT_SET SetClipboard failed
*/
HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)
{
HRESULT hr = S_OK;
IEnumFORMATETC* penumFormatetc = NULL;
FORMATETC rgelt;
BOOL bClipboardOpen = FALSE;
/*
HGLOBAL hDataObject = 0;
OLEClipbrd **ppDataObject;
*/
TRACE("(%p)\n", pDataObj);
/*
* Make sure we have a clipboard object
*/
OLEClipbrd_Initialize();
/*
* If the Ole clipboard window hasn't been created yet, create it now.
*/
if ( !theOleClipboard->hWndClipboard )
theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
if ( !theOleClipboard->hWndClipboard ) /* sanity check */
HANDLE_ERROR( E_FAIL );
/*
* Open the Windows clipboard, associating it with our hidden window
*/
if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
/*
* Empty the current clipboard and make our window the clipboard owner
* NOTE: This will trigger a WM_DESTROYCLIPBOARD message
*/
if ( !EmptyClipboard() )
HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
/*
* If we are already holding on to an IDataObject first release that.
*/
if ( theOleClipboard->pIDataObjectSrc )
{
IDataObject_Release(theOleClipboard->pIDataObjectSrc);
theOleClipboard->pIDataObjectSrc = NULL;
}
/*
* AddRef the data object passed in and save its pointer.
* A NULL value indicates that the clipboard should be emptied.
*/
theOleClipboard->pIDataObjectSrc = pDataObj;
if ( pDataObj )
{
IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
}
/*
* Enumerate all HGLOBAL formats supported by the source and make
* those formats available using delayed rendering using SetClipboardData.
* Only global memory based data items may be made available to non-OLE
* applications via the standard Windows clipboard API. Data based on other
* mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API.
*
* TODO: Do we need to additionally handle TYMED_IStorage media by copying
* the storage into global memory?
*/
if ( pDataObj )
{
if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj,
DATADIR_GET,
&penumFormatetc )))
{
HANDLE_ERROR( hr );
}
while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
{
if ( rgelt.tymed == TYMED_HGLOBAL )
{
CHAR szFmtName[80];
TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
? szFmtName : "");
SetClipboardData( rgelt.cfFormat, NULL);
}
}
IEnumFORMATETC_Release(penumFormatetc);
}
/*
* Windows additionally creates a new "DataObject" clipboard format
* and stores in on the clipboard. We could possibly store a pointer
* to our internal IDataObject interface on the clipboard. I'm not
* sure what the use of this is though.
* Enable the code below for this functionality.
*/
/*
theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject");
hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
sizeof(OLEClipbrd *));
if (hDataObject==0)
HANDLE_ERROR( E_OUTOFMEMORY );
ppDataObject = (OLEClipbrd**)GlobalLock(hDataObject);
*ppDataObject = theOleClipboard;
GlobalUnlock(hDataObject);
if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) )
HANDLE_ERROR( CLIPBRD_E_CANT_SET );
*/
hr = S_OK;
CLEANUP:
/*
* Close Windows clipboard (It remains associated with our window)
*/
if ( bClipboardOpen && !CloseClipboard() )
hr = CLIPBRD_E_CANT_CLOSE;
/*
* Release the source IDataObject if something failed
*/
if ( FAILED(hr) )
{
if (theOleClipboard->pIDataObjectSrc)
{
IDataObject_Release(theOleClipboard->pIDataObjectSrc);
theOleClipboard->pIDataObjectSrc = NULL;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -