VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxService/VBoxService.cpp@ 3198

Last change on this file since 3198 was 3198, checked in by vboxsync, 18 years ago

The secondary display resize for Windows guests.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.8 KB
Line 
1/** @file
2 * VBoxService - Guest Additions Service
3 */
4
5/*
6 * Copyright (C) 2006-2007 innotek GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License as published by the Free Software Foundation,
12 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
13 * distribution. VirtualBox OSE is distributed in the hope that it will
14 * be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * If you received this file as part of a commercial VirtualBox
17 * distribution, then only the terms of your commercial VirtualBox
18 * license agreement apply instead of the previous paragraph.
19 *
20 */
21
22#include "VBoxService.h"
23#include "resource.h"
24#include <malloc.h>
25
26#include "helpers.h"
27
28/* global variables */
29HANDLE gVBoxDriver;
30HANDLE gStopSem;
31SERVICE_STATUS gVBoxServiceStatus;
32SERVICE_STATUS_HANDLE gVBoxServiceStatusHandle;
33HINSTANCE gInstance;
34HWND gToolWindow;
35
36
37/* prototypes */
38VOID DisplayChangeThread(void *dummy);
39LRESULT CALLBACK VBoxToolWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
40
41
42void SvcDebugOut2(char *String, ...)
43{
44 va_list va;
45
46 va_start(va, String);
47
48 CHAR Buffer[1024];
49 if (strlen(String) < 1000)
50 {
51 vsprintf (Buffer, String, va);
52
53 OutputDebugStringA(Buffer);
54
55#ifdef DEBUG_DISPLAY_CHANGE
56 FILE *f = fopen ("vboxservice.log", "ab");
57 if (f)
58 {
59 fprintf (f, "%s", Buffer);
60 fclose (f);
61 }
62#endif /* DEBUG_DISPLAY_CHANGE */
63 }
64
65 SetLastError (0);
66
67 va_end (va);
68}
69
70/**
71 * Helper function to send a message to WinDbg
72 *
73 * @param String message string
74 * @param Status error code, will be inserted into String's placeholder
75 */
76VOID SvcDebugOut(LPSTR String, DWORD Status)
77{
78 SvcDebugOut2(String, Status);
79}
80
81/* The shared clipboard service prototypes. */
82int VBoxClipboardInit (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
83unsigned __stdcall VBoxClipboardThread (void *pInstance);
84void VBoxClipboardDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
85
86/* The service table. */
87static VBOXSERVICEINFO vboxServiceTable[] =
88{
89 {
90 "Shared Clipboard",
91 VBoxClipboardInit,
92 VBoxClipboardThread,
93 VBoxClipboardDestroy
94 },
95 {
96 NULL
97 }
98};
99
100static int vboxStartServices (VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
101{
102 pEnv->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
103
104 if (!pEnv->hStopEvent)
105 {
106 /* Could not create event. */
107 return VERR_NOT_SUPPORTED;
108 }
109
110 while (pTable->pszName)
111 {
112 SvcDebugOut2 ("Starting %s...\n", pTable->pszName);
113
114 int rc = VINF_SUCCESS;
115
116 bool fStartThread = false;
117
118 pTable->hThread = (HANDLE)0;
119 pTable->pInstance = NULL;
120 pTable->fStarted = false;
121
122 if (pTable->pfnInit)
123 {
124 rc = pTable->pfnInit (pEnv, &pTable->pInstance, &fStartThread);
125 }
126
127 if (VBOX_FAILURE (rc))
128 {
129 SvcDebugOut2 ("Failed to initialize rc = %Vrc.\n", rc);
130 }
131 else
132 {
133 if (pTable->pfnThread && fStartThread)
134 {
135 unsigned threadid;
136
137 pTable->hThread = (HANDLE)_beginthreadex (NULL, /* security */
138 0, /* stacksize */
139 pTable->pfnThread,
140 pTable->pInstance,
141 0, /* initflag */
142 &threadid);
143
144 if (pTable->hThread == (HANDLE)(0))
145 {
146 rc = VERR_NOT_SUPPORTED;
147 }
148 }
149
150 if (VBOX_FAILURE (rc))
151 {
152 SvcDebugOut2 ("Failed to start the thread.\n");
153
154 if (pTable->pfnDestroy)
155 {
156 pTable->pfnDestroy (pEnv, pTable->pInstance);
157 }
158 }
159 else
160 {
161 pTable->fStarted = true;
162 }
163 }
164
165 /* Advance to next table element. */
166 pTable++;
167 }
168
169 return VINF_SUCCESS;
170}
171
172static void vboxStopServices (VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
173{
174 if (!pEnv->hStopEvent)
175 {
176 return;
177 }
178
179 /* Signal to all threads. */
180 SetEvent(pEnv->hStopEvent);
181
182 while (pTable->pszName)
183 {
184 if (pTable->fStarted)
185 {
186 if (pTable->pfnThread)
187 {
188 /* There is a thread, wait for termination. */
189 WaitForSingleObject(pTable->hThread, INFINITE);
190
191 CloseHandle (pTable->hThread);
192 pTable->hThread = 0;
193 }
194
195 if (pTable->pfnDestroy)
196 {
197 pTable->pfnDestroy (pEnv, pTable->pInstance);
198 }
199
200 pTable->fStarted = false;
201 }
202
203 /* Advance to next table element. */
204 pTable++;
205 }
206
207 CloseHandle (pEnv->hStopEvent);
208}
209
210
211void WINAPI VBoxServiceStart(void)
212{
213 SvcDebugOut2("VBoxService: Start\n");
214
215 VBOXSERVICEENV svcEnv;
216
217 DWORD status = NO_ERROR;
218
219 /* open VBox guest driver */
220 gVBoxDriver = CreateFile(VBOXGUEST_DEVICE_NAME,
221 GENERIC_READ | GENERIC_WRITE,
222 FILE_SHARE_READ | FILE_SHARE_WRITE,
223 NULL,
224 OPEN_EXISTING,
225 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
226 NULL);
227 if (gVBoxDriver == INVALID_HANDLE_VALUE)
228 {
229 SvcDebugOut("VBoxService: could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
230 status = ERROR_GEN_FAILURE;
231 }
232
233 SvcDebugOut2("VBoxService: Driver h %p, st %p\n", gVBoxDriver, status);
234
235 if (status == NO_ERROR)
236 {
237 /* create a custom window class */
238 WNDCLASS windowClass = {0};
239 windowClass.style = CS_NOCLOSE;
240 windowClass.lpfnWndProc = (WNDPROC)VBoxToolWndProc;
241 windowClass.hInstance = gInstance;
242 windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
243 windowClass.lpszClassName = "VirtualBoxTool";
244 if (!RegisterClass(&windowClass))
245 status = GetLastError();
246 }
247
248 SvcDebugOut2("VBoxService: Class st %p\n", status);
249
250 if (status == NO_ERROR)
251 {
252 /* create our window */
253 gToolWindow = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
254 "VirtualBoxTool", "VirtualBoxTool",
255 WS_POPUPWINDOW,
256 -200, -200, 100, 100, NULL, NULL, gInstance, NULL);
257 if (!gToolWindow)
258 status = GetLastError();
259 else
260 {
261 /* move the window beneach the mouse pointer so that we get access to it */
262 POINT mousePos;
263 GetCursorPos(&mousePos);
264 SetWindowPos(gToolWindow, HWND_TOPMOST, mousePos.x - 10, mousePos.y - 10, 0, 0,
265 SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
266 /* change the mouse pointer so that we can go for a hardware shape */
267 SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
268 SetCursor(LoadCursor(NULL, IDC_ARROW));
269 /* move back our tool window */
270 SetWindowPos(gToolWindow, HWND_TOPMOST, -200, -200, 0, 0,
271 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
272 }
273 }
274
275 SvcDebugOut2("VBoxService: Window h %p, st %p\n", gToolWindow, status);
276
277 if (status == NO_ERROR)
278 {
279 gStopSem = CreateEvent(NULL, TRUE, FALSE, NULL);
280 if (gStopSem == NULL)
281 {
282 SvcDebugOut("VBoxService: CreateEvent failed: rc = %d\n", GetLastError());
283 return;
284 }
285 }
286
287 /*
288 * Start services listed in the vboxServiceTable.
289 */
290 svcEnv.hInstance = gInstance;
291 svcEnv.hDriver = gVBoxDriver;
292
293 if (status == NO_ERROR)
294 {
295 int rc = vboxStartServices (&svcEnv, vboxServiceTable);
296
297 if (VBOX_FAILURE (rc))
298 {
299 status = ERROR_GEN_FAILURE;
300 }
301 }
302
303 /* create display change thread */
304 HANDLE hDisplayChangeThread;
305 if (status == NO_ERROR)
306 {
307 hDisplayChangeThread = (HANDLE)_beginthread(DisplayChangeThread, 0, NULL);
308 if ((int)hDisplayChangeThread == -1L)
309 status = ERROR_GEN_FAILURE;
310 }
311
312 SvcDebugOut2("VBoxService: hDisplayChangeThread h %p, st %p\n", hDisplayChangeThread, status);
313
314 /* terminate service if something went wrong */
315 if (status != NO_ERROR)
316 {
317 vboxStopServices (&svcEnv, vboxServiceTable);
318 return;
319 }
320
321 BOOL fTrayIconCreated = false;
322
323 /* prepare the system tray icon */
324 NOTIFYICONDATA ndata;
325 memset (&ndata, 0, sizeof (ndata));
326 ndata.cbSize = NOTIFYICONDATA_V1_SIZE; // sizeof(NOTIFYICONDATA);
327 ndata.hWnd = gToolWindow;
328 ndata.uID = 2000;
329 ndata.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
330 ndata.uCallbackMessage = WM_USER;
331 ndata.hIcon = LoadIcon(gInstance, MAKEINTRESOURCE(IDI_VIRTUALBOX));
332 sprintf(ndata.szTip, "innotek VirtualBox Guest Additions %d.%d.%d", VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD);
333
334 SvcDebugOut2("VBoxService: ndata.hWnd %08X, ndata.hIcon = %p\n", ndata.hWnd, ndata.hIcon);
335
336 /*
337 * Main execution loop
338 * Wait for the stop semaphore to be posted or a window event to arrive
339 */
340 while(true)
341 {
342 DWORD waitResult = MsgWaitForMultipleObjectsEx(1, &gStopSem, 500, QS_ALLINPUT, 0);
343 if (waitResult == WAIT_OBJECT_0)
344 {
345 SvcDebugOut2("VBoxService: exit\n");
346 /* exit */
347 break;
348 }
349 else if (waitResult == WAIT_OBJECT_0 + 1)
350 {
351 /* a window message, handle it */
352 MSG msg;
353 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
354 {
355 SvcDebugOut2("VBoxService: msg %p\n", msg.message);
356 if (msg.message == WM_QUIT)
357 {
358 SvcDebugOut2("VBoxService: WM_QUIT!\n");
359 SetEvent(gStopSem);
360 continue;
361 }
362 TranslateMessage(&msg);
363 DispatchMessage(&msg);
364 }
365 }
366 else /* timeout */
367 {
368#ifndef DEBUG_sandervl
369 SvcDebugOut2("VBoxService: timed out\n");
370#endif
371 /* we might have to repeat this operation because the shell might not be loaded yet */
372 if (!fTrayIconCreated)
373 {
374 fTrayIconCreated = Shell_NotifyIcon(NIM_ADD, &ndata);
375 SvcDebugOut2("VBoxService: fTrayIconCreated = %d, err %08X\n", fTrayIconCreated, GetLastError ());
376 }
377 }
378 }
379
380 SvcDebugOut("VBoxService: returned from main loop, exiting...\n", 0);
381
382 /* remove the system tray icon */
383 Shell_NotifyIcon(NIM_DELETE, &ndata);
384
385 SvcDebugOut("VBoxService: waiting for display change thread...\n", 0);
386
387 /* wait for the display change thread to terminate */
388 WaitForSingleObject(hDisplayChangeThread, INFINITE);
389
390 vboxStopServices (&svcEnv, vboxServiceTable);
391
392 SvcDebugOut("VBoxService: destroying tool window...\n", 0);
393
394 /* destroy the tool window */
395 DestroyWindow(gToolWindow);
396
397 UnregisterClass("VirtualBoxTool", gInstance);
398
399 CloseHandle(gVBoxDriver);
400 CloseHandle(gStopSem);
401
402 SvcDebugOut("VBoxService: leaving service main function\n", 0);
403
404 return;
405}
406
407
408/**
409 * Main function
410 */
411int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
412{
413 SvcDebugOut2("VBoxService: WinMain\n");
414 gInstance = hInstance;
415 VBoxServiceStart ();
416 return 0;
417}
418
419static bool isVBoxDisplayDriverActive (void)
420{
421 bool result = false;
422
423 DISPLAY_DEVICE dispDevice;
424
425 FillMemory(&dispDevice, sizeof(DISPLAY_DEVICE), 0);
426
427 dispDevice.cb = sizeof(DISPLAY_DEVICE);
428
429 INT devNum = 0;
430
431 while (EnumDisplayDevices(NULL,
432 devNum,
433 &dispDevice,
434 0))
435 {
436 DDCLOG(("DevNum:%d\nName:%s\nString:%s\nID:%s\nKey:%s\nFlags=%08X\n\n",
437 devNum,
438 &dispDevice.DeviceName[0],
439 &dispDevice.DeviceString[0],
440 &dispDevice.DeviceID[0],
441 &dispDevice.DeviceKey[0],
442 dispDevice.StateFlags));
443
444 if (dispDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
445 {
446 DDCLOG(("Primary device.\n"));
447
448 if (strcmp(&dispDevice.DeviceString[0], "VirtualBox Graphics Adapter") == 0)
449 {
450 DDCLOG(("VBox display driver is active.\n"));
451 result = true;
452 }
453
454 break;
455 }
456
457 FillMemory(&dispDevice, sizeof(DISPLAY_DEVICE), 0);
458
459 dispDevice.cb = sizeof(DISPLAY_DEVICE);
460
461 devNum++;
462 }
463
464 return result;
465}
466
467/* ChangeDisplaySettingsEx does not exist in NT. ResizeDisplayDevice uses the function. */
468typedef LONG WINAPI defChangeDisplaySettingsEx(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
469static defChangeDisplaySettingsEx *pChangeDisplaySettingsEx = NULL;
470
471/* Returns TRUE to try again. */
472static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
473{
474 BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
475
476 DISPLAY_DEVICE DisplayDevice;
477
478 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
479 DisplayDevice.cb = sizeof(DisplayDevice);
480
481 /* Find out how many display devices the system has */
482 DWORD NumDevices = 0;
483 DWORD i = 0;
484 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
485 {
486 DDCLOG(("[%d] %s\n", i, DisplayDevice.DeviceName));
487
488 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
489 {
490 DDCLOG(("Found primary device. err %d\n", GetLastError ()));
491 NumDevices++;
492 }
493 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
494 {
495
496 DDCLOG(("Found secondary device. err %d\n", GetLastError ()));
497 NumDevices++;
498 }
499
500 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
501 DisplayDevice.cb = sizeof(DisplayDevice);
502 i++;
503 }
504
505 DDCLOG(("Found total %d devices. err %d\n", NumDevices, GetLastError ()));
506
507 if (NumDevices == 0 || Id >= NumDevices)
508 {
509 DDCLOG(("Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
510 return FALSE;
511 }
512
513 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
514 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
515 RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
516
517 /* Fetch information about current devices and modes. */
518 DWORD DevNum = 0;
519 DWORD DevPrimaryNum = 0;
520
521 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
522 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
523
524 i = 0;
525 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
526 {
527 DDCLOG(("[%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
528
529 BOOL bFetchDevice = FALSE;
530
531 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
532 {
533 DDCLOG(("Found primary device. err %d\n", GetLastError ()));
534 DevPrimaryNum = DevNum;
535 bFetchDevice = TRUE;
536 }
537 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
538 {
539
540 DDCLOG(("Found secondary device. err %d\n", GetLastError ()));
541 bFetchDevice = TRUE;
542 }
543
544 if (bFetchDevice)
545 {
546 if (DevNum >= NumDevices)
547 {
548 DDCLOG(("%d >= %d\n", NumDevices, DevNum));
549 return FALSE;
550 }
551
552 paDisplayDevices[DevNum] = DisplayDevice;
553
554 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
555 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
556 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
557 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
558 {
559 DDCLOG(("EnumDisplaySettings err %d\n", GetLastError ()));
560 return FALSE;
561 }
562
563 DDCLOG(("%dx%d at %d,%d\n",
564 paDeviceModes[DevNum].dmPelsWidth,
565 paDeviceModes[DevNum].dmPelsHeight,
566 paDeviceModes[DevNum].dmPosition.x,
567 paDeviceModes[DevNum].dmPosition.y));
568
569 paRects[DevNum].left = paDeviceModes[DevNum].dmPosition.x;
570 paRects[DevNum].top = paDeviceModes[DevNum].dmPosition.y;
571 paRects[DevNum].right = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
572 paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
573 DevNum++;
574 }
575
576 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
577 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
578 i++;
579 }
580
581 if (Width == 0)
582 {
583 Width = paRects[Id].right - paRects[Id].left;
584 }
585
586 if (Height == 0)
587 {
588 Height = paRects[Id].bottom - paRects[Id].top;
589 }
590
591 /* Check whether a mode reset or a change is requested. */
592 if ( !fModeReset
593 && paRects[Id].right - paRects[Id].left == Width
594 && paRects[Id].bottom - paRects[Id].top == Height
595 && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
596 {
597 DDCLOG(("VBoxService: already at desired resolution.\n"));
598 return FALSE;
599 }
600
601 resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
602
603 /* Without this, Windows will not ask the miniport for its
604 * mode table but uses an internal cache instead.
605 */
606 DEVMODE tempDevMode;
607 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
608 tempDevMode.dmSize = sizeof(DEVMODE);
609 EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
610
611 /* Assign the new rectangles to displays. */
612 for (i = 0; i < NumDevices; i++)
613 {
614 paDeviceModes[i].dmPosition.x = paRects[i].left;
615 paDeviceModes[i].dmPosition.y = paRects[i].top;
616 paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
617 paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
618
619 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH;
620
621 if ( i == Id
622 && BitsPerPixel != 0)
623 {
624 paDeviceModes[i].dmFields |= DM_BITSPERPEL;
625 paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
626 }
627
628 pChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
629 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
630 DDCLOG(("ChangeDisplaySettings position err %d\n", GetLastError ()));
631 }
632
633 /* A second call to ChangeDisplaySettings updates the monitor. */
634 LONG status = ChangeDisplaySettings(NULL, 0);
635 DDCLOG(("ChangeDisplaySettings update status %d\n", status));
636 if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
637 {
638 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
639 return FALSE;
640 }
641
642 /* Retry the request. */
643 return TRUE;
644}
645
646/**
647 * Thread function to wait for and process display change
648 * requests
649 */
650VOID DisplayChangeThread(void *dummy)
651{
652 bool fTerminate = false;
653 VBoxGuestFilterMaskInfo maskInfo;
654 DWORD cbReturned;
655
656 HMODULE hUser = GetModuleHandle("USER32");
657
658 if (hUser)
659 {
660 pChangeDisplaySettingsEx = (defChangeDisplaySettingsEx *)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
661 DDCLOG(("VBoxService: pChangeDisplaySettingsEx = %p\n", pChangeDisplaySettingsEx));
662 }
663
664 maskInfo.u32OrMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
665 maskInfo.u32NotMask = 0;
666 if (DeviceIoControl (gVBoxDriver, IOCTL_VBOXGUEST_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
667 {
668 DDCLOG(("VBoxService: DeviceIOControl(CtlMask - or) succeeded\n"));
669 }
670 else
671 {
672 SvcDebugOut2("VBoxService: DeviceIOControl(CtlMask) failed, DisplayChangeThread exited\n");
673 return;
674 }
675
676 do
677 {
678 /* wait for a display change event */
679 VBoxGuestWaitEventInfo waitEvent;
680 waitEvent.u32TimeoutIn = 100;
681 waitEvent.u32EventMaskIn = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
682 if (DeviceIoControl(gVBoxDriver, IOCTL_VBOXGUEST_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
683 {
684 DDCLOG(("VBoxService: DeviceIOControl succeded\n"));
685
686 /* are we supposed to stop? */
687 if (WaitForSingleObject(gStopSem, 0) == WAIT_OBJECT_0)
688 break;
689
690 DDCLOG(("VBoxService: checking event\n"));
691
692 /* did we get the right event? */
693 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
694 {
695 DDCLOG(("VBoxService: going to get display change information.\n"));
696
697 /* We got at least one event. Read the requested resolution
698 * and try to set it until success. New events will not be seen
699 * but a new resolution will be read in this poll loop.
700 */
701 for (;;)
702 {
703 /* get the display change request */
704 VMMDevDisplayChangeRequest2 displayChangeRequest = {0};
705 displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest2);
706 displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
707 displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest2;
708 displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
709 BOOL fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, IOCTL_VBOXGUEST_VMMREQUEST, &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2),
710 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2), &cbReturned, NULL);
711 if (!fDisplayChangeQueried)
712 {
713 /* Try the old version of the request for old VBox hosts. */
714 displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest);
715 displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
716 displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest;
717 displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
718 fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, IOCTL_VBOXGUEST_VMMREQUEST, &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest),
719 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest), &cbReturned, NULL);
720 displayChangeRequest.display = 0;
721 }
722
723 if (fDisplayChangeQueried)
724 {
725 DDCLOG(("VBoxService: VMMDevReq_GetDisplayChangeRequest2: %dx%dx%d at %d\n", displayChangeRequest.xres, displayChangeRequest.yres, displayChangeRequest.bpp, displayChangeRequest.display));
726
727 /* Horizontal resolution must be a multiple of 8, round down. */
728 displayChangeRequest.xres &= 0xfff8;
729
730 /*
731 * Only try to change video mode if the active display driver is VBox additions.
732 */
733 if (isVBoxDisplayDriverActive ())
734 {
735 if (pChangeDisplaySettingsEx != 0)
736 {
737 /* W2K or later. */
738 if (!ResizeDisplayDevice(displayChangeRequest.display,
739 displayChangeRequest.xres,
740 displayChangeRequest.yres,
741 displayChangeRequest.bpp))
742 {
743 break;
744 }
745 }
746 else
747 {
748 /* Single monitor NT. */
749 DEVMODE devMode;
750 memset (&devMode, 0, sizeof (devMode));
751 devMode.dmSize = sizeof(DEVMODE);
752
753 /* get the current screen setup */
754 if (EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
755 {
756 SvcDebugOut2("VBoxService: Current mode: %dx%dx%d at %d,%d\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmPosition.x, devMode.dmPosition.y);
757
758 /* Check whether a mode reset or a change is requested. */
759 if (displayChangeRequest.xres || displayChangeRequest.yres || displayChangeRequest.bpp)
760 {
761 /* A change is requested.
762 * Set values which are not to be changed to the current values.
763 */
764 if (!displayChangeRequest.xres)
765 displayChangeRequest.xres = devMode.dmPelsWidth;
766 if (!displayChangeRequest.yres)
767 displayChangeRequest.yres = devMode.dmPelsHeight;
768 if (!displayChangeRequest.bpp)
769 displayChangeRequest.bpp = devMode.dmBitsPerPel;
770 }
771 else
772 {
773 /* All zero values means a forced mode reset. Do nothing. */
774 }
775
776 /* Verify that the mode is indeed changed. */
777 if ( devMode.dmPelsWidth == displayChangeRequest.xres
778 && devMode.dmPelsHeight == displayChangeRequest.yres
779 && devMode.dmBitsPerPel == displayChangeRequest.bpp)
780 {
781 SvcDebugOut2("VBoxService: already at desired resolution.\n");
782 break;
783 }
784
785 // without this, Windows will not ask the miniport for its
786 // mode table but uses an internal cache instead
787 DEVMODE tempDevMode = {0};
788 tempDevMode.dmSize = sizeof(DEVMODE);
789 EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
790
791 /* adjust the values that are supposed to change */
792 if (displayChangeRequest.xres)
793 devMode.dmPelsWidth = displayChangeRequest.xres;
794 if (displayChangeRequest.yres)
795 devMode.dmPelsHeight = displayChangeRequest.yres;
796 if (displayChangeRequest.bpp)
797 devMode.dmBitsPerPel = displayChangeRequest.bpp;
798
799 DDCLOG(("VBoxService: setting the new mode %dx%dx%d\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel));
800
801 /* set the new mode */
802 LONG status = ChangeDisplaySettings(&devMode, CDS_UPDATEREGISTRY);
803 if (status != DISP_CHANGE_SUCCESSFUL)
804 {
805 SvcDebugOut("VBoxService: error from ChangeDisplaySettings: %d\n", status);
806
807 if (status == DISP_CHANGE_BADMODE)
808 {
809 /* Our driver can not set the requested mode. Stop trying. */
810 break;
811 }
812 }
813 else
814 {
815 /* Successfully set new video mode. */
816 break;
817 }
818 }
819 else
820 {
821 SvcDebugOut2("VBoxService: error from EnumDisplaySettings: %d\n", GetLastError ());
822 break;
823 }
824 }
825 }
826 else
827 {
828 SvcDebugOut2("VBoxService: vboxDisplayDriver is not active.\n", 0);
829 }
830
831 /* Retry the change a bit later. */
832 /* are we supposed to stop? */
833 if (WaitForSingleObject(gStopSem, 1000) == WAIT_OBJECT_0)
834 {
835 fTerminate = true;
836 break;
837 }
838 }
839 else
840 {
841 SvcDebugOut("VBoxService: error from DeviceIoControl IOCTL_VBOXGUEST_VMMREQUEST\n", 0);
842 /* sleep a bit to not eat too much CPU while retrying */
843 /* are we supposed to stop? */
844 if (WaitForSingleObject(gStopSem, 50) == WAIT_OBJECT_0)
845 {
846 fTerminate = true;
847 break;
848 }
849 }
850 }
851 }
852 } else
853 {
854 SvcDebugOut("VBoxService: error from DeviceIoControl IOCTL_VBOXGUEST_WAITEVENT\n", 0);
855 /* sleep a bit to not eat too much CPU in case the above call always fails */
856 if (WaitForSingleObject(gStopSem, 10) == WAIT_OBJECT_0)
857 {
858 fTerminate = true;
859 break;
860 }
861 }
862 } while (!fTerminate);
863
864 maskInfo.u32OrMask = 0;
865 maskInfo.u32NotMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
866 if (DeviceIoControl (gVBoxDriver, IOCTL_VBOXGUEST_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
867 {
868 DDCLOG(("VBoxService: DeviceIOControl(CtlMask - not) succeeded\n"));
869 }
870 else
871 {
872 SvcDebugOut2 ("VBoxService: DeviceIOControl(CtlMask) failed\n");
873 }
874
875 SvcDebugOut2("VBoxService: finished display change request thread\n");
876}
877
878/**
879 * Window procedure for our tool window
880 */
881LRESULT CALLBACK VBoxToolWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
882{
883 switch (msg)
884 {
885 case WM_CLOSE:
886 break;
887
888 case WM_DESTROY:
889 break;
890
891 default:
892 return DefWindowProc(hwnd, msg, wParam, lParam);
893 }
894 return 0;
895}
Note: See TracBrowser for help on using the repository browser.

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