VirtualBox

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

Last change on this file since 10825 was 10825, checked in by vboxsync, 16 years ago

Additions/commom: switched VBoxControl to use the new guest property syntax

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