VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxControl/VBoxControl.cpp@ 10797

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

Guest properties: initial commit of new interface

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

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