VirtualBox

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

Last change on this file since 71071 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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