VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxControl/VBoxControl.cpp@ 10202

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

Additions/WINNT: make the VBoxControl guest property functions utf8-safe

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