VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxControl/VBoxControl.cpp@ 10541

Last change on this file since 10541 was 10541, checked in by vboxsync, 16 years ago

Removed deprecated IOCTL namings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.4 KB
Line 
1/** @file
2 *
3 * VBoxControl - Guest Additions Utility
4 *
5 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
6 *
7 * This file is part of VirtualBox Open Source Edition (OSE), as
8 * available from http://www.virtualbox.org. This file is free software;
9 * you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License (GPL) as published by the Free Software
11 * Foundation, in version 2 as it comes in the "COPYING" file of the
12 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
14 *
15 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
16 * Clara, CA 95054 USA or visit http://www.sun.com if you need
17 * additional information or have any questions.
18 */
19
20#include <windows.h>
21#include <stdio.h>
22#include <stdarg.h>
23#include <malloc.h>
24
25#include <iprt/string.h>
26#include <iprt/stream.h>
27#include <VBox/VBoxGuest.h>
28#include <VBox/version.h>
29#ifdef VBOX_WITH_INFO_SVC
30# include <VBox/HostServices/VBoxInfoSvc.h>
31#endif /* VBOX_WITH_INFO_SVC */
32
33void printHelp()
34{
35 printf("VBoxControl getversion\n"
36 "\n"
37 "VBoxControl getvideoacceleration\n"
38 "\n"
39 "VBoxControl setvideoacceleration <on|off>\n"
40 "\n"
41 "VBoxControl listcustommodes\n"
42 "\n"
43 "VBoxControl addcustommode <width> <height> <bpp>\n"
44 "\n"
45 "VBoxControl removecustommode <width> <height> <bpp>\n"
46 "\n"
47 "VBoxControl setvideomode <width> <height> <bpp> <screen>\n"
48 "\n"
49#ifdef VBOX_WITH_INFO_SVC
50 "VBoxControl getguestproperty <key>\n"
51 "\n"
52 "VBoxControl setguestproperty <key> [<value>] (no value to delete)\n"
53#endif /* VBOX_WITH_INFO_SVC */
54 );
55}
56
57void printVersion()
58{
59 printf("%d.%d.%dr%d\n", VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
60}
61
62#if defined(DEBUG) || defined(LOG_ENABLED)
63#define dprintf(a) do { int err = GetLastError (); printf a; SetLastError (err); } while (0)
64#else
65#define dprintf(a) do {} while (0)
66#endif /* DEBUG */
67
68LONG (WINAPI * gpfnChangeDisplaySettingsEx)(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
69
70static unsigned nextAdjacentRectXP (RECTL *paRects, unsigned nRects, unsigned iRect)
71{
72 unsigned i;
73 for (i = 0; i < nRects; i++)
74 {
75 if (paRects[iRect].right == paRects[i].left)
76 {
77 return i;
78 }
79 }
80 return ~0;
81}
82
83static unsigned nextAdjacentRectXN (RECTL *paRects, unsigned nRects, unsigned iRect)
84{
85 unsigned i;
86 for (i = 0; i < nRects; i++)
87 {
88 if (paRects[iRect].left == paRects[i].right)
89 {
90 return i;
91 }
92 }
93 return ~0;
94}
95
96static unsigned nextAdjacentRectYP (RECTL *paRects, unsigned nRects, unsigned iRect)
97{
98 unsigned i;
99 for (i = 0; i < nRects; i++)
100 {
101 if (paRects[iRect].bottom == paRects[i].top)
102 {
103 return i;
104 }
105 }
106 return ~0;
107}
108
109unsigned nextAdjacentRectYN (RECTL *paRects, unsigned nRects, unsigned iRect)
110{
111 unsigned i;
112 for (i = 0; i < nRects; i++)
113 {
114 if (paRects[iRect].top == paRects[i].bottom)
115 {
116 return i;
117 }
118 }
119 return ~0;
120}
121
122void resizeRect(RECTL *paRects, unsigned nRects, unsigned iPrimary, unsigned iResized, int NewWidth, int NewHeight)
123{
124 RECTL *paNewRects = (RECTL *)alloca (sizeof (RECTL) * nRects);
125 memcpy (paNewRects, paRects, sizeof (RECTL) * nRects);
126 paNewRects[iResized].right += NewWidth - (paNewRects[iResized].right - paNewRects[iResized].left);
127 paNewRects[iResized].bottom += NewHeight - (paNewRects[iResized].bottom - paNewRects[iResized].top);
128
129 /* Verify all pairs of originally adjacent rectangles for all 4 directions.
130 * If the pair has a "good" delta (that is the first rectangle intersects the second)
131 * at a direction and the second rectangle is not primary one (which can not be moved),
132 * move the second rectangle to make it adjacent to the first one.
133 */
134
135 /* X positive. */
136 unsigned iRect;
137 for (iRect = 0; iRect < nRects; iRect++)
138 {
139 /* Find the next adjacent original rect in x positive direction. */
140 unsigned iNextRect = nextAdjacentRectXP (paRects, nRects, iRect);
141 dprintf(("next %d -> %d\n", iRect, iNextRect));
142
143 if (iNextRect == ~0 || iNextRect == iPrimary)
144 {
145 continue;
146 }
147
148 /* Check whether there is an X intesection between these adjacent rects in the new rectangles
149 * and fix the intersection if delta is "good".
150 */
151 int delta = paNewRects[iRect].right - paNewRects[iNextRect].left;
152
153 if (delta > 0)
154 {
155 dprintf(("XP intersection right %d left %d, diff %d\n",
156 paNewRects[iRect].right, paNewRects[iNextRect].left,
157 delta));
158
159 paNewRects[iNextRect].left += delta;
160 paNewRects[iNextRect].right += delta;
161 }
162 }
163
164 /* X negative. */
165 for (iRect = 0; iRect < nRects; iRect++)
166 {
167 /* Find the next adjacent original rect in x negative direction. */
168 unsigned iNextRect = nextAdjacentRectXN (paRects, nRects, iRect);
169 dprintf(("next %d -> %d\n", iRect, iNextRect));
170
171 if (iNextRect == ~0 || iNextRect == iPrimary)
172 {
173 continue;
174 }
175
176 /* Check whether there is an X intesection between these adjacent rects in the new rectangles
177 * and fix the intersection if delta is "good".
178 */
179 int delta = paNewRects[iRect].left - paNewRects[iNextRect].right;
180
181 if (delta < 0)
182 {
183 dprintf(("XN intersection left %d right %d, diff %d\n",
184 paNewRects[iRect].left, paNewRects[iNextRect].right,
185 delta));
186
187 paNewRects[iNextRect].left += delta;
188 paNewRects[iNextRect].right += delta;
189 }
190 }
191
192 /* Y positive (in the computer sence, top->down). */
193 for (iRect = 0; iRect < nRects; iRect++)
194 {
195 /* Find the next adjacent original rect in y positive direction. */
196 unsigned iNextRect = nextAdjacentRectYP (paRects, nRects, iRect);
197 dprintf(("next %d -> %d\n", iRect, iNextRect));
198
199 if (iNextRect == ~0 || iNextRect == iPrimary)
200 {
201 continue;
202 }
203
204 /* Check whether there is an Y intesection between these adjacent rects in the new rectangles
205 * and fix the intersection if delta is "good".
206 */
207 int delta = paNewRects[iRect].bottom - paNewRects[iNextRect].top;
208
209 if (delta > 0)
210 {
211 dprintf(("YP intersection bottom %d top %d, diff %d\n",
212 paNewRects[iRect].bottom, paNewRects[iNextRect].top,
213 delta));
214
215 paNewRects[iNextRect].top += delta;
216 paNewRects[iNextRect].bottom += delta;
217 }
218 }
219
220 /* Y negative (in the computer sence, down->top). */
221 for (iRect = 0; iRect < nRects; iRect++)
222 {
223 /* Find the next adjacent original rect in x negative direction. */
224 unsigned iNextRect = nextAdjacentRectYN (paRects, nRects, iRect);
225 dprintf(("next %d -> %d\n", iRect, iNextRect));
226
227 if (iNextRect == ~0 || iNextRect == iPrimary)
228 {
229 continue;
230 }
231
232 /* Check whether there is an Y intesection between these adjacent rects in the new rectangles
233 * and fix the intersection if delta is "good".
234 */
235 int delta = paNewRects[iRect].top - paNewRects[iNextRect].bottom;
236
237 if (delta < 0)
238 {
239 dprintf(("YN intersection top %d bottom %d, diff %d\n",
240 paNewRects[iRect].top, paNewRects[iNextRect].bottom,
241 delta));
242
243 paNewRects[iNextRect].top += delta;
244 paNewRects[iNextRect].bottom += delta;
245 }
246 }
247
248 memcpy (paRects, paNewRects, sizeof (RECTL) * nRects);
249 return;
250}
251
252/* Returns TRUE to try again. */
253static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
254{
255 BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
256
257 DISPLAY_DEVICE DisplayDevice;
258
259 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
260 DisplayDevice.cb = sizeof(DisplayDevice);
261
262 /* Find out how many display devices the system has */
263 DWORD NumDevices = 0;
264 DWORD i = 0;
265 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
266 {
267 dprintf(("[%d] %s\n", i, DisplayDevice.DeviceName));
268
269 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
270 {
271 dprintf(("Found primary device. err %d\n", GetLastError ()));
272 NumDevices++;
273 }
274 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
275 {
276
277 dprintf(("Found secondary device. err %d\n", GetLastError ()));
278 NumDevices++;
279 }
280
281 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
282 DisplayDevice.cb = sizeof(DisplayDevice);
283 i++;
284 }
285
286 dprintf(("Found total %d devices. err %d\n", NumDevices, GetLastError ()));
287
288 if (NumDevices == 0 || Id >= NumDevices)
289 {
290 dprintf(("Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
291 return FALSE;
292 }
293
294 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
295 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
296 RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
297
298 /* Fetch information about current devices and modes. */
299 DWORD DevNum = 0;
300 DWORD DevPrimaryNum = 0;
301
302 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
303 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
304
305 i = 0;
306 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
307 {
308 dprintf(("[%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
309
310 BOOL bFetchDevice = FALSE;
311
312 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
313 {
314 dprintf(("Found primary device. err %d\n", GetLastError ()));
315 DevPrimaryNum = DevNum;
316 bFetchDevice = TRUE;
317 }
318 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
319 {
320
321 dprintf(("Found secondary device. err %d\n", GetLastError ()));
322 bFetchDevice = TRUE;
323 }
324
325 if (bFetchDevice)
326 {
327 if (DevNum >= NumDevices)
328 {
329 dprintf(("%d >= %d\n", NumDevices, DevNum));
330 return FALSE;
331 }
332
333 paDisplayDevices[DevNum] = DisplayDevice;
334
335 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
336 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
337 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
338 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
339 {
340 dprintf(("EnumDisplaySettings err %d\n", GetLastError ()));
341 return FALSE;
342 }
343
344 dprintf(("%dx%d at %d,%d\n",
345 paDeviceModes[DevNum].dmPelsWidth,
346 paDeviceModes[DevNum].dmPelsHeight,
347 paDeviceModes[DevNum].dmPosition.x,
348 paDeviceModes[DevNum].dmPosition.y));
349
350 paRects[DevNum].left = paDeviceModes[DevNum].dmPosition.x;
351 paRects[DevNum].top = paDeviceModes[DevNum].dmPosition.y;
352 paRects[DevNum].right = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
353 paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
354 DevNum++;
355 }
356
357 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
358 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
359 i++;
360 }
361
362 if (Width == 0)
363 {
364 Width = paRects[Id].right - paRects[Id].left;
365 }
366
367 if (Height == 0)
368 {
369 Height = paRects[Id].bottom - paRects[Id].top;
370 }
371
372 /* Check whether a mode reset or a change is requested. */
373 if ( !fModeReset
374 && paRects[Id].right - paRects[Id].left == Width
375 && paRects[Id].bottom - paRects[Id].top == Height
376 && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
377 {
378 dprintf(("VBoxDisplayThread : already at desired resolution.\n"));
379 return FALSE;
380 }
381
382 resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
383#ifdef dprintf
384 for (i = 0; i < NumDevices; i++)
385 {
386 dprintf(("[%d]: %d,%d %dx%d\n",
387 i, paRects[i].left, paRects[i].top,
388 paRects[i].right - paRects[i].left,
389 paRects[i].bottom - paRects[i].top));
390 }
391#endif /* dprintf */
392
393 /* Without this, Windows will not ask the miniport for its
394 * mode table but uses an internal cache instead.
395 */
396 DEVMODE tempDevMode;
397 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
398 tempDevMode.dmSize = sizeof(DEVMODE);
399 EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
400
401 /* Assign the new rectangles to displays. */
402 for (i = 0; i < NumDevices; i++)
403 {
404 paDeviceModes[i].dmPosition.x = paRects[i].left;
405 paDeviceModes[i].dmPosition.y = paRects[i].top;
406 paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
407 paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
408
409 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH;
410
411 if ( i == Id
412 && BitsPerPixel != 0)
413 {
414 paDeviceModes[i].dmFields |= DM_BITSPERPEL;
415 paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
416 }
417 dprintf(("calling pfnChangeDisplaySettingsEx %x\n", gpfnChangeDisplaySettingsEx));
418 gpfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
419 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
420 dprintf(("ChangeDisplaySettings position err %d\n", GetLastError ()));
421 }
422
423 /* A second call to ChangeDisplaySettings updates the monitor. */
424 LONG status = ChangeDisplaySettings(NULL, 0);
425 dprintf(("ChangeDisplaySettings update status %d\n", status));
426 if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
427 {
428 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
429 return FALSE;
430 }
431
432 /* Retry the request. */
433 return TRUE;
434}
435
436void handleSetVideoMode(int argc, char *argv[])
437{
438 if (argc != 3 && argc != 4)
439 {
440 printf("Error: not enough parameters!\n");
441 return;
442 }
443
444 DWORD xres = atoi(argv[0]);
445 DWORD yres = atoi(argv[1]);
446 DWORD bpp = atoi(argv[2]);
447 DWORD scr = 0;
448
449 if (argc == 4)
450 {
451 scr = atoi(argv[3]);
452 }
453
454 HMODULE hUser = GetModuleHandle("USER32");
455
456 if (hUser)
457 {
458 *(uintptr_t *)&gpfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
459 dprintf(("VBoxService: pChangeDisplaySettingsEx = %p\n", gpfnChangeDisplaySettingsEx));
460
461 if (gpfnChangeDisplaySettingsEx)
462 {
463 /* The screen index is 0 based in the ResizeDisplayDevice call. */
464 scr = scr > 0? scr - 1: 0;
465
466 /* Horizontal resolution must be a multiple of 8, round down. */
467 xres &= ~0x7;
468
469 ResizeDisplayDevice(scr, xres, yres, bpp);
470 }
471 }
472}
473
474HKEY getVideoKey(bool writable)
475{
476 HKEY hkeyDeviceMap = 0;
477 HKEY hkeyVideo = 0;
478 LONG status;
479
480 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkeyDeviceMap);
481 if ((status != ERROR_SUCCESS) || !hkeyDeviceMap)
482 {
483 printf("Error opening video device map registry key!\n");
484 return 0;
485 }
486 char szVideoLocation[256];
487 DWORD dwKeyType;
488 szVideoLocation[0] = 0;
489 DWORD len = sizeof(szVideoLocation);
490 status = RegQueryValueExA(hkeyDeviceMap, "\\Device\\Video0", NULL, &dwKeyType, (LPBYTE)szVideoLocation, &len);
491 /*
492 * This value will start with a weird value: \REGISTRY\Machine
493 * Make sure this is true.
494 */
495 if ( (status == ERROR_SUCCESS)
496 && (dwKeyType == REG_SZ)
497 && (_strnicmp(szVideoLocation, "\\REGISTRY\\Machine", 17) == 0))
498 {
499 /* open that branch */
500 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, &szVideoLocation[18], 0, KEY_READ | (writable ? KEY_WRITE : 0), &hkeyVideo);
501 }
502 else
503 {
504 printf("Error opening registry key '%s'\n", &szVideoLocation[18]);
505 }
506 RegCloseKey(hkeyDeviceMap);
507 return hkeyVideo;
508}
509
510void handleGetVideoAcceleration(int argc, char *argv[])
511{
512 ULONG status;
513 HKEY hkeyVideo = getVideoKey(false);
514
515 if (hkeyVideo)
516 {
517 /* query the actual value */
518 DWORD fAcceleration = 1;
519 DWORD len = sizeof(fAcceleration);
520 DWORD dwKeyType;
521 status = RegQueryValueExA(hkeyVideo, "EnableVideoAccel", NULL, &dwKeyType, (LPBYTE)&fAcceleration, &len);
522 if (status != ERROR_SUCCESS)
523 printf("Video acceleration: default\n");
524 else
525 printf("Video acceleration: %s\n", fAcceleration ? "on" : "off");
526 RegCloseKey(hkeyVideo);
527 }
528}
529
530void handleSetVideoAcceleration(int argc, char *argv[])
531{
532 ULONG status;
533 HKEY hkeyVideo;
534
535 /* must have exactly one argument: the new offset */
536 if ( (argc != 1)
537 || ( strcmp(argv[0], "on")
538 && strcmp(argv[0], "off")))
539 {
540 printf("Error: invalid video acceleration status!\n");
541 return;
542 }
543
544 hkeyVideo = getVideoKey(true);
545
546 if (hkeyVideo)
547 {
548 int fAccel = 0;
549 if (!strcmp(argv[0], "on"))
550 fAccel = 1;
551 /* set a new value */
552 status = RegSetValueExA(hkeyVideo, "EnableVideoAccel", 0, REG_DWORD, (LPBYTE)&fAccel, sizeof(fAccel));
553 if (status != ERROR_SUCCESS)
554 {
555 printf("Error %d writing video acceleration status!\n", status);
556 }
557 RegCloseKey(hkeyVideo);
558 }
559}
560
561#define MAX_CUSTOM_MODES 128
562
563/* the table of custom modes */
564struct
565{
566 DWORD xres;
567 DWORD yres;
568 DWORD bpp;
569} customModes[MAX_CUSTOM_MODES] = {0};
570
571void getCustomModes(HKEY hkeyVideo)
572{
573 ULONG status;
574 int curMode = 0;
575
576 /* null out the table */
577 memset(customModes, 0, sizeof(customModes));
578
579 do
580 {
581 char valueName[20];
582 DWORD xres, yres, bpp = 0;
583 DWORD dwType;
584 DWORD dwLen = sizeof(DWORD);
585
586 sprintf(valueName, "CustomMode%dWidth", curMode);
587 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&xres, &dwLen);
588 if (status != ERROR_SUCCESS)
589 break;
590 sprintf(valueName, "CustomMode%dHeight", curMode);
591 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&yres, &dwLen);
592 if (status != ERROR_SUCCESS)
593 break;
594 sprintf(valueName, "CustomMode%dBPP", curMode);
595 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&bpp, &dwLen);
596 if (status != ERROR_SUCCESS)
597 break;
598
599 /* check if the mode is OK */
600 if ( (xres > (1 << 16))
601 && (yres > (1 << 16))
602 && ( (bpp != 16)
603 || (bpp != 24)
604 || (bpp != 32)))
605 break;
606
607 /* add mode to table */
608 customModes[curMode].xres = xres;
609 customModes[curMode].yres = yres;
610 customModes[curMode].bpp = bpp;
611
612 ++curMode;
613
614 if (curMode >= MAX_CUSTOM_MODES)
615 break;
616 } while(1);
617}
618
619void writeCustomModes(HKEY hkeyVideo)
620{
621 ULONG status;
622 int tableIndex = 0;
623 int modeIndex = 0;
624
625 /* first remove all values */
626 for (int i = 0; i < MAX_CUSTOM_MODES; i++)
627 {
628 char valueName[20];
629 sprintf(valueName, "CustomMode%dWidth", i);
630 RegDeleteValueA(hkeyVideo, valueName);
631 sprintf(valueName, "CustomMode%dHeight", i);
632 RegDeleteValueA(hkeyVideo, valueName);
633 sprintf(valueName, "CustomMode%dBPP", i);
634 RegDeleteValueA(hkeyVideo, valueName);
635 }
636
637 do
638 {
639 if (tableIndex >= MAX_CUSTOM_MODES)
640 break;
641
642 /* is the table entry present? */
643 if ( (!customModes[tableIndex].xres)
644 || (!customModes[tableIndex].yres)
645 || (!customModes[tableIndex].bpp))
646 {
647 tableIndex++;
648 continue;
649 }
650
651 printf("writing mode %d (%dx%dx%d)\n", modeIndex, customModes[tableIndex].xres, customModes[tableIndex].yres, customModes[tableIndex].bpp);
652 char valueName[20];
653 sprintf(valueName, "CustomMode%dWidth", modeIndex);
654 status = RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].xres,
655 sizeof(customModes[tableIndex].xres));
656 sprintf(valueName, "CustomMode%dHeight", modeIndex);
657 RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].yres,
658 sizeof(customModes[tableIndex].yres));
659 sprintf(valueName, "CustomMode%dBPP", modeIndex);
660 RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].bpp,
661 sizeof(customModes[tableIndex].bpp));
662
663 modeIndex++;
664 tableIndex++;
665
666 } while(1);
667
668}
669
670void handleListCustomModes(int argc, char *argv[])
671{
672 if (argc != 0)
673 {
674 printf("Error: too many parameters!");
675 return;
676 }
677
678 HKEY hkeyVideo = getVideoKey(false);
679
680 if (hkeyVideo)
681 {
682 getCustomModes(hkeyVideo);
683 for (int i = 0; i < (sizeof(customModes) / sizeof(customModes[0])); i++)
684 {
685 if ( !customModes[i].xres
686 || !customModes[i].yres
687 || !customModes[i].bpp)
688 continue;
689
690 printf("Mode: %d x %d x %d\n",
691 customModes[i].xres, customModes[i].yres, customModes[i].bpp);
692 }
693 RegCloseKey(hkeyVideo);
694 }
695}
696
697void handleAddCustomMode(int argc, char *argv[])
698{
699 if (argc != 3)
700 {
701 printf("Error: not enough parameters!\n");
702 return;
703 }
704
705 DWORD xres = atoi(argv[0]);
706 DWORD yres = atoi(argv[1]);
707 DWORD bpp = atoi(argv[2]);
708
709 /** @todo better check including xres mod 8 = 0! */
710 if ( (xres > (1 << 16))
711 && (yres > (1 << 16))
712 && ( (bpp != 16)
713 || (bpp != 24)
714 || (bpp != 32)))
715 {
716 printf("Error: invalid mode specified!\n");
717 return;
718 }
719
720 HKEY hkeyVideo = getVideoKey(true);
721
722 if (hkeyVideo)
723 {
724 int i;
725 int fModeExists = 0;
726 getCustomModes(hkeyVideo);
727 for (i = 0; i < MAX_CUSTOM_MODES; i++)
728 {
729 /* mode exists? */
730 if ( customModes[i].xres == xres
731 && customModes[i].yres == yres
732 && customModes[i].bpp == bpp
733 )
734 {
735 fModeExists = 1;
736 }
737 }
738 if (!fModeExists)
739 {
740 for (i = 0; i < MAX_CUSTOM_MODES; i++)
741 {
742 /* item free? */
743 if (!customModes[i].xres)
744 {
745 customModes[i].xres = xres;
746 customModes[i].yres = yres;
747 customModes[i].bpp = bpp;
748 break;
749 }
750 }
751 writeCustomModes(hkeyVideo);
752 }
753 RegCloseKey(hkeyVideo);
754 }
755}
756
757void handleRemoveCustomMode(int argc, char *argv[])
758{
759 if (argc != 3)
760 {
761 printf("Error: not enough parameters!\n");
762 return;
763 }
764
765 DWORD xres = atoi(argv[0]);
766 DWORD yres = atoi(argv[1]);
767 DWORD bpp = atoi(argv[2]);
768
769 HKEY hkeyVideo = getVideoKey(true);
770
771 if (hkeyVideo)
772 {
773 getCustomModes(hkeyVideo);
774 for (int i = 0; i < MAX_CUSTOM_MODES; i++)
775 {
776 /* correct item? */
777 if ( (customModes[i].xres == xres)
778 && (customModes[i].yres == yres)
779 && (customModes[i].bpp == bpp))
780 {
781printf("found mode at index %d\n", i);
782 memset(&customModes[i], 0, sizeof(customModes[i]));
783 break;
784 }
785 }
786 writeCustomModes(hkeyVideo);
787 RegCloseKey(hkeyVideo);
788 }
789}
790
791
792#ifdef VBOX_WITH_INFO_SVC
793/**
794 * Open the VirtualBox guest device.
795 * @returns IPRT status value
796 * @param hDevice where to store the handle to the open device
797 */
798static int openGuestDevice(HANDLE *hDevice)
799{
800 if (!VALID_PTR(hDevice))
801 return VERR_INVALID_POINTER;
802 *hDevice = CreateFile(VBOXGUEST_DEVICE_NAME,
803 GENERIC_READ | GENERIC_WRITE,
804 FILE_SHARE_READ | FILE_SHARE_WRITE,
805 NULL,
806 OPEN_EXISTING,
807 FILE_ATTRIBUTE_NORMAL,
808 NULL);
809 return (*hDevice != INVALID_HANDLE_VALUE) ? VINF_SUCCESS : VERR_OPEN_FAILED;
810}
811
812
813/**
814 * Connect to an HGCM service.
815 * @returns IPRT status code
816 * @param hDevice handle to the VBox device
817 * @param pszService the name of the service to connect to
818 * @param pu32ClientID where to store the connection handle
819 */
820static int hgcmConnect(HANDLE hDevice, char *pszService, uint32_t *pu32ClientID)
821{
822 if (!VALID_PTR(pszService) || !VALID_PTR(pu32ClientID))
823 return VERR_INVALID_POINTER;
824 VBoxGuestHGCMConnectInfo info;
825 int rc = VINF_SUCCESS;
826
827 memset (&info, 0, sizeof (info));
828 if (strlen(pszService) + 1 > sizeof(info.Loc.u.host.achName))
829 return false;
830 strcpy (info.Loc.u.host.achName, pszService);
831 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
832 DWORD cbReturned;
833 if (DeviceIoControl (hDevice,
834 VBOXGUEST_IOCTL_HGCM_CONNECT,
835 &info, sizeof (info),
836 &info, sizeof (info),
837 &cbReturned,
838 NULL))
839 rc = info.result;
840 else
841 rc = VERR_FILE_IO_ERROR;
842 if (RT_SUCCESS(rc))
843 *pu32ClientID = info.u32ClientID;
844 return rc;
845}
846
847
848/** Set a 32bit unsigned integer parameter to an HGCM request */
849static void VbglHGCMParmUInt32Set(HGCMFunctionParameter *pParm, uint32_t u32)
850{
851 pParm->type = VMMDevHGCMParmType_32bit;
852 pParm->u.value64 = 0; /* init unused bits to 0 */
853 pParm->u.value32 = u32;
854}
855
856
857/** Get a 32bit unsigned integer returned from an HGCM request */
858static int VbglHGCMParmUInt32Get(HGCMFunctionParameter *pParm, uint32_t *pu32)
859{
860 if (pParm->type == VMMDevHGCMParmType_32bit)
861 {
862 *pu32 = pParm->u.value32;
863 return VINF_SUCCESS;
864 }
865 return VERR_INVALID_PARAMETER;
866}
867
868
869/** Set a pointer parameter to an HGCM request */
870static void VbglHGCMParmPtrSet(HGCMFunctionParameter *pParm, void *pv, uint32_t cb)
871{
872 pParm->type = VMMDevHGCMParmType_LinAddr;
873 pParm->u.Pointer.size = cb;
874 pParm->u.Pointer.u.linearAddr = (uintptr_t)pv;
875}
876
877
878/** Make an HGCM call */
879static int hgcmCall(HANDLE hDevice, VBoxGuestHGCMCallInfo *pMsg, size_t cbMsg)
880{
881 DWORD cbReturned;
882 int rc = VERR_NOT_SUPPORTED;
883
884 if (DeviceIoControl (hDevice,
885 VBOXGUEST_IOCTL_HGCM_CALL,
886 pMsg, cbMsg,
887 pMsg, cbMsg,
888 &cbReturned,
889 NULL))
890 rc = VINF_SUCCESS;
891 return rc;
892}
893
894
895/**
896 * Retrieve a property from the host/guest configuration registry
897 * @returns IPRT status code
898 * @param hDevice handle to the VBox device
899 * @param u32ClientID The client id returned by VbglR3ClipboardConnect().
900 * @param pszKey The registry key to save to.
901 * @param pszValue Where to store the value retrieved.
902 * @param cbValue The size of the buffer pszValue points to.
903 * @param pcbActual Where to store the required buffer size on
904 * overflow or the value size on success. A value
905 * of zero means that the property does not exist.
906 * Optional.
907 */
908static int hgcmInfoSvcGetProp(HANDLE hDevice, uint32_t u32ClientID,
909 char *pszKey, char *pszValue,
910 uint32_t cbValue, uint32_t *pcbActual)
911{
912 using namespace svcInfo;
913
914 if (!VALID_PTR(pszValue))
915 return VERR_INVALID_POINTER;
916 GetConfigKey Msg;
917
918 Msg.hdr.result = (uint32_t)VERR_WRONG_ORDER; /** @todo drop the cast when the result type has been fixed! */
919 Msg.hdr.u32ClientID = u32ClientID;
920 Msg.hdr.u32Function = GET_CONFIG_KEY;
921 Msg.hdr.cParms = 3;
922 VbglHGCMParmPtrSet(&Msg.key, pszKey, strlen(pszKey) + 1);
923 VbglHGCMParmPtrSet(&Msg.value, pszValue, cbValue);
924 VbglHGCMParmUInt32Set(&Msg.size, 0);
925 int rc = hgcmCall(hDevice, &Msg.hdr, sizeof(Msg));
926 if (RT_SUCCESS(rc))
927 rc = Msg.hdr.result;
928 uint32_t cbActual;
929 if (RT_SUCCESS(rc) || (VERR_BUFFER_OVERFLOW == rc))
930 {
931 int rc2 = VbglHGCMParmUInt32Get(&Msg.size, &cbActual);
932 if (RT_SUCCESS(rc2))
933 {
934 if (pcbActual != NULL)
935 *pcbActual = cbActual;
936 }
937 else
938 rc = rc2;
939 }
940 return rc;
941}
942
943
944/**
945 * Store a property from the host/guest configuration registry
946 * @returns IPRT status code
947 * @param hDevice handle to the VBox device
948 * @param u32ClientID The client id returned by VbglR3ClipboardConnect().
949 * @param pszKey The registry key to save to.
950 * @param pszValue The value to store. If this is NULL then the key
951 * will be removed.
952 */
953static int hgcmInfoSvcSetProp(HANDLE hDevice, uint32_t u32ClientID,
954 char *pszKey, char *pszValue)
955{
956 using namespace svcInfo;
957
958 if (!VALID_PTR(pszKey))
959 return VERR_INVALID_POINTER;
960 if ((pszValue != NULL) && !VALID_PTR(pszValue))
961 return VERR_INVALID_POINTER;
962 int rc;
963
964 if (pszValue != NULL)
965 {
966 SetConfigKey Msg;
967
968 Msg.hdr.result = (uint32_t)VERR_WRONG_ORDER; /** @todo drop the cast when the result type has been fixed! */
969 Msg.hdr.u32ClientID = u32ClientID;
970 Msg.hdr.u32Function = SET_CONFIG_KEY;
971 Msg.hdr.cParms = 2;
972 VbglHGCMParmPtrSet(&Msg.key, pszKey, strlen(pszKey) + 1);
973 VbglHGCMParmPtrSet(&Msg.value, pszValue, strlen(pszValue) + 1);
974 rc = hgcmCall(hDevice, &Msg.hdr, sizeof(Msg));
975 if (RT_SUCCESS(rc))
976 rc = Msg.hdr.result;
977 }
978 else
979 {
980 DelConfigKey Msg;
981
982 Msg.hdr.result = (uint32_t)VERR_WRONG_ORDER; /** @todo drop the cast when the result type has been fixed! */
983 Msg.hdr.u32ClientID = u32ClientID;
984 Msg.hdr.u32Function = DEL_CONFIG_KEY;
985 Msg.hdr.cParms = 1;
986 VbglHGCMParmPtrSet(&Msg.key, pszKey, strlen(pszKey) + 1);
987 rc = hgcmCall(hDevice, &Msg.hdr, sizeof(Msg));
988 if (RT_SUCCESS(rc))
989 rc = Msg.hdr.result;
990 }
991 return rc;
992}
993
994
995/** Disconnects from an HGCM service. */
996static void hgcmDisconnect(HANDLE hDevice, uint32_t u32ClientID)
997{
998 if (u32ClientID == 0)
999 return;
1000
1001 VBoxGuestHGCMDisconnectInfo info;
1002 memset (&info, 0, sizeof (info));
1003 info.u32ClientID = u32ClientID;
1004
1005 DWORD cbReturned;
1006 DeviceIoControl (hDevice,
1007 VBOXGUEST_IOCTL_HGCM_DISCONNECT,
1008 &info, sizeof (info),
1009 &info, sizeof (info),
1010 &cbReturned,
1011 NULL);
1012}
1013
1014
1015/**
1016 * Retrieves a value from the host/guest configuration registry.
1017 * This is accessed through the "VBoxSharedInfoSvc" HGCM service.
1018 *
1019 * @returns IPRT status value
1020 * @param key (string) the key which the value is stored under.
1021 */
1022static int handleGetGuestProperty(int argc, char *argv[])
1023{
1024 HANDLE hDevice = INVALID_HANDLE_VALUE;
1025 uint32_t u32ClientID = 0;
1026 int rc = VINF_SUCCESS;
1027 char *pszKey = NULL;
1028 char szValue[svcInfo::KEY_MAX_VALUE_LEN];
1029
1030 if (argc != 1)
1031 {
1032 printHelp();
1033 return 1;
1034 }
1035 rc = RTStrCurrentCPToUtf8(&pszKey, argv[0]);
1036 if (!RT_SUCCESS(rc))
1037 RTPrintf("Failed to convert the key name to Utf8, error %Rrc\n", rc);
1038 if (RT_SUCCESS(rc))
1039 {
1040 rc = openGuestDevice(&hDevice);
1041 if (!RT_SUCCESS(rc))
1042 RTPrintf("Failed to open the VirtualBox device, error %Rrc\n", rc);
1043 }
1044 if (RT_SUCCESS(rc))
1045 {
1046 rc = hgcmConnect(hDevice, "VBoxSharedInfoSvc", &u32ClientID);
1047 if (!RT_SUCCESS(rc))
1048 RTPrintf("Failed to connect to the host/guest registry service, error %Rrc\n", rc);
1049 }
1050 if (RT_SUCCESS(rc))
1051 {
1052 rc = hgcmInfoSvcGetProp(hDevice, u32ClientID, pszKey, szValue,
1053 sizeof(szValue), NULL);
1054 if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
1055 RTPrintf("Failed to retrieve the property value, error %Rrc\n", rc);
1056 }
1057 if (VERR_NOT_FOUND == rc)
1058 RTPrintf("No value set!\n");
1059 if (RT_SUCCESS(rc))
1060 RTPrintf("Value: %S\n", szValue);
1061 if (u32ClientID != 0)
1062 hgcmDisconnect(hDevice, u32ClientID);
1063 if (hDevice != INVALID_HANDLE_VALUE)
1064 CloseHandle(hDevice);
1065 RTStrFree(pszKey);
1066 return rc;
1067}
1068
1069
1070/**
1071 * Writes a value to the host/guest configuration registry.
1072 * This is accessed through the "VBoxSharedInfoSvc" HGCM service.
1073 *
1074 * @returns IPRT status value
1075 * @param key (string) the key which the value is stored under.
1076 * @param value (string) the value to write. If empty, the key will be
1077 * removed.
1078 */
1079static int handleSetGuestProperty(int argc, char *argv[])
1080{
1081 HANDLE hDevice = INVALID_HANDLE_VALUE;
1082 uint32_t u32ClientID = 0;
1083 int rc = VINF_SUCCESS;
1084 char *pszKey = NULL;
1085 char *pszValue = NULL;
1086
1087 if (argc != 1 && argc != 2)
1088 {
1089 printHelp();
1090 return 1;
1091 }
1092 rc = RTStrCurrentCPToUtf8(&pszKey, argv[0]);
1093 if (!RT_SUCCESS(rc))
1094 RTPrintf("Failed to convert the key name to Utf8, error %Rrc\n", rc);
1095 if (RT_SUCCESS(rc) && (2 == argc))
1096 {
1097 rc = RTStrCurrentCPToUtf8(&pszValue, argv[1]);
1098 if (!RT_SUCCESS(rc))
1099 RTPrintf("Failed to convert the key value to Utf8, error %Rrc\n", rc);
1100 }
1101 if (RT_SUCCESS(rc))
1102 {
1103 rc = openGuestDevice(&hDevice);
1104 if (!RT_SUCCESS(rc))
1105 RTPrintf("Failed to open the VirtualBox device, error %Rrc\n", rc);
1106 }
1107 if (RT_SUCCESS(rc))
1108 {
1109 rc = hgcmConnect(hDevice, "VBoxSharedInfoSvc", &u32ClientID);
1110 if (!RT_SUCCESS(rc))
1111 RTPrintf("Failed to connect to the host/guest registry service, error %Rrc\n", rc);
1112 }
1113 if (RT_SUCCESS(rc))
1114 {
1115 rc = hgcmInfoSvcSetProp(hDevice, u32ClientID, pszKey, pszValue);
1116 if (!RT_SUCCESS(rc))
1117 RTPrintf("Failed to store the property value, error %Rrc\n", rc);
1118 }
1119 if (u32ClientID != 0)
1120 hgcmDisconnect(hDevice, u32ClientID);
1121 if (hDevice != INVALID_HANDLE_VALUE)
1122 CloseHandle(hDevice);
1123 RTStrFree(pszKey);
1124 RTStrFree(pszValue);
1125 return rc;
1126}
1127#endif /* VBOX_WITH_INFO_SVC */
1128
1129
1130/**
1131 * Main function
1132 */
1133int main(int argc, char *argv[])
1134{
1135 if (argc < 2)
1136 {
1137 printHelp();
1138 return 1;
1139 }
1140
1141 /* todo: add better / stable command line handling here! */
1142
1143 /* determine which command */
1144 if ((stricmp(argv[1], "getversion") == 0) ||
1145 (stricmp(argv[1], "-v") == 0) ||
1146 (stricmp(argv[1], "--version") == 0) ||
1147 (stricmp(argv[1], "-version") == 0))
1148 {
1149 printVersion();
1150 }
1151 else if (stricmp(argv[1], "getvideoacceleration") == 0)
1152 {
1153 handleGetVideoAcceleration(argc - 2, &argv[2]);
1154 }
1155 else if (stricmp(argv[1], "setvideoacceleration") == 0)
1156 {
1157 handleSetVideoAcceleration(argc - 2, &argv[2]);
1158 }
1159 else if (stricmp(argv[1], "listcustommodes") == 0)
1160 {
1161 handleListCustomModes(argc - 2, &argv[2]);
1162 }
1163 else if (stricmp(argv[1], "addcustommode") == 0)
1164 {
1165 handleAddCustomMode(argc - 2, &argv[2]);
1166 }
1167 else if (stricmp(argv[1], "removecustommode") == 0)
1168 {
1169 handleRemoveCustomMode(argc - 2, &argv[2]);
1170 }
1171 else if (stricmp(argv[1], "setvideomode") == 0)
1172 {
1173 handleSetVideoMode(argc - 2, &argv[2]);
1174 }
1175#ifdef VBOX_WITH_INFO_SVC
1176 else if (stricmp(argv[1], "getguestproperty") == 0)
1177 {
1178 int rc = handleGetGuestProperty(argc - 2, &argv[2]);
1179 return RT_SUCCESS(rc) ? 0 : 1;
1180 }
1181 else if (stricmp(argv[1], "setguestproperty") == 0)
1182 {
1183 handleSetGuestProperty(argc - 2, &argv[2]);
1184 }
1185#endif /* VBOX_WITH_INFO_SVC */
1186 else
1187 {
1188 printHelp();
1189 return 1;
1190 }
1191
1192 return 0;
1193}
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