VBoxClipboard.cpp revision 74804912a237136f06d0b49682a119577135902b
/** @file
*
* VBoxClipboard - Shared clipboard
*
*/
/*
* Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "VBoxTray.h"
#include "VBoxHelpers.h"
#include <strsafe.h>
typedef struct _VBOXCLIPBOARDCONTEXT
{
const VBOXSERVICEENV *pEnv;
bool fCBChainPingInProcess;
// bool fOperational;
// uint32_t u32LastSentFormat;
// uint64_t u64LastSentCRC64;
static char gachWindowClassName[] = "VBoxSharedClipboardClass";
{
/* Query list of available formats and report to host. */
int rc = VINF_SUCCESS;
{
}
else
{
uint32_t u32Formats = 0;
{
switch (format)
{
case CF_UNICODETEXT:
case CF_TEXT:
break;
case CF_DIB:
case CF_BITMAP:
break;
default:
if (format >= 0xC000)
{
if (cActual)
{
{
}
}
}
break;
}
}
CloseClipboard ();
}
return rc;
}
/* Add ourselves into the chain of cliboard listeners */
{
}
/* Remove ourselves from the chain of cliboard listeners */
{
}
/* Callback which is invoked when we have successfully pinged ourselves down the
* clipboard chain. We simply unset a boolean flag to say that we are responding.
* There is a race if a ping returns after the next one is initiated, but nothing
* very bad is likely to happen. */
{
(void) hwnd;
(void) uMsg;
(void) lResult;
}
static LRESULT vboxClipboardProcessMsg(VBOXCLIPBOARDCONTEXT *pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CHANGECBCHAIN:
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_CHANGECBCHAIN: hwndRemoved %p, hwndNext %p, hwnd %p\n", hwndRemoved, hwndNext, pCtx->hwnd));
{
/* The window that was next to our in the chain is being removed.
* Relink to the new next window. */
}
else
{
if (pCtx->hwndNextInChain)
{
/* Pass the message further. */
rc = SendMessageTimeout(pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult);
if (!rc)
}
}
} break;
case WM_DRAWCLIPBOARD:
{
if (GetClipboardOwner () != hwnd)
{
/* Clipboard was updated by another application. */
/* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */
if (RT_FAILURE(vboxrc))
}
/* Pass the message to next windows in the clipboard chain. */
} break;
case WM_TIMER:
{
/* Re-register ourselves in the clipboard chain if our last ping
* timed out or there seems to be no valid chain. */
{
}
/* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be
* processed by ourselves to the chain. */
if (hViewer)
SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pCtx->hwndNextInChain, (LPARAM)pCtx->hwndNextInChain, CBChainPingProc, (ULONG_PTR) pCtx);
} break;
case WM_CLOSE:
{
/* Do nothing. Ignore the message. */
} break;
case WM_RENDERFORMAT:
{
/* Insert the requested clipboard format data into the clipboard. */
switch (format)
{
case CF_UNICODETEXT:
break;
case CF_DIB:
break;
default:
if (format >= 0xC000)
{
if (cActual)
{
{
}
}
}
break;
}
if (u32Format == 0)
{
/* Unsupported clipboard format is requested. */
Log(("VBoxTray: vboxClipboardProcessMsg: Unsupported clipboard format requested: %ld\n", u32Format));
}
else
{
const uint32_t cbPrealloc = 4096; /* @todo r=andy Make it dynamic for supporting larger text buffers! */
/* Preallocate a buffer, most of small text transfers will fit into it. */
if (hMem)
{
Log(("VBoxTray: vboxClipboardProcessMsg: Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
if (pMem)
{
/* Read the host data to the preallocated buffer. */
Log(("VBoxTray: vboxClipboardProcessMsg: VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc));
if (RT_SUCCESS(vboxrc))
{
if (cb == 0)
{
/* 0 bytes returned means the clipboard is empty.
* Deallocate the memory and set hMem to NULL to get to
* the clipboard empty code path. */
}
else if (cb > cbPrealloc)
{
/* The preallocated buffer is too small, adjust the size. */
if (hMem)
{
Log(("VBoxTray: vboxClipboardProcessMsg: Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
if (pMem)
{
/* Read the host data to the preallocated buffer. */
Log(("VBoxTray: VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew));
{
}
else
{
}
}
else
{
}
}
}
if (hMem)
{
/* pMem is the address of the data. cb is the size of returned data. */
/* Verify the size of returned text, the memory block for clipboard
* must have the exact string size.
*/
{
{
/* Discard invalid data. */
}
else
{
/* cbActual is the number of bytes, excluding those used
* for the terminating null character.
*/
}
}
}
if (hMem)
{
if (hMem)
{
/* 'hMem' contains the host clipboard data.
* size is 'cb' and format is 'format'. */
if (hClip)
{
/* The hMem ownership has gone to the system. Finish the processing. */
break;
}
/* Cleanup follows. */
}
}
}
if (hMem)
}
if (hMem)
}
/* Something went wrong. */
}
} break;
case WM_RENDERALLFORMATS:
{
/* Do nothing. The clipboard formats will be unavailable now, because the
* windows is to be destroyed and therefore the guest side becomes inactive.
*/
if (OpenClipboard(hwnd))
{
}
} break;
case WM_USER:
{
/* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError()));
}
else
{
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n"));
}
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
}
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format));
if (format != 0)
{
}
}
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: hClip = %p, err = %ld\n", hClip, GetLastError ()));
}
} break;
case WM_USER + 1:
{
/* Send data in the specified format to the host. */
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError()));
}
else
{
int vboxrc;
{
{
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_DIB\n"));
}
else
{
}
}
}
else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
{
{
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_UNICODETEXT\n"));
}
else
{
}
}
}
else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
{
if (format != 0)
{
{
{
Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_HTML\n"));
}
else
{
}
}
}
}
}
{
/* Requested clipboard format is not available, send empty data. */
}
} break;
default:
{
}
}
return rc;
}
{
/* Register the Window Class. */
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
int rc = VINF_SUCCESS;
if (pCtx->atomWindowClass == 0)
{
}
else
{
/* Create the window. */
{
}
else
{
}
}
return rc;
}
{
{
if (pCtx->timerRefresh)
}
if (pCtx->atomWindowClass != 0)
{
pCtx->atomWindowClass = 0;
}
}
/* Static since it is the single instance. Directly used in the windows proc. */
{
/* Forward with proper context. */
}
{
Log(("VBoxTray: VboxClipboardInit\n"));
{
/* Clipboard was already initialized. 2 or more instances are not supported. */
return VERR_NOT_SUPPORTED;
}
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
/* Always start the thread for host messages. */
*pfStartThread = true;
}
else
{
}
}
if (RT_SUCCESS(rc))
*ppInstance = &gCtx;
return rc;
}
{
Log(("VBoxTray: VBoxClipboardThread\n"));
/* The thread waits for incoming messages from the host. */
for (;;)
{
if (RT_FAILURE(rc))
{
Log(("VBoxTray: VBoxClipboardThread: Failed to call the driver for host message! rc = %Rrc\n", rc));
if (rc == VERR_INTERRUPTED)
{
/* Wait for termination event. */
break;
}
/* Wait a bit before retrying. */
{
break;
}
continue;
}
else
{
Log(("VBoxTray: VBoxClipboardThread: VbglR3ClipboardGetHostMsg u32Msg = %ld, u32Formats = %ld\n", u32Msg, u32Formats));
switch (u32Msg)
{
{
/* The host has announced available clipboard formats.
* Forward the information to the window, so it can later
* respond to WM_RENDERFORMAT message. */
} break;
{
/* The host needs data in the specified format. */
} break;
{
/* The host is terminating. */
} break;
default:
{
}
}
}
}
return 0;
}
{
{
}
return;
}