mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-11-02 11:21:12 +00:00
8ce1afff88
To avoid regressions, we let callers specify whether to require a minor and micro version. Callers that were parsing uname() output benefit from defaulting to 0, whereas callers that were parsing version strings from other sources should not change in behavior. * src/util/util.c (virParseVersionString): Allow caller to choose whether to fail if minor or micro is missing. * src/util/util.h (virParseVersionString): Update signature. * src/esx/esx_driver.c (esxGetVersion): Update callers. * src/lxc/lxc_driver.c (lxcVersion): Likewise. * src/openvz/openvz_conf.c (openvzExtractVersionInfo): Likewise. * src/uml/uml_driver.c (umlGetVersion): Likewise. * src/vbox/vbox_MSCOMGlue.c (vboxLookupVersionInRegistry): Likewise. * src/vbox/vbox_tmpl.c (vboxExtractVersion): Likewise. * src/vmware/vmware_conf.c (vmwareExtractVersion): Likewise. * src/xenapi/xenapi_driver.c (xenapiGetVersion): Likewise. Reported by Matthias Bolte.
793 lines
21 KiB
C
793 lines
21 KiB
C
|
|
/*
|
|
* vbox_MSCOMGlue.c: glue to the MSCOM based VirtualBox API
|
|
*
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#define nsCID CLSID
|
|
|
|
#include "internal.h"
|
|
#include "memory.h"
|
|
#include "util.h"
|
|
#include "logging.h"
|
|
#include "virterror_internal.h"
|
|
#include "vbox_MSCOMGlue.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_VBOX
|
|
|
|
#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 ATTRIBUTE_UNUSED,
|
|
const nsID *iid ATTRIBUTE_UNUSED,
|
|
void **resultp ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_AddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_Release(nsISupports *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_GetTypeInfoCount(nsISupports *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_GetTypeInfo(nsISupports *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_GetIDsOfNames(nsISupports *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxSupports_Invoke(nsISupports *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* nsIEventTarget dummy implementation
|
|
*/
|
|
|
|
static nsresult __stdcall
|
|
vboxEventTarget_PostEvent(nsIEventTarget *pThis ATTRIBUTE_UNUSED,
|
|
PLEvent *aEvent ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventTarget_IsOnCurrentThread(nsIEventTarget *pThis ATTRIBUTE_UNUSED,
|
|
PRBool *_retval ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* nsIEventQueue dummy implementation
|
|
*/
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_InitEvent(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PLEvent *aEvent ATTRIBUTE_UNUSED,
|
|
void *owner ATTRIBUTE_UNUSED,
|
|
PLHandleEventProc handler ATTRIBUTE_UNUSED,
|
|
PLDestroyEventProc destructor ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_PostSynchronousEvent(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PLEvent *aEvent ATTRIBUTE_UNUSED,
|
|
void **aResult ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_PendingEvents(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PRBool *_retval ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_ProcessPendingEvents(nsIEventQueue *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_EventLoop(nsIEventQueue *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_EventAvailable(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PRBool *aResult ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_GetEvent(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PLEvent **_retval ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_HandleEvent(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PLEvent *aEvent ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_WaitForEvent(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PLEvent **_retval ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static PRInt32 __stdcall
|
|
vboxEventQueue_GetEventQueueSelectFD(nsIEventQueue *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_Init(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PRBool aNative ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_InitFromPRThread(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PRThread *thread ATTRIBUTE_UNUSED,
|
|
PRBool aNative ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_InitFromPLQueue(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PLEventQueue *aQueue ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_EnterMonitor(nsIEventQueue *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_ExitMonitor(nsIEventQueue *pThis ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_RevokeEvents(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
void *owner ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_GetPLEventQueue(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PLEventQueue **_retval ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_IsQueueNative(nsIEventQueue *pThis ATTRIBUTE_UNUSED,
|
|
PRBool *_retval ATTRIBUTE_UNUSED)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static nsresult __stdcall
|
|
vboxEventQueue_StopAcceptingEvents(nsIEventQueue *pThis ATTRIBUTE_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);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (type != REG_SZ) {
|
|
VIR_ERROR(_("Registry value '%s\\%s' has unexpected type"),
|
|
keyName, valueName);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (length < 2) {
|
|
VIR_ERROR(_("Registry value '%s\\%s' is too short"),
|
|
keyName, valueName);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* +1 for the null-terminator if it's missing */
|
|
if (VIR_ALLOC_N(value, length + 1) < 0) {
|
|
virReportOOMError();
|
|
goto cleanup;
|
|
}
|
|
|
|
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);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (value[length - 1] != '\0') {
|
|
value[length] = '\0';
|
|
}
|
|
|
|
cleanup:
|
|
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);
|
|
|
|
if (virAsprintf(&mbsVirtualBoxIID, "{%s}", pszVirtualBoxIID) < 0 ||
|
|
virAsprintf(&mbsSessionIID, "{%s}", pszSessionIID) < 0) {
|
|
virReportOOMError();
|
|
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;
|
|
}
|