VirtualBox

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

Last change on this file since 53364 was 52793, checked in by vboxsync, 10 years ago

Main/cbinding: introduce a variant of ComSafeArrayAsOutParam which allows specifying the type, to avoid warnings when dealing with the not really existing safearrays on XPCOM

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