VirtualBox

source: vbox/trunk/src/VBox/Main/cbinding/tstCAPIGlue.c@ 50403

Last change on this file since 50403 was 50254, checked in by vboxsync, 11 years ago

Main/cbinding: final touchups, and making things as COM compatible as possible, even where it shouldn't really matter

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.6 KB
Line 
1/* $Revision: 50254 $ */
2/** @file tstCAPIGlue.c
3 * Demonstrator program to illustrate use of C bindings of Main API.
4 *
5 * It has sample code showing how to retrieve all available error information,
6 * and how to handle active (event delivery through callbacks) or passive
7 * (event delivery through a polling mechanism) event listeners.
8 */
9
10/*
11 * Copyright (C) 2009-2014 Oracle Corporation
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 (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include "VBoxCAPIGlue.h"
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#ifndef WIN32
30# include <signal.h>
31# include <unistd.h>
32# include <sys/poll.h>
33#endif
34
35/**
36 * Select between active event listener (defined) and passive event listener
37 * (undefined). The active event listener case needs much more code, and
38 * additionally requires a lot more platform dependent code.
39 */
40#undef USE_ACTIVE_EVENT_LISTENER
41
42
43/*******************************************************************************
44* Global Variables *
45*******************************************************************************/
46/** Set by Ctrl+C handler. */
47static volatile int g_fStop = 0;
48
49#ifdef USE_ACTIVE_EVENT_LISTENER
50# ifdef WIN32
51/** The COM type information for IEventListener, for implementing IDispatch. */
52static ITypeInfo *g_pTInfoIEventListener = NULL;
53# endif /* WIN32 */
54#endif /* USE_ACTIVE_EVENT_LISTENER */
55
56static const char *GetStateName(MachineState_T machineState)
57{
58 switch (machineState)
59 {
60 case MachineState_Null: return "<null>";
61 case MachineState_PoweredOff: return "PoweredOff";
62 case MachineState_Saved: return "Saved";
63 case MachineState_Teleported: return "Teleported";
64 case MachineState_Aborted: return "Aborted";
65 case MachineState_Running: return "Running";
66 case MachineState_Paused: return "Paused";
67 case MachineState_Stuck: return "Stuck";
68 case MachineState_Teleporting: return "Teleporting";
69 case MachineState_LiveSnapshotting: return "LiveSnapshotting";
70 case MachineState_Starting: return "Starting";
71 case MachineState_Stopping: return "Stopping";
72 case MachineState_Saving: return "Saving";
73 case MachineState_Restoring: return "Restoring";
74 case MachineState_TeleportingPausedVM: return "TeleportingPausedVM";
75 case MachineState_TeleportingIn: return "TeleportingIn";
76 case MachineState_FaultTolerantSyncing: return "FaultTolerantSyncing";
77 case MachineState_DeletingSnapshotOnline: return "DeletingSnapshotOnline";
78 case MachineState_DeletingSnapshotPaused: return "DeletingSnapshotPaused";
79 case MachineState_RestoringSnapshot: return "RestoringSnapshot";
80 case MachineState_DeletingSnapshot: return "DeletingSnapshot";
81 case MachineState_SettingUp: return "SettingUp";
82 default: return "no idea";
83 }
84}
85
86/**
87 * Ctrl+C handler, terminate event listener.
88 *
89 * Remember that most function calls are not allowed in this context (including
90 * printf!), so make sure that this does as little as possible.
91 *
92 * @param iInfo Platform dependent detail info (ignored).
93 */
94static BOOL VBOX_WINAPI ctrlCHandler(DWORD iInfo)
95{
96 (void)iInfo;
97 g_fStop = 1;
98 return TRUE;
99}
100
101/**
102 * Sample event processing function, dumping some event information.
103 * Shared between active and passive event demo, to highlight that this part
104 * is identical between the two.
105 */
106static HRESULT EventListenerDemoProcessEvent(IEvent *event)
107{
108 VBoxEventType_T evType;
109 HRESULT rc;
110
111 if (!event)
112 {
113 printf("event null\n");
114 return S_OK;
115 }
116
117 evType = VBoxEventType_Invalid;
118 rc = IEvent_get_Type(event, &evType);
119 if (FAILED(rc))
120 {
121 printf("cannot get event type, rc=%#x\n", rc);
122 return S_OK;
123 }
124
125 switch (evType)
126 {
127 case VBoxEventType_OnMousePointerShapeChanged:
128 printf("OnMousePointerShapeChanged\n");
129 break;
130
131 case VBoxEventType_OnMouseCapabilityChanged:
132 printf("OnMouseCapabilityChanged\n");
133 break;
134
135 case VBoxEventType_OnKeyboardLedsChanged:
136 printf("OnMouseCapabilityChanged\n");
137 break;
138
139 case VBoxEventType_OnStateChanged:
140 {
141 IStateChangedEvent *ev = NULL;
142 enum MachineState state;
143 rc = IEvent_QueryInterface(event, &IID_IStateChangedEvent, (void **)&ev);
144 if (FAILED(rc))
145 {
146 printf("cannot get StateChangedEvent interface, rc=%#x\n", rc);
147 return S_OK;
148 }
149 if (!ev)
150 {
151 printf("StateChangedEvent reference null\n");
152 return S_OK;
153 }
154 rc = IStateChangedEvent_get_State(ev, &state);
155 if (FAILED(rc))
156 printf("warning: cannot get state, rc=%#x\n", rc);
157 IStateChangedEvent_Release(ev);
158 printf("OnStateChanged: %s\n", GetStateName(state));
159
160 fflush(stdout);
161 if ( state == MachineState_PoweredOff
162 || state == MachineState_Saved
163 || state == MachineState_Teleported
164 || state == MachineState_Aborted
165 )
166 g_fStop = 1;
167 break;
168 }
169
170 case VBoxEventType_OnAdditionsStateChanged:
171 printf("OnAdditionsStateChanged\n");
172 break;
173
174 case VBoxEventType_OnNetworkAdapterChanged:
175 printf("OnNetworkAdapterChanged\n");
176 break;
177
178 case VBoxEventType_OnSerialPortChanged:
179 printf("OnSerialPortChanged\n");
180 break;
181
182 case VBoxEventType_OnParallelPortChanged:
183 printf("OnParallelPortChanged\n");
184 break;
185
186 case VBoxEventType_OnStorageControllerChanged:
187 printf("OnStorageControllerChanged\n");
188 break;
189
190 case VBoxEventType_OnMediumChanged:
191 printf("OnMediumChanged\n");
192 break;
193
194 case VBoxEventType_OnVRDEServerChanged:
195 printf("OnVRDEServerChanged\n");
196 break;
197
198 case VBoxEventType_OnUSBControllerChanged:
199 printf("OnUSBControllerChanged\n");
200 break;
201
202 case VBoxEventType_OnUSBDeviceStateChanged:
203 printf("OnUSBDeviceStateChanged\n");
204 break;
205
206 case VBoxEventType_OnSharedFolderChanged:
207 printf("OnSharedFolderChanged\n");
208 break;
209
210 case VBoxEventType_OnRuntimeError:
211 printf("OnRuntimeError\n");
212 break;
213
214 case VBoxEventType_OnCanShowWindow:
215 printf("OnCanShowWindow\n");
216 break;
217 case VBoxEventType_OnShowWindow:
218 printf("OnShowWindow\n");
219 break;
220
221 default:
222 printf("unknown event: %d\n", evType);
223 }
224
225 return S_OK;
226}
227
228#ifdef USE_ACTIVE_EVENT_LISTENER
229
230struct IEventListenerDemo;
231typedef struct IEventListenerDemo IEventListenerDemo;
232
233typedef struct IEventListenerDemoVtbl
234{
235 HRESULT (*QueryInterface)(IEventListenerDemo *pThis, REFIID riid, void **ppvObject);
236 ULONG (*AddRef)(IEventListenerDemo *pThis);
237 ULONG (*Release)(IEventListenerDemo *pThis);
238#ifdef WIN32
239 HRESULT (*GetTypeInfoCount)(IEventListenerDemo *pThis, UINT *pctinfo);
240 HRESULT (*GetTypeInfo)(IEventListenerDemo *pThis, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
241 HRESULT (*GetIDsOfNames)(IEventListenerDemo *pThis, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
242 HRESULT (*Invoke)(IEventListenerDemo *pThis, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
243#endif
244 HRESULT (*HandleEvent)(IEventListenerDemo *pThis, IEvent *aEvent);
245} IEventListenerDemoVtbl;
246
247typedef struct IEventListenerDemo
248{
249 struct IEventListenerDemoVtbl *lpVtbl;
250
251 int cRef;
252
253#ifdef WIN32
254 /* Active event delivery needs a free threaded marshaler, as the default
255 * proxy marshaling cannot deal correctly with this case. */
256 IUnknown *pUnkMarshaler;
257#endif
258} IEventListenerDemo;
259
260/* Defines for easily calling IEventListenerDemo functions. */
261
262/* IUnknown functions. */
263#define IEventListenerDemo_QueryInterface(This,riid,ppvObject) \
264 ( (This)->lpVtbl->QueryInterface(This,riid,ppvObject) )
265
266#define IEventListenerDemo_AddRef(This) \
267 ( (This)->lpVtbl->AddRef(This) )
268
269#define IEventListenerDemo_Release(This) \
270 ( (This)->lpVtbl->Release(This) )
271
272#ifdef WIN32
273/* IDispatch functions. */
274#define IEventListenerDemo_GetTypeInfoCount(This,pctinfo) \
275 ( (This)->lpVtbl->GetTypeInfoCount(This,pctinfo) )
276
277#define IEventListenerDemo_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
278 ( (This)->lpVtbl->GetTypeInfo(This,iTInfo,lcid,ppTInfo) )
279
280#define IEventListenerDemo_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
281 ( (This)->lpVtbl->GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) )
282
283#define IEventListenerDemo_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
284 ( (This)->lpVtbl->Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) )
285#endif
286
287/* IEventListener functions. */
288#define IEventListenerDemo_HandleEvent(This,aEvent) \
289 ( (This)->lpVtbl->HandleEvent(This,aEvent) )
290
291
292/**
293 * Event handler function, for active event processing.
294 */
295static HRESULT IEventListenerDemoImpl_HandleEvent(IEventListenerDemo *pThis, IEvent *event)
296{
297 return EventListenerDemoProcessEvent(event);
298}
299
300static HRESULT IEventListenerDemoImpl_QueryInterface(IEventListenerDemo *pThis, const IID *iid, void **resultp)
301{
302 /* match iid */
303 if ( !memcmp(iid, &IID_IEventListener, sizeof(IID))
304 || !memcmp(iid, &IID_IDispatch, sizeof(IID))
305 || !memcmp(iid, &IID_IUnknown, sizeof(IID)))
306 {
307 IEventListenerDemo_AddRef(pThis);
308 *resultp = pThis;
309 return S_OK;
310 }
311#ifdef WIN32
312 if (!memcmp(iid, &IID_IMarshal, sizeof(IID)))
313 return IUnknown_QueryInterface(pThis->pUnkMarshaler, iid, resultp);
314#endif
315
316 return E_NOINTERFACE;
317}
318
319static HRESULT IEventListenerDemoImpl_AddRef(IEventListenerDemo *pThis)
320{
321 return ++(pThis->cRef);
322}
323
324static HRESULT IEventListenerDemoImpl_Release(IEventListenerDemo *pThis)
325{
326 HRESULT c;
327
328 c = --(pThis->cRef);
329 if (!c)
330 free(pThis);
331 return c;
332}
333
334#ifdef WIN32
335static HRESULT IEventListenerDemoImpl_GetTypeInfoCount(IEventListenerDemo *pThis, UINT *pctinfo)
336{
337 if (!pctinfo)
338 return E_POINTER;
339 *pctinfo = 1;
340 return S_OK;
341}
342
343static HRESULT IEventListenerDemoImpl_GetTypeInfo(IEventListenerDemo *pThis, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
344{
345 if (!ppTInfo)
346 return E_POINTER;
347 ITypeInfo_AddRef(g_pTInfoIEventListener);
348 *ppTInfo = g_pTInfoIEventListener;
349 return S_OK;
350}
351
352static HRESULT IEventListenerDemoImpl_GetIDsOfNames(IEventListenerDemo *pThis, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
353{
354 return ITypeInfo_GetIDsOfNames(g_pTInfoIEventListener, rgszNames, cNames, rgDispId);
355}
356
357static HRESULT IEventListenerDemoImpl_Invoke(IEventListenerDemo *pThis, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
358{
359 return ITypeInfo_Invoke(g_pTInfoIEventListener, (IDispatch *)pThis, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
360}
361
362static HRESULT LoadTypeInfo(REFIID riid, ITypeInfo **pTInfo)
363{
364 HRESULT rc;
365 ITypeLib *pTypeLib;
366 rc = LoadRegTypeLib(&LIBID_VirtualBox, 1 /* major */, 0 /* minor */, 0 /* lcid */, &pTypeLib);
367 if (FAILED(rc))
368 return rc;
369 rc = ITypeLib_GetTypeInfoOfGuid(pTypeLib, riid, pTInfo);
370
371 /* No longer need access to the type lib, release it. */
372 ITypeLib_Release(pTypeLib);
373
374 return rc;
375}
376#endif
377
378#ifdef __GNUC__
379typedef struct IEventListenerDemoVtblInt
380{
381 ptrdiff_t offset_to_top;
382 void *typeinfo;
383 IEventListenerDemoVtbl lpVtbl;
384} IEventListenerDemoVtblInt;
385
386static IEventListenerDemoVtblInt g_IEventListenerDemoVtblInt =
387{
388 0, /* offset_to_top */
389 NULL, /* typeinfo, not vital */
390 {
391 IEventListenerDemoImpl_QueryInterface,
392 IEventListenerDemoImpl_AddRef,
393 IEventListenerDemoImpl_Release,
394#ifdef WIN32
395 IEventListenerDemoImpl_GetTypeInfoCount,
396 IEventListenerDemoImpl_GetTypeInfo,
397 IEventListenerDemoImpl_GetIDsOfNames,
398 IEventListenerDemoImpl_Invoke,
399#endif
400 IEventListenerDemoImpl_HandleEvent
401 }
402};
403#elif defined(_MSC_VER)
404typedef struct IEventListenerDemoVtblInt
405{
406 IEventListenerDemoVtbl lpVtbl;
407} IEventListenerDemoVtblInt;
408
409static IEventListenerDemoVtblInt g_IEventListenerDemoVtblInt =
410{
411 {
412 IEventListenerDemoImpl_QueryInterface,
413 IEventListenerDemoImpl_AddRef,
414 IEventListenerDemoImpl_Release,
415#ifdef WIN32
416 IEventListenerDemoImpl_GetTypeInfoCount,
417 IEventListenerDemoImpl_GetTypeInfo,
418 IEventListenerDemoImpl_GetIDsOfNames,
419 IEventListenerDemoImpl_Invoke,
420#endif
421 IEventListenerDemoImpl_HandleEvent
422 }
423};
424#else
425# error Port me!
426#endif
427
428/**
429 * Register active event listener for the selected VM.
430 *
431 * @param virtualBox ptr to IVirtualBox object
432 * @param session ptr to ISession object
433 * @param id identifies the machine to start
434 */
435static void registerActiveEventListener(IVirtualBox *virtualBox, ISession *session, BSTR machineId)
436{
437 IConsole *console = NULL;
438 HRESULT rc;
439
440 rc = ISession_get_Console(session, &console);
441 if ((SUCCEEDED(rc)) && console)
442 {
443 IEventSource *es = NULL;
444 rc = IConsole_get_EventSource(console, &es);
445 if (SUCCEEDED(rc) && es)
446 {
447 static const ULONG interestingEvents[] =
448 {
449 VBoxEventType_OnMousePointerShapeChanged,
450 VBoxEventType_OnMouseCapabilityChanged,
451 VBoxEventType_OnKeyboardLedsChanged,
452 VBoxEventType_OnStateChanged,
453 VBoxEventType_OnAdditionsStateChanged,
454 VBoxEventType_OnNetworkAdapterChanged,
455 VBoxEventType_OnSerialPortChanged,
456 VBoxEventType_OnParallelPortChanged,
457 VBoxEventType_OnStorageControllerChanged,
458 VBoxEventType_OnMediumChanged,
459 VBoxEventType_OnVRDEServerChanged,
460 VBoxEventType_OnUSBControllerChanged,
461 VBoxEventType_OnUSBDeviceStateChanged,
462 VBoxEventType_OnSharedFolderChanged,
463 VBoxEventType_OnRuntimeError,
464 VBoxEventType_OnCanShowWindow,
465 VBoxEventType_OnShowWindow
466 };
467 SAFEARRAY *interestingEventsSA = NULL;
468 IEventListenerDemo *consoleListener = NULL;
469
470 /* The VirtualBox API expects enum values as VT_I4, which in the
471 * future can be hopefully relaxed. */
472 interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, sizeof(interestingEvents) / sizeof(interestingEvents[0]));
473 g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &interestingEvents, sizeof(interestingEvents));
474
475 consoleListener = calloc(1, sizeof(IEventListenerDemo));
476 if (consoleListener)
477 {
478 consoleListener->lpVtbl = &(g_IEventListenerDemoVtblInt.lpVtbl);
479#ifdef WIN32
480 CoCreateFreeThreadedMarshaler((IUnknown *)consoleListener, &consoleListener->pUnkMarshaler);
481#endif
482 IEventListenerDemo_AddRef(consoleListener);
483
484 rc = IEventSource_RegisterListener(es, (IEventListener *)consoleListener,
485 ComSafeArrayAsInParam(interestingEventsSA),
486 1 /* active */);
487 if (SUCCEEDED(rc))
488 {
489 /* Just wait here for events, no easy way to do this better
490 * as there's not much to do after this completes. */
491 printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n");
492 fflush(stdout);
493#ifdef WIN32
494 SetConsoleCtrlHandler(ctrlCHandler, TRUE);
495#else
496 signal(SIGINT, (void (*)(int))ctrlCHandler);
497#endif
498
499 while (!g_fStop)
500 {
501 g_pVBoxFuncs->pfnProcessEventQueue(250);
502 }
503
504#ifdef WIN32
505 SetConsoleCtrlHandler(ctrlCHandler, FALSE);
506#else
507 signal(SIGINT, SIG_DFL);
508#endif
509 }
510 else
511 {
512 printf("Failed to register event listener.\n");
513 }
514 IEventSource_UnregisterListener(es, (IEventListener *)consoleListener);
515#ifdef WIN32
516 if (consoleListener->pUnkMarshaler)
517 IUnknown_Release(consoleListener->pUnkMarshaler);
518#endif
519 IEventListenerDemo_Release(consoleListener);
520 }
521 else
522 {
523 printf("Failed while allocating memory for console event listener.\n");
524 }
525 g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA);
526 IEventSource_Release(es);
527 }
528 else
529 {
530 printf("Failed to get the event source instance.\n");
531 }
532 IConsole_Release(console);
533 }
534}
535
536#else /* !USE_ACTIVE_EVENT_LISTENER */
537
538/**
539 * Register passive event listener for the selected VM.
540 *
541 * @param virtualBox ptr to IVirtualBox object
542 * @param session ptr to ISession object
543 * @param id identifies the machine to start
544 */
545static void registerPassiveEventListener(IVirtualBox *virtualBox, ISession *session, BSTR machineId)
546{
547 IConsole *console = NULL;
548 HRESULT rc;
549
550 rc = ISession_get_Console(session, &console);
551 if ((SUCCEEDED(rc)) && console)
552 {
553 IEventSource *es = NULL;
554 rc = IConsole_get_EventSource(console, &es);
555 if (SUCCEEDED(rc) && es)
556 {
557 static const ULONG interestingEvents[] =
558 {
559 VBoxEventType_OnMousePointerShapeChanged,
560 VBoxEventType_OnMouseCapabilityChanged,
561 VBoxEventType_OnKeyboardLedsChanged,
562 VBoxEventType_OnStateChanged,
563 VBoxEventType_OnAdditionsStateChanged,
564 VBoxEventType_OnNetworkAdapterChanged,
565 VBoxEventType_OnSerialPortChanged,
566 VBoxEventType_OnParallelPortChanged,
567 VBoxEventType_OnStorageControllerChanged,
568 VBoxEventType_OnMediumChanged,
569 VBoxEventType_OnVRDEServerChanged,
570 VBoxEventType_OnUSBControllerChanged,
571 VBoxEventType_OnUSBDeviceStateChanged,
572 VBoxEventType_OnSharedFolderChanged,
573 VBoxEventType_OnRuntimeError,
574 VBoxEventType_OnCanShowWindow,
575 VBoxEventType_OnShowWindow
576 };
577 SAFEARRAY *interestingEventsSA = NULL;
578 IEventListener *consoleListener = NULL;
579
580 /* The VirtualBox API expects enum values as VT_I4, which in the
581 * future can be hopefully relaxed. */
582 interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, sizeof(interestingEvents) / sizeof(interestingEvents[0]));
583 g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &interestingEvents, sizeof(interestingEvents));
584
585 rc = IEventSource_CreateListener(es, &consoleListener);
586 if (SUCCEEDED(rc) && consoleListener)
587 {
588 rc = IEventSource_RegisterListener(es, consoleListener,
589 ComSafeArrayAsInParam(interestingEventsSA),
590 0 /* passive */);
591 if (SUCCEEDED(rc))
592 {
593 /* Just wait here for events, no easy way to do this better
594 * as there's not much to do after this completes. */
595 printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n");
596 fflush(stdout);
597#ifdef WIN32
598 SetConsoleCtrlHandler(ctrlCHandler, TRUE);
599#else
600 signal(SIGINT, (void (*)(int))ctrlCHandler);
601#endif
602
603 while (!g_fStop)
604 {
605 IEvent *ev = NULL;
606 rc = IEventSource_GetEvent(es, consoleListener, 250, &ev);
607 if (FAILED(rc))
608 {
609 printf("Failed getting event: %#x\n", rc);
610 g_fStop = 1;
611 continue;
612 }
613 /* handle timeouts, resulting in NULL events */
614 if (!ev)
615 continue;
616 rc = EventListenerDemoProcessEvent(ev);
617 if (FAILED(rc))
618 {
619 printf("Failed processing event: %#x\n", rc);
620 g_fStop = 1;
621 /* finish processing the event */
622 }
623 rc = IEventSource_EventProcessed(es, consoleListener, ev);
624 if (FAILED(rc))
625 {
626 printf("Failed to mark event as processed: %#x\n", rc);
627 g_fStop = 1;
628 /* continue with event release */
629 }
630 if (ev)
631 {
632 IEvent_Release(ev);
633 ev = NULL;
634 }
635 }
636
637#ifdef WIN32
638 SetConsoleCtrlHandler(ctrlCHandler, FALSE);
639#else
640 signal(SIGINT, SIG_DFL);
641#endif
642 }
643 else
644 {
645 printf("Failed to register event listener.\n");
646 }
647 IEventSource_UnregisterListener(es, (IEventListener *)consoleListener);
648 IEventListener_Release(consoleListener);
649 }
650 else
651 {
652 printf("Failed to create an event listener instance.\n");
653 }
654 g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA);
655 IEventSource_Release(es);
656 }
657 else
658 {
659 printf("Failed to get the event source instance.\n");
660 }
661 IConsole_Release(console);
662 }
663}
664
665#endif /* !USE_ACTIVE_EVENT_LISTENER */
666
667/**
668 * Print detailed error information if available.
669 * @param pszExecutable string with the executable name
670 * @param pszErrorMsg string containing the code location specific error message
671 * @param rc COM/XPCOM result code
672 */
673static void PrintErrorInfo(const char *pszExecutable, const char *pszErrorMsg, HRESULT rc)
674{
675 IErrorInfo *ex;
676 HRESULT rc2 = S_OK;
677 fprintf(stderr, "%s: %s (rc=%#010x)\n", pszExecutable, pszErrorMsg, (unsigned)rc);
678 rc2 = g_pVBoxFuncs->pfnGetException(&ex);
679 if (SUCCEEDED(rc2))
680 {
681 IVirtualBoxErrorInfo *ei;
682 rc2 = IErrorInfo_QueryInterface(ex, &IID_IVirtualBoxErrorInfo, (void **)&ei);
683 if (FAILED(rc2))
684 ei = NULL;
685 if (ei)
686 {
687 /* got extended error info, maybe multiple infos */
688 do
689 {
690 LONG resultCode = S_OK;
691 BSTR componentUtf16 = NULL;
692 char *component = NULL;
693 BSTR textUtf16 = NULL;
694 char *text = NULL;
695 IVirtualBoxErrorInfo *ei_next = NULL;
696 fprintf(stderr, "Extended error info (IVirtualBoxErrorInfo):\n");
697
698 IVirtualBoxErrorInfo_get_ResultCode(ei, &resultCode);
699 fprintf(stderr, " resultCode=%#010x\n", (unsigned)resultCode);
700
701 IVirtualBoxErrorInfo_get_Component(ei, &componentUtf16);
702 g_pVBoxFuncs->pfnUtf16ToUtf8(componentUtf16, &component);
703 g_pVBoxFuncs->pfnComUnallocString(componentUtf16);
704 fprintf(stderr, " component=%s\n", component);
705 g_pVBoxFuncs->pfnUtf8Free(component);
706
707 IVirtualBoxErrorInfo_get_Text(ei, &textUtf16);
708 g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text);
709 g_pVBoxFuncs->pfnComUnallocString(textUtf16);
710 fprintf(stderr, " text=%s\n", text);
711 g_pVBoxFuncs->pfnUtf8Free(text);
712
713 rc2 = IVirtualBoxErrorInfo_get_Next(ei, &ei_next);
714 if (FAILED(rc2))
715 ei_next = NULL;
716 IVirtualBoxErrorInfo_Release(ei);
717 ei = ei_next;
718 }
719 while (ei);
720 }
721
722 IErrorInfo_Release(ex);
723 g_pVBoxFuncs->pfnClearException();
724 }
725}
726
727/**
728 * Start a VM.
729 *
730 * @param argv0 executable name
731 * @param virtualBox ptr to IVirtualBox object
732 * @param session ptr to ISession object
733 * @param id identifies the machine to start
734 */
735static void startVM(const char *argv0, IVirtualBox *virtualBox, ISession *session, BSTR id)
736{
737 HRESULT rc;
738 IMachine *machine = NULL;
739 IProgress *progress = NULL;
740 BSTR env = NULL;
741 BSTR sessionType;
742
743 rc = IVirtualBox_FindMachine(virtualBox, id, &machine);
744 if (FAILED(rc) || !machine)
745 {
746 PrintErrorInfo(argv0, "Error: Couldn't get the Machine reference", rc);
747 return;
748 }
749
750 g_pVBoxFuncs->pfnUtf8ToUtf16("gui", &sessionType);
751 rc = IMachine_LaunchVMProcess(machine, session, sessionType, env, &progress);
752 g_pVBoxFuncs->pfnUtf16Free(sessionType);
753 if (SUCCEEDED(rc))
754 {
755 BOOL completed;
756 LONG resultCode;
757
758 printf("Waiting for the remote session to open...\n");
759 IProgress_WaitForCompletion(progress, -1);
760
761 rc = IProgress_get_Completed(progress, &completed);
762 if (FAILED(rc))
763 fprintf(stderr, "Error: GetCompleted status failed\n");
764
765 IProgress_get_ResultCode(progress, &resultCode);
766 if (FAILED(resultCode))
767 {
768 IVirtualBoxErrorInfo *errorInfo;
769 BSTR textUtf16;
770 char *text;
771
772 IProgress_get_ErrorInfo(progress, &errorInfo);
773 IVirtualBoxErrorInfo_get_Text(errorInfo, &textUtf16);
774 g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text);
775 printf("Error: %s\n", text);
776
777 g_pVBoxFuncs->pfnComUnallocString(textUtf16);
778 g_pVBoxFuncs->pfnUtf8Free(text);
779 IVirtualBoxErrorInfo_Release(errorInfo);
780 }
781 else
782 {
783 fprintf(stderr, "VM process has been successfully started\n");
784
785 /* Kick off the event listener demo part, which is quite separate.
786 * Ignore it if you need a more basic sample. */
787#ifdef USE_ACTIVE_EVENT_LISTENER
788 registerActiveEventListener(virtualBox, session, id);
789#else /* !USE_ACTIVE_EVENT_LISTENER */
790 registerPassiveEventListener(virtualBox, session, id);
791#endif /* !USE_ACTIVE_EVENT_LISTENER */
792 }
793 IProgress_Release(progress);
794 }
795 else
796 PrintErrorInfo(argv0, "Error: LaunchVMProcess failed", rc);
797
798 /* It's important to always release resources. */
799 IMachine_Release(machine);
800}
801
802/**
803 * List the registered VMs.
804 *
805 * @param argv0 executable name
806 * @param virtualBox ptr to IVirtualBox object
807 * @param session ptr to ISession object
808 */
809static void listVMs(const char *argv0, IVirtualBox *virtualBox, ISession *session)
810{
811 HRESULT rc;
812 SAFEARRAY *machinesSA = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc();
813 IMachine **machines = NULL;
814 ULONG machineCnt = 0;
815 ULONG i;
816 unsigned start_id;
817
818 /*
819 * Get the list of all registered VMs.
820 */
821 rc = IVirtualBox_get_Machines(virtualBox, ComSafeArrayAsOutIfaceParam(machinesSA, IMachine *));
822 if (FAILED(rc))
823 {
824 PrintErrorInfo(argv0, "could not get list of machines", rc);
825 return;
826 }
827
828 /*
829 * Extract interface pointers from machinesSA, and update the reference
830 * counter of each object, as destroying machinesSA would call Release.
831 */
832 g_pVBoxFuncs->pfnSafeArrayCopyOutIfaceParamHelper((IUnknown ***)&machines, &machineCnt, machinesSA);
833 g_pVBoxFuncs->pfnSafeArrayDestroy(machinesSA);
834
835 if (!machineCnt)
836 {
837 printf("\tNo VMs\n");
838 return;
839 }
840
841 printf("VM List:\n\n");
842
843 /*
844 * Iterate through the collection.
845 */
846
847 for (i = 0; i < machineCnt; ++i)
848 {
849 IMachine *machine = machines[i];
850 BOOL isAccessible = FALSE;
851
852 printf("\tMachine #%u\n", (unsigned)i);
853
854 if (!machine)
855 {
856 printf("\t(skipped, NULL)\n");
857 continue;
858 }
859
860 IMachine_get_Accessible(machine, &isAccessible);
861
862 if (isAccessible)
863 {
864 BSTR machineNameUtf16;
865 char *machineName;
866
867 IMachine_get_Name(machine, &machineNameUtf16);
868 g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16,&machineName);
869 g_pVBoxFuncs->pfnComUnallocString(machineNameUtf16);
870 printf("\tName: %s\n", machineName);
871 g_pVBoxFuncs->pfnUtf8Free(machineName);
872 }
873 else
874 {
875 printf("\tName: <inaccessible>\n");
876 }
877
878 {
879 BSTR uuidUtf16;
880 char *uuidUtf8;
881
882 IMachine_get_Id(machine, &uuidUtf16);
883 g_pVBoxFuncs->pfnUtf16ToUtf8(uuidUtf16, &uuidUtf8);
884 g_pVBoxFuncs->pfnComUnallocString(uuidUtf16);
885 printf("\tUUID: %s\n", uuidUtf8);
886 g_pVBoxFuncs->pfnUtf8Free(uuidUtf8);
887 }
888
889 if (isAccessible)
890 {
891 {
892 BSTR configFileUtf16;
893 char *configFileUtf8;
894
895 IMachine_get_SettingsFilePath(machine, &configFileUtf16);
896 g_pVBoxFuncs->pfnUtf16ToUtf8(configFileUtf16, &configFileUtf8);
897 g_pVBoxFuncs->pfnComUnallocString(configFileUtf16);
898 printf("\tConfig file: %s\n", configFileUtf8);
899 g_pVBoxFuncs->pfnUtf8Free(configFileUtf8);
900 }
901
902 {
903 ULONG memorySize;
904
905 IMachine_get_MemorySize(machine, &memorySize);
906 printf("\tMemory size: %uMB\n", memorySize);
907 }
908
909 {
910 BSTR typeId;
911 BSTR osNameUtf16;
912 char *osName;
913 IGuestOSType *osType = NULL;
914
915 IMachine_get_OSTypeId(machine, &typeId);
916 IVirtualBox_GetGuestOSType(virtualBox, typeId, &osType);
917 g_pVBoxFuncs->pfnComUnallocString(typeId);
918 IGuestOSType_get_Description(osType, &osNameUtf16);
919 g_pVBoxFuncs->pfnUtf16ToUtf8(osNameUtf16,&osName);
920 g_pVBoxFuncs->pfnComUnallocString(osNameUtf16);
921 printf("\tGuest OS: %s\n\n", osName);
922 g_pVBoxFuncs->pfnUtf8Free(osName);
923
924 IGuestOSType_Release(osType);
925 }
926 }
927 }
928
929 /*
930 * Let the user chose a machine to start.
931 */
932
933 printf("Type Machine# to start (0 - %u) or 'quit' to do nothing: ",
934 (unsigned)(machineCnt - 1));
935 fflush(stdout);
936
937 if (scanf("%u", &start_id) == 1 && start_id < machineCnt)
938 {
939 IMachine *machine = machines[start_id];
940
941 if (machine)
942 {
943 BSTR uuidUtf16 = NULL;
944
945 IMachine_get_Id(machine, &uuidUtf16);
946 startVM(argv0, virtualBox, session, uuidUtf16);
947 g_pVBoxFuncs->pfnComUnallocString(uuidUtf16);
948 }
949 }
950
951 /*
952 * Don't forget to release the objects in the array.
953 */
954
955 for (i = 0; i < machineCnt; ++i)
956 {
957 IMachine *machine = machines[i];
958
959 if (machine)
960 {
961 IMachine_Release(machine);
962 }
963 }
964 if (machines)
965 free(machines);
966}
967
968/* Main - Start the ball rolling. */
969
970int main(int argc, char **argv)
971{
972 IVirtualBoxClient *vboxclient = NULL;
973 IVirtualBox *vbox = NULL;
974 ISession *session = NULL;
975 ULONG revision = 0;
976 BSTR versionUtf16 = NULL;
977 BSTR homefolderUtf16 = NULL;
978 HRESULT rc; /* Result code of various function (method) calls. */
979
980 printf("Starting main()\n");
981
982 if (VBoxCGlueInit())
983 {
984 fprintf(stderr, "%s: FATAL: VBoxCGlueInit failed: %s\n",
985 argv[0], g_szVBoxErrMsg);
986 return EXIT_FAILURE;
987 }
988
989 {
990 unsigned ver = g_pVBoxFuncs->pfnGetVersion();
991 printf("VirtualBox version: %u.%u.%u\n", ver / 1000000, ver / 1000 % 1000, ver % 1000);
992 ver = g_pVBoxFuncs->pfnGetAPIVersion();
993 printf("VirtualBox API version: %u.%u\n", ver / 1000, ver % 1000);
994 }
995
996 g_pVBoxFuncs->pfnClientInitialize(NULL, &vboxclient);
997 if (!vboxclient)
998 {
999 fprintf(stderr, "%s: FATAL: could not get VirtualBoxClient reference\n", argv[0]);
1000 return EXIT_FAILURE;
1001 }
1002
1003 printf("----------------------------------------------------\n");
1004
1005 rc = IVirtualBoxClient_get_VirtualBox(vboxclient, &vbox);
1006 if (FAILED(rc) || !vbox)
1007 {
1008 PrintErrorInfo(argv[0], "FATAL: could not get VirtualBox reference", rc);
1009 return EXIT_FAILURE;
1010 }
1011 rc = IVirtualBoxClient_get_Session(vboxclient, &session);
1012 if (FAILED(rc) || !session)
1013 {
1014 PrintErrorInfo(argv[0], "FATAL: could not get Session reference", rc);
1015 return EXIT_FAILURE;
1016 }
1017
1018#ifdef USE_ACTIVE_EVENT_LISTENER
1019# ifdef WIN32
1020 rc = LoadTypeInfo(&IID_IEventListener, &g_pTInfoIEventListener);
1021 if (FAILED(rc) || !g_pTInfoIEventListener)
1022 {
1023 PrintErrorInfo(argv[0], "FATAL: could not get type information for IEventListener", rc);
1024 return EXIT_FAILURE;
1025 }
1026# endif /* WIN32 */
1027#endif /* USE_ACTIVE_EVENT_LISTENER */
1028
1029 /*
1030 * Now ask for revision, version and home folder information of
1031 * this vbox. Were not using fancy macros here so it
1032 * remains easy to see how we access C++'s vtable.
1033 */
1034
1035 /* 1. Revision */
1036
1037 rc = IVirtualBox_get_Revision(vbox, &revision);
1038 if (SUCCEEDED(rc))
1039 printf("\tRevision: %u\n", revision);
1040 else
1041 PrintErrorInfo(argv[0], "GetRevision() failed", rc);
1042
1043 /* 2. Version */
1044
1045 rc = IVirtualBox_get_Version(vbox, &versionUtf16);
1046 if (SUCCEEDED(rc))
1047 {
1048 char *version = NULL;
1049 g_pVBoxFuncs->pfnUtf16ToUtf8(versionUtf16, &version);
1050 printf("\tVersion: %s\n", version);
1051 g_pVBoxFuncs->pfnUtf8Free(version);
1052 g_pVBoxFuncs->pfnComUnallocString(versionUtf16);
1053 }
1054 else
1055 PrintErrorInfo(argv[0], "GetVersion() failed", rc);
1056
1057 /* 3. Home Folder */
1058
1059 rc = IVirtualBox_get_HomeFolder(vbox, &homefolderUtf16);
1060 if (SUCCEEDED(rc))
1061 {
1062 char *homefolder = NULL;
1063 g_pVBoxFuncs->pfnUtf16ToUtf8(homefolderUtf16, &homefolder);
1064 printf("\tHomeFolder: %s\n", homefolder);
1065 g_pVBoxFuncs->pfnUtf8Free(homefolder);
1066 g_pVBoxFuncs->pfnComUnallocString(homefolderUtf16);
1067 }
1068 else
1069 PrintErrorInfo(argv[0], "GetHomeFolder() failed", rc);
1070
1071 listVMs(argv[0], vbox, session);
1072 ISession_UnlockMachine(session);
1073
1074 printf("----------------------------------------------------\n");
1075
1076 /*
1077 * Do as mom told us: always clean up after yourself.
1078 */
1079
1080#ifdef USE_ACTIVE_EVENT_LISTENER
1081# ifdef WIN32
1082 if (g_pTInfoIEventListener)
1083 {
1084 ITypeInfo_Release(g_pTInfoIEventListener);
1085 g_pTInfoIEventListener = NULL;
1086 }
1087# endif /* WIN32 */
1088#endif /* USE_ACTIVE_EVENT_LISTENER */
1089
1090 if (session)
1091 {
1092 ISession_Release(session);
1093 session = NULL;
1094 }
1095 if (vbox)
1096 {
1097 IVirtualBox_Release(vbox);
1098 vbox = NULL;
1099 }
1100 if (vboxclient)
1101 {
1102 IVirtualBoxClient_Release(vboxclient);
1103 vboxclient = NULL;
1104 }
1105
1106 g_pVBoxFuncs->pfnClientUninitialize();
1107 VBoxCGlueTerm();
1108 printf("Finished main()\n");
1109
1110 return 0;
1111}
1112/* vim: set ts=4 sw=4 et: */
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