VirtualBox

source: vbox/trunk/src/VBox/Main/testcase/tstVBoxAPILinux.cpp@ 5292

Last change on this file since 5292 was 5292, checked in by vboxsync, 17 years ago

API change to allow VM to be created with predefined UUID.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.0 KB
Line 
1/** @file
2 *
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.
7 *
8 */
9
10/*
11 * Copyright (C) 2006-2007 innotek GmbH
12 *
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.
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <iconv.h>
25#include <errno.h>
26
27
28/*
29 * Include the XPCOM headers
30 */
31#include <nsXPCOMGlue.h>
32#include <nsMemory.h>
33#include <nsString.h>
34#include <nsIServiceManager.h>
35#include <nsEventQueueUtils.h>
36
37#include <nsIExceptionService.h>
38
39/*
40 * VirtualBox XPCOM interface. This header is generated
41 * from IDL which in turn is generated from a custom XML format.
42 */
43#include "VirtualBox_XPCOM.h"
44
45/*
46 * Prototypes
47 */
48char *nsIDToString(nsID *guid);
49void printErrorInfo();
50
51
52/**
53 * Display all registered VMs on the screen with some information about each
54 *
55 * @param virtualBox VirtualBox instance object.
56 */
57void listVMs(IVirtualBox *virtualBox)
58{
59 nsresult rc;
60
61 printf("----------------------------------------------------\n");
62 printf("VM List:\n\n");
63
64 /*
65 * Get the list of all registered VMs
66 */
67 IMachineCollection *collection = nsnull;
68 IMachineEnumerator *enumerator = nsnull;
69 rc = virtualBox->GetMachines(&collection);
70 if (NS_SUCCEEDED(rc))
71 rc = collection->Enumerate(&enumerator);
72 if (NS_SUCCEEDED(rc))
73 {
74 /*
75 * Iterate through the collection
76 */
77 PRBool hasMore = false;
78 while (enumerator->HasMore(&hasMore), hasMore)
79 {
80 IMachine *machine = nsnull;
81 rc = enumerator->GetNext(&machine);
82 if ((NS_SUCCEEDED(rc)) && machine)
83 {
84 nsXPIDLString machineName;
85 machine->GetName(getter_Copies(machineName));
86 char *machineNameAscii = ToNewCString(machineName);
87 printf("\tName: %s\n", machineNameAscii);
88 free(machineNameAscii);
89
90 nsID *iid = nsnull;
91 machine->GetId(&iid);
92 const char *uuidString = nsIDToString(iid);
93 printf("\tUUID: %s\n", uuidString);
94 free((void*)uuidString);
95 nsMemory::Free(iid);
96
97 nsXPIDLString configFile;
98 machine->GetSettingsFilePath(getter_Copies(configFile));
99 char *configFileAscii = ToNewCString(configFile);
100 printf("\tConfig file: %s\n", configFileAscii);
101 free(configFileAscii);
102
103 PRUint32 memorySize;
104 machine->GetMemorySize(&memorySize);
105 printf("\tMemory size: %uMB\n", memorySize);
106
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);
115 free(osNameAscii);
116 osType->Release();
117
118 machine->Release();
119 }
120 }
121 }
122 printf("----------------------------------------------------\n\n");
123 /* don't forget to release the objects... */
124 if (enumerator)
125 enumerator->Release();
126 if (collection)
127 collection->Release();
128}
129
130/**
131 * Create a sample VM
132 *
133 * @param virtualBox VirtualBox instance object.
134 */
135void createVM(IVirtualBox *virtualBox)
136{
137 nsresult rc;
138 /*
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.
141 */
142 nsID VMuuid = {0};
143 nsCOMPtr <IMachine> machine;
144 rc = virtualBox->CreateMachine(nsnull, NS_LITERAL_STRING("A brand new name").get(),
145 VMuuid, getter_AddRefs(machine));
146 if (NS_FAILED(rc))
147 {
148 printf("Error: could not create machine! rc=%08X\n", rc);
149 return;
150 }
151
152 /*
153 * Set some properties
154 */
155 /* alternative to illustrate the use of string classes */
156 rc = machine->SetName(NS_ConvertUTF8toUTF16("A new name").get());
157 rc = machine->SetMemorySize(128);
158
159 /*
160 * Now a more advanced property -- the guest OS type. This is
161 * an object by itself which has to be found first. Note that we
162 * use the ID of the guest OS type here which is an internal
163 * representation (you can find that by configuring the OS type of
164 * a machine in the GUI and then looking at the <Guest ostype=""/>
165 * setting in the XML file. It is also possible to get the OS type from
166 * its description (win2k would be "Windows 2000") by getting the
167 * guest OS type collection and enumerating it.
168 */
169 nsCOMPtr <IGuestOSType> osType;
170 rc = virtualBox->GetGuestOSType(NS_LITERAL_STRING("win2k").get(),
171 getter_AddRefs(osType));
172 if (NS_FAILED(rc))
173 {
174 printf("Error: could not find guest OS type! rc=%08X\n", rc);
175 }
176 else
177 {
178 machine->SetOSTypeId (NS_LITERAL_STRING("win2k").get());
179 }
180
181 /*
182 * Register the VM. Note that this call also saves the VM config
183 * to disk. It is also possible to save the VM settings but not
184 * register the VM.
185 *
186 * Also note that due to current VirtualBox limitations, the machine
187 * must be registered *before* we can attach hard disks to it.
188 */
189 rc = virtualBox->RegisterMachine(machine);
190 if (NS_FAILED(rc))
191 {
192 printf("Error: could not register machine! rc=%08X\n", rc);
193 printErrorInfo();
194 return;
195 }
196
197 /*
198 * In order to manipulate the registered machine, we must open a session
199 * for that machine. Do it now.
200 */
201 nsCOMPtr<ISession> session;
202 {
203 nsCOMPtr<nsIComponentManager> manager;
204 rc = NS_GetComponentManager (getter_AddRefs (manager));
205 if (NS_FAILED(rc))
206 {
207 printf("Error: could not get component manager! rc=%08X\n", rc);
208 return;
209 }
210 rc = manager->CreateInstanceByContractID (NS_SESSION_CONTRACTID,
211 nsnull,
212 NS_GET_IID(ISession),
213 getter_AddRefs(session));
214 if (NS_FAILED(rc))
215 {
216 printf("Error, could not instantiate Session object! rc=0x%x\n", rc);
217 return;
218 }
219
220 nsID *machineUUID = nsnull;
221 machine->GetId(&machineUUID);
222 rc = virtualBox->OpenSession(session, *machineUUID);
223 nsMemory::Free(machineUUID);
224 if (NS_FAILED(rc))
225 {
226 printf("Error, could not open session! rc=0x%x\n", rc);
227 return;
228 }
229
230 /*
231 * After the machine is registered, the initial machine object becomes
232 * immutable. In order to get a mutable machine object, we must query
233 * it from the opened session object.
234 */
235 rc = session->GetMachine(getter_AddRefs(machine));
236 if (NS_FAILED(rc))
237 {
238 printf("Error, could not get sessioned machine! rc=0x%x\n", rc);
239 return;
240 }
241 }
242
243 /*
244 * Create a virtual harddisk
245 */
246 nsCOMPtr<IHardDisk> hardDisk = 0;
247 nsCOMPtr<IVirtualDiskImage> vdi = 0;
248 rc = virtualBox->CreateHardDisk(HardDiskStorageType::VirtualDiskImage,
249 getter_AddRefs(hardDisk));
250 if (NS_SUCCEEDED (rc))
251 {
252 rc = hardDisk->QueryInterface(NS_GET_IID(IVirtualDiskImage),
253 (void **)(getter_AddRefs(vdi)));
254 if (NS_SUCCEEDED (rc))
255 rc = vdi->SetFilePath(NS_LITERAL_STRING("TestHardDisk.vdi").get());
256 }
257
258 if (NS_FAILED(rc))
259 {
260 printf("Failed creating a hard disk object! rc=%08X\n", rc);
261 }
262 else
263 {
264 /*
265 * We have only created an object so far. No on disk representation exists
266 * because none of its properties has been set so far. Let's continue creating
267 * a dynamically expanding image.
268 */
269 nsCOMPtr <IProgress> progress;
270 rc = vdi->CreateDynamicImage(100, // size in megabytes
271 getter_AddRefs(progress)); // optional progress object
272 if (NS_FAILED(rc))
273 {
274 printf("Failed creating hard disk image! rc=%08X\n", rc);
275 }
276 else
277 {
278 /*
279 * Creating the image is done in the background because it can take quite
280 * some time (at least fixed size images). We have to wait for its completion.
281 * Here we wait forever (timeout -1) which is potentially dangerous.
282 */
283 rc = progress->WaitForCompletion(-1);
284 nsresult resultCode;
285 progress->GetResultCode(&resultCode);
286 if (NS_FAILED(rc) || NS_FAILED(resultCode))
287 {
288 printf("Error: could not create hard disk! rc=%08X\n",
289 NS_FAILED(rc) ? rc : resultCode);
290 }
291 else
292 {
293 /*
294 * Now we have to register the new hard disk with VirtualBox.
295 */
296 rc = virtualBox->RegisterHardDisk(hardDisk);
297 if (NS_FAILED(rc))
298 {
299 printf("Error: could not register hard disk! rc=%08X\n", rc);
300 }
301 else
302 {
303 /*
304 * Now that it's registered, we can assign it to the VM. This is done
305 * by UUID, so query that one fist. The UUID has been assigned automatically
306 * when we've created the image.
307 */
308 nsID *vdiUUID = nsnull;
309 hardDisk->GetId(&vdiUUID);
310 rc = machine->AttachHardDisk(*vdiUUID,
311 DiskControllerType::IDE0Controller, // controler identifier
312 0); // device number on the controller
313 nsMemory::Free(vdiUUID);
314 if (NS_FAILED(rc))
315 {
316 printf("Error: could not attach hard disk! rc=%08X\n", rc);
317 }
318 }
319 }
320 }
321 }
322
323 /*
324 * It's got a hard disk but that one is new and thus not bootable. Make it
325 * boot from an ISO file. This requires some processing. First the ISO file
326 * has to be registered and then mounted to the VM's DVD drive and selected
327 * as the boot device.
328 */
329 nsID uuid = {0};
330 nsCOMPtr<IDVDImage> dvdImage;
331
332 rc = virtualBox->OpenDVDImage(NS_LITERAL_STRING("/home/achimha/isoimages/winnt4ger.iso").get(),
333 uuid, /* NULL UUID, i.e. a new one will be created */
334 getter_AddRefs(dvdImage));
335 if (NS_FAILED(rc))
336 {
337 printf("Error: could not open CD image! rc=%08X\n", rc);
338 }
339 else
340 {
341 /*
342 * Register it with VBox
343 */
344 rc = virtualBox->RegisterDVDImage(dvdImage);
345 if (NS_FAILED(rc))
346 {
347 printf("Error: could not register CD image! rc=%08X\n", rc);
348 }
349 else
350 {
351 /*
352 * Now assign it to our VM
353 */
354 nsID *isoUUID = nsnull;
355 dvdImage->GetId(&isoUUID);
356 nsCOMPtr<IDVDDrive> dvdDrive;
357 machine->GetDVDDrive(getter_AddRefs(dvdDrive));
358 rc = dvdDrive->MountImage(*isoUUID);
359 nsMemory::Free(isoUUID);
360 if (NS_FAILED(rc))
361 {
362 printf("Error: could not mount ISO image! rc=%08X\n", rc);
363 }
364 else
365 {
366 /*
367 * Last step: tell the VM to boot from the CD.
368 */
369 rc = machine->SetBootOrder (1, DeviceType::DVDDevice);
370 if (NS_FAILED(rc))
371 {
372 printf("Could not set boot device! rc=%08X\n", rc);
373 }
374 }
375 }
376 }
377
378 /*
379 * Save all changes we've just made.
380 */
381 rc = machine->SaveSettings();
382 if (NS_FAILED(rc))
383 {
384 printf("Could not save machine settings! rc=%08X\n", rc);
385 }
386
387 /*
388 * It is always important to close the open session when it becomes not
389 * necessary any more.
390 */
391 session->Close();
392}
393
394// main
395///////////////////////////////////////////////////////////////////////////////
396
397int main(int argc, char *argv[])
398{
399 /*
400 * Check that PRUnichar is equal in size to what compiler composes L""
401 * strings from; otherwise NS_LITERAL_STRING macros won't work correctly
402 * and we will get a meaningless SIGSEGV. This, of course, must be checked
403 * at compile time in xpcom/string/nsTDependentString.h, but XPCOM lacks
404 * compile-time assert macros and I'm not going to add them now.
405 */
406 if (sizeof(PRUnichar) != sizeof(wchar_t))
407 {
408 printf("Error: sizeof(PRUnichar) {%d} != sizeof(wchar_t) {%d}!\n"
409 "Probably, you forgot the -fshort-wchar compiler option.\n",
410 sizeof(PRUnichar), sizeof(wchar_t));
411 return -1;
412 }
413
414 nsresult rc;
415
416 /*
417 * This is the standard XPCOM init procedure.
418 * What we do is just follow the required steps to get an instance
419 * of our main interface, which is IVirtualBox.
420 */
421 XPCOMGlueStartup(nsnull);
422
423 /*
424 * Note that we scope all nsCOMPtr variables in order to have all XPCOM
425 * objects automatically released before we call NS_ShutdownXPCOM at the
426 * end. This is an XPCOM requirement.
427 */
428 {
429 nsCOMPtr<nsIServiceManager> serviceManager;
430 rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull);
431 if (NS_FAILED(rc))
432 {
433 printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
434 return -1;
435 }
436
437#if 0
438 /*
439 * Register our components. This step is only necessary if this executable
440 * implements XPCOM components itself which is not the case for this
441 * simple example.
442 */
443 nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager);
444 if (!registrar)
445 {
446 printf("Error: could not query nsIComponentRegistrar interface!\n");
447 return -1;
448 }
449 registrar->AutoRegister(nsnull);
450#endif
451
452 /*
453 * Make sure the main event queue is created. This event queue is
454 * responsible for dispatching incoming XPCOM IPC messages. The main
455 * thread should run this event queue's loop during lengthy non-XPCOM
456 * operations to ensure messages from the VirtualBox server and other
457 * XPCOM IPC clients are processed. This use case doesn't perform such
458 * operations so it doesn't run the event loop.
459 */
460 nsCOMPtr<nsIEventQueue> eventQ;
461 rc = NS_GetMainEventQ(getter_AddRefs (eventQ));
462 if (NS_FAILED(rc))
463 {
464 printf("Error: could not get main event queue! rc=%08X\n", rc);
465 return -1;
466 }
467
468 /*
469 * Now XPCOM is ready and we can start to do real work.
470 * IVirtualBox is the root interface of VirtualBox and will be
471 * retrieved from the XPCOM component manager. We use the
472 * XPCOM provided smart pointer nsCOMPtr for all objects because
473 * that's very convenient and removes the need deal with reference
474 * counting and freeing.
475 */
476 nsCOMPtr<nsIComponentManager> manager;
477 rc = NS_GetComponentManager (getter_AddRefs (manager));
478 if (NS_FAILED(rc))
479 {
480 printf("Error: could not get component manager! rc=%08X\n", rc);
481 return -1;
482 }
483
484 nsCOMPtr<IVirtualBox> virtualBox;
485 rc = manager->CreateInstanceByContractID (NS_VIRTUALBOX_CONTRACTID,
486 nsnull,
487 NS_GET_IID(IVirtualBox),
488 getter_AddRefs(virtualBox));
489 if (NS_FAILED(rc))
490 {
491 printf("Error, could not instantiate VirtualBox object! rc=0x%x\n", rc);
492 return -1;
493 }
494 printf("VirtualBox object created\n");
495
496 ////////////////////////////////////////////////////////////////////////////////
497 ////////////////////////////////////////////////////////////////////////////////
498 ////////////////////////////////////////////////////////////////////////////////
499
500
501 listVMs(virtualBox);
502
503 createVM(virtualBox);
504
505
506 ////////////////////////////////////////////////////////////////////////////////
507 ////////////////////////////////////////////////////////////////////////////////
508 ////////////////////////////////////////////////////////////////////////////////
509
510 /* this is enough to free the IVirtualBox instance -- smart pointers rule! */
511 virtualBox = nsnull;
512
513 /*
514 * Process events that might have queued up in the XPCOM event
515 * queue. If we don't process them, the server might hang.
516 */
517 eventQ->ProcessPendingEvents();
518 }
519
520 /*
521 * Perform the standard XPCOM shutdown procedure.
522 */
523 NS_ShutdownXPCOM(nsnull);
524 XPCOMGlueShutdown();
525 printf("Done!\n");
526 return 0;
527}
528
529
530//////////////////////////////////////////////////////////////////////////////////////////////////////
531//// Helpers
532//////////////////////////////////////////////////////////////////////////////////////////////////////
533
534/**
535 * Helper function to convert an nsID into a human readable string
536 *
537 * @returns result string, allocated. Has to be freed using free()
538 * @param guid Pointer to nsID that will be converted.
539 */
540char *nsIDToString(nsID *guid)
541{
542 char *res = (char*)malloc(39);
543
544 if (res != NULL)
545 {
546 snprintf(res, 39, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
547 guid->m0, (PRUint32)guid->m1, (PRUint32)guid->m2,
548 (PRUint32)guid->m3[0], (PRUint32)guid->m3[1], (PRUint32)guid->m3[2],
549 (PRUint32)guid->m3[3], (PRUint32)guid->m3[4], (PRUint32)guid->m3[5],
550 (PRUint32)guid->m3[6], (PRUint32)guid->m3[7]);
551 }
552 return res;
553}
554
555/**
556 * Helper function to print XPCOM exception information set on the current
557 * thread after a failed XPCOM method call. This function will also print
558 * extended VirtualBox error info if it is available.
559 */
560void printErrorInfo()
561{
562 nsresult rc;
563
564 nsCOMPtr <nsIExceptionService> es;
565 es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
566 if (NS_SUCCEEDED (rc))
567 {
568 nsCOMPtr <nsIExceptionManager> em;
569 rc = es->GetCurrentExceptionManager (getter_AddRefs (em));
570 if (NS_SUCCEEDED (rc))
571 {
572 nsCOMPtr<nsIException> ex;
573 rc = em->GetCurrentException (getter_AddRefs (ex));
574 if (NS_SUCCEEDED (rc) && ex)
575 {
576 nsCOMPtr <IVirtualBoxErrorInfo> info;
577 info = do_QueryInterface(ex, &rc);
578 if (NS_SUCCEEDED(rc) && info)
579 {
580 /* got extended error info */
581 printf ("Extended error info (IVirtualBoxErrorInfo):\n");
582 nsresult resultCode = NS_OK;
583 info->GetResultCode (&resultCode);
584 printf (" resultCode=%08X\n", resultCode);
585 nsXPIDLString component;
586 info->GetComponent (getter_Copies (component));
587 printf (" component=%s\n", NS_ConvertUTF16toUTF8(component).get());
588 nsXPIDLString text;
589 info->GetText (getter_Copies (text));
590 printf (" text=%s\n", NS_ConvertUTF16toUTF8(text).get());
591 }
592 else
593 {
594 /* got basic error info */
595 printf ("Basic error info (nsIException):\n");
596 nsresult resultCode = NS_OK;
597 ex->GetResult (&resultCode);
598 printf (" resultCode=%08X\n", resultCode);
599 nsXPIDLCString message;
600 ex->GetMessage (getter_Copies (message));
601 printf (" message=%s\n", message.get());
602 }
603
604 /* reset the exception to NULL to indicate we've processed it */
605 em->SetCurrentException (NULL);
606
607 rc = NS_OK;
608 }
609 }
610 }
611}
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