VirtualBox

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

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

Main/tstVBoxAPILinux: fixed a printf format warning

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

© 2023 Oracle
ContactPrivacy policyTerms of Use