diff options
Diffstat (limited to 'src/VBox/Main/cbinding')
-rw-r--r-- | src/VBox/Main/cbinding/Makefile.kmk | 158 | ||||
-rw-r--r-- | src/VBox/Main/cbinding/VBoxCAPI.cpp | 1023 | ||||
-rw-r--r-- | src/VBox/Main/cbinding/VBoxCAPI.rc | 61 | ||||
-rw-r--r-- | src/VBox/Main/cbinding/VBoxCAPIGlue.c | 345 | ||||
-rw-r--r-- | src/VBox/Main/cbinding/VBoxCAPIGlue.h.in | 68 | ||||
-rw-r--r-- | src/VBox/Main/cbinding/capiidl.xsl | 2736 | ||||
-rw-r--r-- | src/VBox/Main/cbinding/makefile.tstCAPIGlue | 63 | ||||
-rw-r--r-- | src/VBox/Main/cbinding/tstCAPIGlue.c | 1145 |
8 files changed, 5599 insertions, 0 deletions
diff --git a/src/VBox/Main/cbinding/Makefile.kmk b/src/VBox/Main/cbinding/Makefile.kmk new file mode 100644 index 00000000..7f45b28c --- /dev/null +++ b/src/VBox/Main/cbinding/Makefile.kmk @@ -0,0 +1,158 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the VBox C Binding. +# + +# +# Copyright (C) 2009-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + + +# +# The samples +# +INSTALLS += CAPISamples +CAPISamples_MODE = a+r,u+rw +CAPISamples_INST = \ + $(INST_SDK)bindings/c/samples/ +CAPISamples_SOURCES = \ + tstCAPIGlue.c \ + makefile.tstCAPIGlue=>Makefile + +# +# The ???. +# +INSTALLS += CAPIGlue +CAPIGlue_MODE = a+r,u+rw +CAPIGlue_INST = \ + $(INST_SDK)bindings/c/glue/ +CAPIGlue_SOURCES = \ + VBoxCAPIGlue.c \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPIGlue.h +CAPIGlue_CLEAN = \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPIGlue.h + +$$(CAPIHeaders_0_OUTDIR)/VBoxCAPIGlue.h: \ + $(PATH_SUB_CURRENT)/VBoxCAPIGlue.h.in \ + $(MAKEFILE_CURRENT) \ + | $$(dir $$@) + $(call MSG_GENERATE,,$@) + $(QUIET)$(SED) \ + -e 's/@VBOX_API_VERSION@/$(VBOX_API_VERSION)/' \ + < $< > $@ + +# +# The ???. +# +INSTALLS += CAPIHeaders +CAPIHeaders_MODE = a+r,u+rw +CAPIHeaders_INST = $(INST_SDK)bindings/c/include/ +CAPIHeaders_SOURCES = \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h=>VBoxCAPI_v$(VBOX_API_VERSION).h +CAPIHeaders_CLEAN = \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h + +$$(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h: \ + $(PATH_SUB_CURRENT)/capiidl.xsl \ + $(PATH_SUB_CURRENT)/../idl/typemap-shared.inc.xsl \ + $(VBOX_XIDL_FILE) \ + | $$(dir $$@) + $(call MSG_TOOL,xsltproc,CAPIHeaders,$<,$@) + $(QUIET)$(VBOX_XSLTPROC) -o $@ $^ + +ifndef VBOX_ONLY_SDK + + # + # The C API binding utility DLL + # + DLLS += VBoxCAPI + VBoxCAPI_TEMPLATE = VBoxMainClientDll + ifdef VBOX_WITH_XPCOM + # Keep old name on XPCOM so that legacy code is happy. + VBoxCAPI_INST = $(INST_BIN)VBoxXPCOMC$(VBOX_SUFF_DLL) + endif + VBoxCAPI_DEFS = IN_VBOXCAPI + VBoxCAPI_SOURCES = \ + VBoxCAPI.cpp + VBoxCAPI_SOURCES.win = \ + VBoxCAPI.rc + VBoxCAPI_INCS = \ + $(CAPIHeaders_0_OUTDIR) + VBoxCAPI_INTERMEDIATES = \ + $(CAPIHeaders_0_OUTDIR)/VBoxCAPI.h + + # + # The C glue library. + # + LIBRARIES += VBoxCAPIGlue + VBoxCAPIGlue_TEMPLATE = VBoxMainExe + VBoxCAPIGlue_DEFS = IN_VBOXCAPI + VBoxCAPIGlue_SOURCES = \ + VBoxCAPIGlue.c + ifdef VBOX_WITH_XPCOM + VBoxCAPIGlue_SOURCES += \ + $(VBOX_PATH_SDK)/bindings/xpcom/lib/VirtualBox_i.c + else + VBoxCAPIGlue_SOURCES += \ + $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c + endif + VBoxCAPIGlue_INCS = \ + $(VBOX_PATH_SDK)/bindings/c/include \ + $(VBOX_PATH_SDK)/bindings/c/glue + VBoxCAPIGlue_INTERMEDIATES = \ + $(VBOX_PATH_SDK)/bindings/c/glue/VBoxCAPIGlue.h \ + $(VBOX_PATH_SDK)/bindings/c/include/VBoxCAPI_v$(VBOX_API_VERSION).h + + if defined(VBOX_WITH_TESTCASES) && "$(KBUILD_TARGET)" != "darwin" + # + # The testcase (also in samples). + # C testcase using the dynamic glue. + # + PROGRAMS += tstCAPIGlue + tstCAPIGlue_TEMPLATE = VBoxR3TstExe + tstCAPIGlue_INCS = \ + $(VBOX_PATH_SDK)/bindings/c/include \ + $(VBOX_PATH_SDK)/bindings/c/glue + ifdef VBOX_WITH_XPCOM + tstCAPIGlue_INCS += \ + $(VBOX_PATH_SDK)/bindings/xpcom/include + else + tstCAPIGlue_INCS += \ + $(VBOX_PATH_SDK)/bindings/mscom/include + endif + tstCAPIGlue_INTERMEDIATES = \ + $(VBOX_PATH_SDK)/bindings/c/glue/VBoxCAPIGlue.h \ + $(VBOX_PATH_SDK)/bindings/c/include/VBoxCAPI_v$(VBOX_API_VERSION).h \ + $(if-expr !defined(VBOX_WITH_XPCOM),$(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h,) + tstCAPIGlue_SOURCES = \ + tstCAPIGlue.c + tstCAPIGlue_LIBS = \ + $(VBoxCAPIGlue_1_TARGET) + endif + +endif # !VBOX_ONLY_SDK + +# generate rules. +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/Main/cbinding/VBoxCAPI.cpp b/src/VBox/Main/cbinding/VBoxCAPI.cpp new file mode 100644 index 00000000..52d951e1 --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPI.cpp @@ -0,0 +1,1023 @@ +/* $Id: VBoxCAPI.cpp $ */ +/** @file VBoxCAPI.cpp + * Utility functions to use with the C API binding. + */ + +/* + * Copyright (C) 2009-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_GROUP LOG_GROUP_MAIN + +#include "VBoxCAPI.h" + +#ifdef VBOX_WITH_XPCOM +# include <nsMemory.h> +# include <nsIServiceManager.h> +# include <nsEventQueueUtils.h> +# include <nsIExceptionService.h> +# include <stdlib.h> +#endif /* VBOX_WITH_XPCOM */ + +#include <iprt/env.h> +#include <iprt/err.h> +#include <iprt/initterm.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/utf16.h> +#include <iprt/uuid.h> +#include <VBox/log.h> +#include <VBox/version.h> + +#include "VBox/com/com.h" +#include "VBox/com/NativeEventQueue.h" + + +#ifndef RT_OS_DARWIN /* Probably not used for xpcom, so clang gets upset: error: using directive refers to implicitly-defined namespace 'std' [-Werror]*/ +using namespace std; +#endif + +/* The following 2 object references should be eliminated once the legacy + * way to initialize the COM/XPCOM C bindings is removed. */ +static ISession *g_Session = NULL; +static IVirtualBox *g_VirtualBox = NULL; + +#ifdef VBOX_WITH_XPCOM +/* This object reference should be eliminated once the legacy way of handling + * the event queue (XPCOM specific) is removed. */ +static nsIEventQueue *g_EventQueue = NULL; +#endif /* VBOX_WITH_XPCOM */ + +static void VBoxComUninitialize(void); +static void VBoxClientUninitialize(void); + +static int +VBoxUtf16ToUtf8(CBSTR pwszString, char **ppszString) +{ + if (!pwszString) + { + *ppszString = NULL; + return VINF_SUCCESS; + } + return RTUtf16ToUtf8(pwszString, ppszString); +} + +static int +VBoxUtf8ToUtf16(const char *pszString, BSTR *ppwszString) +{ + *ppwszString = NULL; + if (!pszString) + return VINF_SUCCESS; +#ifdef VBOX_WITH_XPCOM + return RTStrToUtf16(pszString, ppwszString); +#else /* !VBOX_WITH_XPCOM */ + PRTUTF16 pwsz; + int vrc = RTStrToUtf16(pszString, &pwsz); + if (RT_SUCCESS(vrc)) + { + *ppwszString = ::SysAllocString(pwsz); + if (!*ppwszString) + vrc = VERR_NO_STR_MEMORY; + RTUtf16Free(pwsz); + } + return vrc; +#endif /* !VBOX_WITH_XPCOM */ +} + +static void +VBoxUtf8Clear(char *pszString) +{ + RT_BZERO(pszString, strlen(pszString)); +} + +static void +VBoxUtf16Clear(BSTR pwszString) +{ + RT_BZERO(pwszString, RTUtf16Len(pwszString) * sizeof(RTUTF16)); +} + +static void +VBoxUtf16Free(BSTR pwszString) +{ +#ifdef VBOX_WITH_XPCOM + RTUtf16Free(pwszString); +#else + ::SysFreeString(pwszString); +#endif +} + +static void +VBoxUtf8Free(char *pszString) +{ + RTStrFree(pszString); +} + +static void +VBoxComUnallocString(BSTR pwsz) +{ + if (pwsz) + { +#ifdef VBOX_WITH_XPCOM + nsMemory::Free(pwsz); +#else + ::SysFreeString(pwsz); +#endif + } +} + +static void +VBoxComUnallocMem(void *pv) +{ + VBoxComUnallocString((BSTR)pv); +} + +static ULONG +VBoxVTElemSize(VARTYPE vt) +{ + switch (vt) + { + case VT_BOOL: + case VT_I1: + case VT_UI1: + return 1; + case VT_I2: + case VT_UI2: + return 2; + case VT_I4: + case VT_UI4: + case VT_HRESULT: + return 4; + case VT_I8: + case VT_UI8: + return 8; + case VT_BSTR: + case VT_DISPATCH: + case VT_UNKNOWN: + return sizeof(void *); + default: + return 0; + } +} + +static SAFEARRAY * +VBoxSafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements) +{ +#ifdef VBOX_WITH_XPCOM + NOREF(lLbound); + ULONG cbElement = VBoxVTElemSize(vt); + if (!cbElement) + return NULL; + SAFEARRAY *psa = (SAFEARRAY *)RTMemAllocZ(sizeof(SAFEARRAY)); + if (!psa) + return psa; + if (cElements) + { + void *pv = nsMemory::Alloc(cElements * cbElement); + if (!pv) + { + RTMemFree(psa); + return NULL; + } + psa->pv = pv; + psa->c = cElements; + } + return psa; +#else /* !VBOX_WITH_XPCOM */ + return SafeArrayCreateVector(vt, lLbound, cElements); +#endif /* !VBOX_WITH_XPCOM */ +} + +static SAFEARRAY * +VBoxSafeArrayOutParamAlloc(void) +{ +#ifdef VBOX_WITH_XPCOM + return (SAFEARRAY *)RTMemAllocZ(sizeof(SAFEARRAY)); +#else /* !VBOX_WITH_XPCOM */ + return NULL; +#endif /* !VBOX_WITH_XPCOM */ +} + +static HRESULT +VBoxSafeArrayDestroy(SAFEARRAY *psa) +{ +#ifdef VBOX_WITH_XPCOM + if (psa) + { + if (psa->pv) + nsMemory::Free(psa->pv); + RTMemFree(psa); + } + return S_OK; +#else /* !VBOX_WITH_XPCOM */ + VARTYPE vt = VT_UNKNOWN; + HRESULT hrc = SafeArrayGetVartype(psa, &vt); + if (FAILED(hrc)) + return hrc; + if (vt == VT_BSTR) + { + /* Special treatment: strings are to be freed explicitly, see sample + * C binding code, so zap it here. No way to reach compatible code + * behavior between COM and XPCOM without this kind of trickery. */ + void *pData; + hrc = SafeArrayAccessData(psa, &pData); + if (FAILED(hrc)) + return hrc; + ULONG cbElement = VBoxVTElemSize(vt); + if (!cbElement) + return E_INVALIDARG; + Assert(cbElement = psa->cbElements); + ULONG cElements = psa->rgsabound[0].cElements; + memset(pData, '\0', cbElement * cElements); + SafeArrayUnaccessData(psa); + } + return SafeArrayDestroy(psa); +#endif /* !VBOX_WITH_XPCOM */ +} + +static HRESULT +VBoxSafeArrayCopyInParamHelper(SAFEARRAY *psa, const void *pv, ULONG cb) +{ + if (!pv || !psa) + return E_POINTER; + if (!cb) + return S_OK; + + void *pData; +#ifdef VBOX_WITH_XPCOM + pData = psa->pv; +#else /* !VBOX_WITH_XPCOM */ + HRESULT hrc = SafeArrayAccessData(psa, &pData); + if (FAILED(hrc)) + return hrc; +#endif /* !VBOX_WITH_XPCOM */ + memcpy(pData, pv, cb); +#ifndef VBOX_WITH_XPCOM + SafeArrayUnaccessData(psa); +#endif + return S_OK; +} + +static HRESULT +VBoxSafeArrayCopyOutParamHelper(void **ppv, ULONG *pcb, VARTYPE vt, SAFEARRAY *psa) +{ + if (!ppv) + return E_POINTER; + ULONG cbElement = VBoxVTElemSize(vt); + if (!cbElement) + { + *ppv = NULL; + if (pcb) + *pcb = 0; + return E_INVALIDARG; + } +#ifndef VBOX_WITH_XPCOM + if (psa->cDims != 1) + { + *ppv = NULL; + if (pcb) + *pcb = 0; + return E_INVALIDARG; + } + Assert(cbElement = psa->cbElements); +#endif /* !VBOX_WITH_XPCOM */ + void *pData; + ULONG cElements; +#ifdef VBOX_WITH_XPCOM + pData = psa->pv; + cElements = psa->c; +#else /* !VBOX_WITH_XPCOM */ + HRESULT hrc = SafeArrayAccessData(psa, &pData); + if (FAILED(hrc)) + { + *ppv = NULL; + if (pcb) + *pcb = 0; + return hrc; + } + cElements = psa->rgsabound[0].cElements; +#endif /* !VBOX_WITH_XPCOM */ + size_t cbTotal = cbElement * cElements; + void *pv = NULL; + if (cbTotal) + { + pv = malloc(cbTotal); + if (!pv) + { + *ppv = NULL; + if (pcb) + *pcb = 0; + return E_OUTOFMEMORY; + } + else + memcpy(pv, pData, cbTotal); + } + *ppv = pv; + if (pcb) + *pcb = (ULONG)cbTotal; +#ifndef VBOX_WITH_XPCOM + SafeArrayUnaccessData(psa); +#endif + return S_OK; +} + +static HRESULT +VBoxSafeArrayCopyOutIfaceParamHelper(IUnknown ***ppaObj, ULONG *pcObj, SAFEARRAY *psa) +{ + ULONG mypcb; + HRESULT hrc = VBoxSafeArrayCopyOutParamHelper((void **)ppaObj, &mypcb, VT_UNKNOWN, psa); + if (FAILED(hrc)) + { + if (pcObj) + *pcObj = 0; + return hrc; + } + ULONG cElements = mypcb / sizeof(void *); + if (pcObj) + *pcObj = cElements; +#ifndef VBOX_WITH_XPCOM + /* Do this only for COM, as there the SAFEARRAY destruction will release + * the contained references automatically. XPCOM doesn't do that, which + * means that copying implicitly transfers ownership. */ + IUnknown **paObj = *ppaObj; + for (ULONG i = 0; i < cElements; i++) + { + IUnknown *pObj = paObj[i]; + if (pObj) + pObj->AddRef(); + } +#endif /* VBOX_WITH_XPCOM */ + return S_OK; +} + +static HRESULT +VBoxArrayOutFree(void *pv) +{ + free(pv); + return S_OK; +} + +static void +VBoxComInitialize(const char *pszVirtualBoxIID, IVirtualBox **ppVirtualBox, + const char *pszSessionIID, ISession **ppSession) +{ + int vrc; + IID virtualBoxIID; + IID sessionIID; + + *ppSession = NULL; + *ppVirtualBox = NULL; + + /* convert the string representation of the UUIDs (if provided) to IID */ + if (pszVirtualBoxIID && *pszVirtualBoxIID) + { + vrc = ::RTUuidFromStr((RTUUID *)&virtualBoxIID, pszVirtualBoxIID); + if (RT_FAILURE(vrc)) + return; + } + else + virtualBoxIID = IID_IVirtualBox; + if (pszSessionIID && *pszSessionIID) + { + vrc = ::RTUuidFromStr((RTUUID *)&sessionIID, pszSessionIID); + if (RT_FAILURE(vrc)) + return; + } + else + sessionIID = IID_ISession; + + HRESULT hrc = com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING); + if (FAILED(hrc)) + { + Log(("Cbinding: COM/XPCOM could not be initialized! hrc=%Rhrc\n", hrc)); + VBoxComUninitialize(); + return; + } + +#ifdef VBOX_WITH_XPCOM + hrc = NS_GetMainEventQ(&g_EventQueue); + if (FAILED(hrc)) + { + Log(("Cbinding: Could not get XPCOM event queue! hrc=%Rhrc\n", hrc)); + VBoxComUninitialize(); + return; + } +#endif /* VBOX_WITH_XPCOM */ + +#ifdef VBOX_WITH_XPCOM + nsIComponentManager *pManager; + hrc = NS_GetComponentManager(&pManager); + if (FAILED(hrc)) + { + Log(("Cbinding: Could not get component manager! hrc=%Rhrc\n", hrc)); + VBoxComUninitialize(); + return; + } + + hrc = pManager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID, + nsnull, + virtualBoxIID, + (void **)&g_VirtualBox); +#else /* !VBOX_WITH_XPCOM */ + IVirtualBoxClient *pVirtualBoxClient; + hrc = CoCreateInstance(CLSID_VirtualBoxClient, NULL, CLSCTX_INPROC_SERVER, IID_IVirtualBoxClient, (void **)&pVirtualBoxClient); + if (SUCCEEDED(hrc)) + { + IVirtualBox *pVirtualBox; + hrc = pVirtualBoxClient->get_VirtualBox(&pVirtualBox); + if (SUCCEEDED(hrc)) + { + hrc = pVirtualBox->QueryInterface(virtualBoxIID, (void **)&g_VirtualBox); + pVirtualBox->Release(); + } + pVirtualBoxClient->Release(); + } +#endif /* !VBOX_WITH_XPCOM */ + if (FAILED(hrc)) + { + Log(("Cbinding: Could not instantiate VirtualBox object! hrc=%Rhrc\n",hrc)); +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + VBoxComUninitialize(); + return; + } + + Log(("Cbinding: IVirtualBox object created.\n")); + +#ifdef VBOX_WITH_XPCOM + hrc = pManager->CreateInstanceByContractID(NS_SESSION_CONTRACTID, nsnull, sessionIID, (void **)&g_Session); +#else /* !VBOX_WITH_XPCOM */ + hrc = CoCreateInstance(CLSID_Session, NULL, CLSCTX_INPROC_SERVER, sessionIID, (void **)&g_Session); +#endif /* !VBOX_WITH_XPCOM */ + if (FAILED(hrc)) + { + Log(("Cbinding: Could not instantiate Session object! hrc=%Rhrc\n",hrc)); +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + VBoxComUninitialize(); + return; + } + + Log(("Cbinding: ISession object created.\n")); + +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + + *ppSession = g_Session; + *ppVirtualBox = g_VirtualBox; +} + +static void +VBoxComInitializeV1(IVirtualBox **ppVirtualBox, ISession **ppSession) +{ + VBoxComInitialize(NULL, ppVirtualBox, NULL, ppSession); +} + +static void +VBoxComUninitialize(void) +{ + if (g_Session) + { + g_Session->Release(); + g_Session = NULL; + } + if (g_VirtualBox) + { + g_VirtualBox->Release(); + g_VirtualBox = NULL; + } +#ifdef VBOX_WITH_XPCOM + if (g_EventQueue) + { + g_EventQueue->Release(); + g_EventQueue = NULL; + } +#endif /* VBOX_WITH_XPCOM */ + com::Shutdown(); + Log(("Cbinding: Cleaned up the created objects.\n")); +} + +#ifdef VBOX_WITH_XPCOM +static void +VBoxGetEventQueue(nsIEventQueue **ppEventQueue) +{ + *ppEventQueue = g_EventQueue; +} +#endif /* VBOX_WITH_XPCOM */ + +static int +VBoxProcessEventQueue(LONG64 iTimeoutMS) +{ + RTMSINTERVAL iTimeout; + if (iTimeoutMS < 0 || iTimeoutMS > UINT32_MAX) + iTimeout = RT_INDEFINITE_WAIT; + else + iTimeout = (RTMSINTERVAL)iTimeoutMS; + int vrc = com::NativeEventQueue::getMainEventQueue()->processEventQueue(iTimeout); + switch (vrc) + { + case VINF_SUCCESS: + return 0; + case VINF_INTERRUPTED: + return 1; + case VERR_INTERRUPTED: + return 2; + case VERR_TIMEOUT: + return 3; + case VERR_INVALID_CONTEXT: + return 4; + default: + return 5; + } +} + +static int +VBoxInterruptEventQueueProcessing(void) +{ + com::NativeEventQueue::getMainEventQueue()->interruptEventQueueProcessing(); + return 0; +} + +static HRESULT +VBoxGetException(IErrorInfo **ppException) +{ + HRESULT hrc; + + *ppException = NULL; + +#ifdef VBOX_WITH_XPCOM + nsIServiceManager *mgr = NULL; + hrc = NS_GetServiceManager(&mgr); + if (FAILED(hrc) || !mgr) + return hrc; + + IID esid = NS_IEXCEPTIONSERVICE_IID; + nsIExceptionService *es = NULL; + hrc = mgr->GetServiceByContractID(NS_EXCEPTIONSERVICE_CONTRACTID, esid, (void **)&es); + if (FAILED(hrc) || !es) + { + mgr->Release(); + return hrc; + } + + nsIExceptionManager *em; + hrc = es->GetCurrentExceptionManager(&em); + if (FAILED(hrc) || !em) + { + es->Release(); + mgr->Release(); + return hrc; + } + + nsIException *ex; + hrc = em->GetCurrentException(&ex); + if (FAILED(hrc)) + { + em->Release(); + es->Release(); + mgr->Release(); + return hrc; + } + + *ppException = ex; + em->Release(); + es->Release(); + mgr->Release(); +#else /* !VBOX_WITH_XPCOM */ + IErrorInfo *ex; + hrc = ::GetErrorInfo(0, &ex); + if (FAILED(hrc)) + return hrc; + + *ppException = ex; +#endif /* !VBOX_WITH_XPCOM */ + + return hrc; +} + +static HRESULT +VBoxClearException(void) +{ + HRESULT hrc; + +#ifdef VBOX_WITH_XPCOM + nsIServiceManager *mgr = NULL; + hrc = NS_GetServiceManager(&mgr); + if (FAILED(hrc) || !mgr) + return hrc; + + IID esid = NS_IEXCEPTIONSERVICE_IID; + nsIExceptionService *es = NULL; + hrc = mgr->GetServiceByContractID(NS_EXCEPTIONSERVICE_CONTRACTID, esid, (void **)&es); + if (FAILED(hrc) || !es) + { + mgr->Release(); + return hrc; + } + + nsIExceptionManager *em; + hrc = es->GetCurrentExceptionManager(&em); + if (FAILED(hrc) || !em) + { + es->Release(); + mgr->Release(); + return hrc; + } + + hrc = em->SetCurrentException(NULL); + em->Release(); + es->Release(); + mgr->Release(); +#else /* !VBOX_WITH_XPCOM */ + hrc = ::SetErrorInfo(0, NULL); +#endif /* !VBOX_WITH_XPCOM */ + + return hrc; +} + +static HRESULT +VBoxClientInitialize(const char *pszVirtualBoxClientIID, IVirtualBoxClient **ppVirtualBoxClient) +{ + IID virtualBoxClientIID; + + *ppVirtualBoxClient = NULL; + + /* convert the string representation of UUID to IID type */ + if (pszVirtualBoxClientIID && *pszVirtualBoxClientIID) + { + int vrc = ::RTUuidFromStr((RTUUID *)&virtualBoxClientIID, pszVirtualBoxClientIID); + if (RT_FAILURE(vrc)) + return E_INVALIDARG; + } + else + virtualBoxClientIID = IID_IVirtualBoxClient; + + HRESULT hrc = com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING); + if (FAILED(hrc)) + { + Log(("Cbinding: COM/XPCOM could not be initialized! hrc=%Rhrc\n", hrc)); + VBoxClientUninitialize(); + return hrc; + } + +#ifdef VBOX_WITH_XPCOM + hrc = NS_GetMainEventQ(&g_EventQueue); + if (NS_FAILED(hrc)) + { + Log(("Cbinding: Could not get XPCOM event queue! hrc=%Rhrc\n", hrc)); + VBoxClientUninitialize(); + return hrc; + } +#endif /* VBOX_WITH_XPCOM */ + +#ifdef VBOX_WITH_XPCOM + nsIComponentManager *pManager; + hrc = NS_GetComponentManager(&pManager); + if (FAILED(hrc)) + { + Log(("Cbinding: Could not get component manager! hrc=%Rhrc\n", hrc)); + VBoxClientUninitialize(); + return hrc; + } + + hrc = pManager->CreateInstanceByContractID(NS_VIRTUALBOXCLIENT_CONTRACTID, + nsnull, + virtualBoxClientIID, + (void **)ppVirtualBoxClient); +#else /* !VBOX_WITH_XPCOM */ + hrc = CoCreateInstance(CLSID_VirtualBoxClient, NULL, CLSCTX_INPROC_SERVER, virtualBoxClientIID, (void **)ppVirtualBoxClient); +#endif /* !VBOX_WITH_XPCOM */ + if (FAILED(hrc)) + { + Log(("Cbinding: Could not instantiate VirtualBoxClient object! hrc=%Rhrc\n",hrc)); +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + VBoxClientUninitialize(); + return hrc; + } + +#ifdef VBOX_WITH_XPCOM + pManager->Release(); + pManager = NULL; +#endif /* VBOX_WITH_XPCOM */ + + Log(("Cbinding: IVirtualBoxClient object created.\n")); + + return S_OK; +} + +static HRESULT +VBoxClientThreadInitialize(void) +{ + return com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING); +} + +static HRESULT +VBoxClientThreadUninitialize(void) +{ + return com::Shutdown(); +} + +static void +VBoxClientUninitialize(void) +{ +#ifdef VBOX_WITH_XPCOM + if (g_EventQueue) + { + NS_RELEASE(g_EventQueue); + g_EventQueue = NULL; + } +#endif /* VBOX_WITH_XPCOM */ + com::Shutdown(); + Log(("Cbinding: Cleaned up the created objects.\n")); +} + +static unsigned int +VBoxVersion(void) +{ + return VBOX_VERSION_MAJOR * 1000 * 1000 + VBOX_VERSION_MINOR * 1000 + VBOX_VERSION_BUILD; +} + +static unsigned int +VBoxAPIVersion(void) +{ + return VBOX_VERSION_MAJOR * 1000 + VBOX_VERSION_MINOR + (VBOX_VERSION_BUILD > 50 ? 1 : 0); +} + +VBOXCAPI_DECL(PCVBOXCAPI) +VBoxGetCAPIFunctions(unsigned uVersion) +{ + /* This is the first piece of code which knows that IPRT exists, so + * initialize it properly. The limited initialization in VBoxC is not + * sufficient, and causes trouble with com::Initialize() misbehaving. */ + RTR3InitDll(0); + + /* + * The current interface version. + */ + static const VBOXCAPI s_Functions = + { + sizeof(VBOXCAPI), + VBOX_CAPI_VERSION, + + VBoxVersion, + VBoxAPIVersion, + + VBoxClientInitialize, + VBoxClientThreadInitialize, + VBoxClientThreadUninitialize, + VBoxClientUninitialize, + + VBoxComInitialize, + VBoxComUninitialize, + + VBoxComUnallocString, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + VBoxUtf8Free, + VBoxUtf16Free, + + VBoxSafeArrayCreateVector, + VBoxSafeArrayOutParamAlloc, + VBoxSafeArrayCopyInParamHelper, + VBoxSafeArrayCopyOutParamHelper, + VBoxSafeArrayCopyOutIfaceParamHelper, + VBoxSafeArrayDestroy, + VBoxArrayOutFree, + +#ifdef VBOX_WITH_XPCOM + VBoxGetEventQueue, +#endif /* VBOX_WITH_XPCOM */ + VBoxGetException, + VBoxClearException, + VBoxProcessEventQueue, + VBoxInterruptEventQueueProcessing, + + VBoxUtf8Clear, + VBoxUtf16Clear, + + VBOX_CAPI_VERSION + }; + + if ((uVersion & 0xffff0000U) == (VBOX_CAPI_VERSION & 0xffff0000U)) + return &s_Functions; + + /* + * Legacy interface version 3.0. + */ + static const struct VBOXCAPIV3 + { + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + unsigned int (*pfnGetVersion)(void); + + unsigned int (*pfnGetAPIVersion)(void); + + HRESULT (*pfnClientInitialize)(const char *pszVirtualBoxClientIID, + IVirtualBoxClient **ppVirtualBoxClient); + void (*pfnClientUninitialize)(void); + + void (*pfnComInitialize)(const char *pszVirtualBoxIID, + IVirtualBox **ppVirtualBox, + const char *pszSessionIID, + ISession **ppSession); + + void (*pfnComUninitialize)(void); + + void (*pfnComUnallocMem)(void *pv); + + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + void (*pfnUtf8Free)(char *pszString); + void (*pfnUtf16Free)(BSTR pwszString); + +#ifdef VBOX_WITH_XPCOM + void (*pfnGetEventQueue)(nsIEventQueue **ppEventQueue); +#endif /* VBOX_WITH_XPCOM */ + HRESULT (*pfnGetException)(IErrorInfo **ppException); + HRESULT (*pfnClearException)(void); + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; + } s_Functions_v3_0 = + { + sizeof(s_Functions_v3_0), + 0x00030000U, + + VBoxVersion, + VBoxAPIVersion, + + VBoxClientInitialize, + VBoxClientUninitialize, + + VBoxComInitialize, + VBoxComUninitialize, + + VBoxComUnallocMem, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + VBoxUtf8Free, + VBoxUtf16Free, + +#ifdef VBOX_WITH_XPCOM + VBoxGetEventQueue, +#endif /* VBOX_WITH_XPCOM */ + VBoxGetException, + VBoxClearException, + + 0x00030000U + }; + + if ((uVersion & 0xffff0000U) == 0x00030000U) + return (PCVBOXCAPI)&s_Functions_v3_0; + + /* + * Legacy interface version 2.0. + */ + static const struct VBOXCAPIV2 + { + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + unsigned int (*pfnGetVersion)(void); + + void (*pfnComInitialize)(const char *pszVirtualBoxIID, + IVirtualBox **ppVirtualBox, + const char *pszSessionIID, + ISession **ppSession); + + void (*pfnComUninitialize)(void); + + void (*pfnComUnallocMem)(void *pv); + void (*pfnUtf16Free)(BSTR pwszString); + void (*pfnUtf8Free)(char *pszString); + + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + +#ifdef VBOX_WITH_XPCOM + void (*pfnGetEventQueue)(nsIEventQueue **ppEventQueue); +#endif /* VBOX_WITH_XPCOM */ + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; + } s_Functions_v2_0 = + { + sizeof(s_Functions_v2_0), + 0x00020000U, + + VBoxVersion, + + VBoxComInitialize, + VBoxComUninitialize, + + VBoxComUnallocMem, + VBoxUtf16Free, + VBoxUtf8Free, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + +#ifdef VBOX_WITH_XPCOM + VBoxGetEventQueue, +#endif /* VBOX_WITH_XPCOM */ + + 0x00020000U + }; + + if ((uVersion & 0xffff0000U) == 0x00020000U) + return (PCVBOXCAPI)&s_Functions_v2_0; + + /* + * Legacy interface version 1.0. + */ + static const struct VBOXCAPIV1 + { + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + unsigned int (*pfnGetVersion)(void); + + void (*pfnComInitialize)(IVirtualBox **virtualBox, ISession **session); + void (*pfnComUninitialize)(void); + + void (*pfnComUnallocMem)(void *pv); + void (*pfnUtf16Free)(BSTR pwszString); + void (*pfnUtf8Free)(char *pszString); + + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + + /** Tail version, same as uVersion. */ + unsigned uEndVersion; + } s_Functions_v1_0 = + { + sizeof(s_Functions_v1_0), + 0x00010000U, + + VBoxVersion, + + VBoxComInitializeV1, + VBoxComUninitialize, + + VBoxComUnallocMem, + VBoxUtf16Free, + VBoxUtf8Free, + + VBoxUtf16ToUtf8, + VBoxUtf8ToUtf16, + + 0x00010000U + }; + + if ((uVersion & 0xffff0000U) == 0x00010000U) + return (PCVBOXCAPI)&s_Functions_v1_0; + + /* + * Unsupported interface version. + */ + return NULL; +} + +#ifdef VBOX_WITH_XPCOM +VBOXCAPI_DECL(PCVBOXCAPI) +VBoxGetXPCOMCFunctions(unsigned uVersion) +{ + return VBoxGetCAPIFunctions(uVersion); +} +#endif /* VBOX_WITH_XPCOM */ +/* vim: set ts=4 sw=4 et: */ diff --git a/src/VBox/Main/cbinding/VBoxCAPI.rc b/src/VBox/Main/cbinding/VBoxCAPI.rc new file mode 100644 index 00000000..59fe2115 --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPI.rc @@ -0,0 +1,61 @@ +/* $Id: VBoxCAPI.rc $ */ +/** @file + * VBoxCAPI - Resource file containing version info. + */ + +/* + * Copyright (C) 2015-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include <windows.h> +#include <VBox/version.h> + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_RC_FILE_VERSION + PRODUCTVERSION VBOX_RC_FILE_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS VBOX_RC_FILE_FLAGS + FILEOS VBOX_RC_FILE_OS + FILETYPE VBOX_RC_TYPE_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "FileDescription", "VirtualBox C Bindings\0" + VALUE "InternalName", "VBoxCAPI\0" + VALUE "OriginalFilename", "VBoxCAPI.dll\0" + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR + VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR + VBOX_RC_MORE_STRINGS + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/VBox/Main/cbinding/VBoxCAPIGlue.c b/src/VBox/Main/cbinding/VBoxCAPIGlue.c new file mode 100644 index 00000000..476bfddf --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPIGlue.c @@ -0,0 +1,345 @@ +/* $Id: VBoxCAPIGlue.c $ */ +/** @file + * Glue code for dynamically linking to VBoxCAPI. + */ + +/* + * Copyright (C) 2008-2023 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +/* NOTE: do NOT use any include files here which are only available in the + * VirtualBox tree, e.g. iprt. They are not available in the SDK, which is + * where this file will provided as source code and has to be compilable. */ +#include "VBoxCAPIGlue.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#ifdef WIN32 +# define _INTPTR 2 /* on Windows stdint.h compares this in #if, causing warnings if not defined */ +#endif /* WIN32 */ +#include <stdint.h> +#ifndef WIN32 +# include <dlfcn.h> +# include <pthread.h> +#else /* WIN32 */ +# include <Windows.h> +#endif /* WIN32 */ + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if defined(__linux__) || defined(__linux_gnu__) || defined(__sun__) || defined(__FreeBSD__) +# define DYNLIB_NAME "VBoxXPCOMC.so" +#elif defined(__APPLE__) +# define DYNLIB_NAME "VBoxXPCOMC.dylib" +#elif defined(__OS2__) +# define DYNLIB_NAME "VBoxXPCOMC.dll" +#elif defined(WIN32) +# define DYNLIB_NAME "VBoxCAPI.dll" +#else +# error "Port me" +#endif + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** The so/dynsym/dll handle for VBoxCAPI. */ +#ifndef WIN32 +void *g_hVBoxCAPI = NULL; +#else /* WIN32 */ +HMODULE g_hVBoxCAPI = NULL; +#endif /* WIN32 */ +/** The last load error. */ +char g_szVBoxErrMsg[256] = ""; +/** Pointer to the VBOXCAPI function table. */ +PCVBOXCAPI g_pVBoxFuncs = NULL; +/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */ +PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions = NULL; + +typedef void FNDUMMY(void); +typedef FNDUMMY *PFNDUMMY; +/** Just a dummy global structure containing a bunch of + * function pointers to code which is wanted in the link. */ +PFNDUMMY g_apfnVBoxCAPIGlue[] = +{ +#ifndef WIN32 + /* The following link dependency is for helping gdb as it gets hideously + * confused if the application doesn't drag in pthreads, but uses it. */ + (PFNDUMMY)pthread_create, +#endif /* !WIN32 */ + NULL +}; + + +/** + * Wrapper for setting g_szVBoxErrMsg. Can be an empty stub. + * + * @param fAlways When 0 the g_szVBoxErrMsg is only set if empty. + * @param pszFormat The format string. + * @param ... The arguments. + */ +static void setErrMsg(int fAlways, const char *pszFormat, ...) +{ + if ( fAlways + || !g_szVBoxErrMsg[0]) + { + va_list va; + va_start(va, pszFormat); + vsnprintf(g_szVBoxErrMsg, sizeof(g_szVBoxErrMsg), pszFormat, va); + va_end(va); + } +} + + +/** + * Try load C API .so/dylib/dll from the specified location and resolve all + * the symbols we need. Tries both the new style and legacy name. + * + * @returns 0 on success, -1 on failure. + * @param pszHome The directory where to try load VBoxCAPI/VBoxXPCOMC + * from. Can be NULL. + * @param fSetAppHome Whether to set the VBOX_APP_HOME env.var. or not + * (boolean). + */ +static int tryLoadLibrary(const char *pszHome, int fSetAppHome) +{ + size_t cchHome = pszHome ? strlen(pszHome) : 0; + size_t cbBufNeeded; + char szName[4096]; + + /* + * Construct the full name. + */ + cbBufNeeded = cchHome + sizeof("/" DYNLIB_NAME); + if (cbBufNeeded > sizeof(szName)) + { + setErrMsg(1, "path buffer too small: %u bytes needed", + (unsigned)cbBufNeeded); + return -1; + } + if (cchHome) + { + memcpy(szName, pszHome, cchHome); + szName[cchHome] = '/'; + cchHome++; + } + memcpy(&szName[cchHome], DYNLIB_NAME, sizeof(DYNLIB_NAME)); + + /* + * Try load it by that name, setting the VBOX_APP_HOME first (for now). + * Then resolve and call the function table getter. + */ + if (fSetAppHome) + { +#ifndef WIN32 + if (pszHome) + setenv("VBOX_APP_HOME", pszHome, 1 /* always override */); + else + unsetenv("VBOX_APP_HOME"); +#endif /* !WIN32 */ + } + +#ifndef WIN32 + g_hVBoxCAPI = dlopen(szName, RTLD_NOW | RTLD_LOCAL); +#else /* WIN32 */ + g_hVBoxCAPI = LoadLibraryExA(szName, NULL /* hFile */, 0 /* dwFlags */); +#endif /* WIN32 */ + if (g_hVBoxCAPI) + { + PFNVBOXGETCAPIFUNCTIONS pfnGetFunctions; +#ifndef WIN32 + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t) + dlsym(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME); +# ifdef VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME + if (!pfnGetFunctions) + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t) + dlsym(g_hVBoxCAPI, VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME); +# endif /* VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME */ +#else /* WIN32 */ + pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS) + GetProcAddress(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME); +#endif /* WIN32 */ + if (pfnGetFunctions) + { + g_pVBoxFuncs = pfnGetFunctions(VBOX_CAPI_VERSION); + if (g_pVBoxFuncs) + { + if ( ( VBOX_CAPI_MAJOR(g_pVBoxFuncs->uVersion) + == VBOX_CAPI_MAJOR(VBOX_CAPI_VERSION)) + && ( VBOX_CAPI_MINOR(g_pVBoxFuncs->uVersion) + >= VBOX_CAPI_MINOR(VBOX_CAPI_VERSION))) + { + g_pfnGetFunctions = pfnGetFunctions; + return 0; + } + setErrMsg(1, "%.80s: pfnGetFunctions(%#x) returned incompatible version %#x", + szName, VBOX_CAPI_VERSION, g_pVBoxFuncs->uVersion); + g_pVBoxFuncs = NULL; + } + else + { + /* bail out */ + setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed", + szName, VBOX_CAPI_VERSION); + } + } + else + { +#ifndef WIN32 + setErrMsg(1, "dlsym(%.80s/%.32s): %.128s", + szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, dlerror()); +#else /* WIN32 */ + setErrMsg(1, "GetProcAddress(%.80s/%.32s): %d", + szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, GetLastError()); +#endif /* WIN32 */ + } + +#ifndef WIN32 + dlclose(g_hVBoxCAPI); +#else /* WIN32 */ + FreeLibrary(g_hVBoxCAPI); +#endif /* WIN32 */ + g_hVBoxCAPI = NULL; + } + else + { +#ifndef WIN32 + setErrMsg(0, "dlopen(%.80s): %.160s", szName, dlerror()); +#else /* WIN32 */ + setErrMsg(0, "LoadLibraryEx(%.80s): %d", szName, GetLastError()); +#endif /* WIN32 */ + } + + return -1; +} + + +/** + * Tries to locate and load VBoxCAPI.so/dylib/dll, resolving all the related + * function pointers. + * + * @returns 0 on success, -1 on failure. + * + * @remark This should be considered moved into a separate glue library since + * its its going to be pretty much the same for any user of VBoxCAPI + * and it will just cause trouble to have duplicate versions of this + * source code all around the place. + */ +int VBoxCGlueInit(void) +{ + const char *pszHome; + + memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg)); + + /* + * If the user specifies the location, try only that. + */ + pszHome = getenv("VBOX_APP_HOME"); + if (pszHome) + return tryLoadLibrary(pszHome, 0); + + /* + * Try the known standard locations. + */ +#if defined(__gnu__linux__) || defined(__linux__) + if (tryLoadLibrary("/opt/VirtualBox", 1) == 0) + return 0; + if (tryLoadLibrary("/usr/lib/virtualbox", 1) == 0) + return 0; +#elif defined(__sun__) + if (tryLoadLibrary("/opt/VirtualBox/amd64", 1) == 0) + return 0; + if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0) + return 0; +#elif defined(__APPLE__) + if (tryLoadLibrary("/Applications/VirtualBox.app/Contents/MacOS", 1) == 0) + return 0; +#elif defined(__FreeBSD__) + if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0) + return 0; +#elif defined(__OS2__) + if (tryLoadLibrary("C:/Apps/VirtualBox", 1) == 0) + return 0; +#elif defined(WIN32) + pszHome = getenv("ProgramFiles"); + if (pszHome) + { + char szPath[4096]; + size_t cb = sizeof(szPath); + char *tmp = szPath; + strncpy(tmp, pszHome, cb); + tmp[cb - 1] = '\0'; + cb -= strlen(tmp); + tmp += strlen(tmp); + strncpy(tmp, "/Oracle/VirtualBox", cb); + tmp[cb - 1] = '\0'; + if (tryLoadLibrary(szPath, 1) == 0) + return 0; + } + if (tryLoadLibrary("C:/Program Files/Oracle/VirtualBox", 1) == 0) + return 0; +#else +# error "port me" +#endif + + /* + * Finally try the dynamic linker search path. + */ + if (tryLoadLibrary(NULL, 1) == 0) + return 0; + + /* No luck, return failure. */ + return -1; +} + + +/** + * Terminate the C glue library. + */ +void VBoxCGlueTerm(void) +{ + if (g_hVBoxCAPI) + { +#if 0 /* VBoxRT.so doesn't like being reloaded. See @bugref{3725}. */ +#ifndef WIN32 + dlclose(g_hVBoxCAPI); +#else + FreeLibrary(g_hVBoxCAPI); +#endif +#endif + g_hVBoxCAPI = NULL; + } + g_pVBoxFuncs = NULL; + g_pfnGetFunctions = NULL; + memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg)); +} + diff --git a/src/VBox/Main/cbinding/VBoxCAPIGlue.h.in b/src/VBox/Main/cbinding/VBoxCAPIGlue.h.in new file mode 100644 index 00000000..60ec8b6f --- /dev/null +++ b/src/VBox/Main/cbinding/VBoxCAPIGlue.h.in @@ -0,0 +1,68 @@ +/* $Id: VBoxCAPIGlue.h.in $ */ +/** @file VBoxCAPIGlue.h + * Glue for dynamically linking with VBoxCAPI. + */ + +/* + * Copyright (C) 2008-2023 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___VBoxCAPIGlue_h +#define ___VBoxCAPIGlue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#undef VBOX_WITH_GLUE +#define VBOX_WITH_GLUE +#include "VBoxCAPI_v@VBOX_API_VERSION@.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** The so/dynsym/dll handle for VBoxCAPI. */ +#ifndef WIN32 +extern void *g_hVBoxCAPI; +#else +extern HMODULE g_hVBoxCAPI; +#endif +/** The last load error. */ +extern char g_szVBoxErrMsg[256]; +/** Pointer to the VBOXCAPI function table. */ +extern PCVBOXCAPI g_pVBoxFuncs; +/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */ +extern PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions; + + +int VBoxCGlueInit(void); +void VBoxCGlueTerm(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* !___VBoxCAPIGlue_h */ + diff --git a/src/VBox/Main/cbinding/capiidl.xsl b/src/VBox/Main/cbinding/capiidl.xsl new file mode 100644 index 00000000..b9dabcfd --- /dev/null +++ b/src/VBox/Main/cbinding/capiidl.xsl @@ -0,0 +1,2736 @@ +<?xml version="1.0"?> +<!-- $Id: capiidl.xsl $ --> + +<!-- + * A template to generate a C header file for all relevant XPCOM interfaces + * provided or needed for calling the VirtualBox API. The header file also + * works on Windows, by using the C bindings header created by the MS COM IDL + * compiler (which simultaneously supports C and C++, unlike XPCOM). +--> +<!-- + Copyright (C) 2008-2023 Oracle and/or its affiliates. + + This file is part of VirtualBox base platform packages, as + available from https://www.virtualbox.org. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, in version 3 of the + License. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <https://www.gnu.org/licenses>. + + SPDX-License-Identifier: GPL-3.0-only +--> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="text"/> + +<xsl:strip-space elements="*"/> + + +<xsl:include href="../idl/typemap-shared.inc.xsl"/> + +<!-- +// Keys for more efficiently looking up of types. +///////////////////////////////////////////////////////////////////////////// +--> + +<xsl:key name="G_keyInterfacesByName" match="//interface[@name]" use="@name"/> + + +<!-- +// templates +///////////////////////////////////////////////////////////////////////////// +--> + + +<!-- + * not explicitly matched elements and attributes +--> +<xsl:template match="*"/> + + +<!-- + * header +--> +<xsl:template match="/idl"> + <xsl:text>/* + * DO NOT EDIT! This is a generated file. + * + * Header file which provides C declarations for VirtualBox Main API + * (COM interfaces), generated from XIDL (XML interface definition). + * On Windows (which uses COM instead of XPCOM) the native C support + * is used, and most of this file is not used. + * + * Source : src/VBox/Main/idl/VirtualBox.xidl + * Generator : src/VBox/Main/cbinding/capiidl.xsl + * + * This file contains portions from the following Mozilla XPCOM files: + * xpcom/include/xpcom/nsID.h + * xpcom/include/nsIException.h + * xpcom/include/nsprpub/prtypes.h + * xpcom/include/xpcom/nsISupportsBase.h + * + * These files were originally triple-licensed (MPL/GPL2/LGPL2.1). Oracle + * elects to distribute this derived work under the LGPL2.1 only. + */ + +/* + * Copyright (C) 2008-2023 Oracle and/or its affiliates. + * + * This file is part of a free software library; you can redistribute + * it and/or modify it under the terms of the GNU Lesser General + * Public License version 2.1 as published by the Free Software + * Foundation and shipped in the "COPYING.LIB" file with this library. + * The library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY of any kind. + * + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if + * any license choice other than GPL or LGPL is available it will + * apply instead, Oracle elects to use only the Lesser General Public + * License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the + * language indicating that LGPLv2 or any later version may be used, + * or where a choice of which version of the LGPL is applied is + * otherwise unspecified. + * + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#ifndef ___VirtualBox_CAPI_h +#define ___VirtualBox_CAPI_h + +#ifdef _WIN32 +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4668 4255) /* -Wall and windows.h */ +# if _MSC_VER >= 1800 /*RT_MSC_VER_VC120*/ +# pragma warning(disable:4005) /* sdk/v7.1/include/sal_supp.h(57) : warning C4005: '__useHeader' : macro redefinition */ +# endif +# ifdef __cplusplus +# if _MSC_VER >= 1900 /*RT_MSC_VER_VC140*/ +# pragma warning(disable:5039) /* winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. */ +# endif +# endif +# endif +# undef COBJMACROS +# define COBJMACROS +# include "Windows.h" +# pragma warning(pop) +#endif /* _WIN32 */ + +#ifdef WIN32 +# ifdef IN_VBOXCAPI +# define VBOXCAPI_DECL(type) extern __declspec(dllexport) type +# else /* !IN_VBOXCAPI */ +# define VBOXCAPI_DECL(type) __declspec(dllimport) type +# endif /* !IN_VBOXCAPI */ +#endif /* WIN32 */ + +#ifdef __cplusplus +/* The C++ treatment in this file is not meant for SDK users, it only exists + * so that this file can be used to produce the VBoxCAPI shared library which + * has to use C++ as it does all the conversion magic. */ +# ifdef IN_VBOXCAPI +# include "VBox/com/VirtualBox.h" +# ifndef WIN32 +# include "nsIEventQueue.h" +# endif /* !WIN32 */ +# else /* !IN_VBOXCAPI */ +# error Do not include this header file from C++ code +# endif /* !IN_VBOXCAPI */ +#endif /* __cplusplus */ + +#ifdef __GNUC__ +# define VBOX_EXTERN_CONST(type, name) extern const type name __attribute__((nocommon)) +#else /* !__GNUC__ */ +# define VBOX_EXTERN_CONST(type, name) extern const type name +#endif /* !__GNUC__ */ + +/* Treat WIN32 completely separately, as on Windows VirtualBox uses COM, not + * XPCOM like on all other platforms. While the code below would also compile + * on Windows, we need to switch to the native C support provided by the header + * files produced by the COM IDL compiler. */ +#ifdef WIN32 +# include "ObjBase.h" +# include "oaidl.h" +# include "VirtualBox.h" + +#ifndef __cplusplus +/* Skip this in the C++ case as there's already a definition for CBSTR. */ +typedef const BSTR CBSTR; +#endif /* !__cplusplus */ + +#define VBOX_WINAPI WINAPI + +#define ComSafeArrayAsInParam(f) (f) +#define ComSafeArrayAsOutParam(f) (&(f)) +#define ComSafeArrayAsOutTypeParam(f,t) (&(f)) +#define ComSafeArrayAsOutIfaceParam(f,t) (&(f)) + +#else /* !WIN32 */ + +#include <stddef.h> +#include "wchar.h" + +#ifdef IN_VBOXCAPI +# define VBOXCAPI_DECL(type) PR_EXPORT(type) +#else /* !IN_VBOXCAPI */ +# define VBOXCAPI_DECL(type) PR_IMPORT(type) +#endif /* !IN_VBOXCAPI */ + +#ifndef __cplusplus + +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(WIN16) + +#define PR_CALLBACK_DECL __cdecl + +#if defined(_WINDLL) +#define PR_EXPORT(__type) extern __type _cdecl _export _loadds +#define PR_IMPORT(__type) extern __type _cdecl _export _loadds +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export _loadds +#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* this must be .EXE */ +#define PR_EXPORT(__type) extern __type _cdecl _export +#define PR_IMPORT(__type) extern __type _cdecl _export +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export +#define PR_IMPLEMENT(__type) __type _cdecl _export +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK +#endif /* _WINDLL */ + +#elif defined(XP_MAC) + +#define PR_EXPORT(__type) extern __declspec(export) __type +#define PR_EXPORT_DATA(__type) extern __declspec(export) __type +#define PR_IMPORT(__type) extern __declspec(export) __type +#define PR_IMPORT_DATA(__type) extern __declspec(export) __type + +#define PR_EXTERN(__type) extern __declspec(export) __type +#define PR_IMPLEMENT(__type) __declspec(export) __type +#define PR_EXTERN_DATA(__type) extern __declspec(export) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2) && defined(__declspec) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2_VACPP) + +#define PR_EXPORT(__type) extern __type +#define PR_EXPORT_DATA(__type) extern __type +#define PR_IMPORT(__type) extern __type +#define PR_IMPORT_DATA(__type) extern __type + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type +#define PR_CALLBACK _Optlink +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* Unix */ + +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define PR_EXPORT(__type) __attribute__((visibility("default"))) extern __type +# define PR_EXPORT_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT(__type) __attribute__((visibility("default"))) __type +# define PR_EXTERN_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT_DATA(__type) __attribute__((visibility("default"))) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# else +# define PR_EXPORT(__type) extern __type +# define PR_EXPORT_DATA(__type) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) extern __type +# define PR_IMPLEMENT(__type) __type +# define PR_EXTERN_DATA(__type) extern __type +# define PR_IMPLEMENT_DATA(__type) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# endif +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +typedef unsigned char PRUint8; +#if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +#else +typedef signed char PRInt8; +#endif + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +typedef unsigned short PRUint16; +typedef short PRInt16; + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +typedef long PRInt64; +typedef unsigned long PRUint64; +typedef int PRIntn; +typedef unsigned int PRUintn; + +typedef double PRFloat64; +typedef size_t PRSize; + +typedef ptrdiff_t PRPtrdiff; + +typedef unsigned long PRUptrdiff; + +typedef PRIntn PRBool; + +#define PR_TRUE 1 +#define PR_FALSE 0 + +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +typedef PRUnichar *BSTR; +typedef const PRUnichar *CBSTR; +#endif + +typedef long PRWord; +typedef unsigned long PRUword; + +#define nsnull 0 +typedef PRUint32 nsresult; + +#if defined(__GNUC__) && (__GNUC__ > 2) +#define NS_LIKELY(x) (__builtin_expect((x), 1)) +#define NS_UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define NS_LIKELY(x) (x) +#define NS_UNLIKELY(x) (x) +#endif + +#define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +#define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000))) + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_IntervalNow VBoxNsprPR_IntervalNow +# define PR_TicksPerSecond VBoxNsprPR_TicksPerSecond +# define PR_SecondsToInterval VBoxNsprPR_SecondsToInterval +# define PR_MillisecondsToInterval VBoxNsprPR_MillisecondsToInterval +# define PR_MicrosecondsToInterval VBoxNsprPR_MicrosecondsToInterval +# define PR_IntervalToSeconds VBoxNsprPR_IntervalToSeconds +# define PR_IntervalToMilliseconds VBoxNsprPR_IntervalToMilliseconds +# define PR_IntervalToMicroseconds VBoxNsprPR_IntervalToMicroseconds +# define PR_EnterMonitor VBoxNsprPR_EnterMonitor +# define PR_ExitMonitor VBoxNsprPR_ExitMonitor +# define PR_Notify VBoxNsprPR_Notify +# define PR_NotifyAll VBoxNsprPR_NotifyAll +# define PR_Wait VBoxNsprPR_Wait +# define PR_NewMonitor VBoxNsprPR_NewMonitor +# define PR_DestroyMonitor VBoxNsprPR_DestroyMonitor +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef PRUint32 PRIntervalTime; + +#define PR_INTERVAL_MIN 1000UL +#define PR_INTERVAL_MAX 100000UL +#define PR_INTERVAL_NO_WAIT 0UL +#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL + +NSPR_API(PRIntervalTime) PR_IntervalNow(void); +NSPR_API(PRUint32) PR_TicksPerSecond(void); +NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); +NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); +NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); +NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); + +typedef struct PRMonitor PRMonitor; + +NSPR_API(PRMonitor*) PR_NewMonitor(void); +NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); +NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); +NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); +NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); +NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); +NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_CreateThread VBoxNsprPR_CreateThread +# define PR_JoinThread VBoxNsprPR_JoinThread +# define PR_Sleep VBoxNsprPR_Sleep +# define PR_GetCurrentThread VBoxNsprPR_GetCurrentThread +# define PR_GetThreadState VBoxNsprPR_GetThreadState +# define PR_SetThreadPrivate VBoxNsprPR_SetThreadPrivate +# define PR_GetThreadPrivate VBoxNsprPR_GetThreadPrivate +# define PR_NewThreadPrivateIndex VBoxNsprPR_NewThreadPrivateIndex +# define PR_GetThreadPriority VBoxNsprPR_GetThreadPriority +# define PR_SetThreadPriority VBoxNsprPR_SetThreadPriority +# define PR_Interrupt VBoxNsprPR_Interrupt +# define PR_ClearInterrupt VBoxNsprPR_ClearInterrupt +# define PR_BlockInterrupt VBoxNsprPR_BlockInterrupt +# define PR_UnblockInterrupt VBoxNsprPR_UnblockInterrupt +# define PR_GetThreadScope VBoxNsprPR_GetThreadScope +# define PR_GetThreadType VBoxNsprPR_GetThreadType +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRThread PRThread; +typedef struct PRThreadStack PRThreadStack; + +typedef enum PRThreadType { + PR_USER_THREAD, + PR_SYSTEM_THREAD +} PRThreadType; + +typedef enum PRThreadScope { + PR_LOCAL_THREAD, + PR_GLOBAL_THREAD, + PR_GLOBAL_BOUND_THREAD +} PRThreadScope; + +typedef enum PRThreadState { + PR_JOINABLE_THREAD, + PR_UNJOINABLE_THREAD +} PRThreadState; + +typedef enum PRThreadPriority +{ + PR_PRIORITY_FIRST = 0, /* just a placeholder */ + PR_PRIORITY_LOW = 0, /* the lowest possible priority */ + PR_PRIORITY_NORMAL = 1, /* most common expected priority */ + PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ + PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ + PR_PRIORITY_LAST = 3 /* this is just a placeholder */ +} PRThreadPriority; + +NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, + void (PR_CALLBACK *start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); +NSPR_API(PRThread*) PR_GetCurrentThread(void); +#ifndef NO_NSPR_10_SUPPORT +#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ +#endif /* NO_NSPR_10_SUPPORT */ +NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); +NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); + +typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); + +NSPR_API(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR destructor); +NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); +NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); +NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); +NSPR_API(void) PR_ClearInterrupt(void); +NSPR_API(void) PR_BlockInterrupt(void); +NSPR_API(void) PR_UnblockInterrupt(void); +NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); +NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); +NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); +NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_DestroyLock VBoxNsprPR_DestroyLock +# define PR_Lock VBoxNsprPR_Lock +# define PR_NewLock VBoxNsprPR_NewLock +# define PR_Unlock VBoxNsprPR_Unlock +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRLock PRLock; + +NSPR_API(PRLock*) PR_NewLock(void); +NSPR_API(void) PR_DestroyLock(PRLock *lock); +NSPR_API(void) PR_Lock(PRLock *lock); +NSPR_API(PRStatus) PR_Unlock(PRLock *lock); + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PR_NewCondVar VBoxNsprPR_NewCondVar +# define PR_DestroyCondVar VBoxNsprPR_DestroyCondVar +# define PR_WaitCondVar VBoxNsprPR_WaitCondVar +# define PR_NotifyCondVar VBoxNsprPR_NotifyCondVar +# define PR_NotifyAllCondVar VBoxNsprPR_NotifyAllCondVar +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PRCondVar PRCondVar; + +NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); +NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); +NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); +NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); +NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); + +typedef struct PRCListStr PRCList; + +struct PRCListStr { + PRCList *next; + PRCList *prev; +}; + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +# define PL_DestroyEvent VBoxNsplPL_DestroyEvent +# define PL_HandleEvent VBoxNsplPL_HandleEvent +# define PL_InitEvent VBoxNsplPL_InitEvent +# define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue +# define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue +# define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue +# define PL_DequeueEvent VBoxNsplPL_DequeueEvent +# define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue +# define PL_EventAvailable VBoxNsplPL_EventAvailable +# define PL_EventLoop VBoxNsplPL_EventLoop +# define PL_GetEvent VBoxNsplPL_GetEvent +# define PL_GetEventOwner VBoxNsplPL_GetEventOwner +# define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor +# define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD +# define PL_MapEvents VBoxNsplPL_MapEvents +# define PL_PostEvent VBoxNsplPL_PostEvent +# define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent +# define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID +# define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents +# define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc +# define PL_RevokeEvents VBoxNsplPL_RevokeEvents +# define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc +# define PL_WaitForEvent VBoxNsplPL_WaitForEvent +# define PL_IsQueueNative VBoxNsplPL_IsQueueNative +# define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread +# define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +typedef struct PLEvent PLEvent; +typedef struct PLEventQueue PLEventQueue; + +PR_EXTERN(PLEventQueue*) +PL_CreateEventQueue(const char* name, PRThread* handlerThread); +PR_EXTERN(PLEventQueue *) + PL_CreateNativeEventQueue( + const char *name, + PRThread *handlerThread + ); +PR_EXTERN(PLEventQueue *) + PL_CreateMonitoredEventQueue( + const char *name, + PRThread *handlerThread + ); +PR_EXTERN(void) +PL_DestroyEventQueue(PLEventQueue* self); +PR_EXTERN(PRMonitor*) +PL_GetEventQueueMonitor(PLEventQueue* self); + +#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \ + PR_EnterMonitor(PL_GetEventQueueMonitor(queue)) + +#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \ + PR_ExitMonitor(PL_GetEventQueueMonitor(queue)) + +PR_EXTERN(PRStatus) PL_PostEvent(PLEventQueue* self, PLEvent* event); +PR_EXTERN(void*) PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event); +PR_EXTERN(PLEvent*) PL_GetEvent(PLEventQueue* self); +PR_EXTERN(PRBool) PL_EventAvailable(PLEventQueue* self); + +typedef void (PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue); + +PR_EXTERN(void) PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data); +PR_EXTERN(void) PL_RevokeEvents(PLEventQueue* self, void* owner); +PR_EXTERN(void) PL_ProcessPendingEvents(PLEventQueue* self); +PR_EXTERN(PLEvent*) PL_WaitForEvent(PLEventQueue* self); +PR_EXTERN(void) PL_EventLoop(PLEventQueue* self); +PR_EXTERN(PRInt32) PL_GetEventQueueSelectFD(PLEventQueue* self); +PR_EXTERN(PRBool) PL_IsQueueOnCurrentThread( PLEventQueue *queue ); +PR_EXTERN(PRBool) PL_IsQueueNative(PLEventQueue *queue); + +typedef void* (PR_CALLBACK *PLHandleEventProc)(PLEvent* self); +typedef void (PR_CALLBACK *PLDestroyEventProc)(PLEvent* self); +PR_EXTERN(void) +PL_InitEvent(PLEvent* self, void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor); +PR_EXTERN(void*) PL_GetEventOwner(PLEvent* self); +PR_EXTERN(void) PL_HandleEvent(PLEvent* self); +PR_EXTERN(void) PL_DestroyEvent(PLEvent* self); +PR_EXTERN(void) PL_DequeueEvent(PLEvent* self, PLEventQueue* queue); +PR_EXTERN(void) PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay); + +struct PLEvent { + PRCList link; + PLHandleEventProc handler; + PLDestroyEventProc destructor; + void* owner; + void* synchronousResult; + PRLock* lock; + PRCondVar* condVar; + PRBool handled; +#ifdef PL_POST_TIMINGS + PRIntervalTime postTime; +#endif +#ifdef XP_UNIX + unsigned long id; +#endif /* XP_UNIX */ + /* other fields follow... */ +}; + +#if defined(XP_WIN) || defined(XP_OS2) + +PR_EXTERN(HWND) + PL_GetNativeEventReceiverWindow( + PLEventQueue *eqp + ); +#endif /* XP_WIN || XP_OS2 */ + +#ifdef XP_UNIX + +PR_EXTERN(PRInt32) +PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID); + +typedef unsigned long (PR_CALLBACK *PLGetEventIDFunc)(void *aClosure); + +PR_EXTERN(void) +PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, + void *aClosure); +PR_EXTERN(void) PL_UnregisterEventIDFunc(PLEventQueue *aSelf); + +#endif /* XP_UNIX */ + +/* Standard "it worked" return value */ +#define NS_OK 0 + +#define NS_ERROR_BASE ((nsresult) 0xC1F30000) + +/* Returned when an instance is not initialized */ +#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) + +/* Returned when an instance is already initialized */ +#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2) + +/* Returned by a not implemented function */ +#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L) + +/* Returned when a given interface is not supported. */ +#define NS_NOINTERFACE ((nsresult) 0x80004002L) +#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE + +#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L) +#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER + +/* Returned when a function aborts */ +#define NS_ERROR_ABORT ((nsresult) 0x80004004L) + +/* Returned when a function fails */ +#define NS_ERROR_FAILURE ((nsresult) 0x80004005L) + +/* Returned when an unexpected error occurs */ +#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL) + +/* Returned when a memory allocation fails */ +#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL) + +/* Returned when an illegal value is passed */ +#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L) +#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE + +/* Returned when a class doesn't allow aggregation */ +#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L) + +/* Returned when an operation can't complete due to an unavailable resource */ +#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L) + +/* Returned when a class is not registered */ +#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L) + +/* Returned when a class cannot be registered, but may be tried again later */ +#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L) + +/* Returned when a dynamically loaded factory couldn't be found */ +#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L) + +/* Returned when a factory doesn't support signatures */ +#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \ + (NS_ERROR_BASE + 0x101) + +/* Returned when a factory already is registered */ +#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) + +/** + * An "interface id" which can be used to uniquely identify a given + * interface. + * A "unique identifier". This is modeled after OSF DCE UUIDs. + */ + +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +typedef nsID nsIID; +typedef nsID nsCID; + +#endif /* __cplusplus */ + +#define VBOX_WINAPI + +/* Various COM types defined by their XPCOM equivalent */ +typedef PRInt64 LONG64; +typedef PRInt32 LONG; +typedef PRInt32 DWORD; +typedef PRInt16 SHORT; +typedef PRUint64 ULONG64; +typedef PRUint32 ULONG; +typedef PRUint16 USHORT; + +typedef PRBool BOOL; + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#define HRESULT nsresult +#define SUCCEEDED NS_SUCCEEDED +#define FAILED NS_FAILED + +/* OLE error codes */ +#define S_OK ((nsresult)NS_OK) +#define E_UNEXPECTED NS_ERROR_UNEXPECTED +#define E_NOTIMPL NS_ERROR_NOT_IMPLEMENTED +#define E_OUTOFMEMORY NS_ERROR_OUT_OF_MEMORY +#define E_INVALIDARG NS_ERROR_INVALID_ARG +#define E_NOINTERFACE NS_ERROR_NO_INTERFACE +#define E_POINTER NS_ERROR_NULL_POINTER +#define E_ABORT NS_ERROR_ABORT +#define E_FAIL NS_ERROR_FAILURE +/* Note: a better analog for E_ACCESSDENIED would probably be + * NS_ERROR_NOT_AVAILABLE, but we want binary compatibility for now. */ +#define E_ACCESSDENIED ((nsresult)0x80070005L) + +/* Basic vartype for COM compatibility. */ +typedef enum VARTYPE +{ + VT_I2 = 2, + VT_I4 = 3, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_BOOL = 11, + VT_UNKNOWN = 13, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_HRESULT = 25 +} VARTYPE; + +/* Basic safearray type for COM compatibility. */ +typedef struct SAFEARRAY +{ + void *pv; + ULONG c; +} SAFEARRAY; + +#define ComSafeArrayAsInParam(f) ((f) ? (f)->c : 0), ((f) ? (f)->pv : NULL) +#define ComSafeArrayAsOutParam(f) (&((f)->c)), (&((f)->pv)) +#define ComSafeArrayAsOutTypeParam(f,t) (&((f)->c)), (t**)(&((f)->pv)) +#define ComSafeArrayAsOutIfaceParam(f,t) (&((f)->c)), (t**)(&((f)->pv)) + +/* Glossing over differences between COM and XPCOM */ +#define IErrorInfo nsIException +#define IUnknown nsISupports +#define IDispatch nsISupports + +/* Make things as COM compatible as possible */ +#define interface struct +#ifdef CONST_VTABLE +# define CONST_VTBL const +#else /* !CONST_VTABLE */ +# define CONST_VTBL +#endif /* !CONST_VTABLE */ + +#ifndef __cplusplus + +/** @todo this first batch of forward declarations (and the corresponding ones + * generated for each interface) are 100% redundant, remove eventually. */ +interface nsISupports; /* forward declaration */ +interface nsIException; /* forward declaration */ +interface nsIStackFrame; /* forward declaration */ +interface nsIEventTarget;/* forward declaration */ +interface nsIEventQueue; /* forward declaration */ + +typedef interface nsISupports nsISupports; /* forward declaration */ +typedef interface nsIException nsIException; /* forward declaration */ +typedef interface nsIStackFrame nsIStackFrame; /* forward declaration */ +typedef interface nsIEventTarget nsIEventTarget;/* forward declaration */ +typedef interface nsIEventQueue nsIEventQueue; /* forward declaration */ + +/* starting interface: nsISupports */ +#define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" + +#define NS_ISUPPORTS_IID \ + { 0x00000000, 0x0000, 0x0000, \ + {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} } + +/** + * Reference count values + * + * This is the return type for AddRef() and Release() in nsISupports. + * IUnknown of COM returns an unsigned long from equivalent functions. + * The following ifdef exists to maintain binary compatibility with + * IUnknown. + */ +#if defined(XP_WIN) && PR_BYTES_PER_LONG == 4 +typedef unsigned long nsrefcnt; +#else +typedef PRUint32 nsrefcnt; +#endif + +/** + * Basic component object model interface. Objects which implement + * this interface support runtime interface discovery (QueryInterface) + * and a reference counted memory model (AddRef/Release). This is + * modelled after the win32 IUnknown API. + */ +#ifndef VBOX_WITH_GLUE +struct nsISupports_vtbl +{ + nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsISupports *pThis); + nsrefcnt (*Release)(nsISupports *pThis); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsISupportsVtbl +{ + nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsISupports *pThis); + nsrefcnt (*Release)(nsISupports *pThis); +}; +#define nsISupports_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsISupports_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsISupports_Release(p) ((p)->lpVtbl->Release(p)) +#define IUnknown_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define IUnknown_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define IUnknown_Release(p) ((p)->lpVtbl->Release(p)) +#define IDispatch_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define IDispatch_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define IDispatch_Release(p) ((p)->lpVtbl->Release(p)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsISupports +{ +#ifndef VBOX_WITH_GLUE + struct nsISupports_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsISupportsVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIException */ +#define NS_IEXCEPTION_IID_STR "f3a8d3b4-c424-4edc-8bf6-8974c983ba78" + +#define NS_IEXCEPTION_IID \ + {0xf3a8d3b4, 0xc424, 0x4edc, \ + { 0x8b, 0xf6, 0x89, 0x74, 0xc9, 0x83, 0xba, 0x78 }} + +#ifndef VBOX_WITH_GLUE +struct nsIException_vtbl +{ + /* Methods from the interface nsISupports */ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetMessage)(nsIException *pThis, PRUnichar * *aMessage); + nsresult (*GetResult)(nsIException *pThis, nsresult *aResult); + nsresult (*GetName)(nsIException *pThis, PRUnichar * *aName); + nsresult (*GetFilename)(nsIException *pThis, PRUnichar * *aFilename); + nsresult (*GetLineNumber)(nsIException *pThis, PRUint32 *aLineNumber); + nsresult (*GetColumnNumber)(nsIException *pThis, PRUint32 *aColumnNumber); + nsresult (*GetLocation)(nsIException *pThis, nsIStackFrame * *aLocation); + nsresult (*GetInner)(nsIException *pThis, nsIException * *aInner); + nsresult (*GetData)(nsIException *pThis, nsISupports * *aData); + nsresult (*ToString)(nsIException *pThis, PRUnichar **_retval); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIExceptionVtbl +{ + nsresult (*QueryInterface)(nsIException *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIException *pThis); + nsrefcnt (*Release)(nsIException *pThis); + + nsresult (*GetMessage)(nsIException *pThis, PRUnichar * *aMessage); + nsresult (*GetResult)(nsIException *pThis, nsresult *aResult); + nsresult (*GetName)(nsIException *pThis, PRUnichar * *aName); + nsresult (*GetFilename)(nsIException *pThis, PRUnichar * *aFilename); + nsresult (*GetLineNumber)(nsIException *pThis, PRUint32 *aLineNumber); + nsresult (*GetColumnNumber)(nsIException *pThis, PRUint32 *aColumnNumber); + nsresult (*GetLocation)(nsIException *pThis, nsIStackFrame * *aLocation); + nsresult (*GetInner)(nsIException *pThis, nsIException * *aInner); + nsresult (*GetData)(nsIException *pThis, nsISupports * *aData); + nsresult (*ToString)(nsIException *pThis, PRUnichar **_retval); +}; +#define nsIException_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIException_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIException_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIException_get_Message(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define nsIException_GetMessage(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define nsIException_get_Result(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define nsIException_GetResult(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define nsIException_get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIException_GetName(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIException_get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIException_GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIException_get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIException_GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIException_get_ColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define nsIException_GetColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define nsIException_get_Inner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define nsIException_GetInner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define nsIException_get_Data(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define nsIException_GetData(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define nsIException_ToString(p, retval) ((p)->lpVtbl->ToString(p, retval)) +#define IErrorInfo_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define IErrorInfo_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define IErrorInfo_Release(p) ((p)->lpVtbl->Release(p)) +#define IErrorInfo_get_Message(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define IErrorInfo_GetMessage(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage)) +#define IErrorInfo_get_Result(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define IErrorInfo_GetResult(p, aResult) ((p)->lpVtbl->GetResult(p, aResult)) +#define IErrorInfo_get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define IErrorInfo_GetName(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define IErrorInfo_get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define IErrorInfo_GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define IErrorInfo_get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define IErrorInfo_GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define IErrorInfo_get_ColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define IErrorInfo_GetColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber)) +#define IErrorInfo_get_Inner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define IErrorInfo_GetInner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner)) +#define IErrorInfo_get_Data(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define IErrorInfo_GetData(p, aData) ((p)->lpVtbl->GetData(p, aData)) +#define IErrorInfo_ToString(p, retval) ((p)->lpVtbl->ToString(p, retval)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIException +{ +#ifndef VBOX_WITH_GLUE + struct nsIException_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIExceptionVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIStackFrame */ +#define NS_ISTACKFRAME_IID_STR "91d82105-7c62-4f8b-9779-154277c0ee90" + +#define NS_ISTACKFRAME_IID \ + {0x91d82105, 0x7c62, 0x4f8b, \ + { 0x97, 0x79, 0x15, 0x42, 0x77, 0xc0, 0xee, 0x90 }} + +#ifndef VBOX_WITH_GLUE +struct nsIStackFrame_vtbl +{ + /* Methods from the interface nsISupports */ + struct nsISupports_vtbl nsisupports; + + nsresult (*GetLanguage)(nsIStackFrame *pThis, PRUint32 *aLanguage); + nsresult (*GetLanguageName)(nsIStackFrame *pThis, PRUnichar * *aLanguageName); + nsresult (*GetFilename)(nsIStackFrame *pThis, PRUnichar * *aFilename); + nsresult (*GetName)(nsIStackFrame *pThis, PRUnichar * *aName); + nsresult (*GetLineNumber)(nsIStackFrame *pThis, PRInt32 *aLineNumber); + nsresult (*GetSourceLine)(nsIStackFrame *pThis, PRUnichar * *aSourceLine); + nsresult (*GetCaller)(nsIStackFrame *pThis, nsIStackFrame * *aCaller); + nsresult (*ToString)(nsIStackFrame *pThis, PRUnichar **_retval); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIStackFrameVtbl +{ + nsresult (*QueryInterface)(nsIStackFrame *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIStackFrame *pThis); + nsrefcnt (*Release)(nsIStackFrame *pThis); + + nsresult (*GetLanguage)(nsIStackFrame *pThis, PRUint32 *aLanguage); + nsresult (*GetLanguageName)(nsIStackFrame *pThis, PRUnichar * *aLanguageName); + nsresult (*GetFilename)(nsIStackFrame *pThis, PRUnichar * *aFilename); + nsresult (*GetName)(nsIStackFrame *pThis, PRUnichar * *aName); + nsresult (*GetLineNumber)(nsIStackFrame *pThis, PRInt32 *aLineNumber); + nsresult (*GetSourceLine)(nsIStackFrame *pThis, PRUnichar * *aSourceLine); + nsresult (*GetCaller)(nsIStackFrame *pThis, nsIStackFrame * *aCaller); + nsresult (*ToString)(nsIStackFrame *pThis, PRUnichar **_retval); +}; +#define nsIStackFrame_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIStackFrame_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIStackFrame_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIStackFrame_get_Language(p, aLanguage) ((p)->lpVtbl->GetLanguge(p, aLanguage)) +#define nsIStackFrame_GetLanguage(p, aLanguage) ((p)->lpVtbl->GetLanguge(p, aLanguage)) +#define nsIStackFrame_get_LanguageName(p, aLanguageName) ((p)->lpVtbl->GetLanguageName(p, aLanguageName)) +#define nsIStackFrame_GetLanguageName(p, aLanguageName) ((p)->lpVtbl->GetLanguageName(p, aLanguageName)) +#define nsIStackFrame_get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIStackFrame_GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename)) +#define nsIStackFrame_get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIStackFrame_GetName(p, aName) ((p)->lpVtbl->GetName(p, aName)) +#define nsIStackFrame_get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIStackFrame_GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber)) +#define nsIStackFrame_get_SourceLine(p, aSourceLine) ((p)->lpVtbl->GetSourceLine(p, aSourceLine)) +#define nsIStackFrame_GetSourceLine(p, aSourceLine) ((p)->lpVtbl->GetSourceLine(p, aSourceLine)) +#define nsIStackFrame_get_Caller(p, aCaller) ((p)->lpVtbl->GetCaller(p, aCaller)) +#define nsIStackFrame_GetCaller(p, aCaller) ((p)->lpVtbl->GetCaller(p, aCaller)) +#define nsIStackFrame_ToString(p, retval) ((p)->lpVtbl->ToString(p, retval)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIStackFrame +{ +#ifndef VBOX_WITH_GLUE + struct nsIStackFrame_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIStackFrameVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIEventTarget */ +#define NS_IEVENTTARGET_IID_STR "ea99ad5b-cc67-4efb-97c9-2ef620a59f2a" + +#define NS_IEVENTTARGET_IID \ + {0xea99ad5b, 0xcc67, 0x4efb, \ + { 0x97, 0xc9, 0x2e, 0xf6, 0x20, 0xa5, 0x9f, 0x2a }} + +#ifndef VBOX_WITH_GLUE +struct nsIEventTarget_vtbl +{ + struct nsISupports_vtbl nsisupports; + + nsresult (*PostEvent)(nsIEventTarget *pThis, PLEvent * aEvent); + nsresult (*IsOnCurrentThread)(nsIEventTarget *pThis, PRBool *_retval); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIEventTargetVtbl +{ + nsresult (*QueryInterface)(nsIEventTarget *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIEventTarget *pThis); + nsrefcnt (*Release)(nsIEventTarget *pThis); + + nsresult (*PostEvent)(nsIEventTarget *pThis, PLEvent * aEvent); + nsresult (*IsOnCurrentThread)(nsIEventTarget *pThis, PRBool *_retval); +}; +#define nsIEventTarget_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIEventTarget_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIEventTarget_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIEventTarget_PostEvent(p, aEvent) ((p)->lpVtbl->PostEvent(p, aEvent)) +#define nsIEventTarget_IsOnCurrentThread(p, retval) ((p)->lpVtbl->IsOnCurrentThread(p, retval)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIEventTarget +{ +#ifndef VBOX_WITH_GLUE + struct nsIEventTarget_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIEventTargetVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; + +/* starting interface: nsIEventQueue */ +#define NS_IEVENTQUEUE_IID_STR "176afb41-00a4-11d3-9f2a-00400553eef0" + +#define NS_IEVENTQUEUE_IID \ + {0x176afb41, 0x00a4, 0x11d3, \ + { 0x9f, 0x2a, 0x00, 0x40, 0x05, 0x53, 0xee, 0xf0 }} + +#ifndef VBOX_WITH_GLUE +struct nsIEventQueue_vtbl +{ + struct nsIEventTarget_vtbl nsieventtarget; + + nsresult (*InitEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * owner, PLHandleEventProc handler, PLDestroyEventProc destructor); + nsresult (*PostSynchronousEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * *aResult); + nsresult (*PendingEvents)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*ProcessPendingEvents)(nsIEventQueue *pThis); + nsresult (*EventLoop)(nsIEventQueue *pThis); + nsresult (*EventAvailable)(nsIEventQueue *pThis, PRBool *aResult); + nsresult (*GetEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + nsresult (*HandleEvent)(nsIEventQueue *pThis, PLEvent * aEvent); + nsresult (*WaitForEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + PRInt32 (*GetEventQueueSelectFD)(nsIEventQueue *pThis); + nsresult (*Init)(nsIEventQueue *pThis, PRBool aNative); + nsresult (*InitFromPRThread)(nsIEventQueue *pThis, PRThread * thread, PRBool aNative); + nsresult (*InitFromPLQueue)(nsIEventQueue *pThis, PLEventQueue * aQueue); + nsresult (*EnterMonitor)(nsIEventQueue *pThis); + nsresult (*ExitMonitor)(nsIEventQueue *pThis); + nsresult (*RevokeEvents)(nsIEventQueue *pThis, void * owner); + nsresult (*GetPLEventQueue)(nsIEventQueue *pThis, PLEventQueue * *_retval); + nsresult (*IsQueueNative)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*StopAcceptingEvents)(nsIEventQueue *pThis); +}; +#else /* !VBOX_WITH_GLUE */ +struct nsIEventQueueVtbl +{ + nsresult (*QueryInterface)(nsIEventQueue *pThis, const nsID *iid, void **resultp); + nsrefcnt (*AddRef)(nsIEventQueue *pThis); + nsrefcnt (*Release)(nsIEventQueue *pThis); + + nsresult (*PostEvent)(nsIEventQueue *pThis, PLEvent * aEvent); + nsresult (*IsOnCurrentThread)(nsIEventQueue *pThis, PRBool *_retval); + + nsresult (*InitEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * owner, PLHandleEventProc handler, PLDestroyEventProc destructor); + nsresult (*PostSynchronousEvent)(nsIEventQueue *pThis, PLEvent * aEvent, void * *aResult); + nsresult (*PendingEvents)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*ProcessPendingEvents)(nsIEventQueue *pThis); + nsresult (*EventLoop)(nsIEventQueue *pThis); + nsresult (*EventAvailable)(nsIEventQueue *pThis, PRBool *aResult); + nsresult (*GetEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + nsresult (*HandleEvent)(nsIEventQueue *pThis, PLEvent * aEvent); + nsresult (*WaitForEvent)(nsIEventQueue *pThis, PLEvent * *_retval); + PRInt32 (*GetEventQueueSelectFD)(nsIEventQueue *pThis); + nsresult (*Init)(nsIEventQueue *pThis, PRBool aNative); + nsresult (*InitFromPRThread)(nsIEventQueue *pThis, PRThread * thread, PRBool aNative); + nsresult (*InitFromPLQueue)(nsIEventQueue *pThis, PLEventQueue * aQueue); + nsresult (*EnterMonitor)(nsIEventQueue *pThis); + nsresult (*ExitMonitor)(nsIEventQueue *pThis); + nsresult (*RevokeEvents)(nsIEventQueue *pThis, void * owner); + nsresult (*GetPLEventQueue)(nsIEventQueue *pThis, PLEventQueue * *_retval); + nsresult (*IsQueueNative)(nsIEventQueue *pThis, PRBool *_retval); + nsresult (*StopAcceptingEvents)(nsIEventQueue *pThis); +}; +#define nsIEventQueue_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp)) +#define nsIEventQueue_AddRef(p) ((p)->lpVtbl->AddRef(p)) +#define nsIEventQueue_Release(p) ((p)->lpVtbl->Release(p)) +#define nsIEventQueue_PostEvent(p, aEvent) ((p)->lpVtbl->PostEvent(p, aEvent)) +#define nsIEventQueue_IsOnCurrentThread(p, retval) ((p)->lpVtbl->IsOnCurrentThread(p, retval)) +#define nsIEventQueue_InitEvent(p, aEvent, owner, handler, destructor) ((p)->lpVtbl->InitEvent(p, aEvent, owner, handler, destructor)) +#define nsIEventQueue_PostSynchronousEvent(p, aEvent, aResult) ((p)->lpVtbl->PostSynchronousEvent(p, aEvent, aResult)) +#define nsIEventQueue_ProcessPendingEvents(p) ((p)->lpVtbl->ProcessPendingEvents(p)) +#define nsIEventQueue_EventLoop(p) ((p)->lpVtbl->EventLoop(p)) +#define nsIEventQueue_EventAvailable(p, aResult) ((p)->lpVtbl->EventAvailable(p, aResult)) +#define nsIEventQueue_get_Event(p, aEvent) ((p)->lpVtbl->GetEvent(p, aEvent)) +#define nsIEventQueue_GetEvent(p, aEvent) ((p)->lpVtbl->GetEvent(p, aEvent)) +#define nsIEventQueue_HandleEvent(p, aEvent) ((p)->lpVtbl->HandleEvent(p, aEvent)) +#define nsIEventQueue_WaitForEvent(p, aEvent) ((p)->lpVtbl->WaitForEvent(p, aEvent)) +#define nsIEventQueue_GetEventQueueSelectFD(p) ((p)->lpVtbl->GetEventQueueSelectFD(p)) +#define nsIEventQueue_Init(p, aNative) ((p)->lpVtbl->Init(p, aNative)) +#define nsIEventQueue_InitFromPLQueue(p, aQueue) ((p)->lpVtbl->InitFromPLQueue(p, aQueue)) +#define nsIEventQueue_EnterMonitor(p) ((p)->lpVtbl->EnterMonitor(p)) +#define nsIEventQueue_ExitMonitor(p) ((p)->lpVtbl->ExitMonitor(p)) +#define nsIEventQueue_RevokeEvents(p, owner) ((p)->lpVtbl->RevokeEvents(p, owner)) +#define nsIEventQueue_GetPLEventQueue(p, retval) ((p)->lpVtbl->GetPLEventQueue(p, retval)) +#define nsIEventQueue_IsQueueNative(p, retval) ((p)->lpVtbl->IsQueueNative(p, retval)) +#define nsIEventQueue_StopAcceptingEvents(p) ((p)->lpVtbl->StopAcceptingEvents(p)) +#endif /* !VBOX_WITH_GLUE */ + +interface nsIEventQueue +{ +#ifndef VBOX_WITH_GLUE + struct nsIEventQueue_vtbl *vtbl; +#else /* !VBOX_WITH_GLUE */ + CONST_VTBL struct nsIEventQueueVtbl *lpVtbl; +#endif /* !VBOX_WITH_GLUE */ +}; +</xsl:text> + <xsl:call-template name="xsltprocNewlineOutputHack"/> + <xsl:apply-templates/> + <xsl:text> + +#endif /* __cplusplus */ + +#endif /* !WIN32 */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** + * Function table for dynamic linking. + * Use VBoxGetCAPIFunctions() to obtain the pointer to it. + */ +typedef struct VBOXCAPI +{ + /** The size of the structure. */ + unsigned cb; + /** The structure version. */ + unsigned uVersion; + + /** Gets the VirtualBox version, major * 1000000 + minor * 1000 + patch. */ + unsigned int (*pfnGetVersion)(void); + + /** Gets the VirtualBox API version, major * 1000 + minor, e.g. 4003. */ + unsigned int (*pfnGetAPIVersion)(void); + + /** + * New and preferred way to initialize the C bindings for an API client. + * + * This way is much more flexible, as it can easily handle multiple + * sessions (important with more complicated API clients, including + * multithreaded ones), and even VBoxSVC crashes can be detected and + * processed appropriately by listening for events from the associated + * event source in VirtualBoxClient. It is completely up to the client + * to decide what to do (terminate or continue after getting new + * object references to server-side objects). Must be called in the + * primary thread of the client, later API use can be done in any + * thread. + * + * Note that the returned reference is owned by the caller, and thus it's + * the caller's responsibility to handle the reference count appropriately. + * + * @param pszVirtualBoxClientIID pass IVIRTUALBOXCLIENT_IID_STR + * @param ppVirtualBoxClient output parameter for VirtualBoxClient + * reference, handled as usual with COM/XPCOM. + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClientInitialize)(const char *pszVirtualBoxClientIID, + IVirtualBoxClient **ppVirtualBoxClient); + /** + * Initialize the use of the C bindings in a non-primary thread. + * + * Must be called on any newly created thread which wants to use the + * VirtualBox API. + * + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClientThreadInitialize)(void); + /** + * Uninitialize the use of the C bindings in a non-primary thread. + * + * Should be called before terminating the thread which initialized the + * C bindings using pfnClientThreadInitialize. + * + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClientThreadUninitialize)(void); + /** + * Uninitialize the C bindings for an API client. + * + * Should be called when the API client is about to terminate and does + * not want to use the C bindings any more. It will invalidate all + * object references. It is possible, however, to change one's mind, + * and call pfnClientInitialize again to continue using the API, as long + * as none of the object references from before the re-initialization + * are used. Must be called from the primary thread of the client. + */ + void (*pfnClientUninitialize)(void); + + /** + * Deprecated way to initialize the C bindings and getting important + * object references. Kept for backwards compatibility. + * + * If any returned reference is NULL then the initialization failed. + * Note that the returned references are owned by the C bindings. The + * number of calls to Release in the client code must match the number + * of calls to AddRef, and additionally at no point in time there can + * be more Release calls than AddRef calls. + * + * @param pszVirtualBoxIID pass IVIRTUALBOX_IID_STR + * @param ppVirtualBox output parameter for VirtualBox reference, + * owned by C bindings + * @param pszSessionIID pass ISESSION_IID_STR + * @param ppSession output parameter for Session reference, + * owned by C bindings + */ + void (*pfnComInitialize)(const char *pszVirtualBoxIID, + IVirtualBox **ppVirtualBox, + const char *pszSessionIID, + ISession **ppSession); + /** + * Deprecated way to uninitialize the C bindings for an API client. + * Kept for backwards compatibility and must be used if the C bindings + * were initialized using pfnComInitialize. */ + void (*pfnComUninitialize)(void); + + /** + * Free string managed by COM/XPCOM. + * + * @param pwsz pointer to string to be freed + */ + void (*pfnComUnallocString)(BSTR pwsz); +#ifndef WIN32 + /** Legacy function, was always for freeing strings only. */ +#define pfnComUnallocMem(pv) pfnComUnallocString((BSTR)(pv)) +#endif /* !WIN32 */ + + /** + * Convert string from UTF-16 encoding to UTF-8 encoding. + * + * @param pwszString input string + * @param ppszString output string + * @returns IPRT status code + */ + int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); + /** + * Convert string from UTF-8 encoding to UTF-16 encoding. + * + * @param pszString input string + * @param ppwszString output string + * @returns IPRT status code + */ + int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString); + /** + * Free memory returned by pfnUtf16ToUtf8. Do not use for anything else. + * + * @param pszString string to be freed. + */ + void (*pfnUtf8Free)(char *pszString); + /** + * Free memory returned by pfnUtf8ToUtf16. Do not use for anything else. + * + * @param pwszString string to be freed. + */ + void (*pfnUtf16Free)(BSTR pwszString); + + /** + * Create a safearray (used for passing arrays to COM/XPCOM) + * + * Must be freed by pfnSafeArrayDestroy. + * + * @param vt variant type, defines the size of the elements + * @param lLbound lower bound of the index, should be 0 + * @param cElements number of elements + * @returns pointer to safearray + */ + SAFEARRAY *(*pfnSafeArrayCreateVector)(VARTYPE vt, LONG lLbound, ULONG cElements); + /** + * Pre-allocate a safearray to be used by an out safearray parameter + * + * Must be freed by pfnSafeArrayDestroy. + * + * @returns pointer to safearray (system dependent, may be NULL if + * there is no need to pre-allocate a safearray) + */ + SAFEARRAY *(*pfnSafeArrayOutParamAlloc)(void); + /** + * Copy a C array into a safearray (for passing as an input parameter) + * + * @param psa pointer to already created safearray. + * @param pv pointer to memory block to copy into safearray. + * @param cb number of bytes to copy. + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayCopyInParamHelper)(SAFEARRAY *psa, const void *pv, ULONG cb); + /** + * Copy a safearray into a C array (for getting an output parameter) + * + * @param ppv output pointer to newly created array, which has to + * be freed with pfnArrayOutFree. + * @param pcb number of bytes in the output buffer. + * @param vt variant type, defines the size of the elements + * @param psa pointer to safearray for getting the data + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayCopyOutParamHelper)(void **ppv, ULONG *pcb, VARTYPE vt, SAFEARRAY *psa); + /** + * Copy a safearray into a C array (special variant for interface pointers) + * + * @param ppaObj output pointer to newly created array, which has + * to be freed with pfnArrayOutFree. Note that it's the caller's + * responsibility to call Release() on each non-NULL interface + * pointer before freeing. + * @param pcObj number of pointers in the output buffer. + * @param psa pointer to safearray for getting the data + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayCopyOutIfaceParamHelper)(IUnknown ***ppaObj, ULONG *pcObj, SAFEARRAY *psa); + /** + * Free a safearray + * + * @param psa pointer to safearray + * @returns COM/XPCOM error code + */ + HRESULT (*pfnSafeArrayDestroy)(SAFEARRAY *psa); + /** + * Free an out array created by pfnSafeArrayCopyOutParamHelper or + * pdnSafeArrayCopyOutIfaceParamHelper. + * + * @param psa pointer to memory block + * @returns COM/XPCOM error code + */ + HRESULT (*pfnArrayOutFree)(void *pv); + +#ifndef WIN32 + /** + * Get XPCOM event queue. Deprecated! + * + * @param ppEventQueue output parameter for nsIEventQueue reference, + * owned by C bindings. + */ + void (*pfnGetEventQueue)(nsIEventQueue **ppEventQueue); +#endif /* !WIN32 */ + + /** + * Get current COM/XPCOM exception. + * + * @param ppException output parameter for exception info reference, + * may be @c NULL if no exception object has been created by + * a previous COM/XPCOM call. + * @returns COM/XPCOM error code + */ + HRESULT (*pfnGetException)(IErrorInfo **ppException); + /** + * Clears current COM/XPCOM exception. + * + * @returns COM/XPCOM error code + */ + HRESULT (*pfnClearException)(void); + + /** + * Process the event queue for a given amount of time. + * + * Must be called on the primary thread. Typical timeouts are from 200 to + * 5000 msecs, to allow for checking a volatile variable if the event queue + * processing should be terminated (, + * or 0 if only the pending events should be processed, without waiting. + * + * @param iTimeoutMS how long to process the event queue, -1 means + * infinitely long + * @returns status code + * @retval 0 if at least one event has been processed + * @retval 1 if any signal interrupted the native system call (or returned + * otherwise) + * @retval 2 if the event queue was explicitly interrupted + * @retval 3 if the timeout expired + * @retval 4 if the function was called from the wrong thread + * @retval 5 for all other (unexpected) errors + */ + int (*pfnProcessEventQueue)(LONG64 iTimeoutMS); + /** + * Interrupt event queue processing. + * + * Can be called on any thread. Note that this function is not async-signal + * safe, so never use it in such a context, instead use a volatile global + * variable and a sensible timeout. + * @returns 0 if successful, 1 otherwise. + */ + int (*pfnInterruptEventQueueProcessing)(void); + + /** + * Clear memory used by a UTF-8 string. Must be zero terminated. + * Can be used for any UTF-8 or ASCII/ANSI string. + * + * @param pszString input/output string + */ + void (*pfnUtf8Clear)(char *pszString); + /** + * Clear memory used by a UTF-16 string. Must be zero terminated. + * Can be used for any UTF-16 or UCS-2 string. + * + * @param pwszString input/output string + */ + void (*pfnUtf16Clear)(BSTR pwszString); + + /** Tail version, same as uVersion. + * + * This should only be accessed if for some reason an API client needs + * exactly the version it requested, or if cb is used to calculate the + * address of this field. It may move as the structure before this is + * allowed to grow as long as all the data from earlier minor versions + * remains at the same place. + */ + unsigned uEndVersion; +} VBOXCAPI; +/** Pointer to a const VBOXCAPI function table. */ +typedef VBOXCAPI const *PCVBOXCAPI; +#ifndef WIN32 +/** Backwards compatibility: Pointer to a const VBOXCAPI function table. + * Use PCVBOXCAPI instead. */ +typedef VBOXCAPI const *PCVBOXXPCOM; +#endif /* !WIN32 */ + +#ifndef WIN32 +/** Backwards compatibility: make sure old code using VBOXXPCOMC still compiles. + * Use VBOXCAPI instead. */ +#define VBOXXPCOMC VBOXCAPI +#endif /* !WIN32 */ + +/** Extract the C API style major version. + * Useful for comparing the interface version in VBOXCAPI::uVersion. */ +#define VBOX_CAPI_MAJOR(x) (((x) & 0xffff0000U) >> 16) + +/** Extract the C API style major version. + * Useful for comparing the interface version in VBOXCAPI::uVersion. */ +#define VBOX_CAPI_MINOR(x) ((x) & 0x0000ffffU) + +/** The current interface version. + * For use with VBoxGetCAPIFunctions and to be found in VBOXCAPI::uVersion. */ +#define VBOX_CAPI_VERSION 0x00040001U + +#ifndef WIN32 +/** Backwards compatibility: The current interface version. + * Use VBOX_CAPI_VERSION instead. */ +#define VBOX_XPCOMC_VERSION VBOX_CAPI_VERSION +#endif /* !WIN32 */ + +/** VBoxGetCAPIFunctions. */ +VBOXCAPI_DECL(PCVBOXCAPI) VBoxGetCAPIFunctions(unsigned uVersion); +#ifndef WIN32 +/** Backwards compatibility: VBoxGetXPCOMCFunctions. + * Use VBoxGetCAPIFunctions instead. */ +VBOXCAPI_DECL(PCVBOXCAPI) VBoxGetXPCOMCFunctions(unsigned uVersion); +#endif /* !WIN32 */ + +/** Typedef for VBoxGetCAPIFunctions. */ +typedef PCVBOXCAPI (*PFNVBOXGETCAPIFUNCTIONS)(unsigned uVersion); +#ifndef WIN32 +/** Backwards compatibility: Typedef for VBoxGetXPCOMCFunctions. + * Use PFNVBOXGETCAPIFUNCTIONS instead. */ +typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion); +#endif /* !WIN32 */ + +/** The symbol name of VBoxGetCAPIFunctions. */ +#ifdef __OS2__ +# define VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME "_VBoxGetCAPIFunctions" +#else /* !__OS2__ */ +# define VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME "VBoxGetCAPIFunctions" +#endif /* !__OS2__ */ +#ifndef WIN32 +/** Backwards compatibility: The symbol name of VBoxGetXPCOMCFunctions. + * Use VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME instead. */ +# ifdef __OS2__ +# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "_VBoxGetXPCOMCFunctions" +# else /* !__OS2__ */ +# define VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME "VBoxGetXPCOMCFunctions" +# endif /* !__OS2__ */ +#endif /* !WIN32 */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !___VirtualBox_CAPI_h */ +</xsl:text> +</xsl:template> + +<!-- + * ignore all |if|s except those for XPIDL target +--> +<xsl:template match="if"> + <xsl:if test="@target='xpidl'"> + <xsl:apply-templates/> + </xsl:if> +</xsl:template> +<xsl:template match="if" mode="forward"> + <xsl:if test="@target='xpidl'"> + <xsl:apply-templates mode="forward"/> + </xsl:if> +</xsl:template> +<xsl:template match="if" mode="forwarder"> + <xsl:if test="@target='midl'"> + <xsl:apply-templates mode="forwarder"/> + </xsl:if> +</xsl:template> + + +<!-- + * libraries +--> +<xsl:template match="idl/library"> + <!-- result codes --> + <xsl:call-template name="xsltprocNewlineOutputHack"/> + <xsl:for-each select="application/result"> + <xsl:apply-templates select="."/> + </xsl:for-each> + <xsl:call-template name="xsltprocNewlineOutputHack"/> + <xsl:call-template name="xsltprocNewlineOutputHack"/> + <!-- forward declarations --> + <xsl:apply-templates select="application/interface | application/if/interface" mode="forward"/> + <xsl:call-template name="xsltprocNewlineOutputHack"/> + <!-- typedef'ing the struct declarations --> + <xsl:apply-templates select="application/interface | application/if/interface" mode="typedef"/> + <xsl:call-template name="xsltprocNewlineOutputHack"/> + <!-- all enums go first --> + <xsl:apply-templates select="application/enum | application/if/enum"/> + <!-- everything else but result codes and enums + <xsl:apply-templates select="*[not(self::result or self::enum) and + not(self::if[result] or self::if[enum])]"/> --> + <!-- the modules (i.e. everything else) --> + <xsl:apply-templates select="application/interface | application/if[interface] + | application/module | application/if[module]"/> + <!-- --> +</xsl:template> + + +<!-- + * result codes +--> +<xsl:template match="result"> + <xsl:value-of select="concat('#define ',@name,' ((HRESULT)',@value, ')')"/> + <xsl:text>
</xsl:text> +</xsl:template> + + +<!-- + * forward declarations +--> +<xsl:template match="interface" mode="forward"> + <xsl:if test="not(@internal='yes')"> + <xsl:text>interface </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>;
</xsl:text> + </xsl:if> +</xsl:template> + + +<!-- + * typedef'ing the struct declarations +--> +<xsl:template match="interface" mode="typedef"> + <xsl:if test="not(@internal='yes')"> + <xsl:text>typedef interface </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>;
</xsl:text> + </xsl:if> +</xsl:template> + + +<!-- + * COBJMACRO style convenience macros for calling methods +--> +<xsl:template match="interface" mode="cobjmacro"> + <xsl:param name="iface"/> + + <xsl:variable name="extends" select="@extends"/> + <xsl:choose> + <xsl:when test="$extends='$unknown'"> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_AddRef(p) ((p)->lpVtbl->AddRef(p))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_Release(p) ((p)->lpVtbl->Release(p))
</xsl:text> + </xsl:when> + <xsl:when test="$extends='$errorinfo'"> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_QueryInterface(p, iid, resultp) ((p)->lpVtbl->QueryInterface(p, iid, resultp))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_AddRef(p) ((p)->lpVtbl->AddRef(p))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_Release(p) ((p)->lpVtbl->Release(p))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_Message(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetMessage(p, aMessage) ((p)->lpVtbl->GetMessage(p, aMessage))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_Result(p, aResult) ((p)->lpVtbl->GetResult(p, aResult))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetResult(p, aResult) ((p)->lpVtbl->GetResult(p, aResult))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_Name(p, aName) ((p)->lpVtbl->GetName(p, aName))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetName(p, aName) ((p)->lpVtbl->GetName(p, aName))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_Filename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetFilename(p, aFilename) ((p)->lpVtbl->GetFilename(p, aFilename))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_LineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetLineNumber(p, aLineNumber) ((p)->lpVtbl->GetLineNumber(p, aLineNumber))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_ColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetColumnNumber(p, aColumnNumber) ((p)->lpVtbl->GetColumnNumber(p, aColumnNumber))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_Location(p, aLocation) ((p)->lpVtbl->GetLocation(p, aLocation))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetLocation(p, aLocation) ((p)->lpVtbl->GetLocation(p, aLocation))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_Inner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetInner(p, aInner) ((p)->lpVtbl->GetInner(p, aInner))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_get_Data(p, aData) ((p)->lpVtbl->GetData(p, aData))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_GetData(p, aData) ((p)->lpVtbl->GetData(p, aData))
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>_ToString(p, retval) ((p)->lpVtbl->ToString(p, retval))
</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="key('G_keyInterfacesByName', $extends)" mode="cobjmacro"> + <xsl:with-param name="iface" select="$iface"/> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + <!-- attributes (properties) --> + <xsl:apply-templates select="attribute | if/attribute" mode="cobjmacro"> + <xsl:with-param name="iface" select="$iface"/> + </xsl:apply-templates> + <!-- methods --> + <xsl:apply-templates select="method | if/method" mode="cobjmacro"> + <xsl:with-param name="iface" select="$iface"/> + </xsl:apply-templates> +</xsl:template> + + +<!-- + * emit flat vtable, compatible with COM +--> +<xsl:template match="interface" mode="vtab_flat"> + <xsl:param name="iface"/> + + <xsl:variable name="name" select="@name"/> + <xsl:variable name="extends" select="@extends"/> + <xsl:choose> + <xsl:when test="$extends='$unknown'"> + <xsl:text> nsresult (*QueryInterface)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, const nsID *iid, void **resultp);
</xsl:text> + <xsl:text> nsrefcnt (*AddRef)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis);
</xsl:text> + <xsl:text> nsrefcnt (*Release)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis);
</xsl:text> + </xsl:when> + <xsl:when test="$extends='$errorinfo'"> + <xsl:text> nsresult (*QueryInterface)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, const nsID *iid, void **resultp);
</xsl:text> + <xsl:text> nsrefcnt (*AddRef)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis);
</xsl:text> + <xsl:text> nsrefcnt (*Release)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis);
</xsl:text> + <xsl:text> nsresult (*GetMessage)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, PRUnichar * *aMessage);
</xsl:text> + <xsl:text> nsresult (*GetResult)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, nsresult *aResult);
</xsl:text> + <xsl:text> nsresult (*GetName)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text>*pThis, PRUnichar * *aName);
</xsl:text> + <xsl:text> nsresult (*GetFilename)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, PRUnichar * *aFilename);
</xsl:text> + <xsl:text> nsresult (*GetLineNumber)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, PRUint32 *aLineNumber);
</xsl:text> + <xsl:text> nsresult (*GetColumnNumber)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, PRUint32 *aColumnNumber);
</xsl:text> + <xsl:text> nsresult (*GetLocation)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, nsIStackFrame * *aLocation);
</xsl:text> + <xsl:text> nsresult (*GetInner)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, nsIException * *aInner);
</xsl:text> + <xsl:text> nsresult (*GetData)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, nsISupports * *aData);
</xsl:text> + <xsl:text> nsresult (*ToString)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, PRUnichar **_retval);
</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="key('G_keyInterfacesByName', $extends)" mode="vtab_flat"> + <xsl:with-param name="iface" select="$iface"/> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + <!-- attributes (properties) --> + <xsl:apply-templates select="attribute | if/attribute"> + <xsl:with-param name="iface" select="$iface"/> + </xsl:apply-templates> + <xsl:variable name="reservedAttributes" select="@reservedAttributes"/> + <xsl:if test="$reservedAttributes > 0"> + <!-- tricky way to do a "for" loop without recursion --> + <xsl:for-each select="(//*)[position() <= $reservedAttributes]"> + <xsl:text> nsresult (*GetInternalAndReservedAttribute</xsl:text> + <xsl:value-of select="concat(position(), $name)"/> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis, PRUint32 *reserved);

</xsl:text> + </xsl:for-each> + </xsl:if> + <!-- methods --> + <xsl:apply-templates select="method | if/method"> + <xsl:with-param name="iface" select="$iface"/> + </xsl:apply-templates> + <xsl:variable name="reservedMethods" select="@reservedMethods"/> + <xsl:if test="$reservedMethods > 0"> + <!-- tricky way to do a "for" loop without recursion --> + <xsl:for-each select="(//*)[position() <= $reservedMethods]"> + <xsl:text> nsresult (*InternalAndReservedMethod</xsl:text> + <xsl:value-of select="concat(position(), $name)"/> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface"/> + <xsl:text> *pThis);

</xsl:text> + </xsl:for-each> + </xsl:if> +</xsl:template> + + +<!-- + * interfaces +--> +<xsl:template match="interface"> + <xsl:if test="not(@internal='yes')"> + <xsl:variable name="name" select="@name"/> + <xsl:text>/* Start of struct </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> declaration */
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:call-template name="string-to-upper"> + <xsl:with-param name="str" select="$name"/> + </xsl:call-template> + <xsl:value-of select="concat('_IID_STR "',@uuid,'"')"/> + <xsl:text>
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:call-template name="string-to-upper"> + <xsl:with-param name="str" select="$name"/> + </xsl:call-template> + <xsl:text>_IID { \
</xsl:text> + <xsl:text> 0x</xsl:text><xsl:value-of select="substring(@uuid,1,8)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,10,4)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,15,4)"/> + <xsl:text>, \
 </xsl:text> + <xsl:text>{ 0x</xsl:text><xsl:value-of select="substring(@uuid,20,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,22,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,25,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,27,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,29,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,31,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,33,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,35,2)"/> + <xsl:text> } \
}
</xsl:text> + <xsl:text>/* COM compatibility */
</xsl:text> + <xsl:text>VBOX_EXTERN_CONST(nsIID, IID_</xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>);
</xsl:text> + <xsl:text>#ifndef VBOX_WITH_GLUE
</xsl:text> + <xsl:text>struct </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>_vtbl
{
</xsl:text> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test="@extends='$unknown'">struct nsISupports_vtbl nsisupports;</xsl:when> + <xsl:when test="@extends='$errorinfo'">struct nsIException_vtbl nsiexception;</xsl:when> + <xsl:otherwise> + <xsl:text>struct </xsl:text> + <xsl:value-of select="@extends"/> + <xsl:text>_vtbl </xsl:text> + <xsl:call-template name="string-to-lower"> + <xsl:with-param name="str" select="@extends"/> + </xsl:call-template> + <xsl:text>;</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text>

</xsl:text> + <!-- attributes (properties) --> + <xsl:apply-templates select="attribute | if/attribute"/> + <xsl:variable name="reservedAttributes" select="@reservedAttributes"/> + <xsl:if test="$reservedAttributes > 0"> + <!-- tricky way to do a "for" loop without recursion --> + <xsl:for-each select="(//*)[position() <= $reservedAttributes]"> + <xsl:text> nsresult (*GetInternalAndReservedAttribute</xsl:text> + <xsl:value-of select="concat(position(), $name)"/> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> *pThis, PRUint32 *reserved);

</xsl:text> + </xsl:for-each> + </xsl:if> + <!-- methods --> + <xsl:apply-templates select="method | if/method"/> + <xsl:variable name="reservedMethods" select="@reservedMethods"/> + <xsl:if test="$reservedMethods > 0"> + <!-- tricky way to do a "for" loop without recursion --> + <xsl:for-each select="(//*)[position() <= $reservedMethods]"> + <xsl:text> nsresult (*InternalAndReservedMethod</xsl:text> + <xsl:value-of select="concat(position(), $name)"/> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> *pThis);

</xsl:text> + </xsl:for-each> + </xsl:if> + <!-- --> + <xsl:text>};
</xsl:text> + <xsl:text>#else /* VBOX_WITH_GLUE */
</xsl:text> + <xsl:text>struct </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>Vtbl
{
</xsl:text> + <xsl:apply-templates select="." mode="vtab_flat"> + <xsl:with-param name="iface" select="$name"/> + </xsl:apply-templates> + <xsl:text>};
</xsl:text> + <xsl:apply-templates select="." mode="cobjmacro"> + <xsl:with-param name="iface" select="$name"/> + </xsl:apply-templates> + <!-- --> + <xsl:text>#endif /* VBOX_WITH_GLUE */
</xsl:text> + <xsl:text>
</xsl:text> + <xsl:text>interface </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>
{
</xsl:text> + <xsl:text>#ifndef VBOX_WITH_GLUE
</xsl:text> + <xsl:text> struct </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>_vtbl *vtbl;
</xsl:text> + <xsl:text>#else /* VBOX_WITH_GLUE */
</xsl:text> + <xsl:text> CONST_VTBL struct </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>Vtbl *lpVtbl;
</xsl:text> + <xsl:text>#endif /* VBOX_WITH_GLUE */
</xsl:text> + <xsl:text>};
</xsl:text> + <xsl:text>/* End of struct </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> declaration */

</xsl:text> + <xsl:call-template name="xsltprocNewlineOutputHack"/> + </xsl:if> +</xsl:template> + + +<!-- + * attributes +--> +<xsl:template match="attribute"> + <xsl:param name="iface" select="ancestor::interface/@name"/> + + <xsl:choose> + <!-- safearray pseudo attribute --> + <xsl:when test="@safearray='yes'"> + <!-- getter --> + <xsl:text> nsresult (*Get</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface" /> + <xsl:text> *pThis, </xsl:text> + <!-- array size --> + <xsl:text>PRUint32 *</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>Size, </xsl:text> + <!-- array pointer --> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text> **</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>);
</xsl:text> + <!-- setter --> + <xsl:if test="not(@readonly='yes')"> + <xsl:text> nsresult (*Set</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface" /> + <xsl:text> *pThis, </xsl:text> + <!-- array size --> + <xsl:text>PRUint32 </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>Size, </xsl:text> + <!-- array pointer --> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text> *</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>);
</xsl:text> + </xsl:if> + </xsl:when> + <!-- normal attribute --> + <xsl:otherwise> + <xsl:text> </xsl:text> + <xsl:if test="@readonly='yes'"> + <xsl:text>nsresult (*Get</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface" /> + <xsl:text> *pThis, </xsl:text> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text> *</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>);
</xsl:text> + </xsl:if> + <xsl:choose> + <xsl:when test="@readonly='yes'"> + </xsl:when> + <xsl:otherwise> + <xsl:text>nsresult (*Get</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface" /> + <xsl:text> *pThis, </xsl:text> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text> *</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>);
 </xsl:text> + <xsl:text>nsresult (*Set</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface" /> + <xsl:text> *pThis, </xsl:text> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text> </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>);
</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + <xsl:text>
</xsl:text> +</xsl:template> + +<xsl:template match="attribute" mode="cobjmacro"> + <xsl:param name="iface"/> + + <!-- getter (COM compatible) --> + <xsl:text>#define </xsl:text> + <xsl:value-of select="concat($iface, '_get_')"/> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>) ((p)->lpVtbl->Get</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>))
</xsl:text> + + <!-- getter (XPCOM compatible) --> + <xsl:text>#define </xsl:text> + <xsl:value-of select="concat($iface, '_Get')"/> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>) ((p)->lpVtbl->Get</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>))
</xsl:text> + + <xsl:if test="not(@readonly='yes')"> + <!-- setter (COM compatible) --> + <xsl:text>#define </xsl:text> + <xsl:value-of select="concat($iface, '_put_')"/> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>) ((p)->lpVtbl->Set</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>))
</xsl:text> + + <!-- setter (XPCOM compatible) --> + <xsl:text>#define </xsl:text> + <xsl:value-of select="concat($iface, '_Set')"/> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>) ((p)->lpVtbl->Set</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>))
</xsl:text> + + </xsl:if> +</xsl:template> + +<!-- + * methods +--> +<xsl:template match="method"> + <xsl:param name="iface" select="ancestor::interface/@name"/> + + <xsl:if test="param/@mod='ptr'"> + <!-- methods using native types must be non-scriptable + <xsl:text> [noscript]
</xsl:text>--> + </xsl:if> + <xsl:text> nsresult (*</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:if test="param"> + <xsl:text>)(
</xsl:text> + <xsl:text> </xsl:text> + <xsl:value-of select="$iface" /> + <xsl:text> *pThis,
</xsl:text> + <xsl:for-each select="param [position() != last()]"> + <xsl:text> </xsl:text> + <xsl:apply-templates select="."/> + <xsl:text>,
</xsl:text> + </xsl:for-each> + <xsl:text> </xsl:text> + <xsl:apply-templates select="param [last()]"/> + <xsl:text>
 );
</xsl:text> + </xsl:if> + <xsl:if test="not(param)"> + <xsl:text>)(</xsl:text> + <xsl:value-of select="$iface" /> + <xsl:text> *pThis );
</xsl:text> + </xsl:if> + <xsl:text>
</xsl:text> +</xsl:template> + +<xsl:template match="method" mode="cobjmacro"> + <xsl:param name="iface"/> + + <xsl:text>#define </xsl:text> + <xsl:value-of select="concat($iface, '_')"/> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p</xsl:text> + <xsl:for-each select="param"> + <xsl:text>, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + </xsl:for-each> + <xsl:text>) ((p)->lpVtbl-></xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>(p</xsl:text> + <xsl:for-each select="param"> + <xsl:text>, a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + </xsl:for-each> + <xsl:text>))
</xsl:text> +</xsl:template> + + +<!-- + * modules +--> +<xsl:template match="module"> + <xsl:apply-templates select="class"/> +</xsl:template> + + +<!-- + * co-classes +--> +<xsl:template match="module/class"> + <!-- class and contract id --> + <xsl:text>
</xsl:text> + <xsl:text>#define NS_</xsl:text> + <xsl:call-template name="string-to-upper"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>_CID { \
</xsl:text> + <xsl:text> 0x</xsl:text><xsl:value-of select="substring(@uuid,1,8)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,10,4)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,15,4)"/> + <xsl:text>, \
 </xsl:text> + <xsl:text>{ 0x</xsl:text><xsl:value-of select="substring(@uuid,20,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,22,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,25,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,27,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,29,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,31,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,33,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,35,2)"/> + <xsl:text> } \
}
</xsl:text> + <xsl:text>#define NS_</xsl:text> + <xsl:call-template name="string-to-upper"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <!-- Contract ID --> + <xsl:text>_CONTRACTID "@</xsl:text> + <xsl:value-of select="@namespace"/> + <xsl:text>/</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>;1"
</xsl:text> + <!-- CLSID_xxx declarations for XPCOM, for compatibility with Win32 --> + <xsl:text>/* COM compatibility */
</xsl:text> + <xsl:text>VBOX_EXTERN_CONST(nsCID, CLSID_</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>);
</xsl:text> + <xsl:text>

</xsl:text> +</xsl:template> + + +<!-- + * enums +--> +<xsl:template match="enum"> + <xsl:text>/* Start of enum </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> declaration */
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:call-template name="string-to-upper"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:value-of select="concat('_IID_STR "',@uuid,'"')"/> + <xsl:text>
</xsl:text> + <xsl:text>#define </xsl:text> + <xsl:call-template name="string-to-upper"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>_IID { \
</xsl:text> + <xsl:text> 0x</xsl:text><xsl:value-of select="substring(@uuid,1,8)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,10,4)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,15,4)"/> + <xsl:text>, \
 </xsl:text> + <xsl:text>{ 0x</xsl:text><xsl:value-of select="substring(@uuid,20,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,22,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,25,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,27,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,29,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,31,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,33,2)"/> + <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,35,2)"/> + <xsl:text> } \
}
</xsl:text> + <xsl:text>typedef enum </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>
{
</xsl:text> + <xsl:variable name="this" select="."/> + <xsl:for-each select="const"> + <xsl:text> </xsl:text> + <xsl:value-of select="$this/@name"/> + <xsl:text>_</xsl:text> + <xsl:value-of select="@name"/> = <xsl:value-of select="@value"/> + <xsl:if test="position() != last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text>
</xsl:text> + </xsl:for-each> + <xsl:text>} </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>;
</xsl:text> + <xsl:text>/* End of enum </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> declaration */ +#define </xsl:text> + <xsl:value-of select="concat(@name, '_T PRUint32


')"/> +</xsl:template> + + +<!-- + * method parameters +--> +<xsl:template match="method/param"> + <xsl:choose> + <!-- safearray parameters --> + <xsl:when test="@safearray='yes'"> + <!-- array size --> + <xsl:choose> + <xsl:when test="@dir='in'"> + <xsl:text>PRUint32 </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>Size,
</xsl:text> + </xsl:when> + <xsl:when test="@dir='out'"> + <xsl:text>PRUint32 *</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>Size,
</xsl:text> + </xsl:when> + <xsl:when test="@dir='return'"> + <xsl:text>PRUint32 *</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>Size,
</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>PRUint32 </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>Size,
</xsl:text> + </xsl:otherwise> + </xsl:choose> + <!-- array pointer --> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test="@dir='in'"> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text>*</xsl:text> + </xsl:when> + <xsl:when test="@dir='out'"> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text>**</xsl:text> + </xsl:when> + <xsl:when test="@dir='return'"> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text>**</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text>*</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text> </xsl:text> + <xsl:value-of select="@name"/> + </xsl:when> + <!-- normal and array parameters --> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="@dir='in'"> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text></xsl:text> + </xsl:when> + <xsl:when test="@dir='out'"> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text> *</xsl:text> + </xsl:when> + <xsl:when test="@dir='return'"> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text> *</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:text></xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text> </xsl:text> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +<xsl:template match="method/param" mode="forwarder"> + <xsl:if test="@safearray='yes'"> + <xsl:text>PRUint32</xsl:text> + <xsl:if test="@dir='out' or @dir='return'"> + <xsl:text> *</xsl:text> + </xsl:if> + <xsl:text> a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> + <xsl:text>Size, </xsl:text> + </xsl:if> + <xsl:apply-templates select="@type" mode="forwarder"/> + <xsl:if test="@dir='out' or @dir='return'"> + <xsl:text> *</xsl:text> + </xsl:if> + <xsl:if test="@safearray='yes'"> + <xsl:text> *</xsl:text> + </xsl:if> + <xsl:text> a</xsl:text> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="@name"/> + </xsl:call-template> +</xsl:template> + + +<!-- + * attribute/parameter type conversion +--> +<xsl:template match="attribute/@type | param/@type"> + <xsl:variable name="self_target" select="current()/ancestor::if/@target"/> + + <xsl:choose> + <!-- modifiers --> + <xsl:when test="name(current())='type' and ../@mod"> + <xsl:choose> + <xsl:when test="../@mod='ptr'"> + <xsl:choose> + <!-- standard types --> + <!--xsl:when test=".='result'">??</xsl:when--> + <xsl:when test=".='boolean'">booleanPtr</xsl:when> + <xsl:when test=".='octet'">octetPtr</xsl:when> + <xsl:when test=".='short'">shortPtr</xsl:when> + <xsl:when test=".='unsigned short'">ushortPtr</xsl:when> + <xsl:when test=".='long'">longPtr</xsl:when> + <xsl:when test=".='long long'">llongPtr</xsl:when> + <xsl:when test=".='unsigned long'">ulongPtr</xsl:when> + <xsl:when test=".='unsigned long long'">ullongPtr</xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/> + <xsl:text>attribute 'mod=</xsl:text> + <xsl:value-of select="concat('"',../@mod,'"')"/> + <xsl:text>' cannot be used with type </xsl:text> + <xsl:value-of select="concat('"',current(),'"!')"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="../@mod='string'"> + <xsl:choose> + <!-- standard types --> + <!--xsl:when test=".='result'">??</xsl:when--> + <xsl:when test=".='uuid'">wstring</xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/> + <xsl:text>attribute 'mod=</xsl:text> + <xsl:value-of select="concat('"',../@mod,'"')"/> + <xsl:text>' cannot be used with type </xsl:text> + <xsl:value-of select="concat('"',current(),'"!')"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/> + <xsl:value-of select="concat('value "',../@mod,'" ')"/> + <xsl:text>of attribute 'mod' is invalid!</xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <!-- no modifiers --> + <xsl:otherwise> + <xsl:choose> + <!-- standard types --> + <xsl:when test=".='result'">nsresult</xsl:when> + <xsl:when test=".='boolean'">boolean</xsl:when> + <xsl:when test=".='octet'">octet</xsl:when> + <xsl:when test=".='short'">short</xsl:when> + <xsl:when test=".='unsigned short'">unsigned short</xsl:when> + <xsl:when test=".='long'">long</xsl:when> + <xsl:when test=".='long long'">long long</xsl:when> + <xsl:when test=".='unsigned long'">unsigned long</xsl:when> + <xsl:when test=".='unsigned long long'">unsigned long long</xsl:when> + <xsl:when test=".='char'">char</xsl:when> + <xsl:when test=".='wchar'">wchar</xsl:when> + <xsl:when test=".='string'">string</xsl:when> + <xsl:when test=".='wstring'">wstring</xsl:when> + <!-- UUID type --> + <xsl:when test=".='uuid'"> + <xsl:choose> + <xsl:when test="name(..)='attribute'"> + <xsl:choose> + <xsl:when test="../@readonly='yes'"> + <xsl:text>nsIDPtr</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:value-of select="../@name"/> + <xsl:text>: Non-readonly uuid attributes are not supported!</xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..)='param'"> + <xsl:choose> + <xsl:when test="../@dir='in' and not(../@safearray='yes')"> + <xsl:text>nsIDRef</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>nsIDPtr</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + </xsl:choose> + </xsl:when> + <!-- system interface types --> + <xsl:when test=".='$unknown'">nsISupports</xsl:when> + <xsl:otherwise> + <xsl:choose> + <!-- enum types --> + <xsl:when test=" + (ancestor::library/application/enum[@name=current()]) or + (ancestor::library/application/if[@target=$self_target]/enum[@name=current()]) + "> + <xsl:text>PRUint32</xsl:text> + </xsl:when> + <!-- custom interface types --> + <xsl:when test=" + (ancestor::library/application/interface[@name=current()]) or + (ancestor::library/application/if[@target=$self_target]/interface[@name=current()]) + "> + <xsl:value-of select="."/> + </xsl:when> + <!-- other types --> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>Unknown parameter type: </xsl:text> + <xsl:value-of select="."/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +<xsl:template match="attribute/@type | param/@type" mode="forwarder"> + + <xsl:variable name="self_target" select="current()/ancestor::if/@target"/> + + <xsl:choose> + <!-- modifiers --> + <xsl:when test="name(current())='type' and ../@mod"> + <xsl:choose> + <xsl:when test="../@mod='ptr'"> + <xsl:choose> + <!-- standard types --> + <!--xsl:when test=".='result'">??</xsl:when--> + <xsl:when test=".='boolean'">PRBool *</xsl:when> + <xsl:when test=".='octet'">PRUint8 *</xsl:when> + <xsl:when test=".='short'">PRInt16 *</xsl:when> + <xsl:when test=".='unsigned short'">PRUint16 *</xsl:when> + <xsl:when test=".='long'">PRInt32 *</xsl:when> + <xsl:when test=".='long long'">PRInt64 *</xsl:when> + <xsl:when test=".='unsigned long'">PRUint32 *</xsl:when> + <xsl:when test=".='unsigned long long'">PRUint64 *</xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/> + <xsl:text>attribute 'mod=</xsl:text> + <xsl:value-of select="concat('"',../@mod,'"')"/> + <xsl:text>' cannot be used with type </xsl:text> + <xsl:value-of select="concat('"',current(),'"!')"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="../@mod='string'"> + <xsl:choose> + <!-- standard types --> + <!--xsl:when test=".='result'">??</xsl:when--> + <xsl:when test=".='uuid'">PRUnichar *</xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/> + <xsl:text>attribute 'mod=</xsl:text> + <xsl:value-of select="concat('"',../@mod,'"')"/> + <xsl:text>' cannot be used with type </xsl:text> + <xsl:value-of select="concat('"',current(),'"!')"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + </xsl:choose> + </xsl:when> + <!-- no modifiers --> + <xsl:otherwise> + <xsl:choose> + <!-- standard types --> + <xsl:when test=".='result'">nsresult</xsl:when> + <xsl:when test=".='boolean'">PRBool</xsl:when> + <xsl:when test=".='octet'">PRUint8</xsl:when> + <xsl:when test=".='short'">PRInt16</xsl:when> + <xsl:when test=".='unsigned short'">PRUint16</xsl:when> + <xsl:when test=".='long'">PRInt32</xsl:when> + <xsl:when test=".='long long'">PRInt64</xsl:when> + <xsl:when test=".='unsigned long'">PRUint32</xsl:when> + <xsl:when test=".='unsigned long long'">PRUint64</xsl:when> + <xsl:when test=".='char'">char</xsl:when> + <xsl:when test=".='wchar'">PRUnichar</xsl:when> + <!-- string types --> + <xsl:when test=".='string'">char *</xsl:when> + <xsl:when test=".='wstring'">PRUnichar *</xsl:when> + <!-- UUID type --> + <xsl:when test=".='uuid'"> + <xsl:choose> + <xsl:when test="name(..)='attribute'"> + <xsl:choose> + <xsl:when test="../@readonly='yes'"> + <xsl:text>nsID *</xsl:text> + </xsl:when> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..)='param'"> + <xsl:choose> + <xsl:when test="../@dir='in' and not(../@safearray='yes')"> + <xsl:text>const nsID *</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>nsID *</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + </xsl:choose> + </xsl:when> + <!-- system interface types --> + <xsl:when test=".='$unknown'">nsISupports *</xsl:when> + <xsl:otherwise> + <xsl:choose> + <!-- enum types --> + <xsl:when test=" + (ancestor::library/application/enum[@name=current()]) or + (ancestor::library/application/if[@target=$self_target]/enum[@name=current()]) + "> + <xsl:text>PRUint32</xsl:text> + </xsl:when> + <!-- custom interface types --> + <xsl:when test=" + (ancestor::library/application/interface[@name=current()]) or + (ancestor::library/application/if[@target=$self_target]/interface[@name=current()]) + "> + <xsl:value-of select="."/> + <xsl:text> *</xsl:text> + </xsl:when> + <!-- other types --> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + + +<xsl:template match="application[@uuid='ec0e78e8-fa43-43e8-ac0a-02c784c4a4fa']//module/class" /> + +<xsl:template match="application[@uuid='ec0e78e8-fa43-43e8-ac0a-02c784c4a4fa']/if//interface +| application[@uuid='ec0e78e8-fa43-43e8-ac0a-02c784c4a4fa']//interface" /> + +<xsl:template match="application[@uuid='ec0e78e8-fa43-43e8-ac0a-02c784c4a4fa']//interface" mode="forward" /> + + +</xsl:stylesheet> diff --git a/src/VBox/Main/cbinding/makefile.tstCAPIGlue b/src/VBox/Main/cbinding/makefile.tstCAPIGlue new file mode 100644 index 00000000..53975964 --- /dev/null +++ b/src/VBox/Main/cbinding/makefile.tstCAPIGlue @@ -0,0 +1,63 @@ +# $Id: makefile.tstCAPIGlue $ +## @file makefile.tstCAPIGlue +# Makefile for sample program illustrating use of C binding for COM/XPCOM. +# + +# +# Copyright (C) 2009-2023 Oracle and/or its affiliates. +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +PATH_SDK = ../../.. +CAPI_INC = -I$(PATH_SDK)/bindings/c/include +ifdef ProgramFiles +PLATFORM_INC = -I$(PATH_SDK)/bindings/mscom/include +PLATFORM_LIB = $(PATH_SDK)/bindings/mscom/lib +else +PLATFORM_INC = -I$(PATH_SDK)/bindings/xpcom/include +PLATFORM_LIB = $(PATH_SDK)/bindings/xpcom/lib +endif +GLUE_DIR = $(PATH_SDK)/bindings/c/glue +GLUE_INC = -I$(GLUE_DIR) + +CC = gcc +CFLAGS = -g -Wall + +.PHONY: all +all: tstCAPIGlue + +.PHONY: clean +clean: + rm -f tstCAPIGlue.o VBoxCAPIGlue.o VirtualBox_i.o tstCAPIGlue + +tstCAPIGlue: tstCAPIGlue.o VBoxCAPIGlue.o VirtualBox_i.o + $(CC) -o $@ $^ -ldl -lpthread + +tstCAPIGlue.o: tstCAPIGlue.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< + +VBoxCAPIGlue.o: $(GLUE_DIR)/VBoxCAPIGlue.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< + +VirtualBox_i.o: $(PLATFORM_LIB)/VirtualBox_i.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< diff --git a/src/VBox/Main/cbinding/tstCAPIGlue.c b/src/VBox/Main/cbinding/tstCAPIGlue.c new file mode 100644 index 00000000..d78a8085 --- /dev/null +++ b/src/VBox/Main/cbinding/tstCAPIGlue.c @@ -0,0 +1,1145 @@ +/* $Id: tstCAPIGlue.c $ */ +/** @file tstCAPIGlue.c + * Demonstrator program to illustrate use of C bindings of Main API. + * + * It has sample code showing how to retrieve all available error information, + * and how to handle active (event delivery through callbacks) or passive + * (event delivery through a polling mechanism) event listeners. + */ + +/* + * Copyright (C) 2009-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/** @todo + * Our appologies for the 256+ missing return code checks in this sample file. + * + * We strongly recomment users of the VBoxCAPI to check all return codes! + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "VBoxCAPIGlue.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifndef WIN32 +# include <signal.h> +# include <unistd.h> +# include <sys/poll.h> +#endif +#ifdef IPRT_INCLUDED_cdefs_h +# error "not supposed to involve any IPRT or VBox headers here." +#endif + +/** + * Select between active event listener (defined) and passive event listener + * (undefined). The active event listener case needs much more code, and + * additionally requires a lot more platform dependent code. + */ +#undef USE_ACTIVE_EVENT_LISTENER + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Set by Ctrl+C handler. */ +static volatile int g_fStop = 0; + +#ifdef USE_ACTIVE_EVENT_LISTENER +# ifdef WIN32 +/** The COM type information for IEventListener, for implementing IDispatch. */ +static ITypeInfo *g_pTInfoIEventListener = NULL; +# endif /* WIN32 */ +#endif /* USE_ACTIVE_EVENT_LISTENER */ + +static const char *GetStateName(MachineState_T machineState) +{ + switch (machineState) + { + case MachineState_Null: return "<null>"; + case MachineState_PoweredOff: return "PoweredOff"; + case MachineState_Saved: return "Saved"; + case MachineState_Teleported: return "Teleported"; + case MachineState_Aborted: return "Aborted"; + case MachineState_AbortedSaved: return "Aborted-Saved"; + case MachineState_Running: return "Running"; + case MachineState_Paused: return "Paused"; + case MachineState_Stuck: return "Stuck"; + case MachineState_Teleporting: return "Teleporting"; + case MachineState_LiveSnapshotting: return "LiveSnapshotting"; + case MachineState_Starting: return "Starting"; + case MachineState_Stopping: return "Stopping"; + case MachineState_Saving: return "Saving"; + case MachineState_Restoring: return "Restoring"; + case MachineState_TeleportingPausedVM: return "TeleportingPausedVM"; + case MachineState_TeleportingIn: return "TeleportingIn"; + case MachineState_DeletingSnapshotOnline: return "DeletingSnapshotOnline"; + case MachineState_DeletingSnapshotPaused: return "DeletingSnapshotPaused"; + case MachineState_RestoringSnapshot: return "RestoringSnapshot"; + case MachineState_DeletingSnapshot: return "DeletingSnapshot"; + case MachineState_SettingUp: return "SettingUp"; + default: return "no idea"; + } +} + +/** + * Ctrl+C handler, terminate event listener. + * + * Remember that most function calls are not allowed in this context (including + * printf!), so make sure that this does as little as possible. + * + * @param iInfo Platform dependent detail info (ignored). + */ +#ifdef WIN32 +static BOOL VBOX_WINAPI ctrlCHandler(DWORD iInfo) +{ + (void)iInfo; + g_fStop = 1; + return TRUE; +} +#else +static void ctrlCHandler(int iInfo) +{ + (void)iInfo; + g_fStop = 1; +} +#endif + +/** + * Sample event processing function, dumping some event information. + * Shared between active and passive event demo, to highlight that this part + * is identical between the two. + */ +static HRESULT EventListenerDemoProcessEvent(IEvent *event) +{ + VBoxEventType_T evType; + HRESULT hrc; + + if (!event) + { + printf("event null\n"); + return S_OK; + } + + evType = VBoxEventType_Invalid; + hrc = IEvent_get_Type(event, &evType); + if (FAILED(hrc)) + { + printf("cannot get event type, hrc=%#x\n", (unsigned)hrc); + return S_OK; + } + + switch (evType) + { + case VBoxEventType_OnMousePointerShapeChanged: + printf("OnMousePointerShapeChanged\n"); + break; + + case VBoxEventType_OnMouseCapabilityChanged: + printf("OnMouseCapabilityChanged\n"); + break; + + case VBoxEventType_OnKeyboardLedsChanged: + printf("OnMouseCapabilityChanged\n"); + break; + + case VBoxEventType_OnStateChanged: + { + IStateChangedEvent *ev = NULL; + enum MachineState state; + hrc = IEvent_QueryInterface(event, &IID_IStateChangedEvent, (void **)&ev); + if (FAILED(hrc)) + { + printf("cannot get StateChangedEvent interface, hrc=%#x\n", (unsigned)hrc); + return S_OK; + } + if (!ev) + { + printf("StateChangedEvent reference null\n"); + return S_OK; + } + hrc = IStateChangedEvent_get_State(ev, &state); + if (FAILED(hrc)) + printf("warning: cannot get state, hrc=%#x\n", (unsigned)hrc); + IStateChangedEvent_Release(ev); + printf("OnStateChanged: %s\n", GetStateName(state)); + + fflush(stdout); + if ( state == MachineState_PoweredOff + || state == MachineState_Saved + || state == MachineState_Teleported + || state == MachineState_Aborted + || state == MachineState_AbortedSaved + ) + g_fStop = 1; + break; + } + + case VBoxEventType_OnAdditionsStateChanged: + printf("OnAdditionsStateChanged\n"); + break; + + case VBoxEventType_OnNetworkAdapterChanged: + printf("OnNetworkAdapterChanged\n"); + break; + + case VBoxEventType_OnSerialPortChanged: + printf("OnSerialPortChanged\n"); + break; + + case VBoxEventType_OnParallelPortChanged: + printf("OnParallelPortChanged\n"); + break; + + case VBoxEventType_OnStorageControllerChanged: + printf("OnStorageControllerChanged\n"); + break; + + case VBoxEventType_OnMediumChanged: + printf("OnMediumChanged\n"); + break; + + case VBoxEventType_OnVRDEServerChanged: + printf("OnVRDEServerChanged\n"); + break; + + case VBoxEventType_OnUSBControllerChanged: + printf("OnUSBControllerChanged\n"); + break; + + case VBoxEventType_OnUSBDeviceStateChanged: + printf("OnUSBDeviceStateChanged\n"); + break; + + case VBoxEventType_OnSharedFolderChanged: + printf("OnSharedFolderChanged\n"); + break; + + case VBoxEventType_OnRuntimeError: + printf("OnRuntimeError\n"); + break; + + case VBoxEventType_OnCanShowWindow: + printf("OnCanShowWindow\n"); + break; + case VBoxEventType_OnShowWindow: + printf("OnShowWindow\n"); + break; + + default: + printf("unknown event: %d\n", evType); + } + + return S_OK; +} + +#ifdef USE_ACTIVE_EVENT_LISTENER + +struct IEventListenerDemo; +typedef struct IEventListenerDemo IEventListenerDemo; + +typedef struct IEventListenerDemoVtbl +{ + HRESULT (*QueryInterface)(IEventListenerDemo *pThis, REFIID riid, void **ppvObject); + ULONG (*AddRef)(IEventListenerDemo *pThis); + ULONG (*Release)(IEventListenerDemo *pThis); +#ifdef WIN32 + HRESULT (*GetTypeInfoCount)(IEventListenerDemo *pThis, UINT *pctinfo); + HRESULT (*GetTypeInfo)(IEventListenerDemo *pThis, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo); + HRESULT (*GetIDsOfNames)(IEventListenerDemo *pThis, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId); + HRESULT (*Invoke)(IEventListenerDemo *pThis, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr); +#endif + HRESULT (*HandleEvent)(IEventListenerDemo *pThis, IEvent *aEvent); +} IEventListenerDemoVtbl; + +typedef struct IEventListenerDemo +{ + struct IEventListenerDemoVtbl *lpVtbl; + + int cRef; + +#ifdef WIN32 + /* Active event delivery needs a free threaded marshaler, as the default + * proxy marshaling cannot deal correctly with this case. */ + IUnknown *pUnkMarshaler; +#endif +} IEventListenerDemo; + +/* Defines for easily calling IEventListenerDemo functions. */ + +/* IUnknown functions. */ +#define IEventListenerDemo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl->QueryInterface(This,riid,ppvObject) ) + +#define IEventListenerDemo_AddRef(This) \ + ( (This)->lpVtbl->AddRef(This) ) + +#define IEventListenerDemo_Release(This) \ + ( (This)->lpVtbl->Release(This) ) + +#ifdef WIN32 +/* IDispatch functions. */ +#define IEventListenerDemo_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl->GetTypeInfoCount(This,pctinfo) ) + +#define IEventListenerDemo_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl->GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IEventListenerDemo_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl->GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IEventListenerDemo_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl->Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) +#endif + +/* IEventListener functions. */ +#define IEventListenerDemo_HandleEvent(This,aEvent) \ + ( (This)->lpVtbl->HandleEvent(This,aEvent) ) + + +/** + * Event handler function, for active event processing. + */ +static HRESULT IEventListenerDemoImpl_HandleEvent(IEventListenerDemo *pThis, IEvent *event) +{ + return EventListenerDemoProcessEvent(event); +} + +static HRESULT IEventListenerDemoImpl_QueryInterface(IEventListenerDemo *pThis, const IID *iid, void **resultp) +{ + /* match iid */ + if ( !memcmp(iid, &IID_IEventListener, sizeof(IID)) + || !memcmp(iid, &IID_IDispatch, sizeof(IID)) + || !memcmp(iid, &IID_IUnknown, sizeof(IID))) + { + IEventListenerDemo_AddRef(pThis); + *resultp = pThis; + return S_OK; + } +#ifdef WIN32 + if (!memcmp(iid, &IID_IMarshal, sizeof(IID))) + return IUnknown_QueryInterface(pThis->pUnkMarshaler, iid, resultp); +#endif + + return E_NOINTERFACE; +} + +static HRESULT IEventListenerDemoImpl_AddRef(IEventListenerDemo *pThis) +{ + return ++(pThis->cRef); +} + +static HRESULT IEventListenerDemoImpl_Release(IEventListenerDemo *pThis) +{ + HRESULT c; + + c = --(pThis->cRef); + if (!c) + free(pThis); + return c; +} + +#ifdef WIN32 +static HRESULT IEventListenerDemoImpl_GetTypeInfoCount(IEventListenerDemo *pThis, UINT *pctinfo) +{ + if (!pctinfo) + return E_POINTER; + *pctinfo = 1; + return S_OK; +} + +static HRESULT IEventListenerDemoImpl_GetTypeInfo(IEventListenerDemo *pThis, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + if (!ppTInfo) + return E_POINTER; + ITypeInfo_AddRef(g_pTInfoIEventListener); + *ppTInfo = g_pTInfoIEventListener; + return S_OK; +} + +static HRESULT IEventListenerDemoImpl_GetIDsOfNames(IEventListenerDemo *pThis, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + return ITypeInfo_GetIDsOfNames(g_pTInfoIEventListener, rgszNames, cNames, rgDispId); +} + +static HRESULT IEventListenerDemoImpl_Invoke(IEventListenerDemo *pThis, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + return ITypeInfo_Invoke(g_pTInfoIEventListener, (IDispatch *)pThis, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT LoadTypeInfo(REFIID riid, ITypeInfo **pTInfo) +{ + HRESULT hrc; + ITypeLib *pTypeLib; + hrc = LoadRegTypeLib(&LIBID_VirtualBox, 1 /* major */, 0 /* minor */, 0 /* lcid */, &pTypeLib); + if (FAILED(hrc)) + return hrc; + hrc = ITypeLib_GetTypeInfoOfGuid(pTypeLib, riid, pTInfo); + + /* No longer need access to the type lib, release it. */ + ITypeLib_Release(pTypeLib); + + return hrc; +} +#endif + +#ifdef __GNUC__ +typedef struct IEventListenerDemoVtblInt +{ + ptrdiff_t offset_to_top; + void *typeinfo; + IEventListenerDemoVtbl lpVtbl; +} IEventListenerDemoVtblInt; + +static IEventListenerDemoVtblInt g_IEventListenerDemoVtblInt = +{ + 0, /* offset_to_top */ + NULL, /* typeinfo, not vital */ + { + IEventListenerDemoImpl_QueryInterface, + IEventListenerDemoImpl_AddRef, + IEventListenerDemoImpl_Release, +#ifdef WIN32 + IEventListenerDemoImpl_GetTypeInfoCount, + IEventListenerDemoImpl_GetTypeInfo, + IEventListenerDemoImpl_GetIDsOfNames, + IEventListenerDemoImpl_Invoke, +#endif + IEventListenerDemoImpl_HandleEvent + } +}; +#elif defined(_MSC_VER) +typedef struct IEventListenerDemoVtblInt +{ + IEventListenerDemoVtbl lpVtbl; +} IEventListenerDemoVtblInt; + +static IEventListenerDemoVtblInt g_IEventListenerDemoVtblInt = +{ + { + IEventListenerDemoImpl_QueryInterface, + IEventListenerDemoImpl_AddRef, + IEventListenerDemoImpl_Release, +#ifdef WIN32 + IEventListenerDemoImpl_GetTypeInfoCount, + IEventListenerDemoImpl_GetTypeInfo, + IEventListenerDemoImpl_GetIDsOfNames, + IEventListenerDemoImpl_Invoke, +#endif + IEventListenerDemoImpl_HandleEvent + } +}; +#else +# error Port me! +#endif + +/** + * Register active event listener for the selected VM. + * + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + */ +static void registerActiveEventListener(IVirtualBox *virtualBox, ISession *session) +{ + IConsole *console = NULL; + HRESULT hrc; + + hrc = ISession_get_Console(session, &console); + if (SUCCEEDED(hrc) && console) + { + IEventSource *es = NULL; + hrc = IConsole_get_EventSource(console, &es); + if (SUCCEEDED(hrc) && es) + { + static const ULONG s_auInterestingEvents[] = + { + VBoxEventType_OnMousePointerShapeChanged, + VBoxEventType_OnMouseCapabilityChanged, + VBoxEventType_OnKeyboardLedsChanged, + VBoxEventType_OnStateChanged, + VBoxEventType_OnAdditionsStateChanged, + VBoxEventType_OnNetworkAdapterChanged, + VBoxEventType_OnSerialPortChanged, + VBoxEventType_OnParallelPortChanged, + VBoxEventType_OnStorageControllerChanged, + VBoxEventType_OnMediumChanged, + VBoxEventType_OnVRDEServerChanged, + VBoxEventType_OnUSBControllerChanged, + VBoxEventType_OnUSBDeviceStateChanged, + VBoxEventType_OnSharedFolderChanged, + VBoxEventType_OnRuntimeError, + VBoxEventType_OnCanShowWindow, + VBoxEventType_OnShowWindow + }; + SAFEARRAY *interestingEventsSA = NULL; + IEventListenerDemo *consoleListener = NULL; + + /* The VirtualBox API expects enum values as VT_I4, which in the + * future can be hopefully relaxed. */ + interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, + sizeof(s_auInterestingEvents) + / sizeof(s_auInterestingEvents[0])); + g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &s_auInterestingEvents, + sizeof(s_auInterestingEvents)); + + consoleListener = calloc(1, sizeof(IEventListenerDemo)); + if (consoleListener) + { + consoleListener->lpVtbl = &(g_IEventListenerDemoVtblInt.lpVtbl); +#ifdef WIN32 + CoCreateFreeThreadedMarshaler((IUnknown *)consoleListener, &consoleListener->pUnkMarshaler); +#endif + IEventListenerDemo_AddRef(consoleListener); + + hrc = IEventSource_RegisterListener(es, (IEventListener *)consoleListener, + ComSafeArrayAsInParam(interestingEventsSA), + 1 /* active */); + if (SUCCEEDED(hrc)) + { + /* Just wait here for events, no easy way to do this better + * as there's not much to do after this completes. */ + printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n"); + fflush(stdout); +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, TRUE); +#else + signal(SIGINT, (void (*)(int))ctrlCHandler); +#endif + + while (!g_fStop) + g_pVBoxFuncs->pfnProcessEventQueue(250); + +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, FALSE); +#else + signal(SIGINT, SIG_DFL); +#endif + } + else + printf("Failed to register event listener.\n"); + IEventSource_UnregisterListener(es, (IEventListener *)consoleListener); +#ifdef WIN32 + if (consoleListener->pUnkMarshaler) + IUnknown_Release(consoleListener->pUnkMarshaler); +#endif + IEventListenerDemo_Release(consoleListener); + } + else + printf("Failed while allocating memory for console event listener.\n"); + g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA); + IEventSource_Release(es); + } + else + printf("Failed to get the event source instance.\n"); + IConsole_Release(console); + } +} + +#else /* !USE_ACTIVE_EVENT_LISTENER */ + +/** + * Register passive event listener for the selected VM. + * + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + */ +static void registerPassiveEventListener(ISession *session) +{ + IConsole *console = NULL; + HRESULT hrc; + + hrc = ISession_get_Console(session, &console); + if (SUCCEEDED(hrc) && console) + { + IEventSource *es = NULL; + hrc = IConsole_get_EventSource(console, &es); + if (SUCCEEDED(hrc) && es) + { + static const ULONG s_auInterestingEvents[] = + { + VBoxEventType_OnMousePointerShapeChanged, + VBoxEventType_OnMouseCapabilityChanged, + VBoxEventType_OnKeyboardLedsChanged, + VBoxEventType_OnStateChanged, + VBoxEventType_OnAdditionsStateChanged, + VBoxEventType_OnNetworkAdapterChanged, + VBoxEventType_OnSerialPortChanged, + VBoxEventType_OnParallelPortChanged, + VBoxEventType_OnStorageControllerChanged, + VBoxEventType_OnMediumChanged, + VBoxEventType_OnVRDEServerChanged, + VBoxEventType_OnUSBControllerChanged, + VBoxEventType_OnUSBDeviceStateChanged, + VBoxEventType_OnSharedFolderChanged, + VBoxEventType_OnRuntimeError, + VBoxEventType_OnCanShowWindow, + VBoxEventType_OnShowWindow + }; + SAFEARRAY *interestingEventsSA = NULL; + IEventListener *consoleListener = NULL; + + /* The VirtualBox API expects enum values as VT_I4, which in the + * future can be hopefully relaxed. */ + interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, + sizeof(s_auInterestingEvents) + / sizeof(s_auInterestingEvents[0])); + g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &s_auInterestingEvents, + sizeof(s_auInterestingEvents)); + + hrc = IEventSource_CreateListener(es, &consoleListener); + if (SUCCEEDED(hrc) && consoleListener) + { + hrc = IEventSource_RegisterListener(es, consoleListener, + ComSafeArrayAsInParam(interestingEventsSA), + 0 /* passive */); + if (SUCCEEDED(hrc)) + { + /* Just wait here for events, no easy way to do this better + * as there's not much to do after this completes. */ + printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n"); + fflush(stdout); +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, TRUE); +#else + signal(SIGINT, ctrlCHandler); +#endif + + while (!g_fStop) + { + IEvent *ev = NULL; + hrc = IEventSource_GetEvent(es, consoleListener, 250, &ev); + if (FAILED(hrc)) + { + printf("Failed getting event: %#x\n", (unsigned)hrc); + g_fStop = 1; + continue; + } + /* handle timeouts, resulting in NULL events */ + if (!ev) + continue; + hrc = EventListenerDemoProcessEvent(ev); + if (FAILED(hrc)) + { + printf("Failed processing event: %#x\n", (unsigned)hrc); + g_fStop = 1; + /* finish processing the event */ + } + hrc = IEventSource_EventProcessed(es, consoleListener, ev); + if (FAILED(hrc)) + { + printf("Failed to mark event as processed: %#x\n", (unsigned)hrc); + g_fStop = 1; + /* continue with event release */ + } + if (ev) + { + IEvent_Release(ev); + ev = NULL; + } + } + +#ifdef WIN32 + SetConsoleCtrlHandler(ctrlCHandler, FALSE); +#else + signal(SIGINT, SIG_DFL); +#endif + } + else + printf("Failed to register event listener.\n"); + IEventSource_UnregisterListener(es, (IEventListener *)consoleListener); + IEventListener_Release(consoleListener); + } + else + printf("Failed to create an event listener instance.\n"); + g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA); + IEventSource_Release(es); + } + else + printf("Failed to get the event source instance.\n"); + IConsole_Release(console); + } +} + +#endif /* !USE_ACTIVE_EVENT_LISTENER */ + +/** + * Print detailed error information if available. + * @param pszExecutable string with the executable name + * @param pszErrorMsg string containing the code location specific error message + * @param hrc COM/XPCOM result code + */ +static void PrintErrorInfo(const char *pszExecutable, const char *pszErrorMsg, HRESULT hrc) +{ + IErrorInfo *ex; + HRESULT hrc2; + fprintf(stderr, "%s: %s (hrc=%#010x)\n", pszExecutable, pszErrorMsg, (unsigned)hrc); + hrc2 = g_pVBoxFuncs->pfnGetException(&ex); + if (SUCCEEDED(hrc2) && ex) + { + IVirtualBoxErrorInfo *ei; + hrc2 = IErrorInfo_QueryInterface(ex, &IID_IVirtualBoxErrorInfo, (void **)&ei); + if (SUCCEEDED(hrc2) && ei != NULL) + { + /* got extended error info, maybe multiple infos */ + do + { + LONG resultCode = S_OK; + BSTR componentUtf16 = NULL; + char *component = NULL; + BSTR textUtf16 = NULL; + char *text = NULL; + IVirtualBoxErrorInfo *ei_next = NULL; + fprintf(stderr, "Extended error info (IVirtualBoxErrorInfo):\n"); + + IVirtualBoxErrorInfo_get_ResultCode(ei, &resultCode); + fprintf(stderr, " resultCode=%#010x\n", (unsigned)resultCode); + + IVirtualBoxErrorInfo_get_Component(ei, &componentUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(componentUtf16, &component); + g_pVBoxFuncs->pfnComUnallocString(componentUtf16); + fprintf(stderr, " component=%s\n", component); + g_pVBoxFuncs->pfnUtf8Free(component); + + IVirtualBoxErrorInfo_get_Text(ei, &textUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text); + g_pVBoxFuncs->pfnComUnallocString(textUtf16); + fprintf(stderr, " text=%s\n", text); + g_pVBoxFuncs->pfnUtf8Free(text); + + hrc2 = IVirtualBoxErrorInfo_get_Next(ei, &ei_next); + if (FAILED(hrc2)) + ei_next = NULL; + IVirtualBoxErrorInfo_Release(ei); + ei = ei_next; + } while (ei); + } + + IErrorInfo_Release(ex); + g_pVBoxFuncs->pfnClearException(); + } +} + +/** + * Start a VM. + * + * @param argv0 executable name + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + * @param id identifies the machine to start + */ +static void startVM(const char *argv0, IVirtualBox *virtualBox, ISession *session, BSTR id) +{ + HRESULT hrc; + IMachine *machine = NULL; + IProgress *progress = NULL; + SAFEARRAY *env = NULL; + BSTR sessionType; + SAFEARRAY *groupsSA = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc(); + + hrc = IVirtualBox_FindMachine(virtualBox, id, &machine); + if (FAILED(hrc) || !machine) + { + PrintErrorInfo(argv0, "Error: Couldn't get the Machine reference", hrc); + return; + } + + hrc = IMachine_get_Groups(machine, ComSafeArrayAsOutTypeParam(groupsSA, BSTR)); + if (SUCCEEDED(hrc)) + { + BSTR *groups = NULL; + ULONG cbGroups = 0; + ULONG i, cGroups; + g_pVBoxFuncs->pfnSafeArrayCopyOutParamHelper((void **)&groups, &cbGroups, VT_BSTR, groupsSA); + g_pVBoxFuncs->pfnSafeArrayDestroy(groupsSA); + cGroups = cbGroups / sizeof(groups[0]); + for (i = 0; i < cGroups; ++i) + { + /* Note that the use of %S might be tempting, but it is not + * available on all platforms, and even where it is usable it + * may depend on correct compiler options to make wchar_t a + * 16 bit number. So better play safe and use UTF-8. */ + char *group; + g_pVBoxFuncs->pfnUtf16ToUtf8(groups[i], &group); + printf("Groups[%u]: %s\n", (unsigned)i, group); + g_pVBoxFuncs->pfnUtf8Free(group); + } + for (i = 0; i < cGroups; ++i) + g_pVBoxFuncs->pfnComUnallocString(groups[i]); + g_pVBoxFuncs->pfnArrayOutFree(groups); + } + + g_pVBoxFuncs->pfnUtf8ToUtf16("gui", &sessionType); + hrc = IMachine_LaunchVMProcess(machine, session, sessionType, ComSafeArrayAsInParam(env), &progress); + g_pVBoxFuncs->pfnUtf16Free(sessionType); + if (SUCCEEDED(hrc)) + { + BOOL completed; + LONG resultCode; + + printf("Waiting for the remote session to open...\n"); + IProgress_WaitForCompletion(progress, -1); + + hrc = IProgress_get_Completed(progress, &completed); + if (FAILED(hrc)) + fprintf(stderr, "Error: GetCompleted status failed\n"); + + IProgress_get_ResultCode(progress, &resultCode); + if (FAILED(resultCode)) + { + IVirtualBoxErrorInfo *errorInfo; + BSTR textUtf16; + char *text; + + IProgress_get_ErrorInfo(progress, &errorInfo); + IVirtualBoxErrorInfo_get_Text(errorInfo, &textUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(textUtf16, &text); + printf("Error: %s\n", text); + + g_pVBoxFuncs->pfnComUnallocString(textUtf16); + g_pVBoxFuncs->pfnUtf8Free(text); + IVirtualBoxErrorInfo_Release(errorInfo); + } + else + { + fprintf(stderr, "VM process has been successfully started\n"); + + /* Kick off the event listener demo part, which is quite separate. + * Ignore it if you need a more basic sample. */ +#ifdef USE_ACTIVE_EVENT_LISTENER + registerActiveEventListener(virtualBox, session); +#else + registerPassiveEventListener(session); +#endif + } + IProgress_Release(progress); + } + else + PrintErrorInfo(argv0, "Error: LaunchVMProcess failed", hrc); + + /* It's important to always release resources. */ + IMachine_Release(machine); +} + +/** + * List the registered VMs. + * + * @param argv0 executable name + * @param virtualBox ptr to IVirtualBox object + * @param session ptr to ISession object + */ +static void listVMs(const char *argv0, IVirtualBox *virtualBox, ISession *session) +{ + HRESULT hrc; + SAFEARRAY *machinesSA = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc(); + IMachine **machines = NULL; + ULONG machineCnt = 0; + ULONG i; + unsigned start_id; + + /* + * Get the list of all registered VMs. + */ + hrc = IVirtualBox_get_Machines(virtualBox, ComSafeArrayAsOutIfaceParam(machinesSA, IMachine *)); + if (FAILED(hrc)) + { + PrintErrorInfo(argv0, "could not get list of machines", hrc); + return; + } + + /* + * Extract interface pointers from machinesSA, and update the reference + * counter of each object, as destroying machinesSA would call Release. + */ + g_pVBoxFuncs->pfnSafeArrayCopyOutIfaceParamHelper((IUnknown ***)&machines, &machineCnt, machinesSA); + g_pVBoxFuncs->pfnSafeArrayDestroy(machinesSA); + + if (!machineCnt) + { + g_pVBoxFuncs->pfnArrayOutFree(machines); + printf("\tNo VMs\n"); + return; + } + + printf("VM List:\n\n"); + + /* + * Iterate through the collection. + */ + for (i = 0; i < machineCnt; ++i) + { + IMachine *machine = machines[i]; + BOOL isAccessible = FALSE; + + printf("\tMachine #%u\n", (unsigned)i); + + if (!machine) + { + printf("\t(skipped, NULL)\n"); + continue; + } + + IMachine_get_Accessible(machine, &isAccessible); + + if (isAccessible) + { + BSTR machineNameUtf16; + char *machineName; + + IMachine_get_Name(machine, &machineNameUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(machineNameUtf16,&machineName); + g_pVBoxFuncs->pfnComUnallocString(machineNameUtf16); + printf("\tName: %s\n", machineName); + g_pVBoxFuncs->pfnUtf8Free(machineName); + } + else + printf("\tName: <inaccessible>\n"); + + { + BSTR uuidUtf16; + char *uuidUtf8; + + IMachine_get_Id(machine, &uuidUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(uuidUtf16, &uuidUtf8); + g_pVBoxFuncs->pfnComUnallocString(uuidUtf16); + printf("\tUUID: %s\n", uuidUtf8); + g_pVBoxFuncs->pfnUtf8Free(uuidUtf8); + } + + if (isAccessible) + { + { + BSTR configFileUtf16; + char *configFileUtf8; + + IMachine_get_SettingsFilePath(machine, &configFileUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(configFileUtf16, &configFileUtf8); + g_pVBoxFuncs->pfnComUnallocString(configFileUtf16); + printf("\tConfig file: %s\n", configFileUtf8); + g_pVBoxFuncs->pfnUtf8Free(configFileUtf8); + } + + { + ULONG memorySize; + + IMachine_get_MemorySize(machine, &memorySize); + printf("\tMemory size: %uMB\n", (unsigned)memorySize); + } + + { + BSTR typeId; + BSTR osNameUtf16; + char *osName; + IGuestOSType *osType = NULL; + + IMachine_get_OSTypeId(machine, &typeId); + IVirtualBox_GetGuestOSType(virtualBox, typeId, &osType); + g_pVBoxFuncs->pfnComUnallocString(typeId); + IGuestOSType_get_Description(osType, &osNameUtf16); + g_pVBoxFuncs->pfnUtf16ToUtf8(osNameUtf16,&osName); + g_pVBoxFuncs->pfnComUnallocString(osNameUtf16); + printf("\tGuest OS: %s\n\n", osName); + g_pVBoxFuncs->pfnUtf8Free(osName); + + IGuestOSType_Release(osType); + } + } + } + + /* + * Let the user chose a machine to start. + */ + printf("Type Machine# to start (0 - %u) or 'quit' to do nothing: ", + (unsigned)(machineCnt - 1)); + fflush(stdout); + + if (scanf("%u", &start_id) == 1 && start_id < machineCnt) + { + IMachine *machine = machines[start_id]; + + if (machine) + { + BSTR uuidUtf16 = NULL; + + IMachine_get_Id(machine, &uuidUtf16); + startVM(argv0, virtualBox, session, uuidUtf16); + g_pVBoxFuncs->pfnComUnallocString(uuidUtf16); + } + } + + /* + * Don't forget to release the objects in the array. + */ + for (i = 0; i < machineCnt; ++i) + { + IMachine *machine = machines[i]; + + if (machine) + IMachine_Release(machine); + } + g_pVBoxFuncs->pfnArrayOutFree(machines); +} + +/* Main - Start the ball rolling. */ + +int main(int argc, char **argv) +{ + IVirtualBoxClient *vboxclient = NULL; + IVirtualBox *vbox = NULL; + ISession *session = NULL; + ULONG revision = 0; + BSTR versionUtf16 = NULL; + BSTR homefolderUtf16 = NULL; + HRESULT hrc; /* Result code of various function (method) calls. */ + (void)argc; + + printf("Starting main()\n"); + + if (VBoxCGlueInit()) + { + fprintf(stderr, "%s: FATAL: VBoxCGlueInit failed: %s\n", + argv[0], g_szVBoxErrMsg); + return EXIT_FAILURE; + } + + { + unsigned ver = g_pVBoxFuncs->pfnGetVersion(); + printf("VirtualBox version: %u.%u.%u\n", ver / 1000000, ver / 1000 % 1000, ver % 1000); + ver = g_pVBoxFuncs->pfnGetAPIVersion(); + printf("VirtualBox API version: %u.%u\n", ver / 1000, ver % 1000); + } + + g_pVBoxFuncs->pfnClientInitialize(NULL, &vboxclient); + if (!vboxclient) + { + fprintf(stderr, "%s: FATAL: could not get VirtualBoxClient reference\n", argv[0]); + return EXIT_FAILURE; + } + + printf("----------------------------------------------------\n"); + + hrc = IVirtualBoxClient_get_VirtualBox(vboxclient, &vbox); + if (FAILED(hrc) || !vbox) + { + PrintErrorInfo(argv[0], "FATAL: could not get VirtualBox reference", hrc); + return EXIT_FAILURE; + } + hrc = IVirtualBoxClient_get_Session(vboxclient, &session); + if (FAILED(hrc) || !session) + { + PrintErrorInfo(argv[0], "FATAL: could not get Session reference", hrc); + return EXIT_FAILURE; + } + +#ifdef USE_ACTIVE_EVENT_LISTENER +# ifdef WIN32 + hrc = LoadTypeInfo(&IID_IEventListener, &g_pTInfoIEventListener); + if (FAILED(hrc) || !g_pTInfoIEventListener) + { + PrintErrorInfo(argv[0], "FATAL: could not get type information for IEventListener", hrc); + return EXIT_FAILURE; + } +# endif /* WIN32 */ +#endif /* USE_ACTIVE_EVENT_LISTENER */ + + /* + * Now ask for revision, version and home folder information of + * this vbox. Were not using fancy macros here so it + * remains easy to see how we access C++'s vtable. + */ + + /* 1. Revision */ + hrc = IVirtualBox_get_Revision(vbox, &revision); + if (SUCCEEDED(hrc)) + printf("\tRevision: %u\n", (unsigned)revision); + else + PrintErrorInfo(argv[0], "GetRevision() failed", hrc); + + /* 2. Version */ + hrc = IVirtualBox_get_Version(vbox, &versionUtf16); + if (SUCCEEDED(hrc)) + { + char *version = NULL; + g_pVBoxFuncs->pfnUtf16ToUtf8(versionUtf16, &version); + printf("\tVersion: %s\n", version); + g_pVBoxFuncs->pfnUtf8Free(version); + g_pVBoxFuncs->pfnComUnallocString(versionUtf16); + } + else + PrintErrorInfo(argv[0], "GetVersion() failed", hrc); + + /* 3. Home Folder */ + hrc = IVirtualBox_get_HomeFolder(vbox, &homefolderUtf16); + if (SUCCEEDED(hrc)) + { + char *homefolder = NULL; + g_pVBoxFuncs->pfnUtf16ToUtf8(homefolderUtf16, &homefolder); + printf("\tHomeFolder: %s\n", homefolder); + g_pVBoxFuncs->pfnUtf8Free(homefolder); + g_pVBoxFuncs->pfnComUnallocString(homefolderUtf16); + } + else + PrintErrorInfo(argv[0], "GetHomeFolder() failed", hrc); + + listVMs(argv[0], vbox, session); + ISession_UnlockMachine(session); + + printf("----------------------------------------------------\n"); + + /* + * Do as mom told us: always clean up after yourself. + */ +#ifdef USE_ACTIVE_EVENT_LISTENER +# ifdef WIN32 + if (g_pTInfoIEventListener) + { + ITypeInfo_Release(g_pTInfoIEventListener); + g_pTInfoIEventListener = NULL; + } +# endif /* WIN32 */ +#endif /* USE_ACTIVE_EVENT_LISTENER */ + + if (session) + { + ISession_Release(session); + session = NULL; + } + if (vbox) + { + IVirtualBox_Release(vbox); + vbox = NULL; + } + if (vboxclient) + { + IVirtualBoxClient_Release(vboxclient); + vboxclient = NULL; + } + + g_pVBoxFuncs->pfnClientUninitialize(); + VBoxCGlueTerm(); + printf("Finished main()\n"); + + return 0; +} +/* vim: set ts=4 sw=4 et: */ |