mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-18 18:45:16 +00:00
fc920f704c
There are a large number of different header files that are related to the sockets APIs. The virsocket.h header includes all of the relevant headers for Windows and UNIX in one convenient place. If virsocketaddr.h is already included, then there's no need for virsocket.h Reviewed-by: Pavel Hrdina <phrdina@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
780 lines
20 KiB
C
780 lines
20 KiB
C
/*
|
|
* vbox_MSCOMGlue.c: glue to the MSCOM based VirtualBox API
|
|
*
|
|
* Copyright (C) 2013 Red Hat, Inc.
|
|
* Copyright (C) 2010-2011 Matthias Bolte <matthias.bolte@googlemail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#define nsCID CLSID
|
|
|
|
#include "internal.h"
|
|
#include "viralloc.h"
|
|
#include "virlog.h"
|
|
#include "virerror.h"
|
|
#include "virstring.h"
|
|
#include "virutil.h"
|
|
#include "virsocket.h"
|
|
#include "vbox_MSCOMGlue.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_VBOX
|
|
|
|
VIR_LOG_INIT("vbox.vbox_MSCOMGlue");
|
|
|
|
#define VBOX_REGKEY_ORACLE "Software\\Oracle\\VirtualBox"
|
|
#define VBOX_REGKEY_SUN "Software\\Sun\\xVM VirtualBox"
|
|
|
|
#define IVIRTUALBOX_IID_STR_v2_2 "779264f4-65ed-48ed-be39-518ca549e296"
|
|
#define ISESSION_IID_STR_v2_2 "12F4DCDB-12B2-4ec1-B7CD-DDD9F6C5BF4D"
|
|
|
|
|
|
|
|
typedef struct _VBOXXPCOMC_v1 VBOXXPCOMC_v1;
|
|
typedef struct _VBOXXPCOMC_v2 VBOXXPCOMC_v2;
|
|
|
|
struct _VBOXXPCOMC_v1 {
|
|
unsigned cb;
|
|
unsigned uVersion;
|
|
unsigned int (*pfnGetVersion)(void);
|
|
void (*pfnComInitialize)(IVirtualBox **virtualBox, ISession **session);
|
|
void (*pfnComUninitialize)(void);
|
|
void (*pfnComUnallocMem)(void *pv);
|
|
void (*pfnUtf16Free)(PRUnichar *pwszString);
|
|
void (*pfnUtf8Free)(char *pszString);
|
|
int (*pfnUtf16ToUtf8)(const PRUnichar *pwszString, char **ppszString);
|
|
int (*pfnUtf8ToUtf16)(const char *pszString, PRUnichar **ppwszString);
|
|
unsigned uEndVersion;
|
|
};
|
|
|
|
struct _VBOXXPCOMC_v2 {
|
|
unsigned cb;
|
|
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)(PRUnichar *pwszString);
|
|
void (*pfnUtf8Free)(char *pszString);
|
|
int (*pfnUtf16ToUtf8)(const PRUnichar *pwszString, char **ppszString);
|
|
int (*pfnUtf8ToUtf16)(const char *pszString, PRUnichar **ppwszString);
|
|
void (*pfnGetEventQueue)(nsIEventQueue **eventQueue);
|
|
unsigned uEndVersion;
|
|
};
|
|
|
|
|
|
|
|
PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions = NULL;
|
|
|
|
static unsigned long vboxVersion;
|
|
static IVirtualBox *vboxVirtualBox;
|
|
static ISession *vboxSession;
|
|
|
|
|
|
|
|
/*
|
|
* nsISupports dummy implementation
|
|
*/
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_QueryInterface(nsISupports *pThis G_GNUC_UNUSED,
|
|
const nsID *iid G_GNUC_UNUSED,
|
|
void **resultp G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_AddRef(nsISupports *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_Release(nsISupports *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_GetTypeInfoCount(nsISupports *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_GetTypeInfo(nsISupports *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_GetIDsOfNames(nsISupports *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_Invoke(nsISupports *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* nsIEventTarget dummy implementation
|
|
*/
|
|
|
|
static nsresult __stdcall
|
|
vboxEventTarget_PostEvent(nsIEventTarget *pThis G_GNUC_UNUSED,
|
|
PLEvent *aEvent G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventTarget_IsOnCurrentThread(nsIEventTarget *pThis G_GNUC_UNUSED,
|
|
PRBool *_retval G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* nsIEventQueue dummy implementation
|
|
*/
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_InitEvent(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PLEvent *aEvent G_GNUC_UNUSED,
|
|
void *owner G_GNUC_UNUSED,
|
|
PLHandleEventProc handler G_GNUC_UNUSED,
|
|
PLDestroyEventProc destructor G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_PostSynchronousEvent(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PLEvent *aEvent G_GNUC_UNUSED,
|
|
void **aResult G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_PendingEvents(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PRBool *_retval G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_ProcessPendingEvents(nsIEventQueue *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_EventLoop(nsIEventQueue *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_EventAvailable(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PRBool *aResult G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_GetEvent(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PLEvent **_retval G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_HandleEvent(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PLEvent *aEvent G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_WaitForEvent(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PLEvent **_retval G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static PRInt32 __stdcall
|
|
vboxEventQueue_GetEventQueueSelectFD(nsIEventQueue *pThis G_GNUC_UNUSED)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_Init(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PRBool aNative G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_InitFromPRThread(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PRThread *thread G_GNUC_UNUSED,
|
|
PRBool aNative G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_InitFromPLQueue(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PLEventQueue *aQueue G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_EnterMonitor(nsIEventQueue *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_ExitMonitor(nsIEventQueue *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_RevokeEvents(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
void *owner G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_GetPLEventQueue(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PLEventQueue **_retval G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_IsQueueNative(nsIEventQueue *pThis G_GNUC_UNUSED,
|
|
PRBool *_retval G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_StopAcceptingEvents(nsIEventQueue *pThis G_GNUC_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static struct nsIEventQueue_vtbl vboxEventQueueVtbl = {
|
|
{
|
|
{
|
|
vboxSupports_QueryInterface,
|
|
vboxSupports_AddRef,
|
|
vboxSupports_Release,
|
|
|
|
vboxSupports_GetTypeInfoCount,
|
|
vboxSupports_GetTypeInfo,
|
|
vboxSupports_GetIDsOfNames,
|
|
vboxSupports_Invoke
|
|
},
|
|
|
|
vboxEventTarget_PostEvent,
|
|
vboxEventTarget_IsOnCurrentThread
|
|
},
|
|
|
|
vboxEventQueue_InitEvent,
|
|
vboxEventQueue_PostSynchronousEvent,
|
|
vboxEventQueue_PendingEvents,
|
|
vboxEventQueue_ProcessPendingEvents,
|
|
vboxEventQueue_EventLoop,
|
|
vboxEventQueue_EventAvailable,
|
|
vboxEventQueue_GetEvent,
|
|
vboxEventQueue_HandleEvent,
|
|
vboxEventQueue_WaitForEvent,
|
|
vboxEventQueue_GetEventQueueSelectFD,
|
|
vboxEventQueue_Init,
|
|
vboxEventQueue_InitFromPRThread,
|
|
vboxEventQueue_InitFromPLQueue,
|
|
vboxEventQueue_EnterMonitor,
|
|
vboxEventQueue_ExitMonitor,
|
|
vboxEventQueue_RevokeEvents,
|
|
vboxEventQueue_GetPLEventQueue,
|
|
vboxEventQueue_IsQueueNative,
|
|
vboxEventQueue_StopAcceptingEvents,
|
|
};
|
|
|
|
static nsIEventQueue vboxEventQueue = {
|
|
&vboxEventQueueVtbl
|
|
};
|
|
|
|
|
|
|
|
static char *
|
|
vboxLookupRegistryValue(HKEY key, const char *keyName, const char *valueName)
|
|
{
|
|
LONG status;
|
|
DWORD type;
|
|
DWORD length;
|
|
char *value = NULL;
|
|
|
|
status = RegQueryValueEx(key, valueName, NULL, &type, NULL, &length);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
VIR_ERROR(_("Could not query registry value '%s\\%s'"),
|
|
keyName, valueName);
|
|
return NULL;
|
|
}
|
|
|
|
if (type != REG_SZ) {
|
|
VIR_ERROR(_("Registry value '%s\\%s' has unexpected type"),
|
|
keyName, valueName);
|
|
return NULL;
|
|
}
|
|
|
|
if (length < 2) {
|
|
VIR_ERROR(_("Registry value '%s\\%s' is too short"),
|
|
keyName, valueName);
|
|
return NULL;
|
|
}
|
|
|
|
/* +1 for the null-terminator if it's missing */
|
|
if (VIR_ALLOC_N(value, length + 1) < 0)
|
|
return NULL;
|
|
|
|
status = RegQueryValueEx(key, valueName, NULL, NULL, (LPBYTE)value, &length);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
VIR_FREE(value);
|
|
VIR_ERROR(_("Could not query registry value '%s\\%s'"),
|
|
keyName, valueName);
|
|
return NULL;
|
|
}
|
|
|
|
if (value[length - 1] != '\0')
|
|
value[length] = '\0';
|
|
|
|
return value;
|
|
}
|
|
|
|
static int
|
|
vboxLookupVersionInRegistry(void)
|
|
{
|
|
int result = -1;
|
|
const char *keyName = VBOX_REGKEY_ORACLE;
|
|
LONG status;
|
|
HKEY key;
|
|
char *value = NULL;
|
|
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
keyName = VBOX_REGKEY_SUN;
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
/* Both keys aren't there, or we cannot open them. In general this
|
|
* indicates that VirtualBox is not installed, so we just silently
|
|
* fail here making vboxRegister() register the dummy driver. */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* The registry key layout changed around version 4.0.8. Before the version
|
|
* number was in the Version key, now the Version key can contain %VER% and
|
|
* the actual version number is in the VersionExt key then. */
|
|
value = vboxLookupRegistryValue(key, keyName, "Version");
|
|
|
|
if (value == NULL)
|
|
goto cleanup;
|
|
|
|
if (STREQ(value, "%VER%")) {
|
|
VIR_FREE(value);
|
|
value = vboxLookupRegistryValue(key, keyName, "VersionExt");
|
|
|
|
if (value == NULL)
|
|
goto cleanup;
|
|
}
|
|
|
|
if (virParseVersionString(value, &vboxVersion, false) < 0) {
|
|
VIR_ERROR(_("Could not parse version number from '%s'"), value);
|
|
goto cleanup;
|
|
}
|
|
|
|
result = 0;
|
|
|
|
cleanup:
|
|
VIR_FREE(value);
|
|
RegCloseKey(key);
|
|
|
|
return result;
|
|
}
|
|
|
|
static unsigned int
|
|
vboxGetVersion(void)
|
|
{
|
|
return vboxVersion;
|
|
}
|
|
|
|
static void
|
|
vboxComUnallocMem(void *pv)
|
|
{
|
|
SysFreeString(pv);
|
|
}
|
|
|
|
static void
|
|
vboxUtf16Free(PRUnichar *pwszString)
|
|
{
|
|
SysFreeString(pwszString);
|
|
}
|
|
|
|
static void
|
|
vboxUtf8Free(char *pszString)
|
|
{
|
|
VIR_FREE(pszString);
|
|
}
|
|
|
|
static int
|
|
vboxUtf16ToUtf8(const PRUnichar *pwszString, char **ppszString)
|
|
{
|
|
int length = WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, NULL, 0,
|
|
NULL, NULL);
|
|
|
|
if (length < 1)
|
|
return -1;
|
|
|
|
if (VIR_ALLOC_N(*ppszString, length) < 0)
|
|
return -1;
|
|
|
|
return WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, *ppszString,
|
|
length, NULL, NULL);
|
|
}
|
|
|
|
static int
|
|
vboxUtf8ToUtf16(const char *pszString, PRUnichar **ppwszString)
|
|
{
|
|
int length = MultiByteToWideChar(CP_UTF8, 0, pszString, -1, NULL, 0);
|
|
|
|
if (length < 1)
|
|
return -1;
|
|
|
|
*ppwszString = SysAllocStringLen(NULL, length);
|
|
|
|
if (*ppwszString == NULL)
|
|
return -1;
|
|
|
|
return MultiByteToWideChar(CP_UTF8, 0, pszString, -1, *ppwszString, length);
|
|
}
|
|
|
|
static void
|
|
vboxGetEventQueue(nsIEventQueue **eventQueue)
|
|
{
|
|
*eventQueue = &vboxEventQueue;
|
|
}
|
|
|
|
static void
|
|
vboxComInitialize_v2(const char *pszVirtualBoxIID, IVirtualBox **ppVirtualBox,
|
|
const char *pszSessionIID, ISession **ppSession)
|
|
{
|
|
int result = -1;
|
|
HRESULT hrc;
|
|
IID virtualBoxIID;
|
|
IID sessionIID;
|
|
char *mbsVirtualBoxIID = NULL;
|
|
char *mbsSessionIID = NULL;
|
|
PRUnichar *wcsVirtualBoxIID = NULL;
|
|
PRUnichar *wcsSessionIID = NULL;
|
|
|
|
*ppVirtualBox = NULL;
|
|
*ppSession = NULL;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
mbsVirtualBoxIID = g_strdup_printf("{%s}", pszVirtualBoxIID);
|
|
mbsSessionIID = g_strdup_printf("{%s}", pszSessionIID)
|
|
goto cleanup;
|
|
|
|
if (vboxUtf8ToUtf16(mbsVirtualBoxIID, &wcsVirtualBoxIID) < 0 ||
|
|
vboxUtf8ToUtf16(mbsSessionIID, &wcsSessionIID) < 0) {
|
|
goto cleanup;
|
|
}
|
|
|
|
hrc = IIDFromString(wcsVirtualBoxIID, &virtualBoxIID);
|
|
|
|
if (FAILED(hrc)) {
|
|
VIR_ERROR(_("Could not parse IID from '%s', rc = 0x%08x"),
|
|
pszVirtualBoxIID, (unsigned int)hrc);
|
|
goto cleanup;
|
|
}
|
|
|
|
hrc = IIDFromString(wcsSessionIID, &sessionIID);
|
|
|
|
if (FAILED(hrc)) {
|
|
VIR_ERROR(_("Could not parse IID from '%s', rc = 0x%08x"),
|
|
pszVirtualBoxIID, (unsigned int)hrc);
|
|
goto cleanup;
|
|
}
|
|
|
|
hrc = CoCreateInstance(&CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER,
|
|
&virtualBoxIID, (void**)&vboxVirtualBox);
|
|
|
|
if (FAILED(hrc)) {
|
|
VIR_ERROR(_("Could not create VirtualBox instance, rc = 0x%08x"),
|
|
(unsigned int)hrc);
|
|
goto cleanup;
|
|
}
|
|
|
|
hrc = CoCreateInstance(&CLSID_Session, NULL, CLSCTX_INPROC_SERVER,
|
|
&sessionIID, (void**)&vboxSession);
|
|
|
|
if (FAILED(hrc)) {
|
|
VIR_ERROR(_("Could not create Session instance, rc = 0x%08x"),
|
|
(unsigned int)hrc);
|
|
goto cleanup;
|
|
}
|
|
|
|
*ppVirtualBox = vboxVirtualBox;
|
|
*ppSession = vboxSession;
|
|
|
|
result = 0;
|
|
|
|
cleanup:
|
|
if (result < 0) {
|
|
if (vboxVirtualBox != NULL) {
|
|
vboxVirtualBox->vtbl->nsisupports.Release((nsISupports *)vboxVirtualBox);
|
|
vboxVirtualBox = NULL;
|
|
}
|
|
|
|
if (vboxSession != NULL) {
|
|
vboxSession->vtbl->nsisupports.Release((nsISupports *)vboxSession);
|
|
vboxSession = NULL;
|
|
}
|
|
}
|
|
|
|
vboxUtf16Free(wcsVirtualBoxIID);
|
|
vboxUtf16Free(wcsSessionIID);
|
|
}
|
|
|
|
static void
|
|
vboxComInitialize_v1(IVirtualBox **ppVirtualBox, ISession **ppSession)
|
|
{
|
|
vboxComInitialize_v2(IVIRTUALBOX_IID_STR_v2_2, ppVirtualBox,
|
|
ISESSION_IID_STR_v2_2, ppSession);
|
|
}
|
|
|
|
static void
|
|
vboxComUninitialize(void)
|
|
{
|
|
if (vboxVirtualBox != NULL) {
|
|
vboxVirtualBox->vtbl->nsisupports.Release((nsISupports *)vboxVirtualBox);
|
|
vboxVirtualBox = NULL;
|
|
}
|
|
|
|
if (vboxSession != NULL) {
|
|
vboxSession->vtbl->nsisupports.Release((nsISupports *)vboxSession);
|
|
vboxSession = NULL;
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
|
|
|
|
static VBOXXPCOMC_v1 vboxXPCOMC_v1 = {
|
|
sizeof(VBOXXPCOMC_v1), /* cb */
|
|
0x00010000U, /* uVersion */
|
|
vboxGetVersion, /* pfnGetVersion */
|
|
vboxComInitialize_v1, /* pfnComInitialize */
|
|
vboxComUninitialize, /* pfnComUninitialize */
|
|
vboxComUnallocMem, /* pfnComUnallocMem */
|
|
vboxUtf16Free, /* pfnUtf16Free */
|
|
vboxUtf8Free, /* pfnUtf8Free */
|
|
vboxUtf16ToUtf8, /* pfnUtf16ToUtf8 */
|
|
vboxUtf8ToUtf16, /* pfnUtf8ToUtf16 */
|
|
0x00010000U /* uEndVersion */
|
|
};
|
|
|
|
static VBOXXPCOMC_v2 vboxXPCOMC_v2 = {
|
|
sizeof(VBOXXPCOMC_v2), /* cb */
|
|
0x00020000U, /* uVersion */
|
|
vboxGetVersion, /* pfnGetVersion */
|
|
vboxComInitialize_v2, /* pfnComInitialize */
|
|
vboxComUninitialize, /* pfnComUninitialize */
|
|
vboxComUnallocMem, /* pfnComUnallocMem */
|
|
vboxUtf16Free, /* pfnUtf16Free */
|
|
vboxUtf8Free, /* pfnUtf8Free */
|
|
vboxUtf16ToUtf8, /* pfnUtf16ToUtf8 */
|
|
vboxUtf8ToUtf16, /* pfnUtf8ToUtf16 */
|
|
vboxGetEventQueue, /* pfnGetEventQueue */
|
|
0x00020000U /* uEndVersion */
|
|
};
|
|
|
|
static PCVBOXXPCOM
|
|
vboxGetFunctions(unsigned int version)
|
|
{
|
|
if (version == 0x00010000U) {
|
|
return (PCVBOXXPCOM)&vboxXPCOMC_v1;
|
|
} else if (version == 0x00020000U) {
|
|
return (PCVBOXXPCOM)&vboxXPCOMC_v2;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int
|
|
VBoxCGlueInit(unsigned int *version)
|
|
{
|
|
if (vboxLookupVersionInRegistry() < 0)
|
|
return -1;
|
|
|
|
*version = vboxGetVersion();
|
|
g_pfnGetFunctions = vboxGetFunctions;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
VBoxCGlueTerm(void)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* In MSCOM an array is represented by a SAFEARRAY pointer. To access the items
|
|
* in the array the SafeArrayAccessData function is used to lock the array and
|
|
* get its contents. When the items aren't needed anymore the
|
|
* SafeArrayUnaccessData function is used to unlock the array. The pointer
|
|
* retuned by SafeArrayAccessData function becomes invalid. Finally the
|
|
* SafeArrayDestroy function is called to destroy the array, it also releases
|
|
* or frees all items in the array according to their type.
|
|
*/
|
|
|
|
typedef HRESULT __stdcall (*SafeArrayGetter)(void *self, SAFEARRAY **array);
|
|
typedef HRESULT __stdcall (*SafeArrayGetterWithPtrArg)(void *self, void *arg, SAFEARRAY **array);
|
|
typedef HRESULT __stdcall (*SafeArrayGetterWithUintArg)(void *self, PRUint32 arg, SAFEARRAY **array);
|
|
|
|
static nsresult
|
|
vboxArrayGetHelper(vboxArray *array, HRESULT hrc, SAFEARRAY *safeArray)
|
|
{
|
|
void **items = NULL;
|
|
|
|
array->items = NULL;
|
|
array->count = 0;
|
|
array->handle = NULL;
|
|
|
|
if (FAILED(hrc))
|
|
return hrc;
|
|
|
|
hrc = SafeArrayAccessData(safeArray, (void **)&items);
|
|
|
|
if (FAILED(hrc)) {
|
|
SafeArrayDestroy(safeArray);
|
|
return hrc;
|
|
}
|
|
|
|
array->items = items;
|
|
array->count = safeArray->rgsabound[0].cElements;
|
|
array->handle = safeArray;
|
|
|
|
return hrc;
|
|
}
|
|
|
|
/*
|
|
* Call the getter with self as first argument and fill the array with the
|
|
* returned items.
|
|
*/
|
|
nsresult
|
|
vboxArrayGet(vboxArray *array, void *self, void *getter)
|
|
{
|
|
HRESULT hrc;
|
|
SAFEARRAY *safeArray = NULL;
|
|
|
|
hrc = ((SafeArrayGetter)getter)(self, &safeArray);
|
|
|
|
return vboxArrayGetHelper(array, hrc, safeArray);
|
|
}
|
|
|
|
/*
|
|
* Call the getter with self as first argument and arg as second argument
|
|
* and fill the array with the returned items.
|
|
*/
|
|
nsresult
|
|
vboxArrayGetWithPtrArg(vboxArray *array, void *self, void *getter, void *arg)
|
|
{
|
|
HRESULT hrc;
|
|
SAFEARRAY *safeArray = NULL;
|
|
|
|
hrc = ((SafeArrayGetterWithPtrArg)getter)(self, arg, &safeArray);
|
|
|
|
return vboxArrayGetHelper(array, hrc, safeArray);
|
|
}
|
|
|
|
/*
|
|
* Call the getter with self as first argument and arg as second argument
|
|
* and fill the array with the returned items.
|
|
*/
|
|
nsresult
|
|
vboxArrayGetWithUintArg(vboxArray *array, void *self, void *getter, PRUint32 arg)
|
|
{
|
|
HRESULT hrc;
|
|
SAFEARRAY *safeArray = NULL;
|
|
|
|
hrc = ((SafeArrayGetterWithUintArg)getter)(self, arg, &safeArray);
|
|
|
|
return vboxArrayGetHelper(array, hrc, safeArray);
|
|
}
|
|
|
|
/*
|
|
* Release all items in the array and reset it.
|
|
*
|
|
* SafeArrayDestroy is aware of the item's type and calls release or free
|
|
* for each item according to its type. Therefore, vboxArrayUnalloc and
|
|
* vboxArrayRelease are the same for MSCOM.
|
|
*/
|
|
void
|
|
vboxArrayRelease(vboxArray *array)
|
|
{
|
|
if (array->handle == NULL)
|
|
return;
|
|
|
|
SafeArrayUnaccessData(array->handle);
|
|
SafeArrayDestroy(array->handle);
|
|
|
|
array->items = NULL;
|
|
array->count = 0;
|
|
array->handle = NULL;
|
|
}
|