VirtualBox

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

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

wddm: vboxtray: abstraction display driver API for passing escape codes (using ExtEscape for XPDM & PFND3DKMT stugg for WDDM); WDDM miniport driver: basics for handling autoresize & seamles

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 29.6 KB
 
1/* $Id: VBoxDisplay.cpp 27955 2010-04-02 09:12:26Z 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.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#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#ifdef VBOXWDDM
217 VBOXDISPLAYCONTEXT *pCtx, VBOXDISPLAY_DRIVER_TYPE enmType,
218#endif
219 ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel
220 )
221{
222 BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
223
224 DISPLAY_DEVICE DisplayDevice;
225
226 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
227 DisplayDevice.cb = sizeof(DisplayDevice);
228
229 /* Find out how many display devices the system has */
230 DWORD NumDevices = 0;
231 DWORD i = 0;
232 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
233 {
234 Log(("[%d] %s\n", i, DisplayDevice.DeviceName));
235
236 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
237 {
238 Log(("ResizeDisplayDevice: Found primary device. err %d\n", GetLastError ()));
239 NumDevices++;
240 }
241 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
242 {
243
244 Log(("ResizeDisplayDevice: Found secondary device. err %d\n", GetLastError ()));
245 NumDevices++;
246 }
247
248 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
249 DisplayDevice.cb = sizeof(DisplayDevice);
250 i++;
251 }
252
253 Log(("ResizeDisplayDevice: Found total %d devices. err %d\n", NumDevices, GetLastError ()));
254
255 if (NumDevices == 0 || Id >= NumDevices)
256 {
257 Log(("ResizeDisplayDevice: Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
258 return FALSE;
259 }
260
261 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
262 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
263 RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
264
265 /* Fetch information about current devices and modes. */
266 DWORD DevNum = 0;
267 DWORD DevPrimaryNum = 0;
268
269 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
270 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
271
272 i = 0;
273 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
274 {
275 Log(("ResizeDisplayDevice: [%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
276
277 BOOL bFetchDevice = FALSE;
278
279 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
280 {
281 Log(("ResizeDisplayDevice: Found primary device. err %d\n", GetLastError ()));
282 DevPrimaryNum = DevNum;
283 bFetchDevice = TRUE;
284 }
285 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
286 {
287
288 Log(("ResizeDisplayDevice: Found secondary device. err %d\n", GetLastError ()));
289 bFetchDevice = TRUE;
290 }
291
292 if (bFetchDevice)
293 {
294 if (DevNum >= NumDevices)
295 {
296 Log(("ResizeDisplayDevice: %d >= %d\n", NumDevices, DevNum));
297 return FALSE;
298 }
299
300 paDisplayDevices[DevNum] = DisplayDevice;
301
302 /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
303 * A secondary display could be not active at the moment and would not have
304 * a current video mode (ENUM_CURRENT_SETTINGS).
305 */
306 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
307 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
308 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
309 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
310 {
311 Log(("ResizeDisplayDevice: EnumDisplaySettings err %d\n", GetLastError ()));
312 return FALSE;
313 }
314
315 if ( paDeviceModes[DevNum].dmPelsWidth == 0
316 || paDeviceModes[DevNum].dmPelsHeight == 0)
317 {
318 /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
319 * Get the current video mode then.
320 */
321 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
322 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
323 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
324 ENUM_CURRENT_SETTINGS, &paDeviceModes[DevNum]))
325 {
326 /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
327 * for example a disabled secondary display.
328 * Do not return here, ignore the error and set the display info to 0x0x0.
329 */
330 Log(("EnumDisplaySettings(ENUM_CURRENT_SETTINGS) err %d\n", GetLastError ()));
331 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
332 }
333 }
334
335 Log(("ResizeDisplayDevice: %dx%dx%d at %d,%d\n",
336 paDeviceModes[DevNum].dmPelsWidth,
337 paDeviceModes[DevNum].dmPelsHeight,
338 paDeviceModes[DevNum].dmBitsPerPel,
339 paDeviceModes[DevNum].dmPosition.x,
340 paDeviceModes[DevNum].dmPosition.y));
341
342 paRects[DevNum].left = paDeviceModes[DevNum].dmPosition.x;
343 paRects[DevNum].top = paDeviceModes[DevNum].dmPosition.y;
344 paRects[DevNum].right = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
345 paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
346 DevNum++;
347 }
348
349 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
350 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
351 i++;
352 }
353
354 /* Width, height equal to 0 means that this value must be not changed.
355 * Update input parameters if necessary.
356 * Note: BitsPerPixel is taken into account later, when new rectangles
357 * are assigned to displays.
358 */
359 if (Width == 0)
360 {
361 Width = paRects[Id].right - paRects[Id].left;
362 }
363
364 if (Height == 0)
365 {
366 Height = paRects[Id].bottom - paRects[Id].top;
367 }
368
369 /* Check whether a mode reset or a change is requested. */
370 if ( !fModeReset
371 && paRects[Id].right - paRects[Id].left == Width
372 && paRects[Id].bottom - paRects[Id].top == Height
373 && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
374 {
375 Log(("ResizeDisplayDevice: Already at desired resolution.\n"));
376 return FALSE;
377 }
378
379 resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
380#ifdef Log
381 for (i = 0; i < NumDevices; i++)
382 {
383 Log(("ResizeDisplayDevice: [%d]: %d,%d %dx%d\n",
384 i, paRects[i].left, paRects[i].top,
385 paRects[i].right - paRects[i].left,
386 paRects[i].bottom - paRects[i].top));
387 }
388#endif /* Log */
389
390 /* Without this, Windows will not ask the miniport for its
391 * mode table but uses an internal cache instead.
392 */
393 for (i = 0; i < NumDevices; i++)
394 {
395 DEVMODE tempDevMode;
396 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
397 tempDevMode.dmSize = sizeof(DEVMODE);
398 EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
399 Log(("ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
400 }
401
402#ifdef VBOXWDDM
403 if (enmType == VBOXDISPLAY_DRIVER_TYPE_WDDM)
404 vboxWddmReinitVideoModes(pCtx);
405#endif
406
407 /* Assign the new rectangles to displays. */
408 for (i = 0; i < NumDevices; i++)
409 {
410 paDeviceModes[i].dmPosition.x = paRects[i].left;
411 paDeviceModes[i].dmPosition.y = paRects[i].top;
412 paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
413 paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
414
415 /* On Vista one must specify DM_BITSPERPEL.
416 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
417 */
418 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
419
420 if ( i == Id
421 && BitsPerPixel != 0)
422 {
423 /* Change dmBitsPerPel if requested. */
424 paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
425 }
426
427 Log(("ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
428 gCtx.pfnChangeDisplaySettingsEx,
429 paDeviceModes[i].dmPelsWidth,
430 paDeviceModes[i].dmPelsHeight,
431 paDeviceModes[i].dmBitsPerPel,
432 paDeviceModes[i].dmPosition.x,
433 paDeviceModes[i].dmPosition.y));
434
435 LONG status = gCtx.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
436 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
437 Log(("ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", status, GetLastError ()));
438 }
439
440 /* A second call to ChangeDisplaySettings updates the monitor. */
441 LONG status = gCtx.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
442 Log(("ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
443 if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
444 {
445 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
446 return FALSE;
447 }
448
449 /* Retry the request. */
450 return TRUE;
451}
452
453/**
454 * Thread function to wait for and process display change
455 * requests
456 */
457unsigned __stdcall VBoxDisplayThread (void *pInstance)
458{
459 VBOXDISPLAYCONTEXT *pCtx = (VBOXDISPLAYCONTEXT *)pInstance;
460 HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
461 bool fTerminate = false;
462 VBoxGuestFilterMaskInfo maskInfo;
463 DWORD cbReturned;
464
465 maskInfo.u32OrMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED;
466 maskInfo.u32NotMask = 0;
467 if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
468 {
469 Log(("VBoxDisplayThread : DeviceIOControl(CtlMask - or) succeeded\n"));
470 }
471 else
472 {
473 Log(("VBoxDisplayThread : DeviceIOControl(CtlMask) failed, DisplayChangeThread exited\n"));
474 return -1;
475 }
476
477 do
478 {
479 /* wait for a display change event */
480 VBoxGuestWaitEventInfo waitEvent;
481 waitEvent.u32TimeoutIn = 1000;
482 waitEvent.u32EventMaskIn = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED;
483 if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
484 {
485 /*Log(("VBoxDisplayThread : DeviceIOControl succeded\n"));*/
486
487 if (NULL == pCtx) {
488 Log(("VBoxDisplayThread : Invalid context detected!\n"));
489 break;
490 }
491
492 if (NULL == pCtx->pEnv) {
493 Log(("VBoxDisplayThread : Invalid context environment detected!\n"));
494 break;
495 }
496
497 /* are we supposed to stop? */
498 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
499 break;
500
501 /*Log(("VBoxDisplayThread : checking event\n"));*/
502
503 /* did we get the right event? */
504 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
505 {
506 Log(("VBoxDisplayThread : going to get display change information.\n"));
507
508 /* We got at least one event. Read the requested resolution
509 * and try to set it until success. New events will not be seen
510 * but a new resolution will be read in this poll loop.
511 */
512 for (;;)
513 {
514 /* get the display change request */
515 VMMDevDisplayChangeRequest2 displayChangeRequest = {0};
516 displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest2);
517 displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
518 displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest2;
519 displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
520 BOOL fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequest2)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2),
521 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2), &cbReturned, NULL);
522 if (!fDisplayChangeQueried)
523 {
524 /* Try the old version of the request for old VBox hosts. */
525 displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest);
526 displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
527 displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest;
528 displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
529 fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequest)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest),
530 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest), &cbReturned, NULL);
531 displayChangeRequest.display = 0;
532 }
533
534 if (fDisplayChangeQueried)
535 {
536 Log(("VBoxDisplayThread : VMMDevReq_GetDisplayChangeRequest2: %dx%dx%d at %d\n", displayChangeRequest.xres, displayChangeRequest.yres, displayChangeRequest.bpp, displayChangeRequest.display));
537
538 /* Horizontal resolution must be a multiple of 8, round down. */
539 displayChangeRequest.xres &= 0xfff8;
540
541 /*
542 * Only try to change video mode if the active display driver is VBox additions.
543 */
544#ifdef VBOXWDDM
545 VBOXDISPLAY_DRIVER_TYPE enmDriverType = getVBoxDisplayDriverType (pCtx);
546
547 if (enmDriverType == VBOXDISPLAY_DRIVER_TYPE_WDDM)
548 Log(("VBoxDisplayThread : Detected WDDM Driver\n"));
549
550 if (enmDriverType != VBOXDISPLAY_DRIVER_TYPE_UNKNOWN)
551#else
552 if (isVBoxDisplayDriverActive (pCtx))
553#endif
554 {
555 Log(("VBoxDisplayThread : Display driver is active!\n"));
556
557 if (pCtx->pfnChangeDisplaySettingsEx != 0)
558 {
559 Log(("VBoxDisplayThread : Detected W2K or later.\n"));
560
561 /* W2K or later. */
562 if (!ResizeDisplayDevice(
563#ifdef VBOXWDDM
564 pCtx, enmDriverType ,
565#endif
566 displayChangeRequest.display,
567 displayChangeRequest.xres,
568 displayChangeRequest.yres,
569 displayChangeRequest.bpp
570 ))
571 {
572 break;
573 }
574 }
575 else
576 {
577 Log(("VBoxDisplayThread : Detected NT.\n"));
578
579 /* Single monitor NT. */
580 DEVMODE devMode;
581 RT_ZERO(devMode);
582 devMode.dmSize = sizeof(DEVMODE);
583
584 /* get the current screen setup */
585 if (EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
586 {
587 Log(("VBoxDisplayThread : Current mode: %dx%dx%d at %d,%d\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmPosition.x, devMode.dmPosition.y));
588
589 /* Check whether a mode reset or a change is requested. */
590 if (displayChangeRequest.xres || displayChangeRequest.yres || displayChangeRequest.bpp)
591 {
592 /* A change is requested.
593 * Set values which are not to be changed to the current values.
594 */
595 if (!displayChangeRequest.xres)
596 displayChangeRequest.xres = devMode.dmPelsWidth;
597 if (!displayChangeRequest.yres)
598 displayChangeRequest.yres = devMode.dmPelsHeight;
599 if (!displayChangeRequest.bpp)
600 displayChangeRequest.bpp = devMode.dmBitsPerPel;
601 }
602 else
603 {
604 /* All zero values means a forced mode reset. Do nothing. */
605 Log(("VBoxDisplayThread : Forced mode reset.\n"));
606 }
607
608 /* Verify that the mode is indeed changed. */
609 if ( devMode.dmPelsWidth == displayChangeRequest.xres
610 && devMode.dmPelsHeight == displayChangeRequest.yres
611 && devMode.dmBitsPerPel == displayChangeRequest.bpp)
612 {
613 Log(("VBoxDisplayThread : already at desired resolution.\n"));
614 break;
615 }
616
617 // without this, Windows will not ask the miniport for its
618 // mode table but uses an internal cache instead
619 DEVMODE tempDevMode = {0};
620 tempDevMode.dmSize = sizeof(DEVMODE);
621 EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
622
623 /* adjust the values that are supposed to change */
624 if (displayChangeRequest.xres)
625 devMode.dmPelsWidth = displayChangeRequest.xres;
626 if (displayChangeRequest.yres)
627 devMode.dmPelsHeight = displayChangeRequest.yres;
628 if (displayChangeRequest.bpp)
629 devMode.dmBitsPerPel = displayChangeRequest.bpp;
630
631 Log(("VBoxDisplayThread : setting the new mode %dx%dx%d\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel));
632
633 /* set the new mode */
634 LONG status = ChangeDisplaySettings(&devMode, CDS_UPDATEREGISTRY);
635 if (status != DISP_CHANGE_SUCCESSFUL)
636 {
637 Log(("VBoxDisplayThread : error from ChangeDisplaySettings: %d\n", status));
638
639 if (status == DISP_CHANGE_BADMODE)
640 {
641 /* Our driver can not set the requested mode. Stop trying. */
642 break;
643 }
644 }
645 else
646 {
647 /* Successfully set new video mode. */
648 break;
649 }
650 }
651 else
652 {
653 Log(("VBoxDisplayThread : error from EnumDisplaySettings: %d\n", GetLastError ()));
654 break;
655 }
656 }
657 }
658 else
659 {
660 Log(("VBoxDisplayThread : vboxDisplayDriver is not active.\n"));
661 }
662
663 /* Retry the change a bit later. */
664 /* are we supposed to stop? */
665 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0)
666 {
667 fTerminate = true;
668 break;
669 }
670 }
671 else
672 {
673 Log(("VBoxDisplayThread : error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"));
674 /* sleep a bit to not eat too much CPU while retrying */
675 /* are we supposed to stop? */
676 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 50) == WAIT_OBJECT_0)
677 {
678 fTerminate = true;
679 break;
680 }
681 }
682 }
683 }
684 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED)
685 VBoxServiceReloadCursor();
686 } else
687 {
688 Log(("VBoxDisplayThread : error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
689 /* sleep a bit to not eat too much CPU in case the above call always fails */
690 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
691 {
692 fTerminate = true;
693 break;
694 }
695 }
696 } while (!fTerminate);
697
698 maskInfo.u32OrMask = 0;
699 maskInfo.u32NotMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED;
700 if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
701 {
702 Log(("VBoxDisplayThread : DeviceIOControl(CtlMask - not) succeeded\n"));
703 }
704 else
705 {
706 Log(("VBoxDisplayThread : DeviceIOControl(CtlMask) failed\n"));
707 }
708
709 Log(("VBoxDisplayThread : finished display change request thread\n"));
710 return 0;
711}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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