VirtualBox

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

Last change on this file since 81422 was 80824, checked in by vboxsync, 5 years ago

Main: bugref:9341: The "environment" parameter in the IMachine::launchVMProcess renamed to "environmentChanges" and changed the type from wstring to "safearray of wstrings"

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