VirtualBox

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

Last change on this file since 26131 was 25875, checked in by vboxsync, 15 years ago

Additions/VBoxControl: undo accidentally committed testing hacks

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 43.6 KB
Line 
1/* $Id: VBoxControl.cpp 25875 2010-01-18 09:07:38Z vboxsync $ */
2/** @file
3 * VBoxControl - Guest Additions Command Line Management Interface.
4 */
5
6/*
7 * Copyright (C) 2008-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. 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* Header Files *
24*******************************************************************************/
25#include <iprt/alloca.h>
26#include <iprt/cpp/autores.h>
27#include <iprt/buildconfig.h>
28#include <iprt/initterm.h>
29#include <iprt/mem.h>
30#include <iprt/path.h>
31#include <iprt/string.h>
32#include <iprt/stream.h>
33#include <VBox/log.h>
34#include <VBox/version.h>
35#include <VBox/VBoxGuestLib.h>
36#ifdef RT_OS_WINDOWS
37# include <Windows.h>
38#endif
39#ifdef VBOX_WITH_GUEST_PROPS
40# include <VBox/HostServices/GuestPropertySvc.h>
41#endif
42
43/*******************************************************************************
44* Global Variables *
45*******************************************************************************/
46/** The program name (derived from argv[0]). */
47char const *g_pszProgName = "";
48/** The current verbosity level. */
49int g_cVerbosity = 0;
50
51
52/**
53 * Displays the program usage message.
54 *
55 * @param u64Which
56 *
57 * @{
58 */
59
60/** Helper function */
61static void doUsage(char const *line, char const *name = "", char const *command = "")
62{
63 /* Allow for up to 15 characters command name length (VBoxControl.exe) with
64 * perfect column alignment. Beyond that there's at least one space between
65 * the command if there are command line parameters. */
66 RTPrintf("%s %-*s%s%s\n", name, strlen(line) ? 35 - strlen(name) : 1,
67 command, strlen(line) ? " " : "", line);
68}
69
70/** Enumerate the different parts of the usage we might want to print out */
71enum g_eUsage
72{
73#ifdef RT_OS_WINDOWS
74 GET_VIDEO_ACCEL,
75 SET_VIDEO_ACCEL,
76 LIST_CUST_MODES,
77 ADD_CUST_MODE,
78 REMOVE_CUST_MODE,
79 SET_VIDEO_MODE,
80#endif
81#ifdef VBOX_WITH_GUEST_PROPS
82 GUEST_PROP,
83#endif
84 USAGE_ALL = UINT32_MAX
85};
86
87static void usage(g_eUsage eWhich = USAGE_ALL)
88{
89 RTPrintf("Usage:\n\n");
90 doUsage("print version number and exit", g_pszProgName, "[-v|-version]");
91 doUsage("suppress the logo", g_pszProgName, "-nologo ...");
92 RTPrintf("\n");
93
94/* Exclude the Windows bits from the test version. Anyone who needs to test
95 * them can fix this. */
96#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
97 if ((GET_VIDEO_ACCEL == eWhich) || (USAGE_ALL == eWhich))
98 doUsage("", g_pszProgName, "getvideoacceleration");
99 if ((SET_VIDEO_ACCEL == eWhich) || (USAGE_ALL == eWhich))
100 doUsage("<on|off>", g_pszProgName, "setvideoacceleration");
101 if ((LIST_CUST_MODES == eWhich) || (USAGE_ALL == eWhich))
102 doUsage("", g_pszProgName, "listcustommodes");
103 if ((ADD_CUST_MODE == eWhich) || (USAGE_ALL == eWhich))
104 doUsage("<width> <height> <bpp>", g_pszProgName, "addcustommode");
105 if ((REMOVE_CUST_MODE == eWhich) || (USAGE_ALL == eWhich))
106 doUsage("<width> <height> <bpp>", g_pszProgName, "removecustommode");
107 if ((SET_VIDEO_MODE == eWhich) || (USAGE_ALL == eWhich))
108 doUsage("<width> <height> <bpp> <screen>", g_pszProgName, "setvideomode");
109#endif
110#ifdef VBOX_WITH_GUEST_PROPS
111 if ((GUEST_PROP == eWhich) || (USAGE_ALL == eWhich))
112 {
113 doUsage("get <property> [-verbose]", g_pszProgName, "guestproperty");
114 doUsage("set <property> [<value> [-flags <flags>]]", g_pszProgName, "guestproperty");
115 doUsage("enumerate [-patterns <patterns>]", g_pszProgName, "guestproperty");
116 doUsage("wait <patterns>", g_pszProgName, "guestproperty");
117 doUsage("[-timestamp <last timestamp>]");
118 doUsage("[-timeout <timeout in ms>");
119 }
120#endif
121}
122/** @} */
123
124/**
125 * Displays an error message.
126 *
127 * @param pszFormat The message text.
128 * @param ... Format arguments.
129 */
130static void VBoxControlError(const char *pszFormat, ...)
131{
132 // RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
133
134 va_list va;
135 va_start(va, pszFormat);
136 RTStrmPrintfV(g_pStdErr, pszFormat, va);
137 va_end(va);
138}
139
140#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
141
142LONG (WINAPI * gpfnChangeDisplaySettingsEx)(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
143
144static unsigned nextAdjacentRectXP (RECTL *paRects, unsigned nRects, unsigned iRect)
145{
146 unsigned i;
147 for (i = 0; i < nRects; i++)
148 {
149 if (paRects[iRect].right == paRects[i].left)
150 {
151 return i;
152 }
153 }
154 return ~0;
155}
156
157static unsigned nextAdjacentRectXN (RECTL *paRects, unsigned nRects, unsigned iRect)
158{
159 unsigned i;
160 for (i = 0; i < nRects; i++)
161 {
162 if (paRects[iRect].left == paRects[i].right)
163 {
164 return i;
165 }
166 }
167 return ~0;
168}
169
170static unsigned nextAdjacentRectYP (RECTL *paRects, unsigned nRects, unsigned iRect)
171{
172 unsigned i;
173 for (i = 0; i < nRects; i++)
174 {
175 if (paRects[iRect].bottom == paRects[i].top)
176 {
177 return i;
178 }
179 }
180 return ~0;
181}
182
183unsigned nextAdjacentRectYN (RECTL *paRects, unsigned nRects, unsigned iRect)
184{
185 unsigned i;
186 for (i = 0; i < nRects; i++)
187 {
188 if (paRects[iRect].top == paRects[i].bottom)
189 {
190 return i;
191 }
192 }
193 return ~0;
194}
195
196void resizeRect(RECTL *paRects, unsigned nRects, unsigned iPrimary, unsigned iResized, int NewWidth, int NewHeight)
197{
198 RECTL *paNewRects = (RECTL *)alloca (sizeof (RECTL) * nRects);
199 memcpy (paNewRects, paRects, sizeof (RECTL) * nRects);
200 paNewRects[iResized].right += NewWidth - (paNewRects[iResized].right - paNewRects[iResized].left);
201 paNewRects[iResized].bottom += NewHeight - (paNewRects[iResized].bottom - paNewRects[iResized].top);
202
203 /* Verify all pairs of originally adjacent rectangles for all 4 directions.
204 * If the pair has a "good" delta (that is the first rectangle intersects the second)
205 * at a direction and the second rectangle is not primary one (which can not be moved),
206 * move the second rectangle to make it adjacent to the first one.
207 */
208
209 /* X positive. */
210 unsigned iRect;
211 for (iRect = 0; iRect < nRects; iRect++)
212 {
213 /* Find the next adjacent original rect in x positive direction. */
214 unsigned iNextRect = nextAdjacentRectXP (paRects, nRects, iRect);
215 Log(("next %d -> %d\n", iRect, iNextRect));
216
217 if (iNextRect == ~0 || iNextRect == iPrimary)
218 {
219 continue;
220 }
221
222 /* Check whether there is an X intesection between these adjacent rects in the new rectangles
223 * and fix the intersection if delta is "good".
224 */
225 int delta = paNewRects[iRect].right - paNewRects[iNextRect].left;
226
227 if (delta > 0)
228 {
229 Log(("XP intersection right %d left %d, diff %d\n",
230 paNewRects[iRect].right, paNewRects[iNextRect].left,
231 delta));
232
233 paNewRects[iNextRect].left += delta;
234 paNewRects[iNextRect].right += delta;
235 }
236 }
237
238 /* X negative. */
239 for (iRect = 0; iRect < nRects; iRect++)
240 {
241 /* Find the next adjacent original rect in x negative direction. */
242 unsigned iNextRect = nextAdjacentRectXN (paRects, nRects, iRect);
243 Log(("next %d -> %d\n", iRect, iNextRect));
244
245 if (iNextRect == ~0 || iNextRect == iPrimary)
246 {
247 continue;
248 }
249
250 /* Check whether there is an X intesection between these adjacent rects in the new rectangles
251 * and fix the intersection if delta is "good".
252 */
253 int delta = paNewRects[iRect].left - paNewRects[iNextRect].right;
254
255 if (delta < 0)
256 {
257 Log(("XN intersection left %d right %d, diff %d\n",
258 paNewRects[iRect].left, paNewRects[iNextRect].right,
259 delta));
260
261 paNewRects[iNextRect].left += delta;
262 paNewRects[iNextRect].right += delta;
263 }
264 }
265
266 /* Y positive (in the computer sence, top->down). */
267 for (iRect = 0; iRect < nRects; iRect++)
268 {
269 /* Find the next adjacent original rect in y positive direction. */
270 unsigned iNextRect = nextAdjacentRectYP (paRects, nRects, iRect);
271 Log(("next %d -> %d\n", iRect, iNextRect));
272
273 if (iNextRect == ~0 || iNextRect == iPrimary)
274 {
275 continue;
276 }
277
278 /* Check whether there is an Y intesection between these adjacent rects in the new rectangles
279 * and fix the intersection if delta is "good".
280 */
281 int delta = paNewRects[iRect].bottom - paNewRects[iNextRect].top;
282
283 if (delta > 0)
284 {
285 Log(("YP intersection bottom %d top %d, diff %d\n",
286 paNewRects[iRect].bottom, paNewRects[iNextRect].top,
287 delta));
288
289 paNewRects[iNextRect].top += delta;
290 paNewRects[iNextRect].bottom += delta;
291 }
292 }
293
294 /* Y negative (in the computer sence, down->top). */
295 for (iRect = 0; iRect < nRects; iRect++)
296 {
297 /* Find the next adjacent original rect in x negative direction. */
298 unsigned iNextRect = nextAdjacentRectYN (paRects, nRects, iRect);
299 Log(("next %d -> %d\n", iRect, iNextRect));
300
301 if (iNextRect == ~0 || iNextRect == iPrimary)
302 {
303 continue;
304 }
305
306 /* Check whether there is an Y intesection between these adjacent rects in the new rectangles
307 * and fix the intersection if delta is "good".
308 */
309 int delta = paNewRects[iRect].top - paNewRects[iNextRect].bottom;
310
311 if (delta < 0)
312 {
313 Log(("YN intersection top %d bottom %d, diff %d\n",
314 paNewRects[iRect].top, paNewRects[iNextRect].bottom,
315 delta));
316
317 paNewRects[iNextRect].top += delta;
318 paNewRects[iNextRect].bottom += delta;
319 }
320 }
321
322 memcpy (paRects, paNewRects, sizeof (RECTL) * nRects);
323 return;
324}
325
326/* Returns TRUE to try again. */
327static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
328{
329 BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
330
331 DISPLAY_DEVICE DisplayDevice;
332
333 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
334 DisplayDevice.cb = sizeof(DisplayDevice);
335
336 /* Find out how many display devices the system has */
337 DWORD NumDevices = 0;
338 DWORD i = 0;
339 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
340 {
341 Log(("[%d] %s\n", i, DisplayDevice.DeviceName));
342
343 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
344 {
345 Log(("Found primary device. err %d\n", GetLastError ()));
346 NumDevices++;
347 }
348 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
349 {
350
351 Log(("Found secondary device. err %d\n", GetLastError ()));
352 NumDevices++;
353 }
354
355 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
356 DisplayDevice.cb = sizeof(DisplayDevice);
357 i++;
358 }
359
360 Log(("Found total %d devices. err %d\n", NumDevices, GetLastError ()));
361
362 if (NumDevices == 0 || Id >= NumDevices)
363 {
364 Log(("Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
365 return FALSE;
366 }
367
368 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
369 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
370 RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
371
372 /* Fetch information about current devices and modes. */
373 DWORD DevNum = 0;
374 DWORD DevPrimaryNum = 0;
375
376 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
377 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
378
379 i = 0;
380 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
381 {
382 Log(("[%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
383
384 BOOL bFetchDevice = FALSE;
385
386 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
387 {
388 Log(("Found primary device. err %d\n", GetLastError ()));
389 DevPrimaryNum = DevNum;
390 bFetchDevice = TRUE;
391 }
392 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
393 {
394
395 Log(("Found secondary device. err %d\n", GetLastError ()));
396 bFetchDevice = TRUE;
397 }
398
399 if (bFetchDevice)
400 {
401 if (DevNum >= NumDevices)
402 {
403 Log(("%d >= %d\n", NumDevices, DevNum));
404 return FALSE;
405 }
406
407 paDisplayDevices[DevNum] = DisplayDevice;
408
409 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
410 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
411 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
412 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
413 {
414 Log(("EnumDisplaySettings err %d\n", GetLastError ()));
415 return FALSE;
416 }
417
418 Log(("%dx%d at %d,%d\n",
419 paDeviceModes[DevNum].dmPelsWidth,
420 paDeviceModes[DevNum].dmPelsHeight,
421 paDeviceModes[DevNum].dmPosition.x,
422 paDeviceModes[DevNum].dmPosition.y));
423
424 paRects[DevNum].left = paDeviceModes[DevNum].dmPosition.x;
425 paRects[DevNum].top = paDeviceModes[DevNum].dmPosition.y;
426 paRects[DevNum].right = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
427 paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
428 DevNum++;
429 }
430
431 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
432 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
433 i++;
434 }
435
436 if (Width == 0)
437 {
438 Width = paRects[Id].right - paRects[Id].left;
439 }
440
441 if (Height == 0)
442 {
443 Height = paRects[Id].bottom - paRects[Id].top;
444 }
445
446 /* Check whether a mode reset or a change is requested. */
447 if ( !fModeReset
448 && paRects[Id].right - paRects[Id].left == Width
449 && paRects[Id].bottom - paRects[Id].top == Height
450 && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
451 {
452 Log(("VBoxDisplayThread : already at desired resolution.\n"));
453 return FALSE;
454 }
455
456 resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
457#ifdef Log
458 for (i = 0; i < NumDevices; i++)
459 {
460 Log(("[%d]: %d,%d %dx%d\n",
461 i, paRects[i].left, paRects[i].top,
462 paRects[i].right - paRects[i].left,
463 paRects[i].bottom - paRects[i].top));
464 }
465#endif /* Log */
466
467 /* Without this, Windows will not ask the miniport for its
468 * mode table but uses an internal cache instead.
469 */
470 DEVMODE tempDevMode;
471 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
472 tempDevMode.dmSize = sizeof(DEVMODE);
473 EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
474
475 /* Assign the new rectangles to displays. */
476 for (i = 0; i < NumDevices; i++)
477 {
478 paDeviceModes[i].dmPosition.x = paRects[i].left;
479 paDeviceModes[i].dmPosition.y = paRects[i].top;
480 paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
481 paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
482
483 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH;
484
485 if ( i == Id
486 && BitsPerPixel != 0)
487 {
488 paDeviceModes[i].dmFields |= DM_BITSPERPEL;
489 paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
490 }
491 Log(("calling pfnChangeDisplaySettingsEx %x\n", gpfnChangeDisplaySettingsEx));
492 gpfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
493 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
494 Log(("ChangeDisplaySettings position err %d\n", GetLastError ()));
495 }
496
497 /* A second call to ChangeDisplaySettings updates the monitor. */
498 LONG status = ChangeDisplaySettings(NULL, 0);
499 Log(("ChangeDisplaySettings update status %d\n", status));
500 if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
501 {
502 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
503 return FALSE;
504 }
505
506 /* Retry the request. */
507 return TRUE;
508}
509
510int handleSetVideoMode(int argc, char *argv[])
511{
512 if (argc != 3 && argc != 4)
513 {
514 usage(SET_VIDEO_MODE);
515 return 1;
516 }
517
518 DWORD xres = atoi(argv[0]);
519 DWORD yres = atoi(argv[1]);
520 DWORD bpp = atoi(argv[2]);
521 DWORD scr = 0;
522
523 if (argc == 4)
524 {
525 scr = atoi(argv[3]);
526 }
527
528 HMODULE hUser = GetModuleHandle("USER32");
529
530 if (hUser)
531 {
532 *(uintptr_t *)&gpfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
533 Log(("VBoxService: pChangeDisplaySettingsEx = %p\n", gpfnChangeDisplaySettingsEx));
534
535 if (gpfnChangeDisplaySettingsEx)
536 {
537 /* The screen index is 0 based in the ResizeDisplayDevice call. */
538 scr = scr > 0? scr - 1: 0;
539
540 /* Horizontal resolution must be a multiple of 8, round down. */
541 xres &= ~0x7;
542
543 RTPrintf("Setting resolution of display %d to %dx%dx%d ...", scr, xres, yres, bpp);
544 ResizeDisplayDevice(scr, xres, yres, bpp);
545 RTPrintf("done.\n");
546 }
547 else VBoxControlError("Error retrieving API for display change!");
548 }
549 else VBoxControlError("Error retrieving handle to user32.dll!");
550
551 return 0;
552}
553
554HKEY getVideoKey(bool writable)
555{
556 HKEY hkeyDeviceMap = 0;
557 HKEY hkeyVideo = 0;
558 LONG status;
559
560 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkeyDeviceMap);
561 if ((status != ERROR_SUCCESS) || !hkeyDeviceMap)
562 {
563 VBoxControlError("Error opening video device map registry key!\n");
564 return 0;
565 }
566 char szVideoLocation[256];
567 DWORD dwKeyType;
568 szVideoLocation[0] = 0;
569 DWORD len = sizeof(szVideoLocation);
570 status = RegQueryValueExA(hkeyDeviceMap, "\\Device\\Video0", NULL, &dwKeyType, (LPBYTE)szVideoLocation, &len);
571 /*
572 * This value will start with a weird value: \REGISTRY\Machine
573 * Make sure this is true.
574 */
575 if ( (status == ERROR_SUCCESS)
576 && (dwKeyType == REG_SZ)
577 && (_strnicmp(szVideoLocation, "\\REGISTRY\\Machine", 17) == 0))
578 {
579 /* open that branch */
580 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, &szVideoLocation[18], 0, KEY_READ | (writable ? KEY_WRITE : 0), &hkeyVideo);
581 }
582 else
583 {
584 VBoxControlError("Error opening registry key '%s'\n", &szVideoLocation[18]);
585 }
586 RegCloseKey(hkeyDeviceMap);
587 return hkeyVideo;
588}
589
590int handleGetVideoAcceleration(int argc, char *argv[])
591{
592 ULONG status;
593 HKEY hkeyVideo = getVideoKey(false);
594
595 if (hkeyVideo)
596 {
597 /* query the actual value */
598 DWORD fAcceleration = 1;
599 DWORD len = sizeof(fAcceleration);
600 DWORD dwKeyType;
601 status = RegQueryValueExA(hkeyVideo, "EnableVideoAccel", NULL, &dwKeyType, (LPBYTE)&fAcceleration, &len);
602 if (status != ERROR_SUCCESS)
603 RTPrintf("Video acceleration: default\n");
604 else
605 RTPrintf("Video acceleration: %s\n", fAcceleration ? "on" : "off");
606 RegCloseKey(hkeyVideo);
607 }
608 return 0;
609}
610
611int handleSetVideoAcceleration(int argc, char *argv[])
612{
613 ULONG status;
614 HKEY hkeyVideo;
615
616 /* must have exactly one argument: the new offset */
617 if ( (argc != 1)
618 || ( strcmp(argv[0], "on")
619 && strcmp(argv[0], "off")))
620 {
621 usage(SET_VIDEO_ACCEL);
622 return 1;
623 }
624
625 hkeyVideo = getVideoKey(true);
626
627 if (hkeyVideo)
628 {
629 int fAccel = 0;
630 if (!strcmp(argv[0], "on"))
631 fAccel = 1;
632 /* set a new value */
633 status = RegSetValueExA(hkeyVideo, "EnableVideoAccel", 0, REG_DWORD, (LPBYTE)&fAccel, sizeof(fAccel));
634 if (status != ERROR_SUCCESS)
635 {
636 VBoxControlError("Error %d writing video acceleration status!\n", status);
637 }
638 RegCloseKey(hkeyVideo);
639 }
640 return 0;
641}
642
643#define MAX_CUSTOM_MODES 128
644
645/* the table of custom modes */
646struct
647{
648 DWORD xres;
649 DWORD yres;
650 DWORD bpp;
651} customModes[MAX_CUSTOM_MODES] = {0};
652
653void getCustomModes(HKEY hkeyVideo)
654{
655 ULONG status;
656 int curMode = 0;
657
658 /* null out the table */
659 RT_ZERO(customModes);
660
661 do
662 {
663 char valueName[20];
664 DWORD xres, yres, bpp = 0;
665 DWORD dwType;
666 DWORD dwLen = sizeof(DWORD);
667
668 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", curMode);
669 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&xres, &dwLen);
670 if (status != ERROR_SUCCESS)
671 break;
672 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", curMode);
673 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&yres, &dwLen);
674 if (status != ERROR_SUCCESS)
675 break;
676 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dBPP", curMode);
677 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&bpp, &dwLen);
678 if (status != ERROR_SUCCESS)
679 break;
680
681 /* check if the mode is OK */
682 if ( (xres > (1 << 16))
683 && (yres > (1 << 16))
684 && ( (bpp != 16)
685 || (bpp != 24)
686 || (bpp != 32)))
687 break;
688
689 /* add mode to table */
690 customModes[curMode].xres = xres;
691 customModes[curMode].yres = yres;
692 customModes[curMode].bpp = bpp;
693
694 ++curMode;
695
696 if (curMode >= MAX_CUSTOM_MODES)
697 break;
698 } while(1);
699}
700
701void writeCustomModes(HKEY hkeyVideo)
702{
703 ULONG status;
704 int tableIndex = 0;
705 int modeIndex = 0;
706
707 /* first remove all values */
708 for (int i = 0; i < MAX_CUSTOM_MODES; i++)
709 {
710 char valueName[20];
711 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", i);
712 RegDeleteValueA(hkeyVideo, valueName);
713 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", i);
714 RegDeleteValueA(hkeyVideo, valueName);
715 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dBPP", i);
716 RegDeleteValueA(hkeyVideo, valueName);
717 }
718
719 do
720 {
721 if (tableIndex >= MAX_CUSTOM_MODES)
722 break;
723
724 /* is the table entry present? */
725 if ( (!customModes[tableIndex].xres)
726 || (!customModes[tableIndex].yres)
727 || (!customModes[tableIndex].bpp))
728 {
729 tableIndex++;
730 continue;
731 }
732
733 RTPrintf("writing mode %d (%dx%dx%d)\n", modeIndex, customModes[tableIndex].xres, customModes[tableIndex].yres, customModes[tableIndex].bpp);
734 char valueName[20];
735 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", modeIndex);
736 status = RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].xres,
737 sizeof(customModes[tableIndex].xres));
738 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", modeIndex);
739 RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].yres,
740 sizeof(customModes[tableIndex].yres));
741 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dBPP", modeIndex);
742 RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].bpp,
743 sizeof(customModes[tableIndex].bpp));
744
745 modeIndex++;
746 tableIndex++;
747
748 } while(1);
749
750}
751
752int handleListCustomModes(int argc, char *argv[])
753{
754 if (argc != 0)
755 {
756 usage(LIST_CUST_MODES);
757 return 1;
758 }
759
760 HKEY hkeyVideo = getVideoKey(false);
761
762 if (hkeyVideo)
763 {
764 getCustomModes(hkeyVideo);
765 for (int i = 0; i < (sizeof(customModes) / sizeof(customModes[0])); i++)
766 {
767 if ( !customModes[i].xres
768 || !customModes[i].yres
769 || !customModes[i].bpp)
770 continue;
771
772 RTPrintf("Mode: %d x %d x %d\n",
773 customModes[i].xres, customModes[i].yres, customModes[i].bpp);
774 }
775 RegCloseKey(hkeyVideo);
776 }
777 return 0;
778}
779
780int handleAddCustomMode(int argc, char *argv[])
781{
782 if (argc != 3)
783 {
784 usage(ADD_CUST_MODE);
785 return 1;
786 }
787
788 DWORD xres = atoi(argv[0]);
789 DWORD yres = atoi(argv[1]);
790 DWORD bpp = atoi(argv[2]);
791
792 /** @todo better check including xres mod 8 = 0! */
793 if ( (xres > (1 << 16))
794 && (yres > (1 << 16))
795 && ( (bpp != 16)
796 || (bpp != 24)
797 || (bpp != 32)))
798 {
799 VBoxControlError("Error: invalid mode specified!\n");
800 return 1;
801 }
802
803 HKEY hkeyVideo = getVideoKey(true);
804
805 if (hkeyVideo)
806 {
807 int i;
808 int fModeExists = 0;
809 getCustomModes(hkeyVideo);
810 for (i = 0; i < MAX_CUSTOM_MODES; i++)
811 {
812 /* mode exists? */
813 if ( customModes[i].xres == xres
814 && customModes[i].yres == yres
815 && customModes[i].bpp == bpp
816 )
817 {
818 fModeExists = 1;
819 }
820 }
821 if (!fModeExists)
822 {
823 for (i = 0; i < MAX_CUSTOM_MODES; i++)
824 {
825 /* item free? */
826 if (!customModes[i].xres)
827 {
828 customModes[i].xres = xres;
829 customModes[i].yres = yres;
830 customModes[i].bpp = bpp;
831 break;
832 }
833 }
834 writeCustomModes(hkeyVideo);
835 }
836 RegCloseKey(hkeyVideo);
837 }
838 return 0;
839}
840
841int handleRemoveCustomMode(int argc, char *argv[])
842{
843 if (argc != 3)
844 {
845 usage(REMOVE_CUST_MODE);
846 return 1;
847 }
848
849 DWORD xres = atoi(argv[0]);
850 DWORD yres = atoi(argv[1]);
851 DWORD bpp = atoi(argv[2]);
852
853 HKEY hkeyVideo = getVideoKey(true);
854
855 if (hkeyVideo)
856 {
857 getCustomModes(hkeyVideo);
858 for (int i = 0; i < MAX_CUSTOM_MODES; i++)
859 {
860 /* correct item? */
861 if ( (customModes[i].xres == xres)
862 && (customModes[i].yres == yres)
863 && (customModes[i].bpp == bpp))
864 {
865 RTPrintf("found mode at index %d\n", i);
866 RT_ZERO(customModes[i]);
867 break;
868 }
869 }
870 writeCustomModes(hkeyVideo);
871 RegCloseKey(hkeyVideo);
872 }
873
874 return 0;
875}
876
877#endif /* RT_OS_WINDOWS */
878
879#ifdef VBOX_WITH_GUEST_PROPS
880/**
881 * Retrieves a value from the guest property store.
882 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
883 *
884 * @returns 0 on success, 1 on failure
885 * @note see the command line API description for parameters
886 */
887int getGuestProperty(int argc, char **argv)
888{
889 using namespace guestProp;
890
891 bool verbose = false;
892 if ((2 == argc) && (0 == strcmp(argv[1], "-verbose")))
893 verbose = true;
894 else if (argc != 1)
895 {
896 usage(GUEST_PROP);
897 return 1;
898 }
899
900 uint32_t u32ClientId = 0;
901 int rc = VINF_SUCCESS;
902
903 rc = VbglR3GuestPropConnect(&u32ClientId);
904 if (!RT_SUCCESS(rc))
905 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
906
907/*
908 * Here we actually retrieve the value from the host.
909 */
910 const char *pszName = argv[0];
911 char *pszValue = NULL;
912 uint64_t u64Timestamp = 0;
913 char *pszFlags = NULL;
914 /* The buffer for storing the data and its initial size. We leave a bit
915 * of space here in case the maximum values are raised. */
916 void *pvBuf = NULL;
917 uint32_t cbBuf = MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024;
918 if (RT_SUCCESS(rc))
919 {
920 /* Because there is a race condition between our reading the size of a
921 * property and the guest updating it, we loop a few times here and
922 * hope. Actually this should never go wrong, as we are generous
923 * enough with buffer space. */
924 bool finish = false;
925 for (unsigned i = 0; (i < 10) && !finish; ++i)
926 {
927 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
928 if (NULL == pvTmpBuf)
929 {
930 rc = VERR_NO_MEMORY;
931 VBoxControlError("Out of memory\n");
932 }
933 else
934 {
935 pvBuf = pvTmpBuf;
936 rc = VbglR3GuestPropRead(u32ClientId, pszName, pvBuf, cbBuf,
937 &pszValue, &u64Timestamp, &pszFlags,
938 &cbBuf);
939 }
940 if (VERR_BUFFER_OVERFLOW == rc)
941 /* Leave a bit of extra space to be safe */
942 cbBuf += 1024;
943 else
944 finish = true;
945 }
946 if (VERR_TOO_MUCH_DATA == rc)
947 VBoxControlError("Temporarily unable to retrieve the property\n");
948 else if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
949 VBoxControlError("Failed to retrieve the property value, error %Rrc\n", rc);
950 }
951/*
952 * And display it on the guest console.
953 */
954 if (VERR_NOT_FOUND == rc)
955 RTPrintf("No value set!\n");
956 else if (RT_SUCCESS(rc))
957 {
958 RTPrintf("Value: %S\n", pszValue);
959 if (verbose)
960 {
961 RTPrintf("Timestamp: %lld ns\n", u64Timestamp);
962 RTPrintf("Flags: %S\n", pszFlags);
963 }
964 }
965
966 if (u32ClientId != 0)
967 VbglR3GuestPropDisconnect(u32ClientId);
968 RTMemFree(pvBuf);
969 return RT_SUCCESS(rc) ? 0 : 1;
970}
971
972
973/**
974 * Writes a value to the guest property store.
975 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
976 *
977 * @returns 0 on success, 1 on failure
978 * @note see the command line API description for parameters
979 */
980static int setGuestProperty(int argc, char *argv[])
981{
982/*
983 * Check the syntax. We can deduce the correct syntax from the number of
984 * arguments.
985 */
986 bool usageOK = true;
987 const char *pszName = NULL;
988 const char *pszValue = NULL;
989 const char *pszFlags = NULL;
990 if (2 == argc)
991 {
992 pszValue = argv[1];
993 }
994 else if (3 == argc)
995 usageOK = false;
996 else if (4 == argc)
997 {
998 pszValue = argv[1];
999 if (strcmp(argv[2], "-flags") != 0)
1000 usageOK = false;
1001 pszFlags = argv[3];
1002 }
1003 else if (argc != 1)
1004 usageOK = false;
1005 if (!usageOK)
1006 {
1007 usage(GUEST_PROP);
1008 return 1;
1009 }
1010 /* This is always needed. */
1011 pszName = argv[0];
1012
1013/*
1014 * Do the actual setting.
1015 */
1016 uint32_t u32ClientId = 0;
1017 int rc = VINF_SUCCESS;
1018 rc = VbglR3GuestPropConnect(&u32ClientId);
1019 if (!RT_SUCCESS(rc))
1020 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
1021 if (RT_SUCCESS(rc))
1022 {
1023 if (pszFlags != NULL)
1024 rc = VbglR3GuestPropWrite(u32ClientId, pszName, pszValue, pszFlags);
1025 else
1026 rc = VbglR3GuestPropWriteValue(u32ClientId, pszName, pszValue);
1027 if (!RT_SUCCESS(rc))
1028 VBoxControlError("Failed to store the property value, error %Rrc\n", rc);
1029 }
1030
1031 if (u32ClientId != 0)
1032 VbglR3GuestPropDisconnect(u32ClientId);
1033 return RT_SUCCESS(rc) ? 0 : 1;
1034}
1035
1036
1037/**
1038 * Enumerates the properties in the guest property store.
1039 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1040 *
1041 * @returns 0 on success, 1 on failure
1042 * @note see the command line API description for parameters
1043 */
1044static int enumGuestProperty(int argc, char *argv[])
1045{
1046 /*
1047 * Check the syntax. We can deduce the correct syntax from the number of
1048 * arguments.
1049 */
1050 char const * const *papszPatterns = NULL;
1051 uint32_t cPatterns = 0;
1052 if ( argc > 1
1053 && !strcmp(argv[0], "-patterns"))
1054 {
1055 papszPatterns = (char const * const *)&argv[1];
1056 cPatterns = argc - 1;
1057 }
1058 else if (argc != 0)
1059 {
1060 usage(GUEST_PROP);
1061 return 1;
1062 }
1063
1064 /*
1065 * Do the actual enumeration.
1066 */
1067 uint32_t u32ClientId = 0;
1068 int rc = VbglR3GuestPropConnect(&u32ClientId);
1069 if (RT_SUCCESS(rc))
1070 {
1071 PVBGLR3GUESTPROPENUM pHandle;
1072 const char *pszName, *pszValue, *pszFlags;
1073 uint64_t u64Timestamp;
1074
1075 rc = VbglR3GuestPropEnum(u32ClientId, papszPatterns, cPatterns, &pHandle,
1076 &pszName, &pszValue, &u64Timestamp, &pszFlags);
1077 if (RT_SUCCESS(rc))
1078 {
1079 while (RT_SUCCESS(rc) && pszName)
1080 {
1081 RTPrintf("Name: %s, value: %s, timestamp: %lld, flags: %s\n",
1082 pszName, pszValue, u64Timestamp, pszFlags);
1083
1084 rc = VbglR3GuestPropEnumNext(pHandle, &pszName, &pszValue, &u64Timestamp, &pszFlags);
1085 if (RT_FAILURE(rc))
1086 VBoxControlError("Error while enumerating guest properties: %Rrc\n", rc);
1087 }
1088
1089 VbglR3GuestPropEnumFree(pHandle);
1090 }
1091 else if (VERR_NOT_FOUND == rc)
1092 RTPrintf("No properties found.\n");
1093 else
1094 VBoxControlError("Failed to enumerate the guest properties! Error: %Rrc\n", rc);
1095 VbglR3GuestPropDisconnect(u32ClientId);
1096 }
1097 else
1098 VBoxControlError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
1099 return RT_SUCCESS(rc) ? 0 : 1;
1100}
1101
1102
1103/**
1104 * Waits for notifications of changes to guest properties.
1105 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1106 *
1107 * @returns 0 on success, 1 on failure
1108 * @note see the command line API description for parameters
1109 */
1110int waitGuestProperty(int argc, char **argv)
1111{
1112 using namespace guestProp;
1113
1114 /*
1115 * Handle arguments
1116 */
1117 const char *pszPatterns = NULL;
1118 uint64_t u64TimestampIn = 0;
1119 uint32_t u32Timeout = RT_INDEFINITE_WAIT;
1120 bool usageOK = true;
1121 if (argc < 1)
1122 usageOK = false;
1123 pszPatterns = argv[0];
1124 for (int i = 1; usageOK && i < argc; ++i)
1125 {
1126 if (strcmp(argv[i], "-timeout") == 0)
1127 {
1128 if ( i + 1 >= argc
1129 || RTStrToUInt32Full(argv[i + 1], 10, &u32Timeout)
1130 != VINF_SUCCESS
1131 )
1132 usageOK = false;
1133 else
1134 ++i;
1135 }
1136 else if (strcmp(argv[i], "-timestamp") == 0)
1137 {
1138 if ( i + 1 >= argc
1139 || RTStrToUInt64Full(argv[i + 1], 10, &u64TimestampIn)
1140 != VINF_SUCCESS
1141 )
1142 usageOK = false;
1143 else
1144 ++i;
1145 }
1146 else
1147 usageOK = false;
1148 }
1149 if (!usageOK)
1150 {
1151 usage(GUEST_PROP);
1152 return 1;
1153 }
1154
1155 /*
1156 * Connect to the service
1157 */
1158 uint32_t u32ClientId = 0;
1159 int rc = VINF_SUCCESS;
1160
1161 rc = VbglR3GuestPropConnect(&u32ClientId);
1162 if (!RT_SUCCESS(rc))
1163 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
1164
1165 /*
1166 * Retrieve the notification from the host
1167 */
1168 char *pszName = NULL;
1169 char *pszValue = NULL;
1170 uint64_t u64TimestampOut = 0;
1171 char *pszFlags = NULL;
1172 /* The buffer for storing the data and its initial size. We leave a bit
1173 * of space here in case the maximum values are raised. */
1174 void *pvBuf = NULL;
1175 uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024;
1176 /* Because there is a race condition between our reading the size of a
1177 * property and the guest updating it, we loop a few times here and
1178 * hope. Actually this should never go wrong, as we are generous
1179 * enough with buffer space. */
1180 bool finish = false;
1181 for (unsigned i = 0;
1182 (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) && !finish && (i < 10);
1183 ++i)
1184 {
1185 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
1186 if (NULL == pvTmpBuf)
1187 {
1188 rc = VERR_NO_MEMORY;
1189 VBoxControlError("Out of memory\n");
1190 }
1191 else
1192 {
1193 pvBuf = pvTmpBuf;
1194 rc = VbglR3GuestPropWait(u32ClientId, pszPatterns, pvBuf, cbBuf,
1195 u64TimestampIn, u32Timeout,
1196 &pszName, &pszValue, &u64TimestampOut,
1197 &pszFlags, &cbBuf);
1198 }
1199 if (VERR_BUFFER_OVERFLOW == rc)
1200 /* Leave a bit of extra space to be safe */
1201 cbBuf += 1024;
1202 else
1203 finish = true;
1204 if (rc == VERR_TOO_MUCH_DATA)
1205 VBoxControlError("Temporarily unable to get a notification\n");
1206 else if (rc == VERR_INTERRUPTED)
1207 VBoxControlError("The request timed out or was interrupted\n");
1208#ifndef RT_OS_WINDOWS /* Windows guests do not do this right */
1209 else if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
1210 VBoxControlError("Failed to get a notification, error %Rrc\n", rc);
1211#endif
1212 }
1213/*
1214 * And display it on the guest console.
1215 */
1216 if (VERR_NOT_FOUND == rc)
1217 RTPrintf("No value set!\n");
1218 else if (rc == VERR_BUFFER_OVERFLOW)
1219 RTPrintf("Internal error: unable to determine the size of the data!\n");
1220 else if (RT_SUCCESS(rc))
1221 {
1222 RTPrintf("Name: %s\n", pszName);
1223 RTPrintf("Value: %s\n", pszValue);
1224 RTPrintf("Timestamp: %lld ns\n", u64TimestampOut);
1225 RTPrintf("Flags: %s\n", pszFlags);
1226 }
1227
1228 if (u32ClientId != 0)
1229 VbglR3GuestPropDisconnect(u32ClientId);
1230 RTMemFree(pvBuf);
1231 return RT_SUCCESS(rc) ? 0 : 1;
1232}
1233
1234
1235/**
1236 * Access the guest property store through the "VBoxGuestPropSvc" HGCM
1237 * service.
1238 *
1239 * @returns 0 on success, 1 on failure
1240 * @note see the command line API description for parameters
1241 */
1242static int handleGuestProperty(int argc, char *argv[])
1243{
1244 if (0 == argc)
1245 {
1246 usage(GUEST_PROP);
1247 return 1;
1248 }
1249 if (0 == strcmp(argv[0], "get"))
1250 return getGuestProperty(argc - 1, argv + 1);
1251 else if (0 == strcmp(argv[0], "set"))
1252 return setGuestProperty(argc - 1, argv + 1);
1253 else if (0 == strcmp(argv[0], "enumerate"))
1254 return enumGuestProperty(argc - 1, argv + 1);
1255 else if (0 == strcmp(argv[0], "wait"))
1256 return waitGuestProperty(argc - 1, argv + 1);
1257 /* else */
1258 usage(GUEST_PROP);
1259 return 1;
1260}
1261
1262#endif
1263
1264/** command handler type */
1265typedef DECLCALLBACK(int) FNHANDLER(int argc, char *argv[]);
1266typedef FNHANDLER *PFNHANDLER;
1267
1268/** The table of all registered command handlers. */
1269struct COMMANDHANDLER
1270{
1271 const char *command;
1272 PFNHANDLER handler;
1273} g_commandHandlers[] =
1274{
1275#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
1276 { "getvideoacceleration", handleGetVideoAcceleration },
1277 { "setvideoacceleration", handleSetVideoAcceleration },
1278 { "listcustommodes", handleListCustomModes },
1279 { "addcustommode", handleAddCustomMode },
1280 { "removecustommode", handleRemoveCustomMode },
1281 { "setvideomode", handleSetVideoMode },
1282#endif
1283#ifdef VBOX_WITH_GUEST_PROPS
1284 { "guestproperty", handleGuestProperty },
1285#endif
1286 { NULL, NULL } /* terminator */
1287};
1288
1289/** Main function */
1290int main(int argc, char **argv)
1291{
1292 /** The application's global return code */
1293 int rc = 0;
1294 /** An IPRT return code for local use */
1295 int rrc = VINF_SUCCESS;
1296 /** The index of the command line argument we are currently processing */
1297 int iArg = 1;
1298 /** Should we show the logo text? */
1299 bool showlogo = true;
1300 /** Should we print the usage after the logo? For the -help switch. */
1301 bool dohelp = false;
1302 /** Will we be executing a command or just printing information? */
1303 bool onlyinfo = false;
1304
1305/*
1306 * Start by handling command line switches
1307 */
1308
1309 /** Are we finished with handling switches? */
1310 bool done = false;
1311 while (!done && (iArg < argc))
1312 {
1313 if ( (0 == strcmp(argv[iArg], "-v"))
1314 || (0 == strcmp(argv[iArg], "--version"))
1315 || (0 == strcmp(argv[iArg], "-version"))
1316 || (0 == strcmp(argv[iArg], "getversion"))
1317 )
1318 {
1319 /* Print version number, and do nothing else. */
1320 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, RTBldCfgRevision());
1321 onlyinfo = true;
1322 showlogo = false;
1323 done = true;
1324 }
1325 else if (0 == strcmp(argv[iArg], "-nologo"))
1326 showlogo = false;
1327 else if (0 == strcmp(argv[iArg], "-help"))
1328 {
1329 onlyinfo = true;
1330 dohelp = true;
1331 done = true;
1332 }
1333 else
1334 /* We have found an argument which isn't a switch. Exit to the
1335 * command processing bit. */
1336 done = true;
1337 if (!done)
1338 ++iArg;
1339 }
1340
1341/*
1342 * Find the application name, show our logo if the user hasn't suppressed it,
1343 * and show the usage if the user asked us to
1344 */
1345
1346 g_pszProgName = RTPathFilename(argv[0]);
1347 if (showlogo)
1348 RTPrintf("VirtualBox Guest Additions Command Line Management Interface Version "
1349 VBOX_VERSION_STRING "\n"
1350 "(C) 2008-2010 Sun Microsystems, Inc.\n"
1351 "All rights reserved.\n\n");
1352 if (dohelp)
1353 usage();
1354
1355/*
1356 * Do global initialisation for the programme if we will be handling a command
1357 */
1358
1359 if (!onlyinfo)
1360 {
1361 rrc = RTR3Init(); /** @todo r=bird: This ALWAYS goes first, the only exception is when you have to parse args to figure out which to call! */
1362 if (!RT_SUCCESS(rrc))
1363 {
1364 VBoxControlError("Failed to initialise the VirtualBox runtime - error %Rrc\n", rrc);
1365 rc = 1;
1366 }
1367 if (0 == rc)
1368 {
1369 if (!RT_SUCCESS(VbglR3Init()))
1370 {
1371 VBoxControlError("Could not contact the host system. Make sure that you are running this\n"
1372 "application inside a VirtualBox guest system, and that you have sufficient\n"
1373 "user permissions.\n");
1374 rc = 1;
1375 }
1376 }
1377 }
1378
1379/*
1380 * Now look for an actual command in the argument list and handle it.
1381 */
1382
1383 if (!onlyinfo && (0 == rc))
1384 {
1385 /*
1386 * The input is in the guest OS'es codepage (NT guarantees ACP).
1387 * For VBox we use UTF-8. For simplicity, just convert the argv[] array
1388 * here.
1389 */
1390 for (int i = iArg; i < argc; i++)
1391 {
1392 char *converted;
1393 RTStrCurrentCPToUtf8(&converted, argv[i]);
1394 argv[i] = converted;
1395 }
1396
1397 if (argc > iArg)
1398 {
1399 /** Is next parameter a known command? */
1400 bool found = false;
1401 /** And if so, what is its position in the table? */
1402 unsigned index = 0;
1403 while ( index < RT_ELEMENTS(g_commandHandlers)
1404 && !found
1405 && (g_commandHandlers[index].command != NULL))
1406 {
1407 if (0 == strcmp(argv[iArg], g_commandHandlers[index].command))
1408 found = true;
1409 else
1410 ++index;
1411 }
1412 if (found)
1413 rc = g_commandHandlers[index].handler(argc - iArg - 1, argv + iArg + 1);
1414 else
1415 {
1416 rc = 1;
1417 usage();
1418 }
1419 }
1420 else
1421 {
1422 /* The user didn't specify a command. */
1423 rc = 1;
1424 usage();
1425 }
1426
1427 /*
1428 * Free converted argument vector
1429 */
1430 for (int i = iArg; i < argc; i++)
1431 RTStrFree(argv[i]);
1432
1433 }
1434
1435/*
1436 * And exit, returning the status
1437 */
1438
1439 return rc;
1440}
1441
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