VBoxSeamless.cpp revision e0d9b16920de2b8f215d7d4fbba8c358b2aeb4a1
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync/* $Id$ */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync/** @file
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * VBoxSeamless - Seamless windows
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync/*
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync *
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * available from http://www.virtualbox.org. This file is free software;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * General Public License (GPL) as published by the Free Software
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync *
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * additional information or have any questions.
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#define _WIN32_WINNT 0x0500
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#include <windows.h>
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#include "VBoxTray.h"
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#include "VBoxSeamless.h"
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#include <VBoxHook.h>
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#include <VBoxDisplay.h>
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#include <VBox/VMMDev.h>
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync#include <iprt/assert.h>
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#include "helpers.h"
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsynctypedef struct _VBOXSEAMLESSCONTEXT
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync const VBOXSERVICEENV *pEnv;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync HMODULE hModule;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync BOOL (* pfnVBoxInstallHook)(HMODULE hDll);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync BOOL (* pfnVBoxRemoveHook)();
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync PVBOXDISPIFESCAPE lpEscapeData;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync} VBOXSEAMLESSCONTEXT;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsynctypedef struct
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync HDC hdc;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync HRGN hrgn;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#ifndef MMSEAMLESS
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync RECT rect;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#endif
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync} VBOX_ENUM_PARAM, *PVBOX_ENUM_PARAM;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncstatic VBOXSEAMLESSCONTEXT gCtx = {0};
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncvoid VBoxLogString(HANDLE hDriver, char *pszStr);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncint VBoxSeamlessInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxSeamlessInit\n"));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync *pfStartThread = false;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync gCtx.pEnv = pEnv;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync OSVERSIONINFO OSinfo;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync GetVersionEx (&OSinfo);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* We have to jump out here when using NT4, otherwise it complains about
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync a missing API function "UnhookWinEvent" used by the dynamically loaded VBoxHook.dll below */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (OSinfo.dwMajorVersion <= 4) /* Windows NT 4.0 or older */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxSeamlessInit: Windows NT 4.0 or older not supported!\n"));
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync return VERR_NOT_SUPPORTED;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Will fail if SetWinEventHook is not present (version < NT4 SP6 apparently) */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync gCtx.hModule = LoadLibrary(VBOXHOOK_DLL_NAME);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (gCtx.hModule)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync *(uintptr_t *)&gCtx.pfnVBoxInstallHook = (uintptr_t)GetProcAddress(gCtx.hModule, "VBoxInstallHook");
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync *(uintptr_t *)&gCtx.pfnVBoxRemoveHook = (uintptr_t)GetProcAddress(gCtx.hModule, "VBoxRemoveHook");
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* inform the host that we support the seamless window mode */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync VMMDevReqGuestCapabilities vmmreqGuestCaps = {0};
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqGuestCaps, VMMDevReq_ReportGuestCapabilities);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync vmmreqGuestCaps.caps = VMMDEV_GUEST_SUPPORTS_SEAMLESS;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync DWORD cbReturned;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (!DeviceIoControl(pEnv->hDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqGuestCaps)), &vmmreqGuestCaps, sizeof(vmmreqGuestCaps),
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync &vmmreqGuestCaps, sizeof(vmmreqGuestCaps), &cbReturned, NULL))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxSeamlessInit: VMMDevReq_ReportGuestCapabilities: error doing IOCTL, last error: %d\n", GetLastError()));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return VERR_INVALID_PARAMETER;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync *pfStartThread = true;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync *ppInstance = &gCtx;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return VINF_SUCCESS;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync else
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxSeamlessInit: LoadLibrary failed with %d\n", GetLastError()));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return VERR_INVALID_PARAMETER;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return VINF_SUCCESS;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync}
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncvoid VBoxSeamlessDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxSeamlessDestroy\n"));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* inform the host that we no longer support the seamless window mode */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync VMMDevReqGuestCapabilities vmmreqGuestCaps = {0};
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqGuestCaps, VMMDevReq_ReportGuestCapabilities);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync vmmreqGuestCaps.caps = 0;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync DWORD cbReturned;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (!DeviceIoControl(pEnv->hDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqGuestCaps)), &vmmreqGuestCaps, sizeof(vmmreqGuestCaps),
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync &vmmreqGuestCaps, sizeof(vmmreqGuestCaps), &cbReturned, NULL))
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VMMDevReq_ReportGuestCapabilities: error doing IOCTL, last error: %d\n", GetLastError()));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (gCtx.pfnVBoxRemoveHook)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync gCtx.pfnVBoxRemoveHook();
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (gCtx.hModule)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync FreeLibrary(gCtx.hModule);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync gCtx.hModule = 0;
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync return;
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync}
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncvoid VBoxSeamlessInstallHook()
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (gCtx.pfnVBoxInstallHook)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* Check current visible region state */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync VBoxSeamlessCheckWindows();
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync gCtx.pfnVBoxInstallHook(gCtx.hModule);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync}
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncvoid VBoxSeamlessRemoveHook()
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (gCtx.pfnVBoxRemoveHook)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync gCtx.pfnVBoxRemoveHook();
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (gCtx.lpEscapeData)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync free(gCtx.lpEscapeData);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync gCtx.lpEscapeData = NULL;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync}
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
625c607af2ec5549c016c35f80cb8741eafd774bvboxsyncBOOL CALLBACK VBoxEnumFunc(HWND hwnd, LPARAM lParam)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync PVBOX_ENUM_PARAM lpParam = (PVBOX_ENUM_PARAM)lParam;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync DWORD dwStyle, dwExStyle;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync RECT rectWindow, rectVisible;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync dwStyle = GetWindowLong(hwnd, GWL_STYLE);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if ( !(dwStyle & WS_VISIBLE)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync || (dwStyle & WS_CHILD))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return TRUE;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxEnumFunc %x\n", hwnd));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* Only visible windows that are present on the desktop are interesting here */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#ifndef MMSEAMLESS
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if ( GetWindowRect(hwnd, &rectWindow)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync && IntersectRect(&rectVisible, &lpParam->rect, &rectWindow))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#else
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (GetWindowRect(hwnd, &rectWindow))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync rectVisible = rectWindow;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#endif
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync char szWindowText[256];
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync szWindowText[0] = 0;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync GetWindowText(hwnd, szWindowText, sizeof(szWindowText));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* Filter out Windows XP shadow windows */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /** @todo still shows inside the guest */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if ( szWindowText[0] == 0
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync && dwStyle == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync && dwExStyle == (WS_EX_LAYERED|WS_EX_TOOLWINDOW|WS_EX_TRANSPARENT|WS_EX_TOPMOST))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("Filter out shadow window style=%x exstyle=%x\n", dwStyle, dwExStyle));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return TRUE;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /** @todo will this suffice? The Program Manager window covers the whole screen */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (strcmp(szWindowText, "Program Manager"))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("Enum hwnd=%x rect (%d,%d) (%d,%d)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("title=%s style=%x exStyle=%x\n", szWindowText, dwStyle, dwExStyle));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync HRGN hrgn = CreateRectRgn(0,0,0,0);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync int ret = GetWindowRgn(hwnd, hrgn);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (ret == ERROR)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("GetWindowRgn failed with rc=%d\n", GetLastError()));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync SetRectRgn(hrgn, rectVisible.left, rectVisible.top, rectVisible.right, rectVisible.bottom);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync else
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* this region is relative to the window origin instead of the desktop origin */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync OffsetRgn(hrgn, rectWindow.left, rectWindow.top);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (lpParam->hrgn)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* create a union of the current visible region and the visible rectangle of this window. */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync CombineRgn(lpParam->hrgn, lpParam->hrgn, hrgn, RGN_OR);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync DeleteObject(hrgn);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync else
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync lpParam->hrgn = hrgn;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync else
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("Enum hwnd=%x rect (%d,%d) (%d,%d) (ignored)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("title=%s style=%x\n", szWindowText, dwStyle));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return TRUE; /* continue enumeration */
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync}
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync
080aed76fbd7ad91c4986369370b268e39d6db70vboxsyncvoid VBoxSeamlessCheckWindows()
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync{
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync VBOX_ENUM_PARAM param;
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync param.hdc = GetDC(HWND_DESKTOP);
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync param.hrgn = 0;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#ifndef MMSEAMLESS
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync GetWindowRect(GetDesktopWindow(), &param.rect);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxRecheckVisibleWindows desktop=%x rect (%d,%d) (%d,%d)\n", GetDesktopWindow(), param.rect.left, param.rect.top, param.rect.right, param.rect.bottom));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#endif
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync EnumWindows(VBoxEnumFunc, (LPARAM)&param);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (param.hrgn)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync DWORD cbSize;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync cbSize = GetRegionData(param.hrgn, 0, NULL);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (cbSize)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync PVBOXDISPIFESCAPE lpEscapeData = (PVBOXDISPIFESCAPE)malloc(VBOXDISPIFESCAPE_SIZE(cbSize));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (lpEscapeData)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync lpEscapeData->escapeCode = VBOXESC_SETVISIBLEREGION;
15b04a5785f14f37cf6b304b2982cee73d93bb32vboxsync LPRGNDATA lpRgnData = VBOXDISPIFESCAPE_DATA(lpEscapeData, RGNDATA);
15b04a5785f14f37cf6b304b2982cee73d93bb32vboxsync memset(lpRgnData, 0, cbSize);
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync cbSize = GetRegionData(param.hrgn, cbSize, lpRgnData);
15b04a5785f14f37cf6b304b2982cee73d93bb32vboxsync if (cbSize)
15b04a5785f14f37cf6b304b2982cee73d93bb32vboxsync {
15b04a5785f14f37cf6b304b2982cee73d93bb32vboxsync#ifdef DEBUG
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync RECT *lpRect = (RECT *)&lpRgnData->Buffer[0];
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("New visible region: \n"));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync for (DWORD i=0;i<lpRgnData->rdh.nCount;i++)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("visible rect (%d,%d)(%d,%d)\n", lpRect[i].left, lpRect[i].top, lpRect[i].right, lpRect[i].bottom));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync#endif
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync LPRGNDATA lpCtxRgnData = VBOXDISPIFESCAPE_DATA(gCtx.lpEscapeData, RGNDATA);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if ( !gCtx.lpEscapeData
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync || (lpCtxRgnData->rdh.dwSize + lpCtxRgnData->rdh.nRgnSize != cbSize)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync || memcmp(lpCtxRgnData, lpRgnData, cbSize))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* send to display driver */
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync VBoxDispIfEscape(&gCtx.pEnv->dispIf, lpEscapeData, cbSize);
080aed76fbd7ad91c4986369370b268e39d6db70vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (gCtx.lpEscapeData)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync free(gCtx.lpEscapeData);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync gCtx.lpEscapeData = lpEscapeData;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync else
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("Visible rectangles haven't changed; ignore\n"));
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync }
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync if (lpEscapeData != gCtx.lpEscapeData)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync free(lpEscapeData);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync DeleteObject(param.hrgn);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync ReleaseDC(HWND_DESKTOP, param.hdc);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync}
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync/**
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * Thread function to wait for and process seamless mode change
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * requests
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncunsigned __stdcall VBoxSeamlessThread(void *pInstance)
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync{
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync VBOXSEAMLESSCONTEXT *pCtx = (VBOXSEAMLESSCONTEXT *)pInstance;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync bool fTerminate = false;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync VBoxGuestFilterMaskInfo maskInfo;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync DWORD cbReturned;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync BOOL fWasScreenSaverActive = FALSE, ret;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync maskInfo.u32OrMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync maskInfo.u32NotMask = 0;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
625c607af2ec5549c016c35f80cb8741eafd774bvboxsync Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask - or) succeeded\n"));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync else
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync return 0;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync }
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync do
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync {
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* wait for a seamless change event */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync VBoxGuestWaitEventInfo waitEvent;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync waitEvent.u32TimeoutIn = 5000;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync waitEvent.u32EventMaskIn = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
{
Log(("VBoxSeamlessThread: DeviceIOControl succeded\n"));
/* are we supposed to stop? */
if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
break;
Log(("VBoxSeamlessThread: checking event\n"));
/* did we get the right event? */
if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
{
Log(("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 */
VMMDevSeamlessChangeRequest seamlessChangeRequest = {0};
vmmdevInitRequest((VMMDevRequestHeader*)&seamlessChangeRequest, VMMDevReq_GetSeamlessChangeRequest);
seamlessChangeRequest.eventAck = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
BOOL fSeamlessChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(seamlessChangeRequest)), &seamlessChangeRequest, sizeof(seamlessChangeRequest),
&seamlessChangeRequest, sizeof(seamlessChangeRequest), &cbReturned, NULL);
if (fSeamlessChangeQueried)
{
Log(("VBoxSeamlessThread: mode change to %d\n", seamlessChangeRequest.mode));
switch(seamlessChangeRequest.mode)
{
case VMMDev_Seamless_Disabled:
if (fWasScreenSaverActive)
{
Log(("Re-enabling the screensaver\n"));
ret = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, NULL, 0);
if (!ret)
Log(("SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
}
PostMessage(gToolWindow, WM_VBOX_REMOVE_SEAMLESS_HOOK, 0, 0);
break;
case VMMDev_Seamless_Visible_Region:
ret = SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fWasScreenSaverActive, 0);
if (!ret)
Log(("SystemParametersInfo SPI_GETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
if (fWasScreenSaverActive)
Log(("Disabling the screensaver\n"));
ret = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
if (!ret)
Log(("SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
PostMessage(gToolWindow, WM_VBOX_INSTALL_SEAMLESS_HOOK, 0, 0);
break;
case VMMDev_Seamless_Host_Window:
break;
default:
AssertFailed();
break;
}
break;
}
else
{
Log(("VBoxSeamlessThread: error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"));
}
/* sleep a bit to not eat too much CPU while retrying */
/* are we supposed to stop? */
if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 50) == WAIT_OBJECT_0)
{
fTerminate = true;
break;
}
}
}
}
else
{
Log(("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 */
if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
{
fTerminate = true;
break;
}
}
}
while (!fTerminate);
maskInfo.u32OrMask = 0;
maskInfo.u32NotMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
{
Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask - not) succeeded\n"));
}
else
{
Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask) failed\n"));
}
Log(("VBoxSeamlessThread: finished seamless change request thread\n"));
return 0;
}