VirtualBox

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

Last change on this file since 10008 was 10008, checked in by vboxsync, 17 years ago

Additions/WINNT: add support for guest properties to VBoxControl

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