VBoxSeamless.cpp revision 9c5b74b1807a8bba27bb444821acf959c01779cf
/* $Id$ */
/** @file
* VBoxSeamless - Seamless windows
*/
/*
* 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.
*/
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include "VBoxTray.h"
#include "VBoxHelpers.h"
#include "VBoxSeamless.h"
#include <VBoxHook.h>
#include <VBoxDisplay.h>
#include <VBoxGuestInternal.h>
typedef struct _VBOXSEAMLESSCONTEXT
{
const VBOXSERVICEENV *pEnv;
BOOL (* pfnVBoxRemoveHook)();
typedef struct
{
static VBOXSEAMLESSCONTEXT gCtx = {0};
{
Log(("VBoxTray: VBoxSeamlessInit\n"));
*pfStartThread = false;
GetVersionEx (&OSinfo);
int rc = VINF_SUCCESS;
/* We have to jump out here when using NT4, otherwise it complains about
a missing API function "UnhookWinEvent" used by the dynamically loaded VBoxHook.dll below */
{
Log(("VBoxTray: VBoxSeamlessInit: Windows NT 4.0 or older not supported!\n"));
}
else
{
/* Will fail if SetWinEventHook is not present (version < NT4 SP6 apparently) */
{
*(uintptr_t *)&gCtx.pfnVBoxInstallHook = (uintptr_t)GetProcAddress(gCtx.hModule, "VBoxInstallHook");
/* Inform the host that we support the seamless window mode. */
if (RT_SUCCESS(rc))
{
*pfStartThread = true;
*ppInstance = &gCtx;
}
else
Log(("VBoxTray: VBoxSeamlessInit: Failed to set seamless capability\n"));
}
else
{
Log(("VBoxTray: VBoxSeamlessInit: LoadLibrary of \"%s\" failed with rc=%Rrc\n", VBOXHOOK_DLL_NAME, rc));
}
}
return rc;
}
{
Log(("VBoxTray: VBoxSeamlessDestroy\n"));
/* Inform the host that we no longer support the seamless window mode. */
if (RT_FAILURE(rc))
if (gCtx.pfnVBoxRemoveHook)
return;
}
void VBoxSeamlessInstallHook()
{
if (gCtx.pfnVBoxInstallHook)
{
/* Check current visible region state */
}
}
void VBoxSeamlessRemoveHook()
{
if (gCtx.pfnVBoxRemoveHook)
if (gCtx.lpEscapeData)
{
}
}
{
if ( !(dwStyle & WS_VISIBLE)
return TRUE;
/* Only visible windows that are present on the desktop are interesting here */
{
char szWindowText[256];
szWindowText[0] = 0;
/* Filter out Windows XP shadow windows */
/** @todo still shows inside the guest */
if ( szWindowText[0] == 0
{
return TRUE;
}
/** @todo will this suffice? The Program Manager window covers the whole screen */
{
Log(("VBoxTray: Enum hwnd=%x rect (%d,%d) (%d,%d)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
{
}
else
{
/* this region is relative to the window origin instead of the desktop origin */
}
{
/* create a union of the current visible region and the visible rectangle of this window. */
}
else
}
else
{
Log(("VBoxTray: Enum hwnd=%x rect (%d,%d) (%d,%d) (ignored)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
}
}
return TRUE; /* continue enumeration */
}
void VBoxSeamlessCheckWindows()
{
{
if (cbSize)
{
if (lpEscapeData)
{
if (cbSize)
{
#ifdef DEBUG
Log(("VBoxTray: New visible region: \n"));
{
Log(("VBoxTray: visible rect (%d,%d)(%d,%d)\n", lpRect[i].left, lpRect[i].top, lpRect[i].right, lpRect[i].bottom));
}
#endif
if ( !gCtx.lpEscapeData
{
/* send to display driver */
if (gCtx.lpEscapeData)
}
else
Log(("VBoxTray: Visible rectangles haven't changed; ignore\n"));
}
}
}
}
}
/**
* Thread function to wait for and process seamless mode change
* requests
*/
{
bool fTerminate = false;
maskInfo.u32NotMask = 0;
if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
{
Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask - or) succeeded\n"));
}
else
{
Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
return 0;
}
do
{
/* wait for a seamless change event */
if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
{
Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl succeeded\n"));
/* are we supposed to stop? */
break;
Log(("VBoxTray: VBoxSeamlessThread: checking event\n"));
/* did we get the right event? */
{
Log(("VBoxTray: VBoxTray: going to get seamless change information\n"));
/* We got at least one event. Read the requested resolution
* and try to set it until success. New events will not be seen
* but a new resolution will be read in this poll loop.
*/
for (;;)
{
/* get the seamless change request */
vmmdevInitRequest((VMMDevRequestHeader*)&seamlessChangeRequest, VMMDevReq_GetSeamlessChangeRequest);
BOOL fSeamlessChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(seamlessChangeRequest)), &seamlessChangeRequest, sizeof(seamlessChangeRequest),
{
switch(seamlessChangeRequest.mode)
{
case VMMDev_Seamless_Disabled:
{
Log(("VBoxTray: Re-enabling the screensaver\n"));
if (!ret)
}
break;
if (!ret)
Log(("VBoxTray: Disabling the screensaver\n"));
if (!ret)
break;
break;
default:
AssertFailed();
break;
}
break;
}
else
{
Log(("VBoxTray: VBoxSeamlessThread: error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"));
}
/* sleep a bit to not eat too much CPU while retrying */
/* are we supposed to stop? */
{
fTerminate = true;
break;
}
}
}
}
else
{
Log(("VBoxTray: VBoxTray: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
/* sleep a bit to not eat too much CPU in case the above call always fails */
{
fTerminate = true;
break;
}
}
}
while (!fTerminate);
if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
{
Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask - not) succeeded\n"));
}
else
{
Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask) failed\n"));
}
Log(("VBoxTray: VBoxSeamlessThread: finished seamless change request thread\n"));
return 0;
}