VirtualBox

source: vbox/trunk/src/VBox/Main/testcase/tstAPI.cpp@ 55747

Last change on this file since 55747 was 55401, checked in by vboxsync, 10 years ago

added a couple of missing Id headers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.4 KB
Line 
1/* $Id: tstAPI.cpp 55401 2015-04-23 10:03:17Z vboxsync $ */
2/** @file
3 *
4 * tstAPI - test program for our COM/XPCOM interface
5 */
6
7/*
8 * Copyright (C) 2006-2014 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21
22#include <VBox/com/com.h>
23#include <VBox/com/string.h>
24#include <VBox/com/array.h>
25#include <VBox/com/Guid.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28
29#include <VBox/com/VirtualBox.h>
30
31using namespace com;
32
33#define LOG_ENABLED
34#define LOG_GROUP LOG_GROUP_MAIN
35#define LOG_INSTANCE NULL
36#include <VBox/log.h>
37
38#include <iprt/initterm.h>
39#include <iprt/path.h>
40#include <iprt/param.h>
41#include <iprt/stream.h>
42#include <iprt/thread.h>
43
44
45// forward declarations
46///////////////////////////////////////////////////////////////////////////////
47
48static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox,
49 ComPtr<IUnknown> aObject);
50static void queryMetrics(ComPtr<IVirtualBox> aVirtualBox,
51 ComPtr<IPerformanceCollector> collector,
52 ComSafeArrayIn(IUnknown *, objects));
53static void listAffectedMetrics(ComPtr<IVirtualBox> aVirtualBox,
54 ComSafeArrayIn(IPerformanceMetric*, aMetrics));
55
56// funcs
57///////////////////////////////////////////////////////////////////////////////
58
59HRESULT readAndChangeMachineSettings(IMachine *machine, IMachine *readonlyMachine = 0)
60{
61 HRESULT rc = S_OK;
62
63 Bstr name;
64 RTPrintf("Getting machine name...\n");
65 CHECK_ERROR_RET(machine, COMGETTER(Name)(name.asOutParam()), rc);
66 RTPrintf("Name: {%ls}\n", name.raw());
67
68 RTPrintf("Getting machine GUID...\n");
69 Bstr guid;
70 CHECK_ERROR(machine, COMGETTER(Id)(guid.asOutParam()));
71 if (SUCCEEDED(rc) && !guid.isEmpty()) {
72 RTPrintf("Guid::toString(): {%s}\n", Utf8Str(guid).c_str());
73 } else {
74 RTPrintf("WARNING: there's no GUID!");
75 }
76
77 ULONG memorySize;
78 RTPrintf("Getting memory size...\n");
79 CHECK_ERROR_RET(machine, COMGETTER(MemorySize)(&memorySize), rc);
80 RTPrintf("Memory size: %d\n", memorySize);
81
82 MachineState_T machineState;
83 RTPrintf("Getting machine state...\n");
84 CHECK_ERROR_RET(machine, COMGETTER(State)(&machineState), rc);
85 RTPrintf("Machine state: %d\n", machineState);
86
87 BOOL modified;
88 RTPrintf("Are any settings modified?...\n");
89 CHECK_ERROR(machine, COMGETTER(SettingsModified)(&modified));
90 if (SUCCEEDED(rc))
91 RTPrintf("%s\n", modified ? "yes" : "no");
92
93 ULONG memorySizeBig = memorySize * 10;
94 RTPrintf("Changing memory size to %d...\n", memorySizeBig);
95 CHECK_ERROR(machine, COMSETTER(MemorySize)(memorySizeBig));
96
97 if (SUCCEEDED(rc))
98 {
99 RTPrintf("Are any settings modified now?...\n");
100 CHECK_ERROR_RET(machine, COMGETTER(SettingsModified)(&modified), rc);
101 RTPrintf("%s\n", modified ? "yes" : "no");
102 ASSERT_RET(modified, 0);
103
104 ULONG memorySizeGot;
105 RTPrintf("Getting memory size again...\n");
106 CHECK_ERROR_RET(machine, COMGETTER(MemorySize)(&memorySizeGot), rc);
107 RTPrintf("Memory size: %d\n", memorySizeGot);
108 ASSERT_RET(memorySizeGot == memorySizeBig, 0);
109
110 if (readonlyMachine)
111 {
112 RTPrintf("Getting memory size of the counterpart readonly machine...\n");
113 ULONG memorySizeRO;
114 readonlyMachine->COMGETTER(MemorySize)(&memorySizeRO);
115 RTPrintf("Memory size: %d\n", memorySizeRO);
116 ASSERT_RET(memorySizeRO != memorySizeGot, 0);
117 }
118
119 RTPrintf("Discarding recent changes...\n");
120 CHECK_ERROR_RET(machine, DiscardSettings(), rc);
121 RTPrintf("Are any settings modified after discarding?...\n");
122 CHECK_ERROR_RET(machine, COMGETTER(SettingsModified)(&modified), rc);
123 RTPrintf("%s\n", modified ? "yes" : "no");
124 ASSERT_RET(!modified, 0);
125
126 RTPrintf("Getting memory size once more...\n");
127 CHECK_ERROR_RET(machine, COMGETTER(MemorySize)(&memorySizeGot), rc);
128 RTPrintf("Memory size: %d\n", memorySizeGot);
129 ASSERT_RET(memorySizeGot == memorySize, 0);
130
131 memorySize = memorySize > 128 ? memorySize / 2 : memorySize * 2;
132 RTPrintf("Changing memory size to %d...\n", memorySize);
133 CHECK_ERROR_RET(machine, COMSETTER(MemorySize)(memorySize), rc);
134 }
135
136 Bstr desc;
137 RTPrintf("Getting description...\n");
138 CHECK_ERROR_RET(machine, COMGETTER(Description)(desc.asOutParam()), rc);
139 RTPrintf("Description is: \"%ls\"\n", desc.raw());
140
141 desc = L"This is an exemplary description (changed).";
142 RTPrintf("Setting description to \"%ls\"...\n", desc.raw());
143 CHECK_ERROR_RET(machine, COMSETTER(Description)(desc.raw()), rc);
144
145 RTPrintf("Saving machine settings...\n");
146 CHECK_ERROR(machine, SaveSettings());
147 if (SUCCEEDED(rc))
148 {
149 RTPrintf("Are any settings modified after saving?...\n");
150 CHECK_ERROR_RET(machine, COMGETTER(SettingsModified)(&modified), rc);
151 RTPrintf("%s\n", modified ? "yes" : "no");
152 ASSERT_RET(!modified, 0);
153
154 if (readonlyMachine) {
155 RTPrintf("Getting memory size of the counterpart readonly machine...\n");
156 ULONG memorySizeRO;
157 readonlyMachine->COMGETTER(MemorySize)(&memorySizeRO);
158 RTPrintf("Memory size: %d\n", memorySizeRO);
159 ASSERT_RET(memorySizeRO == memorySize, 0);
160 }
161 }
162
163 Bstr extraDataKey = L"Blafasel";
164 Bstr extraData;
165 RTPrintf("Getting extra data key {%ls}...\n", extraDataKey.raw());
166 CHECK_ERROR_RET(machine, GetExtraData(extraDataKey.raw(), extraData.asOutParam()), rc);
167 if (!extraData.isEmpty()) {
168 RTPrintf("Extra data value: {%ls}\n", extraData.raw());
169 } else {
170 RTPrintf("No extra data exists\n");
171 }
172
173 if (extraData.isEmpty())
174 extraData = L"Das ist die Berliner Luft, Luft, Luft...";
175 else
176 extraData.setNull();
177 RTPrintf("Setting extra data key {%ls} to {%ls}...\n",
178 extraDataKey.raw(), extraData.raw());
179 CHECK_ERROR(machine, SetExtraData(extraDataKey.raw(), extraData.raw()));
180
181 if (SUCCEEDED(rc)) {
182 RTPrintf("Getting extra data key {%ls} again...\n", extraDataKey.raw());
183 CHECK_ERROR_RET(machine, GetExtraData(extraDataKey.raw(), extraData.asOutParam()), rc);
184 if (!extraData.isEmpty()) {
185 RTPrintf("Extra data value: {%ls}\n", extraData.raw());
186 } else {
187 RTPrintf("No extra data exists\n");
188 }
189 }
190
191 return rc;
192}
193
194// main
195///////////////////////////////////////////////////////////////////////////////
196
197int main(int argc, char *argv[])
198{
199 /*
200 * Initialize the VBox runtime without loading
201 * the support driver.
202 */
203 RTR3InitExe(argc, &argv, 0);
204
205 HRESULT rc;
206
207 {
208 char homeDir[RTPATH_MAX];
209 GetVBoxUserHomeDirectory(homeDir, sizeof(homeDir));
210 RTPrintf("VirtualBox Home Directory = '%s'\n", homeDir);
211 }
212
213 RTPrintf("Initializing COM...\n");
214
215 rc = com::Initialize();
216 if (FAILED(rc))
217 {
218 RTPrintf("ERROR: failed to initialize COM!\n");
219 return rc;
220 }
221
222 do
223 {
224 // scopes all the stuff till shutdown
225 ////////////////////////////////////////////////////////////////////////////
226
227 ComPtr<IVirtualBox> virtualBox;
228 ComPtr<ISession> session;
229
230#if 0
231 // Utf8Str test
232 ////////////////////////////////////////////////////////////////////////////
233
234 Utf8Str nullUtf8Str;
235 RTPrintf("nullUtf8Str='%s'\n", nullUtf8Str.raw());
236
237 Utf8Str simpleUtf8Str = "simpleUtf8Str";
238 RTPrintf("simpleUtf8Str='%s'\n", simpleUtf8Str.raw());
239
240 Utf8Str utf8StrFmt = Utf8StrFmt("[0=%d]%s[1=%d]", 0, "utf8StrFmt", 1);
241 RTPrintf("utf8StrFmt='%s'\n", utf8StrFmt.raw());
242
243#endif
244
245 RTPrintf("Creating VirtualBox object...\n");
246 rc = virtualBox.createLocalObject(CLSID_VirtualBox);
247 if (FAILED(rc))
248 RTPrintf("ERROR: failed to create the VirtualBox object!\n");
249 else
250 {
251 rc = session.createInprocObject(CLSID_Session);
252 if (FAILED(rc))
253 RTPrintf("ERROR: failed to create a session object!\n");
254 }
255
256 if (FAILED(rc))
257 {
258 com::ErrorInfo info;
259 if (!info.isFullAvailable() && !info.isBasicAvailable())
260 {
261 com::GluePrintRCMessage(rc);
262 RTPrintf("Most likely, the VirtualBox COM server is not running or failed to start.\n");
263 }
264 else
265 com::GluePrintErrorInfo(info);
266 break;
267 }
268
269#if 0
270 // Testing VirtualBox::COMGETTER(ProgressOperations).
271 // This is designed to be tested while running
272 // "./VBoxManage clonehd src.vdi clone.vdi" in parallel.
273 // It will then display the progress every 2 seconds.
274 ////////////////////////////////////////////////////////////////////////////
275 {
276 RTPrintf("Testing VirtualBox::COMGETTER(ProgressOperations)...\n");
277
278 for (;;) {
279 com::SafeIfaceArray<IProgress> operations;
280
281 CHECK_ERROR_BREAK(virtualBox,
282 COMGETTER(ProgressOperations)(ComSafeArrayAsOutParam(operations)));
283
284 RTPrintf("operations: %d\n", operations.size());
285 if (operations.size() == 0)
286 break; // No more operations left.
287
288 for (size_t i = 0; i < operations.size(); ++i) {
289 PRInt32 percent;
290
291 operations[i]->COMGETTER(Percent)(&percent);
292 RTPrintf("operations[%u]: %ld\n", (unsigned)i, (long)percent);
293 }
294 RTThreadSleep(2000); // msec
295 }
296 }
297#endif
298
299#if 0
300 // IUnknown identity test
301 ////////////////////////////////////////////////////////////////////////////
302 {
303 {
304 ComPtr<IVirtualBox> virtualBox2;
305
306 RTPrintf("Creating one more VirtualBox object...\n");
307 CHECK_RC(virtualBox2.createLocalObject(CLSID_VirtualBox));
308 if (FAILED(rc))
309 {
310 CHECK_ERROR_NOCALL();
311 break;
312 }
313
314 RTPrintf("IVirtualBox(virtualBox)=%p IVirtualBox(virtualBox2)=%p\n",
315 (IVirtualBox *)virtualBox, (IVirtualBox *)virtualBox2);
316 Assert((IVirtualBox *)virtualBox == (IVirtualBox *)virtualBox2);
317
318 ComPtr<IUnknown> unk(virtualBox);
319 ComPtr<IUnknown> unk2;
320 unk2 = virtualBox2;
321
322 RTPrintf("IUnknown(virtualBox)=%p IUnknown(virtualBox2)=%p\n",
323 (IUnknown *)unk, (IUnknown *)unk2);
324 Assert((IUnknown *)unk == (IUnknown *)unk2);
325
326 ComPtr<IVirtualBox> vb = unk;
327 ComPtr<IVirtualBox> vb2 = unk;
328
329 RTPrintf("IVirtualBox(IUnknown(virtualBox))=%p IVirtualBox(IUnknown(virtualBox2))=%p\n",
330 (IVirtualBox *)vb, (IVirtualBox *)vb2);
331 Assert((IVirtualBox *)vb == (IVirtualBox *)vb2);
332 }
333
334 {
335 ComPtr<IHost> host;
336 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
337 RTPrintf(" IHost(host)=%p\n", (IHost *)host);
338 ComPtr<IUnknown> unk = host;
339 RTPrintf(" IUnknown(host)=%p\n", (IUnknown *)unk);
340 ComPtr<IHost> host_copy = unk;
341 RTPrintf(" IHost(host_copy)=%p\n", (IHost *)host_copy);
342 ComPtr<IUnknown> unk_copy = host_copy;
343 RTPrintf(" IUnknown(host_copy)=%p\n", (IUnknown *)unk_copy);
344 Assert((IUnknown *)unk == (IUnknown *)unk_copy);
345
346 /* query IUnknown on IUnknown */
347 ComPtr<IUnknown> unk_copy_copy;
348 unk_copy.queryInterfaceTo(unk_copy_copy.asOutParam());
349 RTPrintf(" IUnknown(unk_copy)=%p\n", (IUnknown *)unk_copy_copy);
350 Assert((IUnknown *)unk_copy == (IUnknown *)unk_copy_copy);
351 /* query IUnknown on IUnknown in the opposite direction */
352 unk_copy_copy.queryInterfaceTo(unk_copy.asOutParam());
353 RTPrintf(" IUnknown(unk_copy_copy)=%p\n", (IUnknown *)unk_copy);
354 Assert((IUnknown *)unk_copy == (IUnknown *)unk_copy_copy);
355
356 /* query IUnknown again after releasing all previous IUnknown instances
357 * but keeping IHost -- it should remain the same (Identity Rule) */
358 IUnknown *oldUnk = unk;
359 unk.setNull();
360 unk_copy.setNull();
361 unk_copy_copy.setNull();
362 unk = host;
363 RTPrintf(" IUnknown(host)=%p\n", (IUnknown *)unk);
364 Assert(oldUnk == (IUnknown *)unk);
365 }
366
367// RTPrintf("Will be now released (press Enter)...");
368// getchar();
369 }
370#endif
371
372#if 0
373 // the simplest COM API test
374 ////////////////////////////////////////////////////////////////////////////
375 {
376 Bstr version;
377 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Version)(version.asOutParam()));
378 RTPrintf("VirtualBox version = %ls\n", version.raw());
379 }
380#endif
381
382#if 0
383 // Array test
384 ////////////////////////////////////////////////////////////////////////////
385 {
386 RTPrintf("Calling IVirtualBox::Machines...\n");
387
388 com::SafeIfaceArray<IMachine> machines;
389 CHECK_ERROR_BREAK(virtualBox,
390 COMGETTER(Machines)(ComSafeArrayAsOutParam(machines)));
391
392 RTPrintf("%u machines registered (machines.isNull()=%d).\n",
393 machines.size(), machines.isNull());
394
395 for (size_t i = 0; i < machines.size(); ++ i)
396 {
397 Bstr name;
398 CHECK_ERROR_BREAK(machines[i], COMGETTER(Name)(name.asOutParam()));
399 RTPrintf("machines[%u]='%s'\n", i, Utf8Str(name).raw());
400 }
401
402#if 0
403 {
404 RTPrintf("Testing [out] arrays...\n");
405 com::SafeGUIDArray uuids;
406 CHECK_ERROR_BREAK(virtualBox,
407 COMGETTER(Uuids)(ComSafeArrayAsOutParam(uuids)));
408
409 for (size_t i = 0; i < uuids.size(); ++ i)
410 RTPrintf("uuids[%u]=%RTuuid\n", i, &uuids[i]);
411 }
412
413 {
414 RTPrintf("Testing [in] arrays...\n");
415 com::SafeGUIDArray uuids(5);
416 for (size_t i = 0; i < uuids.size(); ++ i)
417 {
418 Guid id;
419 id.create();
420 uuids[i] = id;
421 RTPrintf("uuids[%u]=%RTuuid\n", i, &uuids[i]);
422 }
423
424 CHECK_ERROR_BREAK(virtualBox,
425 SetUuids(ComSafeArrayAsInParam(uuids)));
426 }
427#endif
428
429 }
430#endif
431
432#if 0
433 // some outdated stuff
434 ////////////////////////////////////////////////////////////////////////////
435
436 RTPrintf("Getting IHost interface...\n");
437 IHost *host;
438 rc = virtualBox->GetHost(&host);
439 if (SUCCEEDED(rc))
440 {
441 IHostDVDDriveCollection *dvdColl;
442 rc = host->GetHostDVDDrives(&dvdColl);
443 if (SUCCEEDED(rc))
444 {
445 IHostDVDDrive *dvdDrive = NULL;
446 dvdColl->GetNextHostDVDDrive(dvdDrive, &dvdDrive);
447 while (dvdDrive)
448 {
449 BSTR driveName;
450 char *driveNameUtf8;
451 dvdDrive->GetDriveName(&driveName);
452 RTUtf16ToUtf8((PCRTUTF16)driveName, &driveNameUtf8);
453 RTPrintf("Host DVD drive name: %s\n", driveNameUtf8);
454 RTStrFree(driveNameUtf8);
455 SysFreeString(driveName);
456 IHostDVDDrive *dvdDriveTemp = dvdDrive;
457 dvdColl->GetNextHostDVDDrive(dvdDriveTemp, &dvdDrive);
458 dvdDriveTemp->Release();
459 }
460 dvdColl->Release();
461 } else
462 {
463 RTPrintf("Could not get host DVD drive collection\n");
464 }
465
466 IHostFloppyDriveCollection *floppyColl;
467 rc = host->GetHostFloppyDrives(&floppyColl);
468 if (SUCCEEDED(rc))
469 {
470 IHostFloppyDrive *floppyDrive = NULL;
471 floppyColl->GetNextHostFloppyDrive(floppyDrive, &floppyDrive);
472 while (floppyDrive)
473 {
474 BSTR driveName;
475 char *driveNameUtf8;
476 floppyDrive->GetDriveName(&driveName);
477 RTUtf16ToUtf8((PCRTUTF16)driveName, &driveNameUtf8);
478 RTPrintf("Host floppy drive name: %s\n", driveNameUtf8);
479 RTStrFree(driveNameUtf8);
480 SysFreeString(driveName);
481 IHostFloppyDrive *floppyDriveTemp = floppyDrive;
482 floppyColl->GetNextHostFloppyDrive(floppyDriveTemp, &floppyDrive);
483 floppyDriveTemp->Release();
484 }
485 floppyColl->Release();
486 } else
487 {
488 RTPrintf("Could not get host floppy drive collection\n");
489 }
490 host->Release();
491 } else
492 {
493 RTPrintf("Call failed\n");
494 }
495 RTPrintf("\n");
496#endif
497
498#if 0
499 // IVirtualBoxErrorInfo test
500 ////////////////////////////////////////////////////////////////////////////
501 {
502 // RPC calls
503
504 // call a method that will definitely fail
505 Guid uuid;
506 ComPtr<IHardDisk> hardDisk;
507 rc = virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
508 RTPrintf("virtualBox->GetHardDisk(null-uuid)=%08X\n", rc);
509
510// {
511// com::ErrorInfo info(virtualBox);
512// PRINT_ERROR_INFO(info);
513// }
514
515 // call a method that will definitely succeed
516 Bstr version;
517 rc = virtualBox->COMGETTER(Version)(version.asOutParam());
518 RTPrintf("virtualBox->COMGETTER(Version)=%08X\n", rc);
519
520 {
521 com::ErrorInfo info(virtualBox);
522 PRINT_ERROR_INFO(info);
523 }
524
525 // Local calls
526
527 // call a method that will definitely fail
528 ComPtr<IMachine> machine;
529 rc = session->COMGETTER(Machine)(machine.asOutParam());
530 RTPrintf("session->COMGETTER(Machine)=%08X\n", rc);
531
532// {
533// com::ErrorInfo info(virtualBox);
534// PRINT_ERROR_INFO(info);
535// }
536
537 // call a method that will definitely succeed
538 SessionState_T state;
539 rc = session->COMGETTER(State)(&state);
540 RTPrintf("session->COMGETTER(State)=%08X\n", rc);
541
542 {
543 com::ErrorInfo info(virtualBox);
544 PRINT_ERROR_INFO(info);
545 }
546 }
547#endif
548
549#if 0
550 // register the existing hard disk image
551 ///////////////////////////////////////////////////////////////////////////
552 do
553 {
554 ComPtr<IHardDisk> hd;
555 Bstr src = L"E:\\develop\\innotek\\images\\NewHardDisk.vdi";
556 RTPrintf("Opening the existing hard disk '%ls'...\n", src.raw());
557 CHECK_ERROR_BREAK(virtualBox, OpenHardDisk(src, AccessMode_ReadWrite, hd.asOutParam()));
558 RTPrintf("Enter to continue...\n");
559 getchar();
560 RTPrintf("Registering the existing hard disk '%ls'...\n", src.raw());
561 CHECK_ERROR_BREAK(virtualBox, RegisterHardDisk(hd));
562 RTPrintf("Enter to continue...\n");
563 getchar();
564 }
565 while (FALSE);
566 RTPrintf("\n");
567#endif
568
569#if 0
570 // find and unregister the existing hard disk image
571 ///////////////////////////////////////////////////////////////////////////
572 do
573 {
574 ComPtr<IVirtualDiskImage> vdi;
575 Bstr src = L"CreatorTest.vdi";
576 RTPrintf("Unregistering the hard disk '%ls'...\n", src.raw());
577 CHECK_ERROR_BREAK(virtualBox, FindVirtualDiskImage(src, vdi.asOutParam()));
578 ComPtr<IHardDisk> hd = vdi;
579 Guid id;
580 CHECK_ERROR_BREAK(hd, COMGETTER(Id)(id.asOutParam()));
581 CHECK_ERROR_BREAK(virtualBox, UnregisterHardDisk(id, hd.asOutParam()));
582 }
583 while (FALSE);
584 RTPrintf("\n");
585#endif
586
587#if 0
588 // clone the registered hard disk
589 ///////////////////////////////////////////////////////////////////////////
590 do
591 {
592#if defined RT_OS_LINUX
593 Bstr src = L"/mnt/hugaida/common/develop/innotek/images/freedos-linux.vdi";
594#else
595 Bstr src = L"E:/develop/innotek/images/freedos.vdi";
596#endif
597 Bstr dst = L"./clone.vdi";
598 RTPrintf("Cloning '%ls' to '%ls'...\n", src.raw(), dst.raw());
599 ComPtr<IVirtualDiskImage> vdi;
600 CHECK_ERROR_BREAK(virtualBox, FindVirtualDiskImage(src, vdi.asOutParam()));
601 ComPtr<IHardDisk> hd = vdi;
602 ComPtr<IProgress> progress;
603 CHECK_ERROR_BREAK(hd, CloneToImage(dst, vdi.asOutParam(), progress.asOutParam()));
604 RTPrintf("Waiting for completion...\n");
605 CHECK_ERROR_BREAK(progress, WaitForCompletion(-1));
606 ProgressErrorInfo ei(progress);
607 if (FAILED(ei.getResultCode()))
608 {
609 PRINT_ERROR_INFO(ei);
610 }
611 else
612 {
613 vdi->COMGETTER(FilePath)(dst.asOutParam());
614 RTPrintf("Actual clone path is '%ls'\n", dst.raw());
615 }
616 }
617 while (FALSE);
618 RTPrintf("\n");
619#endif
620
621#if 0
622 // find a registered hard disk by location and get properties
623 ///////////////////////////////////////////////////////////////////////////
624 do
625 {
626 ComPtr<IHardDisk> hd;
627 static const wchar_t *Names[] =
628 {
629#ifndef RT_OS_LINUX
630 L"freedos.vdi",
631 L"MS-DOS.vmdk",
632 L"iscsi",
633 L"some/path/and/disk.vdi",
634#else
635 L"xp.vdi",
636 L"Xp.vDI",
637#endif
638 };
639
640 RTPrintf("\n");
641
642 for (size_t i = 0; i < RT_ELEMENTS(Names); ++ i)
643 {
644 Bstr src = Names[i];
645 RTPrintf("Searching for hard disk '%ls'...\n", src.raw());
646 rc = virtualBox->FindHardDisk(src, hd.asOutParam());
647 if (SUCCEEDED(rc))
648 {
649 Guid id;
650 Bstr location;
651 CHECK_ERROR_BREAK(hd, COMGETTER(Id)(id.asOutParam()));
652 CHECK_ERROR_BREAK(hd, COMGETTER(Location)(location.asOutParam()));
653 RTPrintf("Found, UUID={%RTuuid}, location='%ls'.\n",
654 id.raw(), location.raw());
655
656 com::SafeArray<BSTR> names;
657 com::SafeArray<BSTR> values;
658
659 CHECK_ERROR_BREAK(hd, GetProperties(NULL,
660 ComSafeArrayAsOutParam(names),
661 ComSafeArrayAsOutParam(values)));
662
663 RTPrintf("Properties:\n");
664 for (size_t i = 0; i < names.size(); ++ i)
665 RTPrintf(" %ls = %ls\n", names[i], values[i]);
666
667 if (names.size() == 0)
668 RTPrintf(" <none>\n");
669
670#if 0
671 Bstr name("TargetAddress");
672 Bstr value = Utf8StrFmt("lalala (%llu)", RTTimeMilliTS());
673
674 RTPrintf("Settings property %ls to %ls...\n", name.raw(), value.raw());
675 CHECK_ERROR(hd, SetProperty(name, value));
676#endif
677 }
678 else
679 {
680 com::ErrorInfo info(virtualBox);
681 PRINT_ERROR_INFO(info);
682 }
683 RTPrintf("\n");
684 }
685 }
686 while (FALSE);
687 RTPrintf("\n");
688#endif
689
690#if 0
691 // access the machine in read-only mode
692 ///////////////////////////////////////////////////////////////////////////
693 do
694 {
695 ComPtr<IMachine> machine;
696 Bstr name = argc > 1 ? argv[1] : "dos";
697 RTPrintf("Getting a machine object named '%ls'...\n", name.raw());
698 CHECK_ERROR_BREAK(virtualBox, FindMachine(name, machine.asOutParam()));
699 RTPrintf("Accessing the machine in read-only mode:\n");
700 readAndChangeMachineSettings(machine);
701#if 0
702 if (argc != 2)
703 {
704 RTPrintf("Error: a string has to be supplied!\n");
705 }
706 else
707 {
708 Bstr secureLabel = argv[1];
709 machine->COMSETTER(ExtraData)(L"VBoxSDL/SecureLabel", secureLabel);
710 }
711#endif
712 }
713 while (0);
714 RTPrintf("\n");
715#endif
716
717#if 0
718 // create a new machine (w/o registering it)
719 ///////////////////////////////////////////////////////////////////////////
720 do
721 {
722 ComPtr<IMachine> machine;
723#if defined(RT_OS_LINUX)
724 Bstr baseDir = L"/tmp/vbox";
725#else
726 Bstr baseDir = L"C:\\vbox";
727#endif
728 Bstr name = L"machina";
729
730 RTPrintf("Creating a new machine object(base dir '%ls', name '%ls')...\n",
731 baseDir.raw(), name.raw());
732 CHECK_ERROR_BREAK(virtualBox, CreateMachine(name, L"", baseDir, L"",
733 false,
734 machine.asOutParam()));
735
736 RTPrintf("Getting name...\n");
737 CHECK_ERROR_BREAK(machine, COMGETTER(Name)(name.asOutParam()));
738 RTPrintf("Name: {%ls}\n", name.raw());
739
740 BOOL modified = FALSE;
741 RTPrintf("Are any settings modified?...\n");
742 CHECK_ERROR_BREAK(machine, COMGETTER(SettingsModified)(&modified));
743 RTPrintf("%s\n", modified ? "yes" : "no");
744
745 ASSERT_BREAK(modified == TRUE);
746
747 name = L"Kakaya prekrasnaya virtual'naya mashina!";
748 RTPrintf("Setting new name ({%ls})...\n", name.raw());
749 CHECK_ERROR_BREAK(machine, COMSETTER(Name)(name));
750
751 RTPrintf("Setting memory size to 111...\n");
752 CHECK_ERROR_BREAK(machine, COMSETTER(MemorySize)(111));
753
754 Bstr desc = L"This is an exemplary description.";
755 RTPrintf("Setting description to \"%ls\"...\n", desc.raw());
756 CHECK_ERROR_BREAK(machine, COMSETTER(Description)(desc));
757
758 ComPtr<IGuestOSType> guestOSType;
759 Bstr type = L"os2warp45";
760 CHECK_ERROR_BREAK(virtualBox, GetGuestOSType(type, guestOSType.asOutParam()));
761
762 RTPrintf("Saving new machine settings...\n");
763 CHECK_ERROR_BREAK(machine, SaveSettings());
764
765 RTPrintf("Accessing the newly created machine:\n");
766 readAndChangeMachineSettings(machine);
767 }
768 while (FALSE);
769 RTPrintf("\n");
770#endif
771
772#if 0
773 // enumerate host DVD drives
774 ///////////////////////////////////////////////////////////////////////////
775 do
776 {
777 ComPtr<IHost> host;
778 CHECK_RC_BREAK(virtualBox->COMGETTER(Host)(host.asOutParam()));
779
780 {
781 ComPtr<IHostDVDDriveCollection> coll;
782 CHECK_RC_BREAK(host->COMGETTER(DVDDrives)(coll.asOutParam()));
783 ComPtr<IHostDVDDriveEnumerator> enumerator;
784 CHECK_RC_BREAK(coll->Enumerate(enumerator.asOutParam()));
785 BOOL hasmore;
786 while (SUCCEEDED(enumerator->HasMore(&hasmore)) && hasmore)
787 {
788 ComPtr<IHostDVDDrive> drive;
789 CHECK_RC_BREAK(enumerator->GetNext(drive.asOutParam()));
790 Bstr name;
791 CHECK_RC_BREAK(drive->COMGETTER(Name)(name.asOutParam()));
792 RTPrintf("Host DVD drive: name={%ls}\n", name.raw());
793 }
794 CHECK_RC_BREAK(rc);
795
796 ComPtr<IHostDVDDrive> drive;
797 CHECK_ERROR(enumerator, GetNext(drive.asOutParam()));
798 CHECK_ERROR(coll, GetItemAt(1000, drive.asOutParam()));
799 CHECK_ERROR(coll, FindByName(Bstr("R:"), drive.asOutParam()));
800 if (SUCCEEDED(rc))
801 {
802 Bstr name;
803 CHECK_RC_BREAK(drive->COMGETTER(Name)(name.asOutParam()));
804 RTPrintf("Found by name: name={%ls}\n", name.raw());
805 }
806 }
807 }
808 while (FALSE);
809 RTPrintf("\n");
810#endif
811
812#if 0
813 // check for available hd backends
814 ///////////////////////////////////////////////////////////////////////////
815 {
816 RTPrintf("Supported hard disk backends: --------------------------\n");
817 ComPtr<ISystemProperties> systemProperties;
818 CHECK_ERROR_BREAK(virtualBox,
819 COMGETTER(SystemProperties)(systemProperties.asOutParam()));
820 com::SafeIfaceArray<IHardDiskFormat> hardDiskFormats;
821 CHECK_ERROR_BREAK(systemProperties,
822 COMGETTER(HardDiskFormats)(ComSafeArrayAsOutParam(hardDiskFormats)));
823
824 for (size_t i = 0; i < hardDiskFormats.size(); ++ i)
825 {
826 /* General information */
827 Bstr id;
828 CHECK_ERROR_BREAK(hardDiskFormats[i],
829 COMGETTER(Id)(id.asOutParam()));
830
831 Bstr description;
832 CHECK_ERROR_BREAK(hardDiskFormats[i],
833 COMGETTER(Id)(description.asOutParam()));
834
835 ULONG caps;
836 CHECK_ERROR_BREAK(hardDiskFormats[i],
837 COMGETTER(Capabilities)(&caps));
838
839 RTPrintf("Backend %u: id='%ls' description='%ls' capabilities=%#06x extensions='",
840 i, id.raw(), description.raw(), caps);
841
842 /* File extensions */
843 com::SafeArray<BSTR> fileExtensions;
844 CHECK_ERROR_BREAK(hardDiskFormats[i],
845 COMGETTER(FileExtensions)(ComSafeArrayAsOutParam(fileExtensions)));
846 for (size_t a = 0; a < fileExtensions.size(); ++ a)
847 {
848 RTPrintf("%ls", Bstr(fileExtensions[a]).raw());
849 if (a != fileExtensions.size()-1)
850 RTPrintf(",");
851 }
852 RTPrintf("'");
853
854 /* Configuration keys */
855 com::SafeArray<BSTR> propertyNames;
856 com::SafeArray<BSTR> propertyDescriptions;
857 com::SafeArray<ULONG> propertyTypes;
858 com::SafeArray<ULONG> propertyFlags;
859 com::SafeArray<BSTR> propertyDefaults;
860 CHECK_ERROR_BREAK(hardDiskFormats[i],
861 DescribeProperties(ComSafeArrayAsOutParam(propertyNames),
862 ComSafeArrayAsOutParam(propertyDescriptions),
863 ComSafeArrayAsOutParam(propertyTypes),
864 ComSafeArrayAsOutParam(propertyFlags),
865 ComSafeArrayAsOutParam(propertyDefaults)));
866
867 RTPrintf(" config=(");
868 if (propertyNames.size() > 0)
869 {
870 for (size_t a = 0; a < propertyNames.size(); ++ a)
871 {
872 RTPrintf("key='%ls' desc='%ls' type=", Bstr(propertyNames[a]).raw(), Bstr(propertyDescriptions[a]).raw());
873 switch (propertyTypes[a])
874 {
875 case DataType_Int32Type: RTPrintf("int"); break;
876 case DataType_Int8Type: RTPrintf("byte"); break;
877 case DataType_StringType: RTPrintf("string"); break;
878 }
879 RTPrintf(" flags=%#04x", propertyFlags[a]);
880 RTPrintf(" default='%ls'", Bstr(propertyDefaults[a]).raw());
881 if (a != propertyNames.size()-1)
882 RTPrintf(",");
883 }
884 }
885 RTPrintf(")\n");
886 }
887 RTPrintf("-------------------------------------------------------\n");
888 }
889#endif
890
891#if 0
892 // enumerate hard disks & dvd images
893 ///////////////////////////////////////////////////////////////////////////
894 do
895 {
896 {
897 com::SafeIfaceArray<IHardDisk> disks;
898 CHECK_ERROR_BREAK(virtualBox,
899 COMGETTER(HardDisks)(ComSafeArrayAsOutParam(disks)));
900
901 RTPrintf("%u base hard disks registered (disks.isNull()=%d).\n",
902 disks.size(), disks.isNull());
903
904 for (size_t i = 0; i < disks.size(); ++ i)
905 {
906 Bstr loc;
907 CHECK_ERROR_BREAK(disks[i], COMGETTER(Location)(loc.asOutParam()));
908 Guid id;
909 CHECK_ERROR_BREAK(disks[i], COMGETTER(Id)(id.asOutParam()));
910 MediaState_T state;
911 CHECK_ERROR_BREAK(disks[i], COMGETTER(State)(&state));
912 Bstr format;
913 CHECK_ERROR_BREAK(disks[i], COMGETTER(Format)(format.asOutParam()));
914
915 RTPrintf(" disks[%u]: '%ls'\n"
916 " UUID: {%RTuuid}\n"
917 " State: %s\n"
918 " Format: %ls\n",
919 i, loc.raw(), id.raw(),
920 state == MediaState_NotCreated ? "Not Created" :
921 state == MediaState_Created ? "Created" :
922 state == MediaState_Inaccessible ? "Inaccessible" :
923 state == MediaState_LockedRead ? "Locked Read" :
924 state == MediaState_LockedWrite ? "Locked Write" :
925 "???",
926 format.raw());
927
928 if (state == MediaState_Inaccessible)
929 {
930 Bstr error;
931 CHECK_ERROR_BREAK(disks[i],
932 COMGETTER(LastAccessError)(error.asOutParam()));
933 RTPrintf(" Access Error: %ls\n", error.raw());
934 }
935
936 /* get usage */
937
938 RTPrintf(" Used by VMs:\n");
939
940 com::SafeGUIDArray ids;
941 CHECK_ERROR_BREAK(disks[i],
942 COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids)));
943 if (ids.size() == 0)
944 {
945 RTPrintf(" <not used>\n");
946 }
947 else
948 {
949 for (size_t j = 0; j < ids.size(); ++ j)
950 {
951 RTPrintf(" {%RTuuid}\n", &ids[j]);
952 }
953 }
954 }
955 }
956 {
957 com::SafeIfaceArray<IDVDImage> images;
958 CHECK_ERROR_BREAK(virtualBox,
959 COMGETTER(DVDImages)(ComSafeArrayAsOutParam(images)));
960
961 RTPrintf("%u DVD images registered (images.isNull()=%d).\n",
962 images.size(), images.isNull());
963
964 for (size_t i = 0; i < images.size(); ++ i)
965 {
966 Bstr loc;
967 CHECK_ERROR_BREAK(images[i], COMGETTER(Location)(loc.asOutParam()));
968 Guid id;
969 CHECK_ERROR_BREAK(images[i], COMGETTER(Id)(id.asOutParam()));
970 MediaState_T state;
971 CHECK_ERROR_BREAK(images[i], COMGETTER(State)(&state));
972
973 RTPrintf(" images[%u]: '%ls'\n"
974 " UUID: {%RTuuid}\n"
975 " State: %s\n",
976 i, loc.raw(), id.raw(),
977 state == MediaState_NotCreated ? "Not Created" :
978 state == MediaState_Created ? "Created" :
979 state == MediaState_Inaccessible ? "Inaccessible" :
980 state == MediaState_LockedRead ? "Locked Read" :
981 state == MediaState_LockedWrite ? "Locked Write" :
982 "???");
983
984 if (state == MediaState_Inaccessible)
985 {
986 Bstr error;
987 CHECK_ERROR_BREAK(images[i],
988 COMGETTER(LastAccessError)(error.asOutParam()));
989 RTPrintf(" Access Error: %ls\n", error.raw());
990 }
991
992 /* get usage */
993
994 RTPrintf(" Used by VMs:\n");
995
996 com::SafeGUIDArray ids;
997 CHECK_ERROR_BREAK(images[i],
998 COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids)));
999 if (ids.size() == 0)
1000 {
1001 RTPrintf(" <not used>\n");
1002 }
1003 else
1004 {
1005 for (size_t j = 0; j < ids.size(); ++ j)
1006 {
1007 RTPrintf(" {%RTuuid}\n", &ids[j]);
1008 }
1009 }
1010 }
1011 }
1012 }
1013 while (FALSE);
1014 RTPrintf("\n");
1015#endif
1016
1017#if 0
1018 // open a (direct) session
1019 ///////////////////////////////////////////////////////////////////////////
1020 do
1021 {
1022 ComPtr<IMachine> machine;
1023 Bstr name = argc > 1 ? argv[1] : "dos";
1024 RTPrintf("Getting a machine object named '%ls'...\n", name.raw());
1025 CHECK_ERROR_BREAK(virtualBox, FindMachine(name, machine.asOutParam()));
1026 Guid guid;
1027 CHECK_RC_BREAK(machine->COMGETTER(Id)(guid.asOutParam()));
1028 RTPrintf("Opening a session for this machine...\n");
1029 CHECK_RC_BREAK(virtualBox->OpenSession(session, guid));
1030#if 1
1031 ComPtr<IMachine> sessionMachine;
1032 RTPrintf("Getting machine session object...\n");
1033 CHECK_RC_BREAK(session->COMGETTER(Machine)(sessionMachine.asOutParam()));
1034 RTPrintf("Accessing the machine within the session:\n");
1035 readAndChangeMachineSettings(sessionMachine, machine);
1036#if 0
1037 RTPrintf("\n");
1038 RTPrintf("Enabling the VRDE server (must succeed even if the VM is saved):\n");
1039 ComPtr<IVRDEServer> vrdeServer;
1040 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(VRDEServer)(vrdeServer.asOutParam()));
1041 if (FAILED(vrdeServer->COMSETTER(Enabled)(TRUE)))
1042 {
1043 PRINT_ERROR_INFO(com::ErrorInfo(vrdeServer));
1044 }
1045 else
1046 {
1047 BOOL enabled = FALSE;
1048 CHECK_ERROR_BREAK(vrdeServer, COMGETTER(Enabled)(&enabled));
1049 RTPrintf("VRDE server is %s\n", enabled ? "enabled" : "disabled");
1050 }
1051#endif
1052#endif
1053#if 0
1054 ComPtr<IConsole> console;
1055 RTPrintf("Getting the console object...\n");
1056 CHECK_RC_BREAK(session->COMGETTER(Console)(console.asOutParam()));
1057 RTPrintf("Discarding the current machine state...\n");
1058 ComPtr<IProgress> progress;
1059 CHECK_ERROR_BREAK(console, DiscardCurrentState(progress.asOutParam()));
1060 RTPrintf("Waiting for completion...\n");
1061 CHECK_ERROR_BREAK(progress, WaitForCompletion(-1));
1062 ProgressErrorInfo ei(progress);
1063 if (FAILED(ei.getResultCode()))
1064 {
1065 PRINT_ERROR_INFO(ei);
1066
1067 ComPtr<IUnknown> initiator;
1068 CHECK_ERROR_BREAK(progress, COMGETTER(Initiator)(initiator.asOutParam()));
1069
1070 RTPrintf("initiator(unk) = %p\n", (IUnknown *)initiator);
1071 RTPrintf("console(unk) = %p\n", (IUnknown *)ComPtr<IUnknown>((IConsole *)console));
1072 RTPrintf("console = %p\n", (IConsole *)console);
1073 }
1074#endif
1075 RTPrintf("Press enter to close session...");
1076 getchar();
1077 session->Close();
1078 }
1079 while (FALSE);
1080 RTPrintf("\n");
1081#endif
1082
1083#if 0
1084 // open a remote session
1085 ///////////////////////////////////////////////////////////////////////////
1086 do
1087 {
1088 ComPtr<IMachine> machine;
1089 Bstr name = L"dos";
1090 RTPrintf("Getting a machine object named '%ls'...\n", name.raw());
1091 CHECK_RC_BREAK(virtualBox->FindMachine(name, machine.asOutParam()));
1092 Guid guid;
1093 CHECK_RC_BREAK(machine->COMGETTER(Id)(guid.asOutParam()));
1094 RTPrintf("Opening a remote session for this machine...\n");
1095 ComPtr<IProgress> progress;
1096 CHECK_RC_BREAK(virtualBox->OpenRemoteSession(session, guid, Bstr("gui"),
1097 NULL, progress.asOutParam()));
1098 RTPrintf("Waiting for the session to open...\n");
1099 CHECK_RC_BREAK(progress->WaitForCompletion(-1));
1100 ComPtr<IMachine> sessionMachine;
1101 RTPrintf("Getting machine session object...\n");
1102 CHECK_RC_BREAK(session->COMGETTER(Machine)(sessionMachine.asOutParam()));
1103 ComPtr<IConsole> console;
1104 RTPrintf("Getting console object...\n");
1105 CHECK_RC_BREAK(session->COMGETTER(Console)(console.asOutParam()));
1106 RTPrintf("Press enter to pause the VM execution in the remote session...");
1107 getchar();
1108 CHECK_RC(console->Pause());
1109 RTPrintf("Press enter to close this session...");
1110 getchar();
1111 session->Close();
1112 }
1113 while (FALSE);
1114 RTPrintf("\n");
1115#endif
1116
1117#if 0
1118 // open an existing remote session
1119 ///////////////////////////////////////////////////////////////////////////
1120 do
1121 {
1122 ComPtr<IMachine> machine;
1123 Bstr name = "dos";
1124 RTPrintf("Getting a machine object named '%ls'...\n", name.raw());
1125 CHECK_RC_BREAK(virtualBox->FindMachine(name, machine.asOutParam()));
1126 Guid guid;
1127 CHECK_RC_BREAK(machine->COMGETTER(Id)(guid.asOutParam()));
1128 RTPrintf("Opening an existing remote session for this machine...\n");
1129 CHECK_RC_BREAK(virtualBox->OpenExistingSession(session, guid));
1130 ComPtr<IMachine> sessionMachine;
1131 RTPrintf("Getting machine session object...\n");
1132 CHECK_RC_BREAK(session->COMGETTER(Machine)(sessionMachine.asOutParam()));
1133
1134#if 0
1135 Bstr extraDataKey = "VBoxSDL/SecureLabel";
1136 Bstr extraData = "Das kommt jetzt noch viel krasser vom total konkreten API!";
1137 CHECK_RC(sessionMachine->SetExtraData(extraDataKey, extraData));
1138#endif
1139#if 0
1140 ComPtr<IConsole> console;
1141 RTPrintf("Getting console object...\n");
1142 CHECK_RC_BREAK(session->COMGETTER(Console)(console.asOutParam()));
1143 RTPrintf("Press enter to pause the VM execution in the remote session...");
1144 getchar();
1145 CHECK_RC(console->Pause());
1146 RTPrintf("Press enter to close this session...");
1147 getchar();
1148#endif
1149 session->Close();
1150 }
1151 while (FALSE);
1152 RTPrintf("\n");
1153#endif
1154
1155#if 1
1156 do {
1157 // Get host
1158 ComPtr<IHost> host;
1159 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
1160
1161 ULONG uMemSize, uMemAvail;
1162 CHECK_ERROR_BREAK(host, COMGETTER(MemorySize)(&uMemSize));
1163 RTPrintf("Total memory (MB): %u\n", uMemSize);
1164 CHECK_ERROR_BREAK(host, COMGETTER(MemoryAvailable)(&uMemAvail));
1165 RTPrintf("Free memory (MB): %u\n", uMemAvail);
1166 } while (0);
1167#endif
1168
1169#if 0
1170 do {
1171 // Get host
1172 ComPtr<IHost> host;
1173 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
1174
1175 com::SafeIfaceArray<IHostNetworkInterface> hostNetworkInterfaces;
1176 CHECK_ERROR_BREAK(host,
1177 COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(hostNetworkInterfaces)));
1178 if (hostNetworkInterfaces.size() > 0)
1179 {
1180 ComPtr<IHostNetworkInterface> networkInterface = hostNetworkInterfaces[0];
1181 Bstr interfaceName;
1182 networkInterface->COMGETTER(Name)(interfaceName.asOutParam());
1183 RTPrintf("Found %d network interfaces, testing with %ls...\n", hostNetworkInterfaces.size(), interfaceName.raw());
1184 Bstr interfaceGuid;
1185 networkInterface->COMGETTER(Id)(interfaceGuid.asOutParam());
1186 // Find the interface by its name
1187 networkInterface.setNull();
1188 CHECK_ERROR_BREAK(host,
1189 FindHostNetworkInterfaceByName(interfaceName.raw(), networkInterface.asOutParam()));
1190 Bstr interfaceGuid2;
1191 networkInterface->COMGETTER(Id)(interfaceGuid2.asOutParam());
1192 if (interfaceGuid2 != interfaceGuid)
1193 RTPrintf("Failed to retrieve an interface by name %ls.\n", interfaceName.raw());
1194 // Find the interface by its guid
1195 networkInterface.setNull();
1196 CHECK_ERROR_BREAK(host,
1197 FindHostNetworkInterfaceById(interfaceGuid.raw(), networkInterface.asOutParam()));
1198 Bstr interfaceName2;
1199 networkInterface->COMGETTER(Name)(interfaceName2.asOutParam());
1200 if (interfaceName != interfaceName2)
1201 RTPrintf("Failed to retrieve an interface by GUID %ls.\n", interfaceGuid.raw());
1202 }
1203 else
1204 {
1205 RTPrintf("No network interfaces found!\n");
1206 }
1207 } while (0);
1208#endif
1209
1210#if 0
1211 // DNS & Co.
1212 ///////////////////////////////////////////////////////////////////////////
1213 /* XXX: Note it's endless loop */
1214 do
1215 {
1216 ComPtr<IHost> host;
1217 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
1218
1219 {
1220 Bstr domainName;
1221 CHECK_ERROR_BREAK(host,COMGETTER(DomainName)(domainName.asOutParam()));
1222 RTPrintf("Domain name: %ls\n", domainName.raw());
1223 }
1224
1225 com::SafeArray<BSTR> strs;
1226 CHECK_ERROR_BREAK(host, COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs)));
1227
1228 unsigned int i;
1229 for (i = 0; i < strs.size(); ++i)
1230 RTPrintf("Name server[%d]:%s\n", i, com::Utf8Str(strs[i]).c_str());
1231
1232 RTThreadSleep(1000);
1233 }
1234 while (1);
1235 RTPrintf("\n");
1236#endif
1237
1238
1239#if 0 && defined(VBOX_WITH_RESOURCE_USAGE_API)
1240 do {
1241 // Get collector
1242 ComPtr<IPerformanceCollector> collector;
1243 CHECK_ERROR_BREAK(virtualBox,
1244 COMGETTER(PerformanceCollector)(collector.asOutParam()));
1245
1246
1247 // Fill base metrics array
1248 Bstr baseMetricNames[] = { L"Net/eth0/Load" };
1249 com::SafeArray<BSTR> baseMetrics(1);
1250 baseMetricNames[0].cloneTo(&baseMetrics[0]);
1251
1252 // Get host
1253 ComPtr<IHost> host;
1254 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
1255
1256 // Get host network interfaces
1257 // com::SafeIfaceArray<IHostNetworkInterface> hostNetworkInterfaces;
1258 // CHECK_ERROR_BREAK(host,
1259 // COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(hostNetworkInterfaces)));
1260
1261 // Setup base metrics
1262 // Note that one needs to set up metrics after a session is open for a machine.
1263 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
1264 com::SafeIfaceArray<IUnknown> objects(1);
1265 host.queryInterfaceTo(&objects[0]);
1266 CHECK_ERROR_BREAK(collector, SetupMetrics(ComSafeArrayAsInParam(baseMetrics),
1267 ComSafeArrayAsInParam(objects), 1u, 10u,
1268 ComSafeArrayAsOutParam(affectedMetrics)));
1269 listAffectedMetrics(virtualBox,
1270 ComSafeArrayAsInParam(affectedMetrics));
1271 affectedMetrics.setNull();
1272
1273 RTPrintf("Sleeping for 5 seconds...\n");
1274 RTThreadSleep(5000); // Sleep for 5 seconds
1275
1276 RTPrintf("\nMetrics collected: --------------------\n");
1277 queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects));
1278 } while (false);
1279#endif /* VBOX_WITH_RESOURCE_USAGE_API */
1280#if 0 && defined(VBOX_WITH_RESOURCE_USAGE_API)
1281 do {
1282 // Get collector
1283 ComPtr<IPerformanceCollector> collector;
1284 CHECK_ERROR_BREAK(virtualBox,
1285 COMGETTER(PerformanceCollector)(collector.asOutParam()));
1286
1287
1288 // Fill base metrics array
1289 //Bstr baseMetricNames[] = { L"CPU/Load,RAM/Usage" };
1290 Bstr baseMetricNames[] = { L"RAM/VMM" };
1291 com::SafeArray<BSTR> baseMetrics(1);
1292 baseMetricNames[0].cloneTo(&baseMetrics[0]);
1293
1294 // Get host
1295 ComPtr<IHost> host;
1296 CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam()));
1297
1298 // Get machine
1299 ComPtr<IMachine> machine;
1300 Bstr name = argc > 1 ? argv[1] : "dsl";
1301 Bstr sessionType = argc > 2 ? argv[2] : "headless";
1302 RTPrintf("Getting a machine object named '%ls'...\n", name.raw());
1303 CHECK_ERROR_BREAK(virtualBox, FindMachine(name.raw(), machine.asOutParam()));
1304
1305 // Open session
1306 ComPtr<IProgress> progress;
1307 RTPrintf("Launching VM process...\n");
1308 CHECK_ERROR_BREAK(machine, LaunchVMProcess(session, sessionType.raw(),
1309 NULL, progress.asOutParam()));
1310 RTPrintf("Waiting for the VM to power on...\n");
1311 CHECK_ERROR_BREAK(progress, WaitForCompletion(-1));
1312
1313 // ComPtr<IMachine> sessionMachine;
1314 // RTPrintf("Getting machine session object...\n");
1315 // CHECK_ERROR_BREAK(session, COMGETTER(Machine)(sessionMachine.asOutParam()));
1316
1317 // Setup base metrics
1318 // Note that one needs to set up metrics after a session is open for a machine.
1319 com::SafeIfaceArray<IPerformanceMetric> affectedMetrics;
1320 com::SafeIfaceArray<IUnknown> objects(1);
1321 host.queryInterfaceTo(&objects[0]);
1322 //machine.queryInterfaceTo(&objects[1]);
1323 CHECK_ERROR_BREAK(collector, SetupMetrics(ComSafeArrayAsInParam(baseMetrics),
1324 ComSafeArrayAsInParam(objects), 1u, 10u,
1325 ComSafeArrayAsOutParam(affectedMetrics)));
1326 listAffectedMetrics(virtualBox,
1327 ComSafeArrayAsInParam(affectedMetrics));
1328 affectedMetrics.setNull();
1329
1330 // Get console
1331 ComPtr<IConsole> console;
1332 RTPrintf("Getting console object...\n");
1333 CHECK_ERROR_BREAK(session, COMGETTER(Console)(console.asOutParam()));
1334
1335 RTThreadSleep(5000); // Sleep for 5 seconds
1336
1337 RTPrintf("\nMetrics collected with VM running: --------------------\n");
1338 queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects));
1339
1340 // Pause
1341 //RTPrintf("Press enter to pause the VM execution in the remote session...");
1342 //getchar();
1343 CHECK_ERROR_BREAK(console, Pause());
1344
1345 RTThreadSleep(5000); // Sleep for 5 seconds
1346
1347 RTPrintf("\nMetrics collected with VM paused: ---------------------\n");
1348 queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects));
1349
1350 RTPrintf("\nDrop collected metrics: ----------------------------------------\n");
1351 CHECK_ERROR_BREAK(collector,
1352 SetupMetrics(ComSafeArrayAsInParam(baseMetrics),
1353 ComSafeArrayAsInParam(objects),
1354 1u, 5u, ComSafeArrayAsOutParam(affectedMetrics)));
1355 listAffectedMetrics(virtualBox,
1356 ComSafeArrayAsInParam(affectedMetrics));
1357 affectedMetrics.setNull();
1358 queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects));
1359
1360 com::SafeIfaceArray<IUnknown> vmObject(1);
1361 machine.queryInterfaceTo(&vmObject[0]);
1362
1363 RTPrintf("\nDisable collection of VM metrics: ------------------------------\n");
1364 CHECK_ERROR_BREAK(collector,
1365 DisableMetrics(ComSafeArrayAsInParam(baseMetrics),
1366 ComSafeArrayAsInParam(vmObject),
1367 ComSafeArrayAsOutParam(affectedMetrics)));
1368 listAffectedMetrics(virtualBox,
1369 ComSafeArrayAsInParam(affectedMetrics));
1370 affectedMetrics.setNull();
1371 RTThreadSleep(5000); // Sleep for 5 seconds
1372 queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects));
1373
1374 RTPrintf("\nRe-enable collection of all metrics: ---------------------------\n");
1375 CHECK_ERROR_BREAK(collector,
1376 EnableMetrics(ComSafeArrayAsInParam(baseMetrics),
1377 ComSafeArrayAsInParam(objects),
1378 ComSafeArrayAsOutParam(affectedMetrics)));
1379 listAffectedMetrics(virtualBox,
1380 ComSafeArrayAsInParam(affectedMetrics));
1381 affectedMetrics.setNull();
1382 RTThreadSleep(5000); // Sleep for 5 seconds
1383 queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects));
1384
1385 // Power off
1386 RTPrintf("Press enter to power off VM...");
1387 getchar();
1388 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
1389 RTPrintf("Waiting for the VM to power down...\n");
1390 CHECK_ERROR_BREAK(progress, WaitForCompletion(-1));
1391 RTPrintf("Press enter to close this session...");
1392 getchar();
1393 session->UnlockMachine();
1394 } while (false);
1395#endif /* VBOX_WITH_RESOURCE_USAGE_API */
1396#if 0
1397 // check of OVF appliance handling
1398 ///////////////////////////////////////////////////////////////////////////
1399 do
1400 {
1401 Bstr ovf = argc > 1 ? argv[1] : "someOVF.ovf";
1402 RTPrintf("Try to open %ls ...\n", ovf.raw());
1403
1404 ComPtr<IAppliance> appliance;
1405 CHECK_ERROR_BREAK(virtualBox,
1406 CreateAppliance(appliance.asOutParam()));
1407 CHECK_ERROR_BREAK(appliance, Read(ovf));
1408 Bstr path;
1409 CHECK_ERROR_BREAK(appliance, COMGETTER(Path)(path.asOutParam()));
1410 RTPrintf("Successfully opened %ls.\n", path.raw());
1411 CHECK_ERROR_BREAK(appliance, Interpret());
1412 RTPrintf("Successfully interpreted %ls.\n", path.raw());
1413 RTPrintf("Appliance:\n");
1414 // Fetch all disks
1415 com::SafeArray<BSTR> retDisks;
1416 CHECK_ERROR_BREAK(appliance,
1417 COMGETTER(Disks)(ComSafeArrayAsOutParam(retDisks)));
1418 if (retDisks.size() > 0)
1419 {
1420 RTPrintf("Disks:");
1421 for (unsigned i = 0; i < retDisks.size(); i++)
1422 RTPrintf(" %ls", Bstr(retDisks[i]).raw());
1423 RTPrintf("\n");
1424 }
1425 /* Fetch all virtual system descriptions */
1426 com::SafeIfaceArray<IVirtualSystemDescription> retVSD;
1427 CHECK_ERROR_BREAK(appliance,
1428 COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(retVSD)));
1429 if (retVSD.size() > 0)
1430 {
1431 for (unsigned i = 0; i < retVSD.size(); ++i)
1432 {
1433 com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
1434 com::SafeArray<BSTR> retRefValues;
1435 com::SafeArray<BSTR> retOrigValues;
1436 com::SafeArray<BSTR> retAutoValues;
1437 com::SafeArray<BSTR> retConfiguration;
1438 CHECK_ERROR_BREAK(retVSD[i],
1439 GetDescription(ComSafeArrayAsOutParam(retTypes),
1440 ComSafeArrayAsOutParam(retRefValues),
1441 ComSafeArrayAsOutParam(retOrigValues),
1442 ComSafeArrayAsOutParam(retAutoValues),
1443 ComSafeArrayAsOutParam(retConfiguration)));
1444
1445 RTPrintf("VirtualSystemDescription:\n");
1446 for (unsigned a = 0; a < retTypes.size(); ++a)
1447 {
1448 RTPrintf(" %d %ls %ls %ls\n",
1449 retTypes[a],
1450 Bstr(retOrigValues[a]).raw(),
1451 Bstr(retAutoValues[a]).raw(),
1452 Bstr(retConfiguration[a]).raw());
1453 }
1454 /* Show warnings from interpret */
1455 com::SafeArray<BSTR> retWarnings;
1456 CHECK_ERROR_BREAK(retVSD[i],
1457 GetWarnings(ComSafeArrayAsOutParam(retWarnings)));
1458 if (retWarnings.size() > 0)
1459 {
1460 RTPrintf("The following warnings occurs on interpret:\n");
1461 for (unsigned r = 0; r < retWarnings.size(); ++r)
1462 RTPrintf("%ls\n", Bstr(retWarnings[r]).raw());
1463 RTPrintf("\n");
1464 }
1465 }
1466 RTPrintf("\n");
1467 }
1468 RTPrintf("Try to import the appliance ...\n");
1469 ComPtr<IProgress> progress;
1470 CHECK_ERROR_BREAK(appliance,
1471 ImportMachines(progress.asOutParam()));
1472 CHECK_ERROR(progress, WaitForCompletion(-1));
1473 if (SUCCEEDED(rc))
1474 {
1475 /* Check if the import was successfully */
1476 progress->COMGETTER(ResultCode)(&rc);
1477 if (FAILED(rc))
1478 {
1479 com::ProgressErrorInfo info(progress);
1480 if (info.isBasicAvailable())
1481 RTPrintf("Error: failed to import appliance. Error message: %ls\n", info.getText().raw());
1482 else
1483 RTPrintf("Error: failed to import appliance. No error message available!\n");
1484 }
1485 else
1486 RTPrintf("Successfully imported the appliance.\n");
1487 }
1488
1489 }
1490 while (FALSE);
1491 RTPrintf("\n");
1492#endif
1493#if 0
1494 // check of network bandwidth control
1495 ///////////////////////////////////////////////////////////////////////////
1496 do
1497 {
1498 Bstr name = argc > 1 ? argv[1] : "ubuntu";
1499 Bstr sessionType = argc > 2 ? argv[2] : "headless";
1500 Bstr grpName = "tstAPI";
1501 {
1502 // Get machine
1503 ComPtr<IMachine> machine;
1504 ComPtr<IBandwidthControl> bwCtrl;
1505 ComPtr<IBandwidthGroup> bwGroup;
1506 ComPtr<INetworkAdapter> nic;
1507 RTPrintf("Getting a machine object named '%ls'...\n", name.raw());
1508 CHECK_ERROR_BREAK(virtualBox, FindMachine(name.raw(), machine.asOutParam()));
1509 /* open a session for the VM (new or shared) */
1510 CHECK_ERROR_BREAK(machine, LockMachine(session, LockType_Shared));
1511 SessionType_T st;
1512 CHECK_ERROR_BREAK(session, COMGETTER(Type)(&st));
1513 bool fRunTime = (st == SessionType_Shared);
1514 if (fRunTime)
1515 {
1516 RTPrintf("Machine %ls must not be running!\n");
1517 break;
1518 }
1519 /* get the mutable session machine */
1520 session->COMGETTER(Machine)(machine.asOutParam());
1521 CHECK_ERROR_BREAK(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam()));
1522
1523 RTPrintf("Creating bandwidth group named '%ls'...\n", grpName.raw());
1524 CHECK_ERROR_BREAK(bwCtrl, CreateBandwidthGroup(grpName.raw(), BandwidthGroupType_Network, 123));
1525
1526
1527 CHECK_ERROR_BREAK(bwCtrl, GetBandwidthGroup(grpName.raw(), bwGroup.asOutParam()));
1528 CHECK_ERROR_BREAK(machine, GetNetworkAdapter(0, nic.asOutParam()));
1529 RTPrintf("Assigning the group to the first network adapter...\n");
1530 CHECK_ERROR_BREAK(nic, COMSETTER(BandwidthGroup)(bwGroup));
1531 CHECK_ERROR_BREAK(machine, SaveSettings());
1532 RTPrintf("Press enter to close this session...");
1533 getchar();
1534 session->UnlockMachine();
1535 }
1536 {
1537 // Get machine
1538 ComPtr<IMachine> machine;
1539 ComPtr<IBandwidthControl> bwCtrl;
1540 ComPtr<IBandwidthGroup> bwGroup;
1541 Bstr grpNameReadFromNic;
1542 ComPtr<INetworkAdapter> nic;
1543 RTPrintf("Getting a machine object named '%ls'...\n", name.raw());
1544 CHECK_ERROR_BREAK(virtualBox, FindMachine(name.raw(), machine.asOutParam()));
1545 /* open a session for the VM (new or shared) */
1546 CHECK_ERROR_BREAK(machine, LockMachine(session, LockType_Shared));
1547 /* get the mutable session machine */
1548 session->COMGETTER(Machine)(machine.asOutParam());
1549 CHECK_ERROR_BREAK(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam()));
1550 CHECK_ERROR_BREAK(machine, GetNetworkAdapter(0, nic.asOutParam()));
1551
1552 RTPrintf("Reading the group back from the first network adapter...\n");
1553 CHECK_ERROR_BREAK(nic, COMGETTER(BandwidthGroup)(bwGroup.asOutParam()));
1554 if (bwGroup.isNull())
1555 RTPrintf("Error: Bandwidth group is null at the first network adapter!\n");
1556 else
1557 {
1558 CHECK_ERROR_BREAK(bwGroup, COMGETTER(Name)(grpNameReadFromNic.asOutParam()));
1559 if (grpName != grpNameReadFromNic)
1560 RTPrintf("Error: Bandwidth group names do not match (%ls != %ls)!\n", grpName.raw(), grpNameReadFromNic.raw());
1561 else
1562 RTPrintf("Successfully retrieved bandwidth group attribute from NIC (name=%ls)\n", grpNameReadFromNic.raw());
1563 ComPtr<IBandwidthGroup> bwGroupEmpty;
1564 RTPrintf("Assigning an empty group to the first network adapter...\n");
1565 CHECK_ERROR_BREAK(nic, COMSETTER(BandwidthGroup)(bwGroupEmpty));
1566 }
1567 RTPrintf("Removing bandwidth group named '%ls'...\n", grpName.raw());
1568 CHECK_ERROR_BREAK(bwCtrl, DeleteBandwidthGroup(grpName.raw()));
1569 CHECK_ERROR_BREAK(machine, SaveSettings());
1570 RTPrintf("Press enter to close this session...");
1571 getchar();
1572 session->UnlockMachine();
1573 }
1574 } while (FALSE);
1575 RTPrintf("\n");
1576#endif
1577
1578 RTPrintf("Press enter to release Session and VirtualBox instances...");
1579 getchar();
1580
1581 // end "all-stuff" scope
1582 ////////////////////////////////////////////////////////////////////////////
1583 }
1584 while (0);
1585
1586 RTPrintf("Press enter to shutdown COM...");
1587 getchar();
1588
1589 com::Shutdown();
1590
1591 RTPrintf("tstAPI FINISHED.\n");
1592
1593 return rc;
1594}
1595
1596#ifdef VBOX_WITH_RESOURCE_USAGE_API
1597static void queryMetrics(ComPtr<IVirtualBox> aVirtualBox,
1598 ComPtr<IPerformanceCollector> collector,
1599 ComSafeArrayIn(IUnknown *, objects))
1600{
1601 HRESULT rc;
1602
1603 //Bstr metricNames[] = { L"CPU/Load/User:avg,CPU/Load/System:avg,CPU/Load/Idle:avg,RAM/Usage/Total,RAM/Usage/Used:avg" };
1604 Bstr metricNames[] = { L"*" };
1605 com::SafeArray<BSTR> metrics(1);
1606 metricNames[0].cloneTo(&metrics[0]);
1607 com::SafeArray<BSTR> retNames;
1608 com::SafeIfaceArray<IUnknown> retObjects;
1609 com::SafeArray<BSTR> retUnits;
1610 com::SafeArray<ULONG> retScales;
1611 com::SafeArray<ULONG> retSequenceNumbers;
1612 com::SafeArray<ULONG> retIndices;
1613 com::SafeArray<ULONG> retLengths;
1614 com::SafeArray<LONG> retData;
1615 CHECK_ERROR(collector, QueryMetricsData(ComSafeArrayAsInParam(metrics),
1616 ComSafeArrayInArg(objects),
1617 ComSafeArrayAsOutParam(retNames),
1618 ComSafeArrayAsOutParam(retObjects),
1619 ComSafeArrayAsOutParam(retUnits),
1620 ComSafeArrayAsOutParam(retScales),
1621 ComSafeArrayAsOutParam(retSequenceNumbers),
1622 ComSafeArrayAsOutParam(retIndices),
1623 ComSafeArrayAsOutParam(retLengths),
1624 ComSafeArrayAsOutParam(retData)));
1625 RTPrintf("Object Metric Values\n"
1626 "---------- -------------------- --------------------------------------------\n");
1627 for (unsigned i = 0; i < retNames.size(); i++)
1628 {
1629 Bstr metricUnit(retUnits[i]);
1630 Bstr metricName(retNames[i]);
1631 RTPrintf("%-10ls %-20ls ", getObjectName(aVirtualBox, retObjects[i]).raw(), metricName.raw());
1632 const char *separator = "";
1633 for (unsigned j = 0; j < retLengths[i]; j++)
1634 {
1635 if (retScales[i] == 1)
1636 RTPrintf("%s%d %ls", separator, retData[retIndices[i] + j], metricUnit.raw());
1637 else
1638 RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[i] + j] / retScales[i],
1639 (retData[retIndices[i] + j] * 100 / retScales[i]) % 100, metricUnit.raw());
1640 separator = ", ";
1641 }
1642 RTPrintf("\n");
1643 }
1644}
1645
1646static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox,
1647 ComPtr<IUnknown> aObject)
1648{
1649 HRESULT rc;
1650
1651 ComPtr<IHost> host = aObject;
1652 if (!host.isNull())
1653 return Bstr("host");
1654
1655 ComPtr<IMachine> machine = aObject;
1656 if (!machine.isNull())
1657 {
1658 Bstr name;
1659 CHECK_ERROR(machine, COMGETTER(Name)(name.asOutParam()));
1660 if (SUCCEEDED(rc))
1661 return name;
1662 }
1663 return Bstr("unknown");
1664}
1665
1666static void listAffectedMetrics(ComPtr<IVirtualBox> aVirtualBox,
1667 ComSafeArrayIn(IPerformanceMetric*, aMetrics))
1668{
1669 HRESULT rc;
1670 com::SafeIfaceArray<IPerformanceMetric> metrics(ComSafeArrayInArg(aMetrics));
1671 if (metrics.size())
1672 {
1673 ComPtr<IUnknown> object;
1674 Bstr metricName;
1675 RTPrintf("The following metrics were modified:\n\n"
1676 "Object Metric\n"
1677 "---------- --------------------\n");
1678 for (size_t i = 0; i < metrics.size(); i++)
1679 {
1680 CHECK_ERROR(metrics[i], COMGETTER(Object)(object.asOutParam()));
1681 CHECK_ERROR(metrics[i], COMGETTER(MetricName)(metricName.asOutParam()));
1682 RTPrintf("%-10ls %-20ls\n",
1683 getObjectName(aVirtualBox, object).raw(), metricName.raw());
1684 }
1685 RTPrintf("\n");
1686 }
1687 else
1688 {
1689 RTPrintf("No metrics match the specified filter!\n");
1690 }
1691}
1692
1693#endif /* VBOX_WITH_RESOURCE_USAGE_API */
1694/* vim: set shiftwidth=4 tabstop=4 expandtab: */
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