diff --git a/configure.ac b/configure.ac index 7a53c7d78c..558bb7757b 100644 --- a/configure.ac +++ b/configure.ac @@ -358,12 +358,23 @@ AC_DEFINE_UNQUOTED([VBOX_XPCOMC_DIR], ["$vbox_xpcomc_dir"], [Location of directory containing VirtualBox XPCOMC library]) if test "x$with_vbox" = "xyes"; then - AC_SEARCH_LIBS([dlopen], [dl], [], [AC_MSG_ERROR([Unable to find dlopen()])]) + AC_SEARCH_LIBS([dlopen], [dl],,) case $ac_cv_search_dlopen in - no*) DLOPEN_LIBS= ;; + no*) DLOPEN_LIBS= + case "$host" in + *-*-mingw* | *-*-msvc*) ;; + *) AC_MSG_ERROR([Unable to find dlopen()]) ;; + esac ;; *) DLOPEN_LIBS=$ac_cv_search_dlopen ;; esac AC_SUBST([DLOPEN_LIBS]) + + case "$host" in + *-*-mingw* | *-*-msvc*) MSCOM_LIBS="-lole32 -loleaut32" ;; + *) MSCOM_LIBS= ;; + esac + AC_SUBST([MSCOM_LIBS]) + AC_DEFINE_UNQUOTED([WITH_VBOX], 1, [whether VirtualBox driver is enabled]) fi AM_CONDITIONAL([WITH_VBOX], [test "$with_vbox" = "yes"]) @@ -2419,6 +2430,11 @@ AC_MSG_NOTICE([ nl: $LIBNL_CFLAGS $LIBNL_LIBS]) else AC_MSG_NOTICE([ nl: no]) fi +if test "$with_vbox" = "yes" && test -n "$MSCOM_LIBS" ; then +AC_MSG_NOTICE([ mscom: $MSCOM_LIBS]) +else +AC_MSG_NOTICE([ mscom: no]) +fi AC_MSG_NOTICE([]) AC_MSG_NOTICE([Test suite]) AC_MSG_NOTICE([]) diff --git a/po/POTFILES.in b/po/POTFILES.in index 090de3b936..3b851f1e91 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -103,6 +103,7 @@ src/util/util.c src/util/virtaudit.c src/util/virterror.c src/util/xml.c +src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c src/vbox/vbox_driver.c src/vbox/vbox_tmpl.c diff --git a/src/Makefile.am b/src/Makefile.am index 0f28f46290..6749786d59 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -259,14 +259,17 @@ VMWARE_DRIVER_SOURCES = \ vmware/vmware_conf.c vmware/vmware_conf.h VBOX_DRIVER_SOURCES = \ - vbox/vbox_XPCOMCGlue.c vbox/vbox_XPCOMCGlue.h \ + vbox/vbox_glue.c vbox/vbox_glue.h \ vbox/vbox_driver.c vbox/vbox_driver.h \ vbox/vbox_V2_2.c vbox/vbox_CAPI_v2_2.h \ vbox/vbox_V3_0.c vbox/vbox_CAPI_v3_0.h \ vbox/vbox_V3_1.c vbox/vbox_CAPI_v3_1.h \ vbox/vbox_V3_2.c vbox/vbox_CAPI_v3_2.h -VBOX_DRIVER_EXTRA_DIST = vbox/vbox_tmpl.c vbox/README +VBOX_DRIVER_EXTRA_DIST = \ + vbox/vbox_tmpl.c vbox/README \ + vbox/vbox_MSCOMGlue.c vbox/vbox_MSCOMGlue.h \ + vbox/vbox_XPCOMCGlue.c vbox/vbox_XPCOMCGlue.h QEMU_DRIVER_SOURCES = \ qemu/qemu_capabilities.c qemu/qemu_capabilities.h\ @@ -634,7 +637,7 @@ libvirt_la_BUILT_LIBADD += libvirt_driver_vbox.la endif libvirt_driver_vbox_la_CFLAGS = \ -I@top_srcdir@/src/conf $(AM_CFLAGS) -libvirt_driver_vbox_la_LIBADD = $(DLOPEN_LIBS) +libvirt_driver_vbox_la_LIBADD = $(DLOPEN_LIBS) $(MSCOM_LIBS) if WITH_DRIVER_MODULES libvirt_driver_vbox_la_LIBADD += ../gnulib/lib/libgnu.la libvirt_driver_vbox_la_LDFLAGS = -module -avoid-version $(AM_LDFLAGS) diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c new file mode 100644 index 0000000000..b1663b1b45 --- /dev/null +++ b/src/vbox/vbox_MSCOMGlue.c @@ -0,0 +1,648 @@ + +/* + * vbox_MSCOMGlue.c: glue to the MSCOM based VirtualBox API + * + * Copyright (C) 2010 Matthias Bolte + * + * 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 + +#include + +#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 int +vboxLookupVersionInRegistry(void) +{ + int result = -1; + const char *keyName = VBOX_REGKEY_ORACLE; + LONG status; + HKEY key; + DWORD type; + DWORD length; + 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) { + VIR_ERROR(_("Could not open registry key '%s' nor '%s'"), + VBOX_REGKEY_ORACLE, VBOX_REGKEY_SUN); + return -1; + } + } + + status = RegQueryValueEx(key, "Version", NULL, &type, NULL, &length); + + if (status != ERROR_SUCCESS) { + VIR_ERROR(_("Could not query registry value '%s\\Version'"), keyName); + goto cleanup; + } + + if (type != REG_SZ) { + VIR_ERROR(_("Registry value '%s\\Version' has unexpected type"), keyName); + goto cleanup; + } + + if (length < 2) { + VIR_ERROR(_("Registry value '%s\\Version' is too short"), keyName); + 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, "Version", NULL, NULL, (LPBYTE)value, &length); + + if (status != ERROR_SUCCESS) { + VIR_ERROR(_("Could not query registry value '%s\\Version'"), keyName); + goto cleanup; + } + + if (value[length - 1] != '\0') { + value[length] = '\0'; + } + + if (virParseVersionString(value, &vboxVersion)) { + 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) +{ +} diff --git a/src/vbox/vbox_MSCOMGlue.h b/src/vbox/vbox_MSCOMGlue.h new file mode 100644 index 0000000000..1d91f09f81 --- /dev/null +++ b/src/vbox/vbox_MSCOMGlue.h @@ -0,0 +1,33 @@ + +/* + * vbox_MSCOMGlue.h: glue to the MSCOM based VirtualBox API + * + * Copyright (C) 2010 Matthias Bolte + * + * 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 + * + */ + +#ifndef __VBOX_MSCOMGLUE_H__ +# define __VBOX_MSCOMGLUE_H__ + +# include "vbox_CAPI_v3_2.h" + +extern PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions; + +int VBoxCGlueInit(unsigned int *version); +void VBoxCGlueTerm(void); + +#endif /* __VBOX_MSCOMGLUE_H__ */ diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index d73e799c7b..03e66bc2e7 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -64,9 +64,9 @@ * Global Variables * *******************************************************************************/ /** The dlopen handle for VBoxXPCOMC. */ -void *g_hVBoxXPCOMC = NULL; +static void *hVBoxXPCOMC = NULL; /** Pointer to the VBoxXPCOMC function table. */ -PCVBOXXPCOM g_pVBoxFuncs = NULL; +static PCVBOXXPCOM pVBoxFuncs_v2_2 = NULL; /** Pointer to VBoxGetXPCOMCFunctions for the loaded VBoxXPCOMC so/dylib/dll. */ PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions = NULL; @@ -80,8 +80,11 @@ PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions = NULL; * be NULL. * @param setAppHome Whether to set the VBOX_APP_HOME env.var. or not. * @param ignoreMissing Whether to ignore missing library or not. + * @param version Version number of the loaded API. */ -static int tryLoadOne(const char *dir, bool setAppHome, bool ignoreMissing) +static int +tryLoadOne(const char *dir, bool setAppHome, bool ignoreMissing, + unsigned int *version) { int result = -1; char *name = NULL; @@ -122,9 +125,9 @@ static int tryLoadOne(const char *dir, bool setAppHome, bool ignoreMissing) } } - g_hVBoxXPCOMC = dlopen(name, RTLD_NOW | RTLD_LOCAL); + hVBoxXPCOMC = dlopen(name, RTLD_NOW | RTLD_LOCAL); - if (g_hVBoxXPCOMC == NULL) { + if (hVBoxXPCOMC == NULL) { /* * FIXME: Don't warn in this case as it currently breaks make check * on systems without VirtualBox. @@ -137,7 +140,7 @@ static int tryLoadOne(const char *dir, bool setAppHome, bool ignoreMissing) } pfnGetFunctions = (PFNVBOXGETXPCOMCFUNCTIONS) - dlsym(g_hVBoxXPCOMC, VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME); + dlsym(hVBoxXPCOMC, VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME); if (pfnGetFunctions == NULL) { VIR_ERROR(_("Could not dlsym %s from '%s': %s"), @@ -145,14 +148,15 @@ static int tryLoadOne(const char *dir, bool setAppHome, bool ignoreMissing) goto cleanup; } - g_pVBoxFuncs = pfnGetFunctions(VBOX_XPCOMC_VERSION); + pVBoxFuncs_v2_2 = pfnGetFunctions(VBOX_XPCOMC_VERSION); - if (g_pVBoxFuncs == NULL) { + if (pVBoxFuncs_v2_2 == NULL) { VIR_ERROR(_("Calling %s from '%s' failed"), VBOX_GET_XPCOMC_FUNCTIONS_SYMBOL_NAME, name); goto cleanup; } + *version = pVBoxFuncs_v2_2->pfnGetVersion(); g_pfnGetFunctions = pfnGetFunctions; result = 0; @@ -163,9 +167,9 @@ static int tryLoadOne(const char *dir, bool setAppHome, bool ignoreMissing) } cleanup: - if (g_hVBoxXPCOMC != NULL && result < 0) { - dlclose(g_hVBoxXPCOMC); - g_hVBoxXPCOMC = NULL; + if (hVBoxXPCOMC != NULL && result < 0) { + dlclose(hVBoxXPCOMC); + hVBoxXPCOMC = NULL; } VIR_FREE(name); @@ -180,7 +184,8 @@ cleanup: * * @returns 0 on success, -1 on failure. */ -int VBoxCGlueInit(void) +int +VBoxCGlueInit(unsigned int *version) { int i; static const char *knownDirs[] = { @@ -203,27 +208,27 @@ int VBoxCGlueInit(void) /* If the user specifies the location, try only that. */ if (home != NULL) { - if (tryLoadOne(home, false, false) < 0) { + if (tryLoadOne(home, false, false, version) < 0) { return -1; } } /* Try the additionally configured location. */ if (VBOX_XPCOMC_DIR[0] != '\0') { - if (tryLoadOne(VBOX_XPCOMC_DIR, true, true) >= 0) { + if (tryLoadOne(VBOX_XPCOMC_DIR, true, true, version) >= 0) { return 0; } } /* Try the known locations. */ for (i = 0; i < ARRAY_CARDINALITY(knownDirs); ++i) { - if (tryLoadOne(knownDirs[i], true, true) >= 0) { + if (tryLoadOne(knownDirs[i], true, true, version) >= 0) { return 0; } } /* Finally try the dynamic linker search path. */ - if (tryLoadOne(NULL, false, true) >= 0) { + if (tryLoadOne(NULL, false, true, version) >= 0) { return 0; } @@ -235,15 +240,16 @@ int VBoxCGlueInit(void) /** * Terminate the C glue library. */ -void VBoxCGlueTerm(void) +void +VBoxCGlueTerm(void) { - if (g_hVBoxXPCOMC != NULL) { + if (hVBoxXPCOMC != NULL) { #if 0 /* VBoxRT.so doesn't like being reloaded. See @bugref{3725}. */ dlclose(g_hVBoxXPCOMC); #endif - g_hVBoxXPCOMC = NULL; + hVBoxXPCOMC = NULL; } - g_pVBoxFuncs = NULL; + pVBoxFuncs_v2_2 = NULL; g_pfnGetFunctions = NULL; } diff --git a/src/vbox/vbox_XPCOMCGlue.h b/src/vbox/vbox_XPCOMCGlue.h index 6c4403087e..1fa873a26a 100644 --- a/src/vbox/vbox_XPCOMCGlue.h +++ b/src/vbox/vbox_XPCOMCGlue.h @@ -32,12 +32,10 @@ /* This has to be the oldest version we support. */ # include "vbox_CAPI_v2_2.h" -/** Pointer to the VBoxXPCOMC function table. */ -extern PCVBOXXPCOM g_pVBoxFuncs; /** Pointer to VBoxGetXPCOMCFunctions for the loaded VBoxXPCOMC so/dylib/dll. */ extern PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions; -int VBoxCGlueInit(void); +int VBoxCGlueInit(unsigned int *version); void VBoxCGlueTerm(void); #endif diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index 3704f8cea6..b39a63b3ab 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -38,8 +38,9 @@ #include "datatypes.h" #include "logging.h" #include "vbox_driver.h" -#include "vbox_XPCOMCGlue.h" +#include "vbox_glue.h" #include "virterror_internal.h" +#include "util.h" #define VIR_FROM_THIS VIR_FROM_VBOX @@ -82,8 +83,7 @@ int vboxRegister(void) { storageDriver = &vbox22StorageDriver; /* Init the glue and get the API version. */ - if (VBoxCGlueInit() == 0) { - uVersion = g_pVBoxFuncs->pfnGetVersion(); + if (VBoxCGlueInit(&uVersion) == 0) { DEBUG("VBoxCGlueInit found API version: %d.%d.%d (%u)", uVersion / 1000000, uVersion % 1000000 / 1000, diff --git a/src/vbox/vbox_glue.c b/src/vbox/vbox_glue.c new file mode 100644 index 0000000000..5fca843769 --- /dev/null +++ b/src/vbox/vbox_glue.c @@ -0,0 +1,29 @@ + +/* + * vbox_glue.c: glue to the VirtualBox API + * + * Copyright (C) 2010 Matthias Bolte + * + * 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 + +#ifdef WIN32 +# include "vbox_MSCOMGlue.c" +#else +# include "vbox_XPCOMCGlue.c" +#endif diff --git a/src/vbox/vbox_glue.h b/src/vbox/vbox_glue.h new file mode 100644 index 0000000000..bbc244b146 --- /dev/null +++ b/src/vbox/vbox_glue.h @@ -0,0 +1,32 @@ + +/* + * vbox_glue.h: glue to the VirtualBox API + * + * Copyright (C) 2010 Matthias Bolte + * + * 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 + * + */ + +#ifndef __VBOX_GLUE_H__ +# define __VBOX_GLUE_H__ + +# ifdef WIN32 +# include "vbox_MSCOMGlue.h" +# else +# include "vbox_XPCOMCGlue.h" +# endif + +#endif /* __VBOX_GLUE_H__ */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 5ae611ac99..6a4589c87d 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -34,12 +34,11 @@ #include -#include #include #include +#include #include "internal.h" - #include "datatypes.h" #include "domain_conf.h" #include "network_conf.h" @@ -68,7 +67,7 @@ #endif /* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */ -#include "vbox_XPCOMCGlue.h" +#include "vbox_glue.h" #define VIR_FROM_THIS VIR_FROM_VBOX @@ -705,10 +704,9 @@ no_memory: return NULL; } -static int vboxInitialize(vboxGlobalData *data) { - - /* Get the API table for out version, g_pVBoxFuncs is for the oldest - version of the API that we support so we cannot use that. */ +static int +vboxInitialize(vboxGlobalData *data) +{ data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION); if (data->pFuncs == NULL)