summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main/cbinding/VBoxCAPI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/cbinding/VBoxCAPI.cpp')
-rw-r--r--src/VBox/Main/cbinding/VBoxCAPI.cpp1026
1 files changed, 1026 insertions, 0 deletions
diff --git a/src/VBox/Main/cbinding/VBoxCAPI.cpp b/src/VBox/Main/cbinding/VBoxCAPI.cpp
new file mode 100644
index 00000000..a0030620
--- /dev/null
+++ b/src/VBox/Main/cbinding/VBoxCAPI.cpp
@@ -0,0 +1,1026 @@
+/* $Id: VBoxCAPI.cpp $ */
+/** @file VBoxCAPI.cpp
+ * Utility functions to use with the C API binding.
+ */
+
+/*
+ * Copyright (C) 2009-2022 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 rc = SafeArrayGetVartype(psa, &vt);
+ if (FAILED(rc))
+ return rc;
+ 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;
+ rc = SafeArrayAccessData(psa, &pData);
+ if (FAILED(rc))
+ return rc;
+ 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 rc = SafeArrayAccessData(psa, &pData);
+ if (FAILED(rc))
+ return rc;
+#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 rc = SafeArrayAccessData(psa, &pData);
+ if (FAILED(rc))
+ {
+ *ppv = NULL;
+ if (pcb)
+ *pcb = 0;
+ return rc;
+ }
+ 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 rc = VBoxSafeArrayCopyOutParamHelper((void **)ppaObj, &mypcb, VT_UNKNOWN, psa);
+ if (FAILED(rc))
+ {
+ if (pcObj)
+ *pcObj = 0;
+ return rc;
+ }
+ 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 rc = com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING);
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: COM/XPCOM could not be initialized! rc=%Rhrc\n", rc));
+ VBoxComUninitialize();
+ return;
+ }
+
+#ifdef VBOX_WITH_XPCOM
+ rc = NS_GetMainEventQ(&g_EventQueue);
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: Could not get XPCOM event queue! rc=%Rhrc\n", rc));
+ VBoxComUninitialize();
+ return;
+ }
+#endif /* VBOX_WITH_XPCOM */
+
+#ifdef VBOX_WITH_XPCOM
+ nsIComponentManager *pManager;
+ rc = NS_GetComponentManager(&pManager);
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: Could not get component manager! rc=%Rhrc\n", rc));
+ VBoxComUninitialize();
+ return;
+ }
+
+ rc = pManager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID,
+ nsnull,
+ virtualBoxIID,
+ (void **)&g_VirtualBox);
+#else /* !VBOX_WITH_XPCOM */
+ IVirtualBoxClient *pVirtualBoxClient;
+ rc = CoCreateInstance(CLSID_VirtualBoxClient, NULL, CLSCTX_INPROC_SERVER, IID_IVirtualBoxClient, (void **)&pVirtualBoxClient);
+ if (SUCCEEDED(rc))
+ {
+ IVirtualBox *pVirtualBox;
+ rc = pVirtualBoxClient->get_VirtualBox(&pVirtualBox);
+ if (SUCCEEDED(rc))
+ {
+ rc = pVirtualBox->QueryInterface(virtualBoxIID, (void **)&g_VirtualBox);
+ pVirtualBox->Release();
+ }
+ pVirtualBoxClient->Release();
+ }
+#endif /* !VBOX_WITH_XPCOM */
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: Could not instantiate VirtualBox object! rc=%Rhrc\n",rc));
+#ifdef VBOX_WITH_XPCOM
+ pManager->Release();
+ pManager = NULL;
+#endif /* VBOX_WITH_XPCOM */
+ VBoxComUninitialize();
+ return;
+ }
+
+ Log(("Cbinding: IVirtualBox object created.\n"));
+
+#ifdef VBOX_WITH_XPCOM
+ rc = pManager->CreateInstanceByContractID(NS_SESSION_CONTRACTID,
+ nsnull,
+ sessionIID,
+ (void **)&g_Session);
+#else /* !VBOX_WITH_XPCOM */
+ rc = CoCreateInstance(CLSID_Session, NULL, CLSCTX_INPROC_SERVER, sessionIID, (void **)&g_Session);
+#endif /* !VBOX_WITH_XPCOM */
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: Could not instantiate Session object! rc=%Rhrc\n",rc));
+#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 rc;
+
+ *ppException = NULL;
+
+#ifdef VBOX_WITH_XPCOM
+ nsIServiceManager *mgr = NULL;
+ rc = NS_GetServiceManager(&mgr);
+ if (FAILED(rc) || !mgr)
+ return rc;
+
+ IID esid = NS_IEXCEPTIONSERVICE_IID;
+ nsIExceptionService *es = NULL;
+ rc = mgr->GetServiceByContractID(NS_EXCEPTIONSERVICE_CONTRACTID, esid, (void **)&es);
+ if (FAILED(rc) || !es)
+ {
+ mgr->Release();
+ return rc;
+ }
+
+ nsIExceptionManager *em;
+ rc = es->GetCurrentExceptionManager(&em);
+ if (FAILED(rc) || !em)
+ {
+ es->Release();
+ mgr->Release();
+ return rc;
+ }
+
+ nsIException *ex;
+ rc = em->GetCurrentException(&ex);
+ if (FAILED(rc))
+ {
+ em->Release();
+ es->Release();
+ mgr->Release();
+ return rc;
+ }
+
+ *ppException = ex;
+ em->Release();
+ es->Release();
+ mgr->Release();
+#else /* !VBOX_WITH_XPCOM */
+ IErrorInfo *ex;
+ rc = ::GetErrorInfo(0, &ex);
+ if (FAILED(rc))
+ return rc;
+
+ *ppException = ex;
+#endif /* !VBOX_WITH_XPCOM */
+
+ return rc;
+}
+
+static HRESULT
+VBoxClearException(void)
+{
+ HRESULT rc;
+
+#ifdef VBOX_WITH_XPCOM
+ nsIServiceManager *mgr = NULL;
+ rc = NS_GetServiceManager(&mgr);
+ if (FAILED(rc) || !mgr)
+ return rc;
+
+ IID esid = NS_IEXCEPTIONSERVICE_IID;
+ nsIExceptionService *es = NULL;
+ rc = mgr->GetServiceByContractID(NS_EXCEPTIONSERVICE_CONTRACTID, esid, (void **)&es);
+ if (FAILED(rc) || !es)
+ {
+ mgr->Release();
+ return rc;
+ }
+
+ nsIExceptionManager *em;
+ rc = es->GetCurrentExceptionManager(&em);
+ if (FAILED(rc) || !em)
+ {
+ es->Release();
+ mgr->Release();
+ return rc;
+ }
+
+ rc = em->SetCurrentException(NULL);
+ em->Release();
+ es->Release();
+ mgr->Release();
+#else /* !VBOX_WITH_XPCOM */
+ rc = ::SetErrorInfo(0, NULL);
+#endif /* !VBOX_WITH_XPCOM */
+
+ return rc;
+}
+
+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 rc = com::Initialize(VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_NO_COM_PATCHING);
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: COM/XPCOM could not be initialized! rc=%Rhrc\n", rc));
+ VBoxClientUninitialize();
+ return rc;
+ }
+
+#ifdef VBOX_WITH_XPCOM
+ rc = NS_GetMainEventQ(&g_EventQueue);
+ if (NS_FAILED(rc))
+ {
+ Log(("Cbinding: Could not get XPCOM event queue! rc=%Rhrc\n", rc));
+ VBoxClientUninitialize();
+ return rc;
+ }
+#endif /* VBOX_WITH_XPCOM */
+
+#ifdef VBOX_WITH_XPCOM
+ nsIComponentManager *pManager;
+ rc = NS_GetComponentManager(&pManager);
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: Could not get component manager! rc=%Rhrc\n", rc));
+ VBoxClientUninitialize();
+ return rc;
+ }
+
+ rc = pManager->CreateInstanceByContractID(NS_VIRTUALBOXCLIENT_CONTRACTID,
+ nsnull,
+ virtualBoxClientIID,
+ (void **)ppVirtualBoxClient);
+#else /* !VBOX_WITH_XPCOM */
+ rc = CoCreateInstance(CLSID_VirtualBoxClient, NULL, CLSCTX_INPROC_SERVER, virtualBoxClientIID, (void **)ppVirtualBoxClient);
+#endif /* !VBOX_WITH_XPCOM */
+ if (FAILED(rc))
+ {
+ Log(("Cbinding: Could not instantiate VirtualBoxClient object! rc=%Rhrc\n",rc));
+#ifdef VBOX_WITH_XPCOM
+ pManager->Release();
+ pManager = NULL;
+#endif /* VBOX_WITH_XPCOM */
+ VBoxClientUninitialize();
+ return rc;
+ }
+
+#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: */