VirtualBox

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

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

vboxtray: 64bit build fix

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