VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.cpp@ 42217

Last change on this file since 42217 was 42217, checked in by vboxsync, 12 years ago

wddm: autoresize, etc. fixes, more to follow..

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 31.9 KB
Line 
1/* $Id: VBoxDisplay.cpp 42217 2012-07-18 20:41:29Z vboxsync $ */
2/** @file
3 * VBoxSeamless - Display notifications.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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#define _WIN32_WINNT 0x0500
18#include <windows.h>
19#include "VBoxTray.h"
20#include "VBoxHelpers.h"
21#include "VBoxSeamless.h"
22#include <VBoxHook.h>
23#include <VBoxDisplay.h>
24#include <VBox/VMMDev.h>
25#include <iprt/assert.h>
26#include <malloc.h>
27#include <VBoxGuestInternal.h>
28#ifdef VBOX_WITH_WDDM
29#include <iprt/asm.h>
30#endif
31
32typedef struct _VBOXDISPLAYCONTEXT
33{
34 const VBOXSERVICEENV *pEnv;
35
36 /* ChangeDisplaySettingsEx does not exist in NT. ResizeDisplayDevice uses the function. */
37 LONG (WINAPI * pfnChangeDisplaySettingsEx)(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
38
39 /* EnumDisplayDevices does not exist in NT. isVBoxDisplayDriverActive et al. are using these functions. */
40 BOOL (WINAPI * pfnEnumDisplayDevices)(IN LPCSTR lpDevice, IN DWORD iDevNum, OUT PDISPLAY_DEVICEA lpDisplayDevice, IN DWORD dwFlags);
41} VBOXDISPLAYCONTEXT;
42
43static VBOXDISPLAYCONTEXT gCtx = {0};
44
45#ifdef VBOX_WITH_WDDM
46typedef enum
47{
48 VBOXDISPLAY_DRIVER_TYPE_UNKNOWN = 0,
49 VBOXDISPLAY_DRIVER_TYPE_XPDM = 1,
50 VBOXDISPLAY_DRIVER_TYPE_WDDM = 2
51} VBOXDISPLAY_DRIVER_TYPE;
52
53static VBOXDISPLAY_DRIVER_TYPE getVBoxDisplayDriverType (VBOXDISPLAYCONTEXT *pCtx);
54#endif
55
56int VBoxDisplayInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
57{
58 Log(("VBoxTray: VBoxDisplayInit ...\n"));
59
60 OSVERSIONINFO OSinfo;
61 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
62 GetVersionEx (&OSinfo);
63
64 HMODULE hUser = GetModuleHandle("USER32");
65
66 gCtx.pEnv = pEnv;
67
68 if (NULL == hUser)
69 {
70 Log(("VBoxTray: VBoxDisplayInit: Could not get module handle of USER32.DLL!\n"));
71 return VERR_NOT_IMPLEMENTED;
72 }
73 else if (OSinfo.dwMajorVersion >= 5) /* APIs available only on W2K and up! */
74 {
75 *(uintptr_t *)&gCtx.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
76 Log(("VBoxTray: VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", gCtx.pfnChangeDisplaySettingsEx));
77
78 *(uintptr_t *)&gCtx.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
79 Log(("VBoxTray: VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", gCtx.pfnEnumDisplayDevices));
80
81#ifdef VBOX_WITH_WDDM
82 if (OSinfo.dwMajorVersion >= 6)
83 {
84 /* this is vista and up, check if we need to switch the display driver if to WDDM mode */
85 Log(("VBoxTray: VBoxDisplayInit: this is Windows Vista and up\n"));
86 VBOXDISPLAY_DRIVER_TYPE enmType = getVBoxDisplayDriverType (&gCtx);
87 if (enmType == VBOXDISPLAY_DRIVER_TYPE_WDDM)
88 {
89 Log(("VBoxTray: VBoxDisplayInit: WDDM driver is installed, switching display driver if to WDDM mode\n"));
90 /* this is hacky, but the most easiest way */
91 DWORD err = VBoxDispIfSwitchMode(const_cast<PVBOXDISPIF>(&pEnv->dispIf), VBOXDISPIF_MODE_WDDM, NULL /* old mode, we don't care about it */);
92 if (err == NO_ERROR)
93 Log(("VBoxTray: VBoxDisplayInit: DispIf switched to WDDM mode successfully\n"));
94 else
95 Log(("VBoxTray: VBoxDisplayInit: Failed to switch DispIf to WDDM mode, err (%d)\n", err));
96 }
97 }
98#endif
99 }
100 else if (OSinfo.dwMajorVersion <= 4) /* Windows NT 4.0 */
101 {
102 /* Nothing to do here yet */
103 }
104 else /* Unsupported platform */
105 {
106 Log(("VBoxTray: VBoxDisplayInit: Warning, display for platform not handled yet!\n"));
107 return VERR_NOT_IMPLEMENTED;
108 }
109
110 Log(("VBoxTray: VBoxDisplayInit: Display init successful\n"));
111
112 *pfStartThread = true;
113 *ppInstance = (void *)&gCtx;
114 return VINF_SUCCESS;
115}
116
117void VBoxDisplayDestroy (const VBOXSERVICEENV *pEnv, void *pInstance)
118{
119 return;
120}
121
122#ifdef VBOX_WITH_WDDM
123static VBOXDISPLAY_DRIVER_TYPE getVBoxDisplayDriverType(VBOXDISPLAYCONTEXT *pCtx)
124#else
125static bool isVBoxDisplayDriverActive(VBOXDISPLAYCONTEXT *pCtx)
126#endif
127{
128#ifdef VBOX_WITH_WDDM
129 VBOXDISPLAY_DRIVER_TYPE enmType = VBOXDISPLAY_DRIVER_TYPE_UNKNOWN;
130#else
131 bool result = false;
132#endif
133
134 if( pCtx->pfnEnumDisplayDevices )
135 {
136 INT devNum = 0;
137 DISPLAY_DEVICE dispDevice;
138 FillMemory(&dispDevice, sizeof(DISPLAY_DEVICE), 0);
139 dispDevice.cb = sizeof(DISPLAY_DEVICE);
140
141 Log(("VBoxTray: isVBoxDisplayDriverActive: Checking for active VBox display driver (W2K+) ...\n"));
142
143 while (EnumDisplayDevices(NULL,
144 devNum,
145 &dispDevice,
146 0))
147 {
148 Log(("VBoxTray: isVBoxDisplayDriverActive: DevNum:%d\nName:%s\nString:%s\nID:%s\nKey:%s\nFlags=%08X\n\n",
149 devNum,
150 &dispDevice.DeviceName[0],
151 &dispDevice.DeviceString[0],
152 &dispDevice.DeviceID[0],
153 &dispDevice.DeviceKey[0],
154 dispDevice.StateFlags));
155
156 if (dispDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
157 {
158 Log(("VBoxTray: isVBoxDisplayDriverActive: Primary device\n"));
159
160 if (strcmp(&dispDevice.DeviceString[0], "VirtualBox Graphics Adapter") == 0)
161#ifndef VBOX_WITH_WDDM
162 result = true;
163#else
164 enmType = VBOXDISPLAY_DRIVER_TYPE_XPDM;
165 /* WDDM driver can now have multiple incarnations,
166 * if the driver name contains VirtualBox, and does NOT match the XPDM name,
167 * assume it to be WDDM */
168 else if (strstr(&dispDevice.DeviceString[0], "VirtualBox"))
169 enmType = VBOXDISPLAY_DRIVER_TYPE_WDDM;
170#endif
171 break;
172 }
173
174 FillMemory(&dispDevice, sizeof(DISPLAY_DEVICE), 0);
175
176 dispDevice.cb = sizeof(DISPLAY_DEVICE);
177
178 devNum++;
179 }
180 }
181 else /* This must be NT 4 or something really old, so don't use EnumDisplayDevices() here ... */
182 {
183 Log(("VBoxTray: isVBoxDisplayDriverActive: Checking for active VBox display driver (NT or older) ...\n"));
184
185 DEVMODE tempDevMode;
186 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
187 tempDevMode.dmSize = sizeof(DEVMODE);
188 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &tempDevMode); /* Get current display device settings */
189
190 /* Check for the short name, because all long stuff would be truncated */
191 if (strcmp((char*)&tempDevMode.dmDeviceName[0], "VBoxDisp") == 0)
192#ifndef VBOX_WITH_WDDM
193 result = true;
194#else
195 enmType = VBOXDISPLAY_DRIVER_TYPE_XPDM;
196#endif
197 }
198
199#ifndef VBOX_WITH_WDDM
200 return result;
201#else
202 return enmType;
203#endif
204}
205
206/* Returns TRUE to try again. */
207static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel,
208 VBOXDISPLAYCONTEXT *pCtx)
209{
210 BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
211
212 DISPLAY_DEVICE DisplayDevice;
213
214 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
215 DisplayDevice.cb = sizeof(DisplayDevice);
216
217 /* Find out how many display devices the system has */
218 DWORD NumDevices = 0;
219 DWORD i = 0;
220 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
221 {
222 Log(("VBoxTray: ResizeDisplayDevice: [%d] %s\n", i, DisplayDevice.DeviceName));
223
224 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
225 {
226 Log(("VBoxTray: ResizeDisplayDevice: Found primary device. err %d\n", GetLastError ()));
227 NumDevices++;
228 }
229 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
230 {
231
232 Log(("VBoxTray: ResizeDisplayDevice: Found secondary device. err %d\n", GetLastError ()));
233 NumDevices++;
234 }
235
236 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
237 DisplayDevice.cb = sizeof(DisplayDevice);
238 i++;
239 }
240
241 Log(("VBoxTray: ResizeDisplayDevice: Found total %d devices. err %d\n", NumDevices, GetLastError ()));
242
243 if (NumDevices == 0 || Id >= NumDevices)
244 {
245 Log(("VBoxTray: ResizeDisplayDevice: Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
246 return FALSE;
247 }
248
249 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
250 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
251 RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
252
253 /* Fetch information about current devices and modes. */
254 DWORD DevNum = 0;
255 DWORD DevPrimaryNum = 0;
256
257 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
258 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
259
260 i = 0;
261 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
262 {
263 Log(("VBoxTray: ResizeDisplayDevice: [%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
264
265 BOOL bFetchDevice = FALSE;
266
267 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
268 {
269 Log(("VBoxTray: ResizeDisplayDevice: Found primary device. err %d\n", GetLastError ()));
270 DevPrimaryNum = DevNum;
271 bFetchDevice = TRUE;
272 }
273 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
274 {
275
276 Log(("VBoxTray: ResizeDisplayDevice: Found secondary device. err %d\n", GetLastError ()));
277 bFetchDevice = TRUE;
278 }
279
280 if (bFetchDevice)
281 {
282 if (DevNum >= NumDevices)
283 {
284 Log(("VBoxTray: ResizeDisplayDevice: %d >= %d\n", NumDevices, DevNum));
285 return FALSE;
286 }
287
288 paDisplayDevices[DevNum] = DisplayDevice;
289
290 /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
291 * A secondary display could be not active at the moment and would not have
292 * a current video mode (ENUM_CURRENT_SETTINGS).
293 */
294 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
295 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
296 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
297 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
298 {
299 Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings error %d\n", GetLastError ()));
300 return FALSE;
301 }
302
303 if ( paDeviceModes[DevNum].dmPelsWidth == 0
304 || paDeviceModes[DevNum].dmPelsHeight == 0)
305 {
306 /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
307 * Get the current video mode then.
308 */
309 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
310 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
311 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
312 ENUM_CURRENT_SETTINGS, &paDeviceModes[DevNum]))
313 {
314 /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
315 * for example a disabled secondary display.
316 * Do not return here, ignore the error and set the display info to 0x0x0.
317 */
318 Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
319 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
320 }
321 }
322
323 Log(("VBoxTray: ResizeDisplayDevice: %dx%dx%d at %d,%d\n",
324 paDeviceModes[DevNum].dmPelsWidth,
325 paDeviceModes[DevNum].dmPelsHeight,
326 paDeviceModes[DevNum].dmBitsPerPel,
327 paDeviceModes[DevNum].dmPosition.x,
328 paDeviceModes[DevNum].dmPosition.y));
329
330 paRects[DevNum].left = paDeviceModes[DevNum].dmPosition.x;
331 paRects[DevNum].top = paDeviceModes[DevNum].dmPosition.y;
332 paRects[DevNum].right = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
333 paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
334 DevNum++;
335 }
336
337 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
338 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
339 i++;
340 }
341
342 /* Width, height equal to 0 means that this value must be not changed.
343 * Update input parameters if necessary.
344 * Note: BitsPerPixel is taken into account later, when new rectangles
345 * are assigned to displays.
346 */
347 if (Width == 0)
348 {
349 Width = paRects[Id].right - paRects[Id].left;
350 }
351
352 if (Height == 0)
353 {
354 Height = paRects[Id].bottom - paRects[Id].top;
355 }
356
357 /* Check whether a mode reset or a change is requested. */
358 if ( !fModeReset
359 && paRects[Id].right - paRects[Id].left == Width
360 && paRects[Id].bottom - paRects[Id].top == Height
361 && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
362 {
363 Log(("VBoxTray: ResizeDisplayDevice: Already at desired resolution\n"));
364 return FALSE;
365 }
366
367 hlpResizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
368#ifdef Log
369 for (i = 0; i < NumDevices; i++)
370 {
371 Log(("VBoxTray: ResizeDisplayDevice: [%d]: %d,%d %dx%d\n",
372 i, paRects[i].left, paRects[i].top,
373 paRects[i].right - paRects[i].left,
374 paRects[i].bottom - paRects[i].top));
375 }
376#endif /* Log */
377
378#ifdef VBOX_WITH_WDDM
379 VBOXDISPLAY_DRIVER_TYPE enmDriverType = getVBoxDisplayDriverType (pCtx);
380 if (enmDriverType == VBOXDISPLAY_DRIVER_TYPE_WDDM)
381 {
382 /* Assign the new rectangles to displays. */
383 for (i = 0; i < NumDevices; i++)
384 {
385 paDeviceModes[i].dmPosition.x = paRects[i].left;
386 paDeviceModes[i].dmPosition.y = paRects[i].top;
387 paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
388 paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
389
390 /* On Vista one must specify DM_BITSPERPEL.
391 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
392 */
393 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
394
395 if ( i == Id
396 && BitsPerPixel != 0)
397 {
398 /* Change dmBitsPerPel if requested. */
399 paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
400 }
401
402 Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
403 gCtx.pfnChangeDisplaySettingsEx,
404 paDeviceModes[i].dmPelsWidth,
405 paDeviceModes[i].dmPelsHeight,
406 paDeviceModes[i].dmBitsPerPel,
407 paDeviceModes[i].dmPosition.x,
408 paDeviceModes[i].dmPosition.y));
409
410 }
411
412 DWORD err = VBoxDispIfResizeModes(&pCtx->pEnv->dispIf, Id, paDisplayDevices, paDeviceModes, NumDevices);
413 if (err == NO_ERROR || err != ERROR_RETRY)
414 {
415 if (err == NO_ERROR)
416 Log(("VBoxTray: VBoxDisplayThread: (WDDM) VBoxDispIfResizeModes succeeded\n"));
417 else
418 Log(("VBoxTray: VBoxDisplayThread: (WDDM) Failure VBoxDispIfResizeModes (%d)\n", err));
419 return FALSE;
420 }
421
422 Log(("VBoxTray: ResizeDisplayDevice: (WDDM) RETRY requested\n"));
423 return TRUE;
424 }
425#endif
426 /* Without this, Windows will not ask the miniport for its
427 * mode table but uses an internal cache instead.
428 */
429 for (i = 0; i < NumDevices; i++)
430 {
431 DEVMODE tempDevMode;
432 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
433 tempDevMode.dmSize = sizeof(DEVMODE);
434 EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
435 Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
436 }
437
438 /* Assign the new rectangles to displays. */
439 for (i = 0; i < NumDevices; i++)
440 {
441 paDeviceModes[i].dmPosition.x = paRects[i].left;
442 paDeviceModes[i].dmPosition.y = paRects[i].top;
443 paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
444 paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
445
446 /* On Vista one must specify DM_BITSPERPEL.
447 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
448 */
449 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
450
451 if ( i == Id
452 && BitsPerPixel != 0)
453 {
454 /* Change dmBitsPerPel if requested. */
455 paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
456 }
457
458 Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
459 gCtx.pfnChangeDisplaySettingsEx,
460 paDeviceModes[i].dmPelsWidth,
461 paDeviceModes[i].dmPelsHeight,
462 paDeviceModes[i].dmBitsPerPel,
463 paDeviceModes[i].dmPosition.x,
464 paDeviceModes[i].dmPosition.y));
465
466 LONG status = gCtx.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
467 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
468 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", status, GetLastError ()));
469 }
470
471 /* A second call to ChangeDisplaySettings updates the monitor. */
472 LONG status = gCtx.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
473 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
474 if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
475 {
476 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
477 return FALSE;
478 }
479
480 /* Retry the request. */
481 return TRUE;
482}
483
484/**
485 * Thread function to wait for and process display change
486 * requests
487 */
488unsigned __stdcall VBoxDisplayThread(void *pInstance)
489{
490 Log(("VBoxTray: VBoxDisplayThread: Entered\n"));
491
492 VBOXDISPLAYCONTEXT *pCtx = (VBOXDISPLAYCONTEXT *)pInstance;
493 HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
494 bool fTerminate = false;
495 VBoxGuestFilterMaskInfo maskInfo;
496 DWORD cbReturned;
497
498 maskInfo.u32OrMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED;
499 maskInfo.u32NotMask = 0;
500 if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
501 {
502 Log(("VBoxTray: VBoxDisplayThread: DeviceIOControl(CtlMask - or) failed, thread exiting\n"));
503 return 0;
504 }
505
506 int rc = VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0);
507 if (RT_FAILURE(rc))
508 {
509 LogRel(("VBoxTray: VBoxDisplayThread: Failed to set the graphics capability with rc=%Rrc, thread exiting\n", rc));
510 return 0;
511 }
512
513 do
514 {
515 /* Wait for a display change event. */
516 VBoxGuestWaitEventInfo waitEvent;
517 waitEvent.u32TimeoutIn = 1000;
518 waitEvent.u32EventMaskIn = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED;
519 if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
520 {
521 /*Log(("VBoxTray: VBoxDisplayThread: DeviceIOControl succeeded\n"));*/
522
523 if (NULL == pCtx) {
524 Log(("VBoxTray: VBoxDisplayThread: Invalid context detected!\n"));
525 break;
526 }
527
528 if (NULL == pCtx->pEnv) {
529 Log(("VBoxTray: VBoxDisplayThread: Invalid context environment detected!\n"));
530 break;
531 }
532
533 /* are we supposed to stop? */
534 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
535 break;
536
537 /*Log(("VBoxTray: VBoxDisplayThread: checking event\n"));*/
538
539 /* did we get the right event? */
540 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
541 {
542 Log(("VBoxTray: VBoxDisplayThread: going to get display change information\n"));
543
544 /* We got at least one event. Read the requested resolution
545 * and try to set it until success. New events will not be seen
546 * but a new resolution will be read in this poll loop.
547 */
548 VMMDevDisplayChangeRequest2 displayChangeRequest = {0};
549 displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest2);
550 displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
551 displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest2;
552 displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
553 BOOL fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequest2)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2),
554 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2), &cbReturned, NULL);
555 if (!fDisplayChangeQueried)
556 {
557 /* Try the old version of the request for old VBox hosts. */
558 displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest);
559 displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
560 displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest;
561 displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
562 fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequest)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest),
563 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest), &cbReturned, NULL);
564 displayChangeRequest.display = 0;
565 }
566
567 if (fDisplayChangeQueried)
568 {
569 /* Try to set the requested video mode. Repeat until it is successful or is rejected by the driver. */
570 for (;;)
571 {
572 Log(("VBoxTray: VBoxDisplayThread: VMMDevReq_GetDisplayChangeRequest2: %dx%dx%d at %d\n", displayChangeRequest.xres, displayChangeRequest.yres, displayChangeRequest.bpp, displayChangeRequest.display));
573
574 /*
575 * Only try to change video mode if the active display driver is VBox additions.
576 */
577#ifdef VBOX_WITH_WDDM
578 VBOXDISPLAY_DRIVER_TYPE enmDriverType = getVBoxDisplayDriverType (pCtx);
579
580 if (enmDriverType == VBOXDISPLAY_DRIVER_TYPE_WDDM)
581 Log(("VBoxTray: VBoxDisplayThread: Detected WDDM Driver\n"));
582
583 if (enmDriverType != VBOXDISPLAY_DRIVER_TYPE_UNKNOWN)
584#else
585 if (isVBoxDisplayDriverActive (pCtx))
586#endif
587 {
588 Log(("VBoxTray: VBoxDisplayThread: Display driver is active!\n"));
589
590 if (pCtx->pfnChangeDisplaySettingsEx != 0)
591 {
592 Log(("VBoxTray: VBoxDisplayThread: Detected W2K or later\n"));
593
594 /* W2K or later. */
595 if (!ResizeDisplayDevice(displayChangeRequest.display,
596 displayChangeRequest.xres,
597 displayChangeRequest.yres,
598 displayChangeRequest.bpp,
599 pCtx
600 ))
601 {
602 break;
603 }
604 }
605 else
606 {
607 Log(("VBoxTray: VBoxDisplayThread: Detected NT\n"));
608
609 /* Single monitor NT. */
610 DEVMODE devMode;
611 RT_ZERO(devMode);
612 devMode.dmSize = sizeof(DEVMODE);
613
614 /* get the current screen setup */
615 if (EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
616 {
617 Log(("VBoxTray: VBoxDisplayThread: Current mode: %d x %d x %d at %d,%d\n",
618 devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmPosition.x, devMode.dmPosition.y));
619
620 /* Check whether a mode reset or a change is requested. */
621 if (displayChangeRequest.xres || displayChangeRequest.yres || displayChangeRequest.bpp)
622 {
623 /* A change is requested.
624 * Set values which are not to be changed to the current values.
625 */
626 if (!displayChangeRequest.xres)
627 displayChangeRequest.xres = devMode.dmPelsWidth;
628 if (!displayChangeRequest.yres)
629 displayChangeRequest.yres = devMode.dmPelsHeight;
630 if (!displayChangeRequest.bpp)
631 displayChangeRequest.bpp = devMode.dmBitsPerPel;
632 }
633 else
634 {
635 /* All zero values means a forced mode reset. Do nothing. */
636 Log(("VBoxTray: VBoxDisplayThread: Forced mode reset\n"));
637 }
638
639 /* Verify that the mode is indeed changed. */
640 if ( devMode.dmPelsWidth == displayChangeRequest.xres
641 && devMode.dmPelsHeight == displayChangeRequest.yres
642 && devMode.dmBitsPerPel == displayChangeRequest.bpp)
643 {
644 Log(("VBoxTray: VBoxDisplayThread: already at desired resolution\n"));
645 break;
646 }
647
648 // without this, Windows will not ask the miniport for its
649 // mode table but uses an internal cache instead
650 DEVMODE tempDevMode = {0};
651 tempDevMode.dmSize = sizeof(DEVMODE);
652 EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
653
654 /* adjust the values that are supposed to change */
655 if (displayChangeRequest.xres)
656 devMode.dmPelsWidth = displayChangeRequest.xres;
657 if (displayChangeRequest.yres)
658 devMode.dmPelsHeight = displayChangeRequest.yres;
659 if (displayChangeRequest.bpp)
660 devMode.dmBitsPerPel = displayChangeRequest.bpp;
661
662 Log(("VBoxTray: VBoxDisplayThread: setting new mode %d x %d, %d BPP\n",
663 devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel));
664
665 /* set the new mode */
666 LONG status = ChangeDisplaySettings(&devMode, CDS_UPDATEREGISTRY);
667 if (status != DISP_CHANGE_SUCCESSFUL)
668 {
669 Log(("VBoxTray: VBoxDisplayThread: error from ChangeDisplaySettings: %d\n", status));
670
671 if (status == DISP_CHANGE_BADMODE)
672 {
673 /* Our driver can not set the requested mode. Stop trying. */
674 break;
675 }
676 }
677 else
678 {
679 /* Successfully set new video mode. */
680 break;
681 }
682 }
683 else
684 {
685 Log(("VBoxTray: VBoxDisplayThread: error from EnumDisplaySettings: %d\n", GetLastError ()));
686 break;
687 }
688 }
689 }
690 else
691 {
692 Log(("VBoxTray: VBoxDisplayThread: vboxDisplayDriver is not active\n"));
693 }
694
695 /* Retry the change a bit later. */
696 /* are we supposed to stop? */
697 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0)
698 {
699 fTerminate = true;
700 break;
701 }
702 }
703 }
704 else
705 {
706 Log(("VBoxTray: VBoxDisplayThread: error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"));
707 /* sleep a bit to not eat too much CPU while retrying */
708 /* are we supposed to stop? */
709 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 50) == WAIT_OBJECT_0)
710 {
711 fTerminate = true;
712 break;
713 }
714 }
715 }
716 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED)
717 hlpReloadCursor();
718 } else
719 {
720 Log(("VBoxTray: VBoxDisplayThread: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
721 /* sleep a bit to not eat too much CPU in case the above call always fails */
722 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
723 {
724 fTerminate = true;
725 break;
726 }
727 }
728 } while (!fTerminate);
729
730 /*
731 * Remove event filter and graphics capability report.
732 */
733 maskInfo.u32OrMask = 0;
734 maskInfo.u32NotMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED;
735 if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
736 Log(("VBoxTray: VBoxDisplayThread: DeviceIOControl(CtlMask - not) failed\n"));
737 VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS);
738
739 Log(("VBoxTray: VBoxDisplayThread: finished display change request thread\n"));
740 return 0;
741}
Note: See TracBrowser for help on using the repository browser.

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