VirtualBox

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

Last change on this file since 27992 was 27988, checked in by vboxsync, 15 years ago

wddm: more impl for guest autoresize support

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