VirtualBox

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

Last change on this file since 28801 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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