VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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