VirtualBox

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

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

wddm: new autoresize mechanism basics

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