VirtualBox

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

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

Added the display index parameter to the SetVideoModeHint (in the guest all hints are still processed only for the primary monitor).

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