VirtualBox

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

Last change on this file since 45542 was 44992, checked in by vboxsync, 12 years ago

VBOX_WITH_DPC_LATENCY_CHECKER: Some adjustments. Please, don't use #pragma pack() unless you really need and mean it! Misaligning data just makes things slow...

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