VirtualBox

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

Last change on this file since 78382 was 76557, checked in by vboxsync, 6 years ago

include/iprt: Use IPRT_INCLUDED_ rather than _iprt_ as header guard prefix, letting scm enforce this (thereby avoiding copy&paste errors like rsa.h).

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