3
* tstVBoxAPILinux - sample program to illustrate the VirtualBox
4
* XPCOM API for machine management on Linux.
5
* It only uses standard C/C++ and XPCOM semantics,
6
* no additional VBox classes/macros/helpers.
11
* Copyright (C) 2006-2007 innotek GmbH
13
* This file is part of VirtualBox Open Source Edition (OSE), as
14
* available from http://www.virtualbox.org. This file is free software;
15
* you can redistribute it and/or modify it under the terms of the GNU
16
* General Public License as published by the Free Software Foundation,
17
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
18
* distribution. VirtualBox OSE is distributed in the hope that it will
19
* be useful, but WITHOUT ANY WARRANTY of any kind.
29
* Include the XPCOM headers
31
#include <nsXPCOMGlue.h>
34
#include <nsIServiceManager.h>
35
#include <nsEventQueueUtils.h>
37
#include <nsIExceptionService.h>
40
* VirtualBox XPCOM interface. This header is generated
41
* from IDL which in turn is generated from a custom XML format.
43
#include "VirtualBox_XPCOM.h"
48
char *nsIDToString(nsID *guid);
49
void printErrorInfo();
53
* Display all registered VMs on the screen with some information about each
55
* @param virtualBox VirtualBox instance object.
57
void listVMs(IVirtualBox *virtualBox)
61
printf("----------------------------------------------------\n");
62
printf("VM List:\n\n");
65
* Get the list of all registered VMs
67
IMachineCollection *collection = nsnull;
68
IMachineEnumerator *enumerator = nsnull;
69
rc = virtualBox->GetMachines(&collection);
71
rc = collection->Enumerate(&enumerator);
75
* Iterate through the collection
77
PRBool hasMore = false;
78
while (enumerator->HasMore(&hasMore), hasMore)
80
IMachine *machine = nsnull;
81
rc = enumerator->GetNext(&machine);
82
if ((NS_SUCCEEDED(rc)) && machine)
84
nsXPIDLString machineName;
85
machine->GetName(getter_Copies(machineName));
86
char *machineNameAscii = ToNewCString(machineName);
87
printf("\tName: %s\n", machineNameAscii);
88
free(machineNameAscii);
92
const char *uuidString = nsIDToString(iid);
93
printf("\tUUID: %s\n", uuidString);
94
free((void*)uuidString);
97
nsXPIDLString configFile;
98
machine->GetSettingsFilePath(getter_Copies(configFile));
99
char *configFileAscii = ToNewCString(configFile);
100
printf("\tConfig file: %s\n", configFileAscii);
101
free(configFileAscii);
104
machine->GetMemorySize(&memorySize);
105
printf("\tMemory size: %uMB\n", memorySize);
107
nsXPIDLString typeId;
108
machine->GetOSTypeId(getter_Copies(typeId));
109
IGuestOSType *osType = nsnull;
110
virtualBox->GetGuestOSType (typeId.get(), &osType);
111
nsXPIDLString osName;
112
osType->GetDescription(getter_Copies(osName));
113
char *osNameAscii = ToNewCString(osName);
114
printf("\tGuest OS: %s\n\n", osNameAscii);
122
printf("----------------------------------------------------\n\n");
123
/* don't forget to release the objects... */
125
enumerator->Release();
127
collection->Release();
133
* @param virtualBox VirtualBox instance object.
135
void createVM(IVirtualBox *virtualBox)
139
* First create a unnamed new VM. It will be unconfigured and not be saved
140
* in the configuration until we explicitely choose to do so.
142
nsCOMPtr <IMachine> machine;
143
rc = virtualBox->CreateMachine(nsnull, NS_LITERAL_STRING("A brand new name").get(),
144
getter_AddRefs(machine));
147
printf("Error: could not create machine! rc=%08X\n", rc);
152
* Set some properties
154
/* alternative to illustrate the use of string classes */
155
rc = machine->SetName(NS_ConvertUTF8toUTF16("A new name").get());
156
rc = machine->SetMemorySize(128);
159
* Now a more advanced property -- the guest OS type. This is
160
* an object by itself which has to be found first. Note that we
161
* use the ID of the guest OS type here which is an internal
162
* representation (you can find that by configuring the OS type of
163
* a machine in the GUI and then looking at the <Guest ostype=""/>
164
* setting in the XML file. It is also possible to get the OS type from
165
* its description (win2k would be "Windows 2000") by getting the
166
* guest OS type collection and enumerating it.
168
nsCOMPtr <IGuestOSType> osType;
169
rc = virtualBox->GetGuestOSType(NS_LITERAL_STRING("win2k").get(),
170
getter_AddRefs(osType));
173
printf("Error: could not find guest OS type! rc=%08X\n", rc);
177
machine->SetOSTypeId (NS_LITERAL_STRING("win2k").get());
181
* Register the VM. Note that this call also saves the VM config
182
* to disk. It is also possible to save the VM settings but not
185
* Also note that due to current VirtualBox limitations, the machine
186
* must be registered *before* we can attach hard disks to it.
188
rc = virtualBox->RegisterMachine(machine);
191
printf("Error: could not register machine! rc=%08X\n", rc);
197
* In order to manipulate the registered machine, we must open a session
198
* for that machine. Do it now.
200
nsCOMPtr<ISession> session;
202
nsCOMPtr<nsIComponentManager> manager;
203
rc = NS_GetComponentManager (getter_AddRefs (manager));
206
printf("Error: could not get component manager! rc=%08X\n", rc);
209
rc = manager->CreateInstanceByContractID (NS_SESSION_CONTRACTID,
211
NS_GET_IID(ISession),
212
getter_AddRefs(session));
215
printf("Error, could not instantiate Session object! rc=0x%x\n", rc);
219
nsID *machineUUID = nsnull;
220
machine->GetId(&machineUUID);
221
rc = virtualBox->OpenSession(session, *machineUUID);
222
nsMemory::Free(machineUUID);
225
printf("Error, could not open session! rc=0x%x\n", rc);
230
* After the machine is registered, the initial machine object becomes
231
* immutable. In order to get a mutable machine object, we must query
232
* it from the opened session object.
234
rc = session->GetMachine(getter_AddRefs(machine));
237
printf("Error, could not get sessioned machine! rc=0x%x\n", rc);
243
* Create a virtual harddisk
245
nsCOMPtr<IHardDisk> hardDisk = 0;
246
nsCOMPtr<IVirtualDiskImage> vdi = 0;
247
rc = virtualBox->CreateHardDisk(HardDiskStorageType::VirtualDiskImage,
248
getter_AddRefs(hardDisk));
249
if (NS_SUCCEEDED (rc))
251
rc = hardDisk->QueryInterface(NS_GET_IID(IVirtualDiskImage),
252
(void **)(getter_AddRefs(vdi)));
253
if (NS_SUCCEEDED (rc))
254
rc = vdi->SetFilePath(NS_LITERAL_STRING("TestHardDisk.vdi").get());
259
printf("Failed creating a hard disk object! rc=%08X\n", rc);
264
* We have only created an object so far. No on disk representation exists
265
* because none of its properties has been set so far. Let's continue creating
266
* a dynamically expanding image.
268
nsCOMPtr <IProgress> progress;
269
rc = vdi->CreateDynamicImage(100, // size in megabytes
270
getter_AddRefs(progress)); // optional progress object
273
printf("Failed creating hard disk image! rc=%08X\n", rc);
278
* Creating the image is done in the background because it can take quite
279
* some time (at least fixed size images). We have to wait for its completion.
280
* Here we wait forever (timeout -1) which is potentially dangerous.
282
rc = progress->WaitForCompletion(-1);
284
progress->GetResultCode(&resultCode);
285
if (NS_FAILED(rc) || NS_FAILED(resultCode))
287
printf("Error: could not create hard disk! rc=%08X\n",
288
NS_FAILED(rc) ? rc : resultCode);
293
* Now we have to register the new hard disk with VirtualBox.
295
rc = virtualBox->RegisterHardDisk(hardDisk);
298
printf("Error: could not register hard disk! rc=%08X\n", rc);
303
* Now that it's registered, we can assign it to the VM. This is done
304
* by UUID, so query that one fist. The UUID has been assigned automatically
305
* when we've created the image.
307
nsID *vdiUUID = nsnull;
308
hardDisk->GetId(&vdiUUID);
309
rc = machine->AttachHardDisk(*vdiUUID,
310
DiskControllerType::IDE0Controller, // controler identifier
311
0); // device number on the controller
312
nsMemory::Free(vdiUUID);
315
printf("Error: could not attach hard disk! rc=%08X\n", rc);
323
* It's got a hard disk but that one is new and thus not bootable. Make it
324
* boot from an ISO file. This requires some processing. First the ISO file
325
* has to be registered and then mounted to the VM's DVD drive and selected
326
* as the boot device.
329
nsCOMPtr<IDVDImage> dvdImage;
331
rc = virtualBox->OpenDVDImage(NS_LITERAL_STRING("/home/achimha/isoimages/winnt4ger.iso").get(),
332
uuid, /* NULL UUID, i.e. a new one will be created */
333
getter_AddRefs(dvdImage));
336
printf("Error: could not open CD image! rc=%08X\n", rc);
341
* Register it with VBox
343
rc = virtualBox->RegisterDVDImage(dvdImage);
346
printf("Error: could not register CD image! rc=%08X\n", rc);
351
* Now assign it to our VM
353
nsID *isoUUID = nsnull;
354
dvdImage->GetId(&isoUUID);
355
nsCOMPtr<IDVDDrive> dvdDrive;
356
machine->GetDVDDrive(getter_AddRefs(dvdDrive));
357
rc = dvdDrive->MountImage(*isoUUID);
358
nsMemory::Free(isoUUID);
361
printf("Error: could not mount ISO image! rc=%08X\n", rc);
366
* Last step: tell the VM to boot from the CD.
368
rc = machine->SetBootOrder (1, DeviceType::DVDDevice);
371
printf("Could not set boot device! rc=%08X\n", rc);
378
* Save all changes we've just made.
380
rc = machine->SaveSettings();
383
printf("Could not save machine settings! rc=%08X\n", rc);
387
* It is always important to close the open session when it becomes not
388
* necessary any more.
394
///////////////////////////////////////////////////////////////////////////////
396
int main(int argc, char *argv[])
399
* Check that PRUnichar is equal in size to what compiler composes L""
400
* strings from; otherwise NS_LITERAL_STRING macros won't work correctly
401
* and we will get a meaningless SIGSEGV. This, of course, must be checked
402
* at compile time in xpcom/string/nsTDependentString.h, but XPCOM lacks
403
* compile-time assert macros and I'm not going to add them now.
405
if (sizeof(PRUnichar) != sizeof(wchar_t))
407
printf("Error: sizeof(PRUnichar) {%d} != sizeof(wchar_t) {%d}!\n"
408
"Probably, you forgot the -fshort-wchar compiler option.\n",
409
sizeof(PRUnichar), sizeof(wchar_t));
416
* This is the standard XPCOM init procedure.
417
* What we do is just follow the required steps to get an instance
418
* of our main interface, which is IVirtualBox.
420
XPCOMGlueStartup(nsnull);
423
* Note that we scope all nsCOMPtr variables in order to have all XPCOM
424
* objects automatically released before we call NS_ShutdownXPCOM at the
425
* end. This is an XPCOM requirement.
428
nsCOMPtr<nsIServiceManager> serviceManager;
429
rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull);
432
printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
438
* Register our components. This step is only necessary if this executable
439
* implements XPCOM components itself which is not the case for this
442
nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager);
445
printf("Error: could not query nsIComponentRegistrar interface!\n");
448
registrar->AutoRegister(nsnull);
452
* Make sure the main event queue is created. This event queue is
453
* responsible for dispatching incoming XPCOM IPC messages. The main
454
* thread should run this event queue's loop during lengthy non-XPCOM
455
* operations to ensure messages from the VirtualBox server and other
456
* XPCOM IPC clients are processed. This use case doesn't perform such
457
* operations so it doesn't run the event loop.
459
nsCOMPtr<nsIEventQueue> eventQ;
460
rc = NS_GetMainEventQ(getter_AddRefs (eventQ));
463
printf("Error: could not get main event queue! rc=%08X\n", rc);
468
* Now XPCOM is ready and we can start to do real work.
469
* IVirtualBox is the root interface of VirtualBox and will be
470
* retrieved from the XPCOM component manager. We use the
471
* XPCOM provided smart pointer nsCOMPtr for all objects because
472
* that's very convenient and removes the need deal with reference
473
* counting and freeing.
475
nsCOMPtr<nsIComponentManager> manager;
476
rc = NS_GetComponentManager (getter_AddRefs (manager));
479
printf("Error: could not get component manager! rc=%08X\n", rc);
483
nsCOMPtr<IVirtualBox> virtualBox;
484
rc = manager->CreateInstanceByContractID (NS_VIRTUALBOX_CONTRACTID,
486
NS_GET_IID(IVirtualBox),
487
getter_AddRefs(virtualBox));
490
printf("Error, could not instantiate VirtualBox object! rc=0x%x\n", rc);
493
printf("VirtualBox object created\n");
495
////////////////////////////////////////////////////////////////////////////////
496
////////////////////////////////////////////////////////////////////////////////
497
////////////////////////////////////////////////////////////////////////////////
502
createVM(virtualBox);
505
////////////////////////////////////////////////////////////////////////////////
506
////////////////////////////////////////////////////////////////////////////////
507
////////////////////////////////////////////////////////////////////////////////
509
/* this is enough to free the IVirtualBox instance -- smart pointers rule! */
513
* Process events that might have queued up in the XPCOM event
514
* queue. If we don't process them, the server might hang.
516
eventQ->ProcessPendingEvents();
520
* Perform the standard XPCOM shutdown procedure.
522
NS_ShutdownXPCOM(nsnull);
529
//////////////////////////////////////////////////////////////////////////////////////////////////////
531
//////////////////////////////////////////////////////////////////////////////////////////////////////
534
* Helper function to convert an nsID into a human readable string
536
* @returns result string, allocated. Has to be freed using free()
537
* @param guid Pointer to nsID that will be converted.
539
char *nsIDToString(nsID *guid)
541
char *res = (char*)malloc(39);
545
snprintf(res, 39, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
546
guid->m0, (PRUint32)guid->m1, (PRUint32)guid->m2,
547
(PRUint32)guid->m3[0], (PRUint32)guid->m3[1], (PRUint32)guid->m3[2],
548
(PRUint32)guid->m3[3], (PRUint32)guid->m3[4], (PRUint32)guid->m3[5],
549
(PRUint32)guid->m3[6], (PRUint32)guid->m3[7]);
555
* Helper function to print XPCOM exception information set on the current
556
* thread after a failed XPCOM method call. This function will also print
557
* extended VirtualBox error info if it is available.
559
void printErrorInfo()
563
nsCOMPtr <nsIExceptionService> es;
564
es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
565
if (NS_SUCCEEDED (rc))
567
nsCOMPtr <nsIExceptionManager> em;
568
rc = es->GetCurrentExceptionManager (getter_AddRefs (em));
569
if (NS_SUCCEEDED (rc))
571
nsCOMPtr<nsIException> ex;
572
rc = em->GetCurrentException (getter_AddRefs (ex));
573
if (NS_SUCCEEDED (rc) && ex)
575
nsCOMPtr <IVirtualBoxErrorInfo> info;
576
info = do_QueryInterface(ex, &rc);
577
if (NS_SUCCEEDED(rc) && info)
579
/* got extended error info */
580
printf ("Extended error info (IVirtualBoxErrorInfo):\n");
581
nsresult resultCode = NS_OK;
582
info->GetResultCode (&resultCode);
583
printf (" resultCode=%08X\n", resultCode);
584
nsXPIDLString component;
585
info->GetComponent (getter_Copies (component));
586
printf (" component=%s\n", NS_ConvertUTF16toUTF8(component).get());
588
info->GetText (getter_Copies (text));
589
printf (" text=%s\n", NS_ConvertUTF16toUTF8(text).get());
593
/* got basic error info */
594
printf ("Basic error info (nsIException):\n");
595
nsresult resultCode = NS_OK;
596
ex->GetResult (&resultCode);
597
printf (" resultCode=%08X\n", resultCode);
598
nsXPIDLCString message;
599
ex->GetMessage (getter_Copies (message));
600
printf (" message=%s\n", message.get());
603
/* reset the exception to NULL to indicate we've processed it */
604
em->SetCurrentException (NULL);