VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.cpp@ 28366

最後變更 在這個檔案從28366是 28366,由 vboxsync 提交於 15 年 前

VBoxTray: seamless should report all guest windows. (xTracker 4655)

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 15.9 KB
 
1/* $Id: VBoxSeamless.cpp 28366 2010-04-15 14:44:38Z vboxsync $ */
2/** @file
3 * VBoxSeamless - Seamless windows
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21#define _WIN32_WINNT 0x0500
22#include <windows.h>
23#include "VBoxTray.h"
24#include "VBoxSeamless.h"
25#include <VBoxHook.h>
26#include <VBoxDisplay.h>
27#include <VBox/VMMDev.h>
28#include <iprt/assert.h>
29#include "helpers.h"
30
31typedef struct _VBOXSEAMLESSCONTEXT
32{
33 const VBOXSERVICEENV *pEnv;
34
35 HMODULE hModule;
36
37 BOOL (* pfnVBoxInstallHook)(HMODULE hDll);
38 BOOL (* pfnVBoxRemoveHook)();
39
40 PVBOXDISPIFESCAPE lpEscapeData;
41} VBOXSEAMLESSCONTEXT;
42
43typedef struct
44{
45 HDC hdc;
46 HRGN hrgn;
47#ifndef MMSEAMLESS
48 RECT rect;
49#endif
50} VBOX_ENUM_PARAM, *PVBOX_ENUM_PARAM;
51
52static VBOXSEAMLESSCONTEXT gCtx = {0};
53
54void VBoxLogString(HANDLE hDriver, char *pszStr);
55
56int VBoxSeamlessInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
57{
58 Log(("VBoxSeamlessInit\n"));
59
60 *pfStartThread = false;
61 gCtx.pEnv = pEnv;
62
63 OSVERSIONINFO OSinfo;
64 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
65 GetVersionEx (&OSinfo);
66
67 /* We have to jump out here when using NT4, otherwise it complains about
68 a missing API function "UnhookWinEvent" used by the dynamically loaded VBoxHook.dll below */
69 if (OSinfo.dwMajorVersion <= 4) /* Windows NT 4.0 or older */
70 {
71 Log(("VBoxSeamlessInit: Windows NT 4.0 or older not supported!\n"));
72 return VERR_NOT_SUPPORTED;
73 }
74
75 /* Will fail if SetWinEventHook is not present (version < NT4 SP6 apparently) */
76 gCtx.hModule = LoadLibrary(VBOXHOOK_DLL_NAME);
77 if (gCtx.hModule)
78 {
79 *(uintptr_t *)&gCtx.pfnVBoxInstallHook = (uintptr_t)GetProcAddress(gCtx.hModule, "VBoxInstallHook");
80 *(uintptr_t *)&gCtx.pfnVBoxRemoveHook = (uintptr_t)GetProcAddress(gCtx.hModule, "VBoxRemoveHook");
81
82 /* inform the host that we support the seamless window mode */
83 VMMDevReqGuestCapabilities vmmreqGuestCaps = {0};
84 vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqGuestCaps, VMMDevReq_ReportGuestCapabilities);
85 vmmreqGuestCaps.caps = VMMDEV_GUEST_SUPPORTS_SEAMLESS;
86
87 DWORD cbReturned;
88 if (!DeviceIoControl(pEnv->hDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqGuestCaps)), &vmmreqGuestCaps, sizeof(vmmreqGuestCaps),
89 &vmmreqGuestCaps, sizeof(vmmreqGuestCaps), &cbReturned, NULL))
90 {
91 Log(("VBoxSeamlessInit: VMMDevReq_ReportGuestCapabilities: error doing IOCTL, last error: %d\n", GetLastError()));
92 return VERR_INVALID_PARAMETER;
93 }
94
95 *pfStartThread = true;
96 *ppInstance = &gCtx;
97 return VINF_SUCCESS;
98 }
99 else
100 {
101 Log(("VBoxSeamlessInit: LoadLibrary failed with %d\n", GetLastError()));
102 return VERR_INVALID_PARAMETER;
103 }
104
105 return VINF_SUCCESS;
106}
107
108
109void VBoxSeamlessDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
110{
111 Log(("VBoxSeamlessDestroy\n"));
112 /* inform the host that we no longer support the seamless window mode */
113 VMMDevReqGuestCapabilities vmmreqGuestCaps = {0};
114 vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqGuestCaps, VMMDevReq_ReportGuestCapabilities);
115 vmmreqGuestCaps.caps = 0;
116
117 DWORD cbReturned;
118 if (!DeviceIoControl(pEnv->hDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqGuestCaps)), &vmmreqGuestCaps, sizeof(vmmreqGuestCaps),
119 &vmmreqGuestCaps, sizeof(vmmreqGuestCaps), &cbReturned, NULL))
120 {
121 Log(("VMMDevReq_ReportGuestCapabilities: error doing IOCTL, last error: %d\n", GetLastError()));
122 }
123
124 if (gCtx.pfnVBoxRemoveHook)
125 gCtx.pfnVBoxRemoveHook();
126 if (gCtx.hModule)
127 FreeLibrary(gCtx.hModule);
128 gCtx.hModule = 0;
129 return;
130}
131
132void VBoxSeamlessInstallHook()
133{
134 if (gCtx.pfnVBoxInstallHook)
135 {
136 /* Check current visible region state */
137 VBoxSeamlessCheckWindows();
138
139 gCtx.pfnVBoxInstallHook(gCtx.hModule);
140 }
141}
142
143void VBoxSeamlessRemoveHook()
144{
145 if (gCtx.pfnVBoxRemoveHook)
146 gCtx.pfnVBoxRemoveHook();
147
148 if (gCtx.lpEscapeData)
149 {
150 free(gCtx.lpEscapeData);
151 gCtx.lpEscapeData = NULL;
152 }
153}
154
155BOOL CALLBACK VBoxEnumFunc(HWND hwnd, LPARAM lParam)
156{
157 PVBOX_ENUM_PARAM lpParam = (PVBOX_ENUM_PARAM)lParam;
158 DWORD dwStyle, dwExStyle;
159 RECT rectWindow, rectVisible;
160
161 dwStyle = GetWindowLong(hwnd, GWL_STYLE);
162 dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
163 if ( !(dwStyle & WS_VISIBLE)
164 || (dwStyle & WS_CHILD))
165 return TRUE;
166
167 Log(("VBoxEnumFunc %x\n", hwnd));
168 /* Only visible windows that are present on the desktop are interesting here */
169#ifndef MMSEAMLESS
170 if ( GetWindowRect(hwnd, &rectWindow)
171 && IntersectRect(&rectVisible, &lpParam->rect, &rectWindow))
172 {
173#else
174 if (GetWindowRect(hwnd, &rectWindow))
175 {
176 rectVisible = rectWindow;
177#endif
178 char szWindowText[256];
179 szWindowText[0] = 0;
180 GetWindowText(hwnd, szWindowText, sizeof(szWindowText));
181
182 /* Filter out Windows XP shadow windows */
183 /** @todo still shows inside the guest */
184 if ( szWindowText[0] == 0
185 && dwStyle == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS)
186 && dwExStyle == (WS_EX_LAYERED|WS_EX_TOOLWINDOW|WS_EX_TRANSPARENT|WS_EX_TOPMOST))
187 {
188 Log(("Filter out shadow window style=%x exstyle=%x\n", dwStyle, dwExStyle));
189 return TRUE;
190 }
191
192 /** @todo will this suffice? The Program Manager window covers the whole screen */
193 if (strcmp(szWindowText, "Program Manager"))
194 {
195 Log(("Enum hwnd=%x rect (%d,%d) (%d,%d)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
196 Log(("title=%s style=%x exStyle=%x\n", szWindowText, dwStyle, dwExStyle));
197
198 HRGN hrgn = CreateRectRgn(0,0,0,0);
199
200 int ret = GetWindowRgn(hwnd, hrgn);
201
202 if (ret == ERROR)
203 {
204 Log(("GetWindowRgn failed with rc=%d\n", GetLastError()));
205 SetRectRgn(hrgn, rectVisible.left, rectVisible.top, rectVisible.right, rectVisible.bottom);
206 }
207 else
208 {
209 /* this region is relative to the window origin instead of the desktop origin */
210 OffsetRgn(hrgn, rectWindow.left, rectWindow.top);
211 }
212 if (lpParam->hrgn)
213 {
214 /* create a union of the current visible region and the visible rectangle of this window. */
215 CombineRgn(lpParam->hrgn, lpParam->hrgn, hrgn, RGN_OR);
216 DeleteObject(hrgn);
217 }
218 else
219 lpParam->hrgn = hrgn;
220 }
221 else
222 {
223 Log(("Enum hwnd=%x rect (%d,%d) (%d,%d) (ignored)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
224 Log(("title=%s style=%x\n", szWindowText, dwStyle));
225 }
226 }
227 return TRUE; /* continue enumeration */
228}
229
230void VBoxSeamlessCheckWindows()
231{
232 VBOX_ENUM_PARAM param;
233
234 param.hdc = GetDC(HWND_DESKTOP);
235 param.hrgn = 0;
236
237#ifndef MMSEAMLESS
238 GetWindowRect(GetDesktopWindow(), &param.rect);
239 Log(("VBoxRecheckVisibleWindows desktop=%x rect (%d,%d) (%d,%d)\n", GetDesktopWindow(), param.rect.left, param.rect.top, param.rect.right, param.rect.bottom));
240#endif
241 EnumWindows(VBoxEnumFunc, (LPARAM)&param);
242
243 if (param.hrgn)
244 {
245 DWORD cbSize;
246
247 cbSize = GetRegionData(param.hrgn, 0, NULL);
248 if (cbSize)
249 {
250 PVBOXDISPIFESCAPE lpEscapeData = (PVBOXDISPIFESCAPE)malloc(VBOXDISPIFESCAPE_SIZE(cbSize));
251 if (lpEscapeData)
252 {
253 lpEscapeData->escapeCode = VBOXESC_SETVISIBLEREGION;
254 LPRGNDATA lpRgnData = VBOXDISPIFESCAPE_DATA(lpEscapeData, RGNDATA);
255 memset(lpRgnData, 0, cbSize);
256 cbSize = GetRegionData(param.hrgn, cbSize, lpRgnData);
257 if (cbSize)
258 {
259#ifdef DEBUG
260 RECT *lpRect = (RECT *)&lpRgnData->Buffer[0];
261 Log(("New visible region: \n"));
262
263 for (DWORD i=0;i<lpRgnData->rdh.nCount;i++)
264 {
265 Log(("visible rect (%d,%d)(%d,%d)\n", lpRect[i].left, lpRect[i].top, lpRect[i].right, lpRect[i].bottom));
266 }
267#endif
268 LPRGNDATA lpCtxRgnData = VBOXDISPIFESCAPE_DATA(gCtx.lpEscapeData, RGNDATA);
269 if ( !gCtx.lpEscapeData
270 || (lpCtxRgnData->rdh.dwSize + lpCtxRgnData->rdh.nRgnSize != cbSize)
271 || memcmp(lpCtxRgnData, lpRgnData, cbSize))
272 {
273 /* send to display driver */
274 VBoxDispIfEscape(&gCtx.pEnv->dispIf, lpEscapeData, cbSize);
275
276 if (gCtx.lpEscapeData)
277 free(gCtx.lpEscapeData);
278 gCtx.lpEscapeData = lpEscapeData;
279 }
280 else
281 Log(("Visible rectangles haven't changed; ignore\n"));
282 }
283 if (lpEscapeData != gCtx.lpEscapeData)
284 free(lpEscapeData);
285 }
286 }
287
288 DeleteObject(param.hrgn);
289 }
290
291 ReleaseDC(HWND_DESKTOP, param.hdc);
292}
293
294/**
295 * Thread function to wait for and process seamless mode change
296 * requests
297 */
298unsigned __stdcall VBoxSeamlessThread(void *pInstance)
299{
300 VBOXSEAMLESSCONTEXT *pCtx = (VBOXSEAMLESSCONTEXT *)pInstance;
301 HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
302 bool fTerminate = false;
303 VBoxGuestFilterMaskInfo maskInfo;
304 DWORD cbReturned;
305 BOOL fWasScreenSaverActive = FALSE, ret;
306
307 maskInfo.u32OrMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
308 maskInfo.u32NotMask = 0;
309 if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
310 {
311 Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask - or) succeeded\n"));
312 }
313 else
314 {
315 Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
316 return 0;
317 }
318
319 do
320 {
321 /* wait for a seamless change event */
322 VBoxGuestWaitEventInfo waitEvent;
323 waitEvent.u32TimeoutIn = 5000;
324 waitEvent.u32EventMaskIn = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
325 if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
326 {
327 Log(("VBoxSeamlessThread: DeviceIOControl succeded\n"));
328
329 /* are we supposed to stop? */
330 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
331 break;
332
333 Log(("VBoxSeamlessThread: checking event\n"));
334
335 /* did we get the right event? */
336 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
337 {
338 Log(("VBoxTray: going to get seamless change information.\n"));
339
340 /* We got at least one event. Read the requested resolution
341 * and try to set it until success. New events will not be seen
342 * but a new resolution will be read in this poll loop.
343 */
344 for (;;)
345 {
346 /* get the seamless change request */
347 VMMDevSeamlessChangeRequest seamlessChangeRequest = {0};
348 vmmdevInitRequest((VMMDevRequestHeader*)&seamlessChangeRequest, VMMDevReq_GetSeamlessChangeRequest);
349 seamlessChangeRequest.eventAck = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
350
351 BOOL fSeamlessChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(seamlessChangeRequest)), &seamlessChangeRequest, sizeof(seamlessChangeRequest),
352 &seamlessChangeRequest, sizeof(seamlessChangeRequest), &cbReturned, NULL);
353 if (fSeamlessChangeQueried)
354 {
355 Log(("VBoxSeamlessThread: mode change to %d\n", seamlessChangeRequest.mode));
356
357 switch(seamlessChangeRequest.mode)
358 {
359 case VMMDev_Seamless_Disabled:
360 if (fWasScreenSaverActive)
361 {
362 Log(("Re-enabling the screensaver\n"));
363 ret = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, NULL, 0);
364 if (!ret)
365 Log(("SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
366 }
367 PostMessage(gToolWindow, WM_VBOX_REMOVE_SEAMLESS_HOOK, 0, 0);
368 break;
369
370 case VMMDev_Seamless_Visible_Region:
371 ret = SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fWasScreenSaverActive, 0);
372 if (!ret)
373 Log(("SystemParametersInfo SPI_GETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
374
375 if (fWasScreenSaverActive)
376 Log(("Disabling the screensaver\n"));
377
378 ret = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
379 if (!ret)
380 Log(("SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
381 PostMessage(gToolWindow, WM_VBOX_INSTALL_SEAMLESS_HOOK, 0, 0);
382 break;
383
384 case VMMDev_Seamless_Host_Window:
385 break;
386
387 default:
388 AssertFailed();
389 break;
390 }
391 break;
392 }
393 else
394 {
395 Log(("VBoxSeamlessThread: error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"));
396 }
397 /* sleep a bit to not eat too much CPU while retrying */
398 /* are we supposed to stop? */
399 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 50) == WAIT_OBJECT_0)
400 {
401 fTerminate = true;
402 break;
403 }
404 }
405 }
406 }
407 else
408 {
409 Log(("VBoxTray: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
410 /* sleep a bit to not eat too much CPU in case the above call always fails */
411 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
412 {
413 fTerminate = true;
414 break;
415 }
416 }
417 }
418 while (!fTerminate);
419
420 maskInfo.u32OrMask = 0;
421 maskInfo.u32NotMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
422 if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
423 {
424 Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask - not) succeeded\n"));
425 }
426 else
427 {
428 Log(("VBoxSeamlessThread: DeviceIOControl(CtlMask) failed\n"));
429 }
430
431 Log(("VBoxSeamlessThread: finished seamless change request thread\n"));
432 return 0;
433}
434
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette