📄 clipboard.c
字号:
return hr;
}
/***********************************************************************
* OleGetClipboard [OLE32.@]
* Returns a pointer to our internal IDataObject which represents the conceptual
* state of the Windows clipboard. If the current clipboard already contains
* an IDataObject, our internal IDataObject will delegate to this object.
*/
HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
{
HRESULT hr = S_OK;
TRACE("()\n");
/*
* Make sure we have a clipboard object
*/
OLEClipbrd_Initialize();
if (!theOleClipboard)
return E_OUTOFMEMORY;
/* Return a reference counted IDataObject */
hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1),
&IID_IDataObject, (void**)ppDataObj);
return hr;
}
/******************************************************************************
* OleFlushClipboard [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;
return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;
}
/*---------------------------------------------------------------------*
* Internal implementation methods for the OLE clipboard
*---------------------------------------------------------------------*/
/***********************************************************************
* OLEClipbrd_Initialize()
* Initializes the OLE clipboard.
*/
void OLEClipbrd_Initialize(void)
{
/*
* Create the clipboard if necessary
*/
if ( !theOleClipboard )
{
TRACE("()\n");
theOleClipboard = OLEClipbrd_Construct();
}
}
/***********************************************************************
* OLEClipbrd_UnInitialize()
* Un-Initializes the OLE clipboard
*/
void OLEClipbrd_UnInitialize(void)
{
TRACE("()\n");
/*
* Destroy the clipboard if no one holds a reference to us.
* Note that the clipboard was created with a reference count of 1.
*/
if ( theOleClipboard && (theOleClipboard->ref <= 1) )
{
OLEClipbrd_Destroy( theOleClipboard );
}
else
{
WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");
}
}
/*********************************************************
* Construct the OLEClipbrd class.
*/
static OLEClipbrd* OLEClipbrd_Construct(void)
{
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(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)
{
/*
* WM_RENDERFORMAT
* We receive this message to allow us to handle delayed rendering of
* a specific clipboard format when an application requests data in
* that format by calling GetClipboardData.
* (Recall that in OleSetClipboard, we used SetClipboardData to
* make all HGLOBAL formats supported by the source IDataObject
* available using delayed rendering)
* On receiving this message we must actually render the data in the
* specified format and place it on the clipboard by calling the
* SetClipboardData function.
*/
case WM_RENDERFORMAT:
{
FORMATETC rgelt;
ZeroMemory( &rgelt, sizeof(FORMATETC));
/*
* Initialize FORMATETC to a Windows clipboard friendly format
*/
rgelt.cfFormat = (UINT) wParam;
rgelt.dwAspect = DVASPECT_CONTENT;
rgelt.lindex = -1;
rgelt.tymed = TYMED_HGLOBAL;
TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat);
/*
* Render the clipboard data.
* (We must have a source data object or we wouldn't be in this WndProc)
*/
OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt );
break;
}
/*
* WM_RENDERALLFORMATS
* Sent before the clipboard owner window is destroyed.
* We should receive this message only when OleUninitialize is called
* while we have an IDataObject in the clipboard.
* For the content of the clipboard to remain available to other
* applications, we must render data in all the formats the source IDataObject
* is capable of generating, and place the data on the clipboard by calling
* SetClipboardData.
*/
case WM_RENDERALLFORMATS:
{
IEnumFORMATETC* penumFormatetc = NULL;
FORMATETC rgelt;
TRACE("(): WM_RENDERALLFORMATS\n");
/*
* Render all HGLOBAL formats supported by the source into
* the windows clipboard.
*/
if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1),
DATADIR_GET, &penumFormatetc) ) )
{
WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n");
return 0;
}
while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
{
if ( rgelt.tymed == TYMED_HGLOBAL )
{
/*
* Render the clipboard data.
*/
if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) )
continue;
TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat);
}
}
IEnumFORMATETC_Release(penumFormatetc);
break;
}
/*
* WM_DESTROYCLIPBOARD
* This is sent by EmptyClipboard before the clipboard is emptied.
* We should release any IDataObject we are holding onto when we receive
* this message, since it indicates that the OLE clipboard should be empty
* from this point on.
*/
case WM_DESTROYCLIPBOARD:
{
TRACE("(): WM_DESTROYCLIPBOARD\n");
/*
* Release the data object we are holding on to
*/
if ( theOleClipboard->pIDataObjectSrc )
{
IDataObject_Release(theOleClipboard->pIDataObjectSrc);
theOleClipboard->pIDataObjectSrc = NULL;
}
break;
}
/*
case WM_ASKCBFORMATNAME:
case WM_CHANGECBCHAIN:
case WM_DRAWCLIPBOARD:
case WM_SIZECLIPBOARD:
case WM_HSCROLLCLIPBOARD:
case WM_VSCROLLCLIPBOARD:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -