[libvirt] [PATCH 0/6] vbox: Add Windows support

This series makes the VirtualBox driver work on Windows. On non-Windows systems VirtualBox uses XPCOM, on Windows it uses MSCOM (Microsoft COM). XPCOM and MSCOM are slightly different. This series adds a new glue layer for MSCOM. The main difference is the representation of arrays. A new vboxArray type hides the differences from the general driver code. I've tested this with the 3.x series of VirtualBox. Testing with 2.x revealed that 2.x and 3.x represent IIDs differently. This problem is not fixed by this series and will need some additional work. Therefore, the VirtualBox driver only works with the 3.x series on Windows for now. VirtualBox 4.x seems to stay in line with the 3.x COM API. I expect it to work properly on Windows once we've added general support for it. Matthias

MSCOM requires stdcall convention. --- This mail is edited and only shows the first affected method in each vbox_CAPI_v.*.h file. The complete patch is 600kb in size :) src/vbox/vbox_CAPI_v2_2.h | 1501 +++++++++++++++++++------------------- src/vbox/vbox_CAPI_v3_0.h | 1556 ++++++++++++++++++++-------------------- src/vbox/vbox_CAPI_v3_1.h | 1574 ++++++++++++++++++++-------------------- src/vbox/vbox_CAPI_v3_2.h | 1746 +++++++++++++++++++++++---------------------- src/vbox/vbox_tmpl.c | 99 ++-- 5 files changed, 3257 insertions(+), 3219 deletions(-) diff --git a/src/vbox/vbox_CAPI_v2_2.h b/src/vbox/vbox_CAPI_v2_2.h index 8058032..7a94ff5 100644 --- a/src/vbox/vbox_CAPI_v2_2.h +++ b/src/vbox/vbox_CAPI_v2_2.h @@ -55,6 +55,12 @@ # include <stddef.h> # include "wchar.h" +# ifdef WIN32 +# define PR_COM_METHOD __stdcall +# else +# define PR_COM_METHOD +# endif + # if defined(WIN32) # define PR_EXPORT(__type) extern __declspec(dllexport) __type @@ -349,7 +355,7 @@ struct nsISupports_vtbl { * instance, NS_NOINTERFACE if it is not. * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. */ - nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsresult PR_COM_METHOD (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); /** * Increases the reference count for this interface. * The associated instance will not be deleted unless diff --git a/src/vbox/vbox_CAPI_v3_0.h b/src/vbox/vbox_CAPI_v3_0.h index effd248..4ff5f83 100644 --- a/src/vbox/vbox_CAPI_v3_0.h +++ b/src/vbox/vbox_CAPI_v3_0.h @@ -55,6 +55,12 @@ # include <stddef.h> # include "wchar.h" +# ifdef WIN32 +# define PR_COM_METHOD __stdcall +# else +# define PR_COM_METHOD +# endif + # if defined(WIN32) # define PR_EXPORT(__type) extern __declspec(dllexport) __type @@ -691,7 +697,7 @@ struct nsISupports_vtbl { * instance, NS_NOINTERFACE if it is not. * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. */ - nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsresult PR_COM_METHOD (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); /** * Increases the reference count for this interface. * The associated instance will not be deleted unless diff --git a/src/vbox/vbox_CAPI_v3_1.h b/src/vbox/vbox_CAPI_v3_1.h index 3e8b153..e8ae73d 100644 --- a/src/vbox/vbox_CAPI_v3_1.h +++ b/src/vbox/vbox_CAPI_v3_1.h @@ -55,6 +55,12 @@ # include <stddef.h> # include "wchar.h" +# ifdef WIN32 +# define PR_COM_METHOD __stdcall +# else +# define PR_COM_METHOD +# endif + # if defined(WIN32) # define PR_EXPORT(__type) extern __declspec(dllexport) __type @@ -691,7 +697,7 @@ struct nsISupports_vtbl { * instance, NS_NOINTERFACE if it is not. * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. */ - nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsresult PR_COM_METHOD (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); /** * Increases the reference count for this interface. * The associated instance will not be deleted unless diff --git a/src/vbox/vbox_CAPI_v3_2.h b/src/vbox/vbox_CAPI_v3_2.h index 0f93c74..b3333b1 100644 --- a/src/vbox/vbox_CAPI_v3_2.h +++ b/src/vbox/vbox_CAPI_v3_2.h @@ -51,6 +51,12 @@ # include <stddef.h> # include "wchar.h" +# ifdef WIN32 +# define PR_COM_METHOD __stdcall +# else +# define PR_COM_METHOD +# endif + # if defined(WIN32) # define PR_EXPORT(__type) extern __declspec(dllexport) __type @@ -687,7 +693,7 @@ struct nsISupports_vtbl { * instance, NS_NOINTERFACE if it is not. * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. */ - nsresult (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); + nsresult PR_COM_METHOD (*QueryInterface)(nsISupports *pThis, const nsID *iid, void **resultp); /** * Increases the reference count for this interface. * The associated instance will not be deleted unless diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index ada71b4..5ae611a 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -6245,9 +6245,10 @@ cleanup: #else /* !(VBOX_API_VERSION == 2002) */ /* Functions needed for Callbacks */ -static nsresult vboxCallbackOnMachineStateChange (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUint32 state) { +static nsresult PR_COM_METHOD +vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis, + PRUnichar *machineId, PRUint32 state) +{ virDomainPtr dom = NULL; int event = 0; int detail = 0; @@ -6318,20 +6319,23 @@ static nsresult vboxCallbackOnMachineStateChange (IVirtualBoxCallback *pThis, return NS_OK; } -static nsresult vboxCallbackOnMachineDataChange (IVirtualBoxCallback *pThis, - PRUnichar * machineId) { +static nsresult PR_COM_METHOD +vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis, + PRUnichar *machineId) +{ DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); return NS_OK; } -static nsresult vboxCallbackOnExtraDataCanChange (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUnichar * key, - PRUnichar * value, - PRUnichar * * error ATTRIBUTE_UNUSED, - PRBool * allowChange) { +static nsresult PR_COM_METHOD +vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis, + PRUnichar *machineId, PRUnichar *key, + PRUnichar *value, + PRUnichar **error ATTRIBUTE_UNUSED, + PRBool *allowChange) +{ DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false"); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("key", key); @@ -6340,10 +6344,10 @@ static nsresult vboxCallbackOnExtraDataCanChange (IVirtualBoxCallback *pThis, return NS_OK; } -static nsresult vboxCallbackOnExtraDataChange (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUnichar * key, - PRUnichar * value) { +static nsresult PR_COM_METHOD +vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis, PRUnichar *machineId, + PRUnichar *key, PRUnichar *value) +{ DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("key", key); @@ -6353,10 +6357,10 @@ static nsresult vboxCallbackOnExtraDataChange (IVirtualBoxCallback *pThis, } # if VBOX_API_VERSION < 3001 -static nsresult vboxCallbackOnMediaRegistered (IVirtualBoxCallback *pThis, - PRUnichar * mediaId, - PRUint32 mediaType, - PRBool registered) { +static nsresult PR_COM_METHOD +vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis, PRUnichar *mediaId, + PRUint32 mediaType, PRBool registered) +{ DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false"); DEBUG("mediaType: %d", mediaType); DEBUGPRUnichar("mediaId", mediaId); @@ -6366,9 +6370,10 @@ static nsresult vboxCallbackOnMediaRegistered (IVirtualBoxCallback *pThis, # else /* VBOX_API_VERSION >= 3001 */ # endif /* VBOX_API_VERSION >= 3001 */ -static nsresult vboxCallbackOnMachineRegistered (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRBool registered) { +static nsresult PR_COM_METHOD +vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis, + PRUnichar *machineId, PRBool registered) +{ virDomainPtr dom = NULL; int event = 0; int detail = 0; @@ -6424,18 +6429,20 @@ static nsresult vboxCallbackOnMachineRegistered (IVirtualBoxCallback *pThis, return NS_OK; } -static nsresult vboxCallbackOnSessionStateChange (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUint32 state) { +static nsresult PR_COM_METHOD +vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis, + PRUnichar *machineId, PRUint32 state) +{ DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state); DEBUGPRUnichar("machineId", machineId); return NS_OK; } -static nsresult vboxCallbackOnSnapshotTaken (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUnichar * snapshotId) { +static nsresult PR_COM_METHOD +vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis, PRUnichar *machineId, + PRUnichar *snapshotId) +{ DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("snapshotId", snapshotId); @@ -6443,9 +6450,10 @@ static nsresult vboxCallbackOnSnapshotTaken (IVirtualBoxCallback *pThis, return NS_OK; } -static nsresult vboxCallbackOnSnapshotDiscarded (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUnichar * snapshotId) { +static nsresult PR_COM_METHOD +vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis, PRUnichar *machineId, + PRUnichar *snapshotId) +{ DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("snapshotId", snapshotId); @@ -6453,9 +6461,10 @@ static nsresult vboxCallbackOnSnapshotDiscarded (IVirtualBoxCallback *pThis, return NS_OK; } -static nsresult vboxCallbackOnSnapshotChange (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUnichar * snapshotId) { +static nsresult PR_COM_METHOD +vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis, PRUnichar *machineId, + PRUnichar *snapshotId) +{ DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("snapshotId", snapshotId); @@ -6463,11 +6472,11 @@ static nsresult vboxCallbackOnSnapshotChange (IVirtualBoxCallback *pThis, return NS_OK; } -static nsresult vboxCallbackOnGuestPropertyChange (IVirtualBoxCallback *pThis, - PRUnichar * machineId, - PRUnichar * name, - PRUnichar * value, - PRUnichar * flags) { +static nsresult PR_COM_METHOD +vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis, + PRUnichar *machineId, PRUnichar *name, + PRUnichar *value, PRUnichar *flags) +{ DEBUG("IVirtualBoxCallback: %p", pThis); DEBUGPRUnichar("machineId", machineId); DEBUGPRUnichar("name", name); @@ -6477,7 +6486,9 @@ static nsresult vboxCallbackOnGuestPropertyChange (IVirtualBoxCallback *pThis, return NS_OK; } -static nsresult vboxCallbackAddRef(nsISupports *pThis) { +static nsresult PR_COM_METHOD +vboxCallbackAddRef(nsISupports *pThis) +{ nsresult c; c = ++g_pVBoxGlobalData->vboxCallBackRefCount; @@ -6487,7 +6498,9 @@ static nsresult vboxCallbackAddRef(nsISupports *pThis) { return c; } -static nsresult vboxCallbackRelease(nsISupports *pThis) { +static nsresult PR_COM_METHOD +vboxCallbackRelease(nsISupports *pThis) +{ nsresult c; c = --g_pVBoxGlobalData->vboxCallBackRefCount; @@ -6502,7 +6515,9 @@ static nsresult vboxCallbackRelease(nsISupports *pThis) { return c; } -static nsresult vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp) { +static nsresult PR_COM_METHOD +vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp) +{ IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis; static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID; static const nsID isupportIID = NS_ISUPPORTS_IID; -- 1.7.0.4

On 12/17/2010 11:56 AM, Matthias Bolte wrote:
MSCOM requires stdcall convention. ---
This mail is edited and only shows the first affected method in each vbox_CAPI_v.*.h file. The complete patch is 600kb in size :)
src/vbox/vbox_CAPI_v2_2.h | 1501 +++++++++++++++++++------------------- src/vbox/vbox_CAPI_v3_0.h | 1556 ++++++++++++++++++++-------------------- src/vbox/vbox_CAPI_v3_1.h | 1574 ++++++++++++++++++++-------------------- src/vbox/vbox_CAPI_v3_2.h | 1746 +++++++++++++++++++++++---------------------- src/vbox/vbox_tmpl.c | 99 ++-- 5 files changed, 3257 insertions(+), 3219 deletions(-)
ACK (assuming of course that the remaining 600k is more of the same :) -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2010/12/17 Eric Blake <eblake@redhat.com>:
On 12/17/2010 11:56 AM, Matthias Bolte wrote:
MSCOM requires stdcall convention. ---
This mail is edited and only shows the first affected method in each vbox_CAPI_v.*.h file. The complete patch is 600kb in size :)
src/vbox/vbox_CAPI_v2_2.h | 1501 +++++++++++++++++++------------------- src/vbox/vbox_CAPI_v3_0.h | 1556 ++++++++++++++++++++-------------------- src/vbox/vbox_CAPI_v3_1.h | 1574 ++++++++++++++++++++-------------------- src/vbox/vbox_CAPI_v3_2.h | 1746 +++++++++++++++++++++++---------------------- src/vbox/vbox_tmpl.c | 99 ++-- 5 files changed, 3257 insertions(+), 3219 deletions(-)
ACK (assuming of course that the remaining 600k is more of the same :)
Thanks, pushed. Matthias

--- src/vbox/vbox_CAPI_v2_2.h | 20 ++++++++++++++++++++ src/vbox/vbox_CAPI_v3_0.h | 9 +++++++++ src/vbox/vbox_CAPI_v3_1.h | 9 +++++++++ src/vbox/vbox_CAPI_v3_2.h | 9 +++++++++ 4 files changed, 47 insertions(+), 0 deletions(-) diff --git a/src/vbox/vbox_CAPI_v2_2.h b/src/vbox/vbox_CAPI_v2_2.h index 7a94ff5..0543fdd 100644 --- a/src/vbox/vbox_CAPI_v2_2.h +++ b/src/vbox/vbox_CAPI_v2_2.h @@ -1563,6 +1563,16 @@ struct IVirtualBox_vtbl { struct nsISupports_vtbl nsisupports; +# ifdef WIN32 + /* The MSCOM implementation has some additional methods here. + * So add them here to get correct binary layout of the object. + * In API version 2.2 this affects IVirtualBox and ISession only. */ + nsresult PR_COM_METHOD (*GetTypeInfoCount)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*GetTypeInfo)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*GetIDsOfNames)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*Invoke)(IVirtualBox *pThis); +# endif + nsresult PR_COM_METHOD (*GetVersion)(IVirtualBox *pThis, PRUnichar * *version); nsresult PR_COM_METHOD (*GetRevision)(IVirtualBox *pThis, PRUint32 *revision); @@ -4567,6 +4577,16 @@ struct ISession_vtbl { struct nsISupports_vtbl nsisupports; +# ifdef WIN32 + /* The MSCOM implementation has some additional methods here. + * So add them here to get correct binary layout of the object. + * In API version 2.2 this affects IVirtualBox and ISession only. */ + nsresult PR_COM_METHOD (*GetTypeInfoCount)(ISession *pThis); + nsresult PR_COM_METHOD (*GetTypeInfo)(ISession *pThis); + nsresult PR_COM_METHOD (*GetIDsOfNames)(ISession *pThis); + nsresult PR_COM_METHOD (*Invoke)(ISession *pThis); +# endif + nsresult PR_COM_METHOD (*GetState)(ISession *pThis, PRUint32 *state); nsresult PR_COM_METHOD (*GetType)(ISession *pThis, PRUint32 *type); diff --git a/src/vbox/vbox_CAPI_v3_0.h b/src/vbox/vbox_CAPI_v3_0.h index 4ff5f83..ed8b3dd 100644 --- a/src/vbox/vbox_CAPI_v3_0.h +++ b/src/vbox/vbox_CAPI_v3_0.h @@ -716,6 +716,15 @@ struct nsISupports_vtbl { */ nsresult PR_COM_METHOD (*Release)(nsISupports *pThis); +# ifdef WIN32 + /* The MSCOM implementation has some additional methods here. + * So add them here to get correct binary layout of the object. + * In API version 3.x this affects all types. */ + nsresult PR_COM_METHOD (*GetTypeInfoCount)(nsISupports *pThis); + nsresult PR_COM_METHOD (*GetTypeInfo)(nsISupports *pThis); + nsresult PR_COM_METHOD (*GetIDsOfNames)(nsISupports *pThis); + nsresult PR_COM_METHOD (*Invoke)(nsISupports *pThis); +# endif }; struct nsISupports { diff --git a/src/vbox/vbox_CAPI_v3_1.h b/src/vbox/vbox_CAPI_v3_1.h index e8ae73d..1eb27c4 100644 --- a/src/vbox/vbox_CAPI_v3_1.h +++ b/src/vbox/vbox_CAPI_v3_1.h @@ -716,6 +716,15 @@ struct nsISupports_vtbl { */ nsresult PR_COM_METHOD (*Release)(nsISupports *pThis); +# ifdef WIN32 + /* The MSCOM implementation has some additional methods here. + * So add them here to get correct binary layout of the object. + * In API version 3.x this affects all types. */ + nsresult PR_COM_METHOD (*GetTypeInfoCount)(nsISupports *pThis); + nsresult PR_COM_METHOD (*GetTypeInfo)(nsISupports *pThis); + nsresult PR_COM_METHOD (*GetIDsOfNames)(nsISupports *pThis); + nsresult PR_COM_METHOD (*Invoke)(nsISupports *pThis); +# endif }; struct nsISupports { diff --git a/src/vbox/vbox_CAPI_v3_2.h b/src/vbox/vbox_CAPI_v3_2.h index b3333b1..0fbe2e1 100644 --- a/src/vbox/vbox_CAPI_v3_2.h +++ b/src/vbox/vbox_CAPI_v3_2.h @@ -712,6 +712,15 @@ struct nsISupports_vtbl { */ nsresult PR_COM_METHOD (*Release)(nsISupports *pThis); +# ifdef WIN32 + /* The MSCOM implementation has some additional methods here. + * So add them here to get correct binary layout of the object. + * In API version 3.x this affects all types. */ + nsresult PR_COM_METHOD (*GetTypeInfoCount)(nsISupports *pThis); + nsresult PR_COM_METHOD (*GetTypeInfo)(nsISupports *pThis); + nsresult PR_COM_METHOD (*GetIDsOfNames)(nsISupports *pThis); + nsresult PR_COM_METHOD (*Invoke)(nsISupports *pThis); +# endif }; struct nsISupports { -- 1.7.0.4

On 12/17/2010 11:56 AM, Matthias Bolte wrote:
--- src/vbox/vbox_CAPI_v2_2.h | 20 ++++++++++++++++++++ src/vbox/vbox_CAPI_v3_0.h | 9 +++++++++ src/vbox/vbox_CAPI_v3_1.h | 9 +++++++++ src/vbox/vbox_CAPI_v3_2.h | 9 +++++++++ 4 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/src/vbox/vbox_CAPI_v2_2.h b/src/vbox/vbox_CAPI_v2_2.h index 7a94ff5..0543fdd 100644 --- a/src/vbox/vbox_CAPI_v2_2.h +++ b/src/vbox/vbox_CAPI_v2_2.h @@ -1563,6 +1563,16 @@ struct IVirtualBox_vtbl { struct nsISupports_vtbl nsisupports;
+# ifdef WIN32 + /* The MSCOM implementation has some additional methods here. + * So add them here to get correct binary layout of the object. + * In API version 2.2 this affects IVirtualBox and ISession only. */ + nsresult PR_COM_METHOD (*GetTypeInfoCount)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*GetTypeInfo)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*GetIDsOfNames)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*Invoke)(IVirtualBox *pThis); +# endif
ACK. Hmm, I'm wondering if MSCOM is usable under cygwin, in which case you might have to adjust the #ifdef WIN32 into #if defined WIN32 || defined __CYGWIN; but that change should come later only after someone reports needing it to build vbox support into cygwin libvirt. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2010/12/17 Eric Blake <eblake@redhat.com>:
On 12/17/2010 11:56 AM, Matthias Bolte wrote:
--- src/vbox/vbox_CAPI_v2_2.h | 20 ++++++++++++++++++++ src/vbox/vbox_CAPI_v3_0.h | 9 +++++++++ src/vbox/vbox_CAPI_v3_1.h | 9 +++++++++ src/vbox/vbox_CAPI_v3_2.h | 9 +++++++++ 4 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/src/vbox/vbox_CAPI_v2_2.h b/src/vbox/vbox_CAPI_v2_2.h index 7a94ff5..0543fdd 100644 --- a/src/vbox/vbox_CAPI_v2_2.h +++ b/src/vbox/vbox_CAPI_v2_2.h @@ -1563,6 +1563,16 @@ struct IVirtualBox_vtbl { struct nsISupports_vtbl nsisupports;
+# ifdef WIN32 + /* The MSCOM implementation has some additional methods here. + * So add them here to get correct binary layout of the object. + * In API version 2.2 this affects IVirtualBox and ISession only. */ + nsresult PR_COM_METHOD (*GetTypeInfoCount)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*GetTypeInfo)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*GetIDsOfNames)(IVirtualBox *pThis); + nsresult PR_COM_METHOD (*Invoke)(IVirtualBox *pThis); +# endif
ACK. Hmm, I'm wondering if MSCOM is usable under cygwin, in which case you might have to adjust the #ifdef WIN32 into #if defined WIN32 || defined __CYGWIN; but that change should come later only after someone reports needing it to build vbox support into cygwin libvirt.
Thanks, pushed. Matthias

Don't require dlopen, but link to ole32 and oleaut32 on Windows. Don't expose g_pVBoxFuncs anymore. It was only used to get the version of the API. Make VBoxCGlueInit return the version instead. This simplifies the implementation of the MSCOM glue layer. Get the VirtualBox version from the registry. Add a dummy implementation of the nsIEventQueue to the MSCOM glue as there seems to be no direct equivalent with MSCOM. It might be implemented using the normal window message loop. This requires additional investigation. --- configure.ac | 15 +- po/POTFILES.in | 1 + src/Makefile.am | 9 +- src/vbox/vbox_MSCOMGlue.c | 649 ++++++++++++++++++++++++++++++++++++++++++++ src/vbox/vbox_MSCOMGlue.h | 33 +++ src/vbox/vbox_XPCOMCGlue.c | 46 ++-- src/vbox/vbox_XPCOMCGlue.h | 4 +- src/vbox/vbox_driver.c | 6 +- src/vbox/vbox_glue.c | 29 ++ src/vbox/vbox_glue.h | 32 +++ src/vbox/vbox_tmpl.c | 12 +- 11 files changed, 798 insertions(+), 38 deletions(-) create mode 100644 src/vbox/vbox_MSCOMGlue.c create mode 100644 src/vbox/vbox_MSCOMGlue.h create mode 100644 src/vbox/vbox_glue.c create mode 100644 src/vbox/vbox_glue.h diff --git a/configure.ac b/configure.ac index 64e76dc..cedd50f 100644 --- a/configure.ac +++ b/configure.ac @@ -352,12 +352,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"]) diff --git a/po/POTFILES.in b/po/POTFILES.in index 355df0b..0f4cf70 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 64e890f..d72a929 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -257,14 +257,17 @@ OPENVZ_DRIVER_SOURCES = \ openvz/openvz_driver.c openvz/openvz_driver.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\ @@ -617,7 +620,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 0000000..81a2c99 --- /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 <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 = NULL; +static ISession *vboxSession = NULL; + + + +/* + * 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 0000000..1d91f09 --- /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 <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 + * + */ + +#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 d73e799..03e66bc 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 6c44030..1fa873a 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 3704f8c..b39a63b 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 0000000..5fca843 --- /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 <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> + +#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 0000000..bbc244b --- /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 <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 + * + */ + +#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 5ae611a..6a4589c 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -34,12 +34,11 @@ #include <config.h> -#include <dlfcn.h> #include <sys/utsname.h> #include <stdbool.h> +#include <unistd.h> #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) -- 1.7.0.4

On 12/17/2010 11:56 AM, Matthias Bolte wrote:
Don't require dlopen, but link to ole32 and oleaut32 on Windows.
Don't expose g_pVBoxFuncs anymore. It was only used to get the version of the API. Make VBoxCGlueInit return the version instead. This simplifies the implementation of the MSCOM glue layer.
Get the VirtualBox version from the registry.
Add a dummy implementation of the nsIEventQueue to the MSCOM glue as there seems to be no direct equivalent with MSCOM. It might be implemented using the normal window message loop. This requires additional investigation. --- configure.ac | 15 +- po/POTFILES.in | 1 + src/Makefile.am | 9 +- src/vbox/vbox_MSCOMGlue.c | 649 ++++++++++++++++++++++++++++++++++++++++++++ src/vbox/vbox_MSCOMGlue.h | 33 +++ src/vbox/vbox_XPCOMCGlue.c | 46 ++-- src/vbox/vbox_XPCOMCGlue.h | 4 +- src/vbox/vbox_driver.c | 6 +- src/vbox/vbox_glue.c | 29 ++ src/vbox/vbox_glue.h | 32 +++ src/vbox/vbox_tmpl.c | 12 +- 11 files changed, 798 insertions(+), 38 deletions(-) create mode 100644 src/vbox/vbox_MSCOMGlue.c create mode 100644 src/vbox/vbox_MSCOMGlue.h create mode 100644 src/vbox/vbox_glue.c create mode 100644 src/vbox/vbox_glue.h
+ + case "$host" in + *-*-mingw* | *-*-msvc*) MSCOM_LIBS="-lole32 -loleaut32" ;; + *) MSCOM_LIBS= ;; + esac + AC_SUBST([MSCOM_LIBS])
Should we also modify the tail end of ./configure output to display what values were set in $MSCOM_LIBS, as is done for various other libraries? But that's a minor nit.
+ +PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions = NULL; + +static unsigned long vboxVersion; +static IVirtualBox *vboxVirtualBox = NULL; +static ISession *vboxSession = NULL;
Is the explicit NULL initialization needed here, or are you okay relying on C-mandated 0-initialization of .bss variables? At any rate, ACK. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2010/12/17 Eric Blake <eblake@redhat.com>:
On 12/17/2010 11:56 AM, Matthias Bolte wrote:
Don't require dlopen, but link to ole32 and oleaut32 on Windows.
Don't expose g_pVBoxFuncs anymore. It was only used to get the version of the API. Make VBoxCGlueInit return the version instead. This simplifies the implementation of the MSCOM glue layer.
Get the VirtualBox version from the registry.
Add a dummy implementation of the nsIEventQueue to the MSCOM glue as there seems to be no direct equivalent with MSCOM. It might be implemented using the normal window message loop. This requires additional investigation. --- configure.ac | 15 +- po/POTFILES.in | 1 + src/Makefile.am | 9 +- src/vbox/vbox_MSCOMGlue.c | 649 ++++++++++++++++++++++++++++++++++++++++++++ src/vbox/vbox_MSCOMGlue.h | 33 +++ src/vbox/vbox_XPCOMCGlue.c | 46 ++-- src/vbox/vbox_XPCOMCGlue.h | 4 +- src/vbox/vbox_driver.c | 6 +- src/vbox/vbox_glue.c | 29 ++ src/vbox/vbox_glue.h | 32 +++ src/vbox/vbox_tmpl.c | 12 +- 11 files changed, 798 insertions(+), 38 deletions(-) create mode 100644 src/vbox/vbox_MSCOMGlue.c create mode 100644 src/vbox/vbox_MSCOMGlue.h create mode 100644 src/vbox/vbox_glue.c create mode 100644 src/vbox/vbox_glue.h
+ + case "$host" in + *-*-mingw* | *-*-msvc*) MSCOM_LIBS="-lole32 -loleaut32" ;; + *) MSCOM_LIBS= ;; + esac + AC_SUBST([MSCOM_LIBS])
Should we also modify the tail end of ./configure output to display what values were set in $MSCOM_LIBS, as is done for various other libraries? But that's a minor nit.
Yes, good idea. I'll fold this in. @@ -2430,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([])
+ +PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions = NULL; + +static unsigned long vboxVersion; +static IVirtualBox *vboxVirtualBox = NULL; +static ISession *vboxSession = NULL;
Is the explicit NULL initialization needed here, or are you okay relying on C-mandated 0-initialization of .bss variables?
Sure, no problem. I'll remove the NULL initialization.
At any rate, ACK.
Thanks, pushed. Matthias

On 18/12/2010, at 9:23 AM, Matthias Bolte wrote:
2010/12/17 Eric Blake <eblake@redhat.com>:
On 12/17/2010 11:56 AM, Matthias Bolte wrote:
Don't require dlopen, but link to ole32 and oleaut32 on Windows.
Don't expose g_pVBoxFuncs anymore. It was only used to get the version of the API. Make VBoxCGlueInit return the version instead. This simplifies the implementation of the MSCOM glue layer.
Turns out this commit broke ./configure on OSX. It now gives: checking for modprobe... no checking where to write libvirtd PID file... ${prefix}/var/run/libvirtd.pid checking for init script flavor... none checking for iptables... /sbin/iptables checking for ebtables... /sbin/ebtables checking for xdrmem_create in -lportablexdr... no checking for library containing xdrmem_create... none required checking for xdr_u_int64_t... yes checking for library containing dlopen... none required configure: error: Unable to find dlopen() $ Rolling back to the commit directly before it, abd0e1d, allows things to work. Anyone up for having a look at it? My brain's not up to the task atm. :(

On 12/20/2010 06:59 AM, Justin Clift wrote:
checking for xdr_u_int64_t... yes checking for library containing dlopen... none required configure: error: Unable to find dlopen() $
Rolling back to the commit directly before it, abd0e1d, allows things to work.
Sounds like the same problem as cygwin is having.
Anyone up for having a look at it? My brain's not up to the task atm. :(
In which case, we may already have a solution: https://www.redhat.com/archives/libvir-list/2010-December/msg00754.html -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On 12/17/2010 11:56 AM, Matthias Bolte wrote:
Don't require dlopen, but link to ole32 and oleaut32 on Windows.
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 ;;
Sorry for not testing this on cygwin earlier - it breaks, because on cygwin, dlopen is part of libc, so $ac_cv_search_dlopen is set to "none required", which happens to match the no*) case. How about instead doing: case $ac_cv_search_dlopen:$host in no:*-*-mingw* | no:*-*-msvc*) ;; no:*) AC_MSG_ERROR([Unable to find dlopen()]) ;; *) DLOPEN_LIBS=$ac_cv_search_dlopen ;; esac I'm testing that now; if it works, I'll post the formal patch. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On 12/18/2010 01:10 AM, Eric Blake wrote:
case $ac_cv_search_dlopen:$host in no:*-*-mingw* | no:*-*-msvc*) ;; no:*) AC_MSG_ERROR([Unable to find dlopen()]) ;;
'none required:*') DLOPEN_LIBS= ;;
*) DLOPEN_LIBS=$ac_cv_search_dlopen ;; esac
? Paolo

Add a vboxArray to hide the details from the general driver code. --- src/vbox/vbox_MSCOMGlue.c | 107 +++++++++++ src/vbox/vbox_MSCOMGlue.h | 15 ++ src/vbox/vbox_XPCOMCGlue.c | 115 ++++++++++++ src/vbox/vbox_XPCOMCGlue.h | 14 ++ src/vbox/vbox_tmpl.c | 445 +++++++++++++++++++------------------------- 5 files changed, 447 insertions(+), 249 deletions(-) diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index 81a2c99..ded1275 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -647,3 +647,110 @@ 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 get's 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 (*SaveArrayGetter)(void *self, SAFEARRAY **array); +typedef HRESULT __stdcall (*SaveArrayGetterWithArg)(void *self, void *arg, SAFEARRAY **array); + +/* + * 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; + void **items = NULL; + + array->items = NULL; + array->count = 0; + array->handle = NULL; + + hrc = ((SaveArrayGetter)getter)(self, &safeArray); + + 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 arg as second argument + * and fill the array with the returned items. + */ +nsresult +vboxArrayGetWithArg(vboxArray *array, void *self, void *getter, void *arg) +{ + HRESULT hrc; + SAFEARRAY *safeArray = NULL; + void **items = NULL; + + array->items = NULL; + array->count = 0; + array->handle = NULL; + + hrc = ((SaveArrayGetterWithArg)getter)(self, arg, &safeArray); + + 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; +} + +/* + * 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; +} diff --git a/src/vbox/vbox_MSCOMGlue.h b/src/vbox/vbox_MSCOMGlue.h index 1d91f09..f1d6c74 100644 --- a/src/vbox/vbox_MSCOMGlue.h +++ b/src/vbox/vbox_MSCOMGlue.h @@ -30,4 +30,19 @@ extern PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions; int VBoxCGlueInit(unsigned int *version); void VBoxCGlueTerm(void); +typedef struct _vboxArray vboxArray; + +struct _vboxArray { + void **items; + size_t count; + void *handle; +}; + +# define VBOX_ARRAY_INITIALIZER { NULL, 0, NULL } + +nsresult vboxArrayGet(vboxArray *array, void *self, void *getter); +nsresult vboxArrayGetWithArg(vboxArray *array, void *self, void *getter, void *arg); +void vboxArrayRelease(vboxArray *array); +# define vboxArrayUnalloc vboxArrayRelease + #endif /* __VBOX_MSCOMGLUE_H__ */ diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 03e66bc..5992350 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -253,3 +253,118 @@ VBoxCGlueTerm(void) pVBoxFuncs_v2_2 = NULL; g_pfnGetFunctions = NULL; } + + + +/* + * In XPCOM an array is represented by 1) a pointer to an array of pointers + * that point to the items and 2) an unsigned int representing the number of + * items in the array. When the items aren't needed anymore they are released + * or freed according to their type. + */ + +typedef nsresult (*ArrayGetter)(void *self, PRUint32 *count, void ***items); +typedef nsresult (*ArrayGetterWithArg)(void *self, void *arg, PRUint32 *count, void ***items); + +/* + * Call the getter with self as first argument and fill the array with the + * returned items. + */ +nsresult +vboxArrayGet(vboxArray *array, void *self, void *getter) +{ + nsresult nsrc; + void **items = NULL; + PRUint32 count = 0; + + array->items = NULL; + array->count = 0; + + nsrc = ((ArrayGetter)getter)(self, &count, &items); + + if (NS_FAILED(nsrc)) { + return nsrc; + } + + array->items = items; + array->count = count; + + return nsrc; +} + +/* + * Call the getter with self as first argument and arg as second argument + * and fill the array with the returned items. + */ +nsresult +vboxArrayGetWithArg(vboxArray *array, void *self, void *getter, void *arg) +{ + nsresult nsrc; + void **items = NULL; + PRUint32 count = 0; + + array->items = NULL; + array->count = 0; + + nsrc = ((ArrayGetterWithArg)getter)(self, arg, &count, &items); + + if (NS_FAILED(nsrc)) { + return nsrc; + } + + array->items = items; + array->count = count; + + return nsrc; +} + +/* + * Release all items in the array and reset it. + */ +void +vboxArrayRelease(vboxArray *array) +{ + int i; + nsISupports *supports; + + if (array->items == NULL) { + return; + } + + for (i = 0; i < array->count; ++i) { + supports = array->items[i]; + + if (supports != NULL) { + supports->vtbl->Release(supports); + } + } + + array->items = NULL; + array->count = 0; +} + + +/* + * Unalloc all items in the array and reset it. + */ +void +vboxArrayUnalloc(vboxArray *array) +{ + int i; + void *item; + + if (array->items == NULL) { + return; + } + + for (i = 0; i < array->count; ++i) { + item = array->items[i]; + + if (item != NULL) { + pVBoxFuncs_v2_2->pfnComUnallocMem(item); + } + } + + array->items = NULL; + array->count = 0; +} diff --git a/src/vbox/vbox_XPCOMCGlue.h b/src/vbox/vbox_XPCOMCGlue.h index 1fa873a..8fd2f13 100644 --- a/src/vbox/vbox_XPCOMCGlue.h +++ b/src/vbox/vbox_XPCOMCGlue.h @@ -38,4 +38,18 @@ extern PFNVBOXGETXPCOMCFUNCTIONS g_pfnGetFunctions; int VBoxCGlueInit(unsigned int *version); void VBoxCGlueTerm(void); +typedef struct _vboxArray vboxArray; + +struct _vboxArray { + void **items; + size_t count; +}; + +# define VBOX_ARRAY_INITIALIZER { NULL, 0 } + +nsresult vboxArrayGet(vboxArray *array, void *self, void *getter); +nsresult vboxArrayGetWithArg(vboxArray *array, void *self, void *getter, void *arg); +void vboxArrayRelease(vboxArray *array); +void vboxArrayUnalloc(vboxArray *array); + #endif diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 6a4589c..c283609 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -77,6 +77,8 @@ #define VBOX_UTF16_TO_UTF8(arg1, arg2) data->pFuncs->pfnUtf16ToUtf8(arg1, arg2) #define VBOX_UTF8_TO_UTF16(arg1, arg2) data->pFuncs->pfnUtf8ToUtf16(arg1, arg2) +#define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg)) + #define VBOX_RELEASE(arg) \ if(arg)\ (arg)->vtbl->nsisupports.Release((nsISupports *)(arg)) @@ -942,26 +944,21 @@ static char *vboxGetCapabilities(virConnectPtr conn) { static int vboxListDomains(virConnectPtr conn, int *ids, int nids) { VBOX_OBJECT_CHECK(conn, int, -1); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; PRUint32 state; nsresult rc; int i, j; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of Domains, rc=%08x"),(unsigned)rc); goto cleanup; } - if (machineCnt == 0) { - ret = 0; - goto cleanup; - } - - for (i = 0,j = 0; (i < machineCnt) && (j < nids); ++i) { - IMachine *machine = machines[i]; + ret = 0; + for (i = 0, j = 0; (i < machines.count) && (j < nids); ++i) { + IMachine *machine = machines.items[i]; if (machine) { PRBool isAccessible = PR_FALSE; @@ -976,37 +973,29 @@ static int vboxListDomains(virConnectPtr conn, int *ids, int nids) { } } } - ret++; cleanup: - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } static int vboxNumOfDomains(virConnectPtr conn) { VBOX_OBJECT_CHECK(conn, int, -1); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; PRUint32 state; nsresult rc; int i; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get number of Domains, rc=%08x"), (unsigned)rc); goto cleanup; } - if (machineCnt == 0) { - ret = 0; - goto cleanup; - } - - /* Do the cleanup as required by GetMachines() */ - for (i = 0; i < machineCnt; ++i) { - IMachine *machine = machines[i]; + ret = 0; + for (i = 0; i < machines.count; ++i) { + IMachine *machine = machines.items[i]; if (machine) { PRBool isAccessible = PR_FALSE; @@ -1019,11 +1008,9 @@ static int vboxNumOfDomains(virConnectPtr conn) { } } } - ret++; cleanup: - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } @@ -1056,13 +1043,11 @@ static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml, static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id) { VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; vboxIID *iid = NULL; unsigned char iidl[VIR_UUID_BUFLEN]; PRUint32 state; nsresult rc; - int i; /* Internal vbox IDs start from 0, the public libvirt ID * starts from 1, so refuse id==0, and adjust the rest*/ @@ -1073,28 +1058,30 @@ static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id) { } id = id - 1; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of machines, rc=%08x"), (unsigned)rc); return NULL; } - if (id < machineCnt) { - if (machines[id]) { + if (id < machines.count) { + IMachine *machine = machines.items[id]; + + if (machine) { PRBool isAccessible = PR_FALSE; - machines[id]->vtbl->GetAccessible(machines[id], &isAccessible); + machine->vtbl->GetAccessible(machine, &isAccessible); if (isAccessible) { - machines[id]->vtbl->GetState(machines[id], &state); + machine->vtbl->GetState(machine, &state); if ( (state >= MachineState_FirstOnline) && (state <= MachineState_LastOnline) ) { PRUnichar *machineNameUtf16 = NULL; char *machineNameUtf8 = NULL; - machines[id]->vtbl->GetName(machines[id], &machineNameUtf16); + machine->vtbl->GetName(machine, &machineNameUtf16); VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8); - machines[id]->vtbl->GetId(machines[id], &iid); + machine->vtbl->GetId(machine, &iid); vboxIIDToUUID(iidl, iid); vboxIIDUnalloc(iid); @@ -1116,17 +1103,14 @@ static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id) { } } - /* Do the cleanup as required by GetMachines() */ - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } static virDomainPtr vboxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; vboxIID *iid = NULL; char *machineNameUtf8 = NULL; PRUnichar *machineNameUtf16 = NULL; @@ -1134,15 +1118,15 @@ static virDomainPtr vboxDomainLookupByUUID(virConnectPtr conn, const unsigned ch int i, matched = 0; nsresult rc; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of machines, rc=%08x"), (unsigned)rc); return NULL; } - for (i = 0; i < machineCnt; ++i) { - IMachine *machine = machines[i]; + for (i = 0; i < machines.count; ++i) { + IMachine *machine = machines.items[i]; PRBool isAccessible = PR_FALSE; if (!machine) @@ -1189,16 +1173,14 @@ static virDomainPtr vboxDomainLookupByUUID(virConnectPtr conn, const unsigned ch /* Do the cleanup and take care you dont leak any memory */ VBOX_UTF8_FREE(machineNameUtf8); VBOX_COM_UNALLOC_MEM(machineNameUtf16); - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } static virDomainPtr vboxDomainLookupByName(virConnectPtr conn, const char *name) { VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; vboxIID *iid = NULL; char *machineNameUtf8 = NULL; PRUnichar *machineNameUtf16 = NULL; @@ -1206,15 +1188,15 @@ static virDomainPtr vboxDomainLookupByName(virConnectPtr conn, const char *name) int i, matched = 0; nsresult rc; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of machines, rc=%08x"), (unsigned)rc); return NULL; } - for (i = 0; i < machineCnt; ++i) { - IMachine *machine = machines[i]; + for (i = 0; i < machines.count; ++i) { + IMachine *machine = machines.items[i]; PRBool isAccessible = PR_FALSE; if (!machine) @@ -1264,9 +1246,7 @@ static virDomainPtr vboxDomainLookupByName(virConnectPtr conn, const char *name) } } - /* Do the cleanup and take care you dont leak any memory */ - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } @@ -1274,8 +1254,7 @@ static virDomainPtr vboxDomainLookupByName(virConnectPtr conn, const char *name) static int vboxDomainIsActive(virDomainPtr dom) { VBOX_OBJECT_CHECK(dom->conn, int, -1); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; vboxIID *iid = NULL; char *machineNameUtf8 = NULL; PRUnichar *machineNameUtf16 = NULL; @@ -1283,15 +1262,15 @@ static int vboxDomainIsActive(virDomainPtr dom) { int i, matched = 0; nsresult rc; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of machines, rc=%08x"), (unsigned)rc); return ret; } - for (i = 0; i < machineCnt; ++i) { - IMachine *machine = machines[i]; + for (i = 0; i < machines.count; ++i) { + IMachine *machine = machines.items[i]; PRBool isAccessible = PR_FALSE; if (!machine) @@ -1332,8 +1311,7 @@ static int vboxDomainIsActive(virDomainPtr dom) { /* Do the cleanup and take care you dont leak any memory */ VBOX_UTF8_FREE(machineNameUtf8); VBOX_COM_UNALLOC_MEM(machineNameUtf16); - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } @@ -1718,14 +1696,13 @@ cleanup: static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { VBOX_OBJECT_CHECK(dom->conn, int, -1); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; char *machineName = NULL; PRUnichar *machineNameUtf16 = NULL; nsresult rc; int i = 0; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of machines, rc=%08x"), (unsigned)rc); @@ -1733,8 +1710,8 @@ static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { } info->nrVirtCpu = 0; - for (i = 0; i < machineCnt; ++i) { - IMachine *machine = machines[i]; + for (i = 0; i < machines.count; ++i) { + IMachine *machine = machines.items[i]; PRBool isAccessible = PR_FALSE; if (!machine) @@ -1815,9 +1792,7 @@ static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { } - /* Do the cleanup and take care you dont leak any memory */ - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); cleanup: return ret; @@ -2034,8 +2009,7 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { PRUnichar *hddBusUtf16 = NULL; IFloppyDrive *floppyDrive = NULL; #else /* VBOX_API_VERSION >= 3001 */ - PRUint32 mediumAttachSize = 0; - IMediumAttachment **mediumAttachments = NULL; + vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; #endif /* VBOX_API_VERSION >= 3001 */ IVRDPServer *VRDPServer = NULL; IAudioAdapter *audioAdapter = NULL; @@ -2436,11 +2410,11 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; def->ndisks = 0; - machine->vtbl->GetMediumAttachments(machine, &mediumAttachSize, &mediumAttachments); + vboxArrayGet(&mediumAttachments, machine, machine->vtbl->GetMediumAttachments); /* get the number of attachments */ - for (i = 0; i < mediumAttachSize; i++) { - IMediumAttachment *imediumattach = mediumAttachments[i]; + for (i = 0; i < mediumAttachments.count; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; if (imediumattach) { IMedium *medium = NULL; @@ -2470,8 +2444,8 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort); /* get the attachment details here */ - for (i = 0; i < mediumAttachSize && diskCount < def->ndisks && !error; i++) { - IMediumAttachment *imediumattach = mediumAttachments[i]; + for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; IStorageController *storageController = NULL; PRUnichar *storageControllerName = NULL; PRUint32 deviceType = DeviceType_Null; @@ -2569,9 +2543,7 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { diskCount++; } - /* free the memory */ - for (i = 0; i < mediumAttachSize; i++) - VBOX_RELEASE(mediumAttachments[i]); + vboxArrayRelease(&mediumAttachments); /* cleanup on error */ if (error) { @@ -3013,23 +2985,22 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { USBController->vtbl->GetEnabled(USBController, &enabled); if (enabled) { - PRUint32 deviceFiltersNum = 0; - IUSBDeviceFilter **deviceFilters = NULL; + vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER; - USBController->vtbl->GetDeviceFilters(USBController, - &deviceFiltersNum, - &deviceFilters); + vboxArrayGet(&deviceFilters, USBController, + USBController->vtbl->GetDeviceFilters); - if (deviceFiltersNum > 0) { + if (deviceFilters.count > 0) { /* check if the filters are active and then only * alloc mem and set def->nhostdevs */ - for(i = 0; i < deviceFiltersNum; i++) { + for(i = 0; i < deviceFilters.count; i++) { PRBool active = PR_FALSE; + IUSBDeviceFilter *deviceFilter = deviceFilters.items[i]; - deviceFilters[i]->vtbl->GetActive(deviceFilters[i], &active); + deviceFilter->vtbl->GetActive(deviceFilter, &active); if (active) { def->nhostdevs++; } @@ -3039,10 +3010,11 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { /* Alloc mem needed for the filters now */ if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) >= 0) { - for(i = 0; (USBFilterCount < def->nhostdevs) || (i < deviceFiltersNum); i++) { + for(i = 0; (USBFilterCount < def->nhostdevs) || (i < deviceFilters.count); i++) { PRBool active = PR_FALSE; + IUSBDeviceFilter *deviceFilter = deviceFilters.items[i]; - deviceFilters[i]->vtbl->GetActive(deviceFilters[i], &active); + deviceFilter->vtbl->GetActive(deviceFilter, &active); if (active) { if (VIR_ALLOC(def->hostdevs[USBFilterCount]) >= 0) { PRUnichar *vendorIdUtf16 = NULL; @@ -3058,8 +3030,8 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { def->hostdevs[USBFilterCount]->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB; - deviceFilters[i]->vtbl->GetVendorId(deviceFilters[i], &vendorIdUtf16); - deviceFilters[i]->vtbl->GetProductId(deviceFilters[i], &productIdUtf16); + deviceFilter->vtbl->GetVendorId(deviceFilter, &vendorIdUtf16); + deviceFilter->vtbl->GetProductId(deviceFilter, &productIdUtf16); VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8); VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8); @@ -3087,8 +3059,7 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { } /* Cleanup */ - for(i = 0; i < deviceFiltersNum; i++) - VBOX_RELEASE(deviceFilters[i]); + vboxArrayRelease(&deviceFilters); } VBOX_RELEASE(USBController); } @@ -3113,15 +3084,14 @@ cleanup: static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) { VBOX_OBJECT_CHECK(conn, int, -1); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; char *machineName = NULL; PRUnichar *machineNameUtf16 = NULL; PRUint32 state; nsresult rc; int i, j; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of Defined Domains, rc=%08x"), @@ -3129,13 +3099,9 @@ static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int m goto cleanup; } - if (machineCnt == 0) { - ret = 0; - goto cleanup; - } - - for (i = 0,j = 0; (i < machineCnt) && (j < maxnames); i++) { - IMachine *machine = machines[i]; + ret = 0; + for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) { + IMachine *machine = machines.items[i]; if (machine) { PRBool isAccessible = PR_FALSE; @@ -3158,25 +3124,22 @@ static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int m } } } - ret++; cleanup: VBOX_UTF8_FREE(machineName); VBOX_UTF16_FREE(machineNameUtf16); - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } static int vboxNumOfDefinedDomains(virConnectPtr conn) { VBOX_OBJECT_CHECK(conn, int, -1); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; PRUint32 state = MachineState_Null; nsresult rc; int i; - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get number of Defined Domains, rc=%08x"), @@ -3184,14 +3147,9 @@ static int vboxNumOfDefinedDomains(virConnectPtr conn) { goto cleanup; } - if (machineCnt == 0) { - ret = 0; - goto cleanup; - } - - /* Do the cleanup as required by GetMachines() */ - for (i = 0; i < machineCnt; ++i) { - IMachine *machine = machines[i]; + ret = 0; + for (i = 0; i < machines.count; ++i) { + IMachine *machine = machines.items[i]; if (machine) { PRBool isAccessible = PR_FALSE; @@ -3205,11 +3163,9 @@ static int vboxNumOfDefinedDomains(virConnectPtr conn) { } } } - ret++; cleanup: - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); return ret; } @@ -3387,8 +3343,7 @@ vboxStartMachine(virDomainPtr dom, int i, IMachine *machine, vboxIID *iid) static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); - IMachine **machines = NULL; - PRUint32 machineCnt = 0; + vboxArray machines = VBOX_ARRAY_INITIALIZER; unsigned char iidl[VIR_UUID_BUFLEN] = {0}; nsresult rc; int i = 0; @@ -3401,15 +3356,15 @@ static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) { goto cleanup; } - rc = data->vboxObj->vtbl->GetMachines(data->vboxObj, &machineCnt, &machines); + rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, _("Could not get list of machines, rc=%08x"), (unsigned)rc); goto cleanup; } - for (i = 0; i < machineCnt; ++i) { - IMachine *machine = machines[i]; + for (i = 0; i < machines.count; ++i) { + IMachine *machine = machines.items[i]; PRBool isAccessible = PR_FALSE; if (!machine) @@ -3446,8 +3401,7 @@ static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) { } /* Do the cleanup and take care you dont leak any memory */ - for (i = 0; i < machineCnt; ++i) - VBOX_RELEASE(machines[i]); + vboxArrayRelease(&machines); cleanup: return ret; @@ -4795,31 +4749,27 @@ static int vboxDomainUndefine(virDomainPtr dom) { /* get all the controller first, then the attachments and * remove them all so that the machine can be undefined */ - PRUint32 strCtlSize = 0; - IStorageController **aStrCtls = NULL; + vboxArray storageControllers = VBOX_ARRAY_INITIALIZER; int i = 0, j = 0; - machine->vtbl->GetStorageControllers(machine, - &strCtlSize, - &aStrCtls); + vboxArrayGet(&storageControllers, machine, + machine->vtbl->GetStorageControllers); - for (i = 0; i < strCtlSize; i++) { - IStorageController *strCtl = aStrCtls[i]; + for (i = 0; i < storageControllers.count; i++) { + IStorageController *strCtl = storageControllers.items[i]; PRUnichar *strCtlName = NULL; - PRUint32 medAttSize = 0; - IMediumAttachment **aMedAtts = NULL; + vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; if (!strCtl) continue; strCtl->vtbl->GetName(strCtl, &strCtlName); - machine->vtbl->GetMediumAttachmentsOfController(machine, - strCtlName, - &medAttSize, - &aMedAtts); + vboxArrayGetWithArg(&mediumAttachments, machine, + machine->vtbl->GetMediumAttachmentsOfController, + strCtlName); - for (j = 0; j < medAttSize; j++) { - IMediumAttachment *medAtt = aMedAtts[j]; + for (j = 0; j < mediumAttachments.count; j++) { + IMediumAttachment *medAtt = mediumAttachments.items[j]; PRInt32 port = ~0U; PRInt32 device = ~0U; @@ -4835,14 +4785,15 @@ static int vboxDomainUndefine(virDomainPtr dom) { port, device); } - - VBOX_RELEASE(medAtt); } - VBOX_RELEASE(strCtl); + vboxArrayRelease(&storageControllers); + machine->vtbl->RemoveStorageController(machine, strCtlName); VBOX_UTF16_FREE(strCtlName); } + + vboxArrayRelease(&storageControllers); #endif /* VBOX_API_VERSION >= 3001 */ machine->vtbl->SaveSettings(machine); @@ -5288,8 +5239,7 @@ vboxDomainSnapshotGetAll(virDomainPtr dom, /* BFS walk through snapshot tree */ top = 1; for (next = 0; next < count; next++) { - PRUint32 childrenCount = 0; - ISnapshot **children = NULL; + vboxArray children = VBOX_ARRAY_INITIALIZER; unsigned int i; if (!list[next]) { @@ -5298,23 +5248,27 @@ vboxDomainSnapshotGetAll(virDomainPtr dom, goto error; } - rc = list[next]->vtbl->GetChildren(list[next], &childrenCount, - &children); + rc = vboxArrayGet(&children, list[next], + list[next]->vtbl->GetChildren); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get children snapshots")); goto error; } - for (i = 0; i < childrenCount; i++) { - if (!children[i]) + for (i = 0; i < children.count; i++) { + ISnapshot *child = children.items[i]; + if (!child) continue; if (top == count) { vboxError(VIR_ERR_INTERNAL_ERROR, _("unexpected number of snapshots > %u"), count); + vboxArrayRelease(&children); goto error; } - list[top++] = children[i]; + VBOX_ADDREF(child); + list[top++] = child; } + vboxArrayRelease(&children); } out: @@ -6137,31 +6091,27 @@ vboxDomainSnapshotDeleteTree(vboxGlobalData *data, IConsole *console, ISnapshot *snapshot) { - PRUint32 childrenCount = 0; - ISnapshot **children = NULL; + vboxArray children = VBOX_ARRAY_INITIALIZER; int ret = -1; nsresult rc; unsigned int i; - rc = snapshot->vtbl->GetChildren(snapshot, &childrenCount, &children); + rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren); if (NS_FAILED(rc)) { vboxError(VIR_ERR_INTERNAL_ERROR, "%s", _("could not get children snapshots")); goto cleanup; } - if (childrenCount > 0) { - for (i = 0; i < childrenCount; i++) { - if (vboxDomainSnapshotDeleteTree(data, console, children[i])) - goto cleanup; - } + for (i = 0; i < children.count; i++) { + if (vboxDomainSnapshotDeleteTree(data, console, children.items[i])) + goto cleanup; } ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot); cleanup: - for (i = 0; i < childrenCount; i++) - VBOX_RELEASE(children[i]); + vboxArrayRelease(&children); return ret; } @@ -6829,30 +6779,31 @@ static int vboxNetworkClose(virConnectPtr conn) { static int vboxNumOfNetworks(virConnectPtr conn) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); - PRUint32 networkInterfacesSize = 0; - IHostNetworkInterface **networkInterfaces = NULL; + vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; int i = 0; - host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces); + vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); - for (i = 0; i < networkInterfacesSize; i++) { - if (networkInterfaces[i]) { + for (i = 0; i < networkInterfaces.count; i++) { + IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; + + if (networkInterface) { PRUint32 interfaceType = 0; - networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType); + networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; - networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status); + networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Up) ret++; } - - VBOX_RELEASE(networkInterfaces[i]); } } + vboxArrayRelease(&networkInterfaces); + VBOX_RELEASE(host); DEBUG("numActive: %d", ret); @@ -6861,28 +6812,29 @@ static int vboxNumOfNetworks(virConnectPtr conn) { static int vboxListNetworks(virConnectPtr conn, char **const names, int nnames) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); - PRUint32 networkInterfacesSize = 0; - IHostNetworkInterface **networkInterfaces = NULL; + vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; int i = 0; - host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces); + vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); + + for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) { + IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; - for (i = 0; (ret < nnames) && (i < networkInterfacesSize); i++) { - if (networkInterfaces[i]) { + if (networkInterface) { PRUint32 interfaceType = 0; - networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType); + networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; - networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status); + networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Up) { char *nameUtf8 = NULL; PRUnichar *nameUtf16 = NULL; - networkInterfaces[i]->vtbl->GetName(networkInterfaces[i], &nameUtf16); + networkInterface->vtbl->GetName(networkInterface, &nameUtf16); VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); DEBUG("nnames[%d]: %s", ret, nameUtf8); @@ -6900,8 +6852,7 @@ static int vboxListNetworks(virConnectPtr conn, char **const names, int nnames) } } - for (i = 0; i < networkInterfacesSize; i++) - VBOX_RELEASE(networkInterfaces[i]); + vboxArrayRelease(&networkInterfaces); VBOX_RELEASE(host); @@ -6910,30 +6861,31 @@ static int vboxListNetworks(virConnectPtr conn, char **const names, int nnames) static int vboxNumOfDefinedNetworks(virConnectPtr conn) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); - PRUint32 networkInterfacesSize = 0; - IHostNetworkInterface **networkInterfaces = NULL; + vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; int i = 0; - host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces); + vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); - for (i = 0; i < networkInterfacesSize; i++) { - if (networkInterfaces[i]) { + for (i = 0; i < networkInterfaces.count; i++) { + IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; + + if (networkInterface) { PRUint32 interfaceType = 0; - networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType); + networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; - networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status); + networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Down) ret++; } - - VBOX_RELEASE(networkInterfaces[i]); } } + vboxArrayRelease(&networkInterfaces); + VBOX_RELEASE(host); DEBUG("numActive: %d", ret); @@ -6942,28 +6894,29 @@ static int vboxNumOfDefinedNetworks(virConnectPtr conn) { static int vboxListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) { VBOX_OBJECT_HOST_CHECK(conn, int, 0); - PRUint32 networkInterfacesSize = 0; - IHostNetworkInterface **networkInterfaces = NULL; + vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER; int i = 0; - host->vtbl->GetNetworkInterfaces(host, &networkInterfacesSize, &networkInterfaces); + vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces); + + for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) { + IHostNetworkInterface *networkInterface = networkInterfaces.items[i]; - for (i = 0; (ret < nnames) && (i < networkInterfacesSize); i++) { - if (networkInterfaces[i]) { + if (networkInterface) { PRUint32 interfaceType = 0; - networkInterfaces[i]->vtbl->GetInterfaceType(networkInterfaces[i], &interfaceType); + networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType); if (interfaceType == HostNetworkInterfaceType_HostOnly) { PRUint32 status = HostNetworkInterfaceStatus_Unknown; - networkInterfaces[i]->vtbl->GetStatus(networkInterfaces[i], &status); + networkInterface->vtbl->GetStatus(networkInterface, &status); if (status == HostNetworkInterfaceStatus_Down) { char *nameUtf8 = NULL; PRUnichar *nameUtf16 = NULL; - networkInterfaces[i]->vtbl->GetName(networkInterfaces[i], &nameUtf16); + networkInterface->vtbl->GetName(networkInterface, &nameUtf16); VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); DEBUG("nnames[%d]: %s", ret, nameUtf8); @@ -6981,8 +6934,7 @@ static int vboxListDefinedNetworks(virConnectPtr conn, char **const names, int n } } - for (i = 0; i < networkInterfacesSize; i++) - VBOX_RELEASE(networkInterfaces[i]); + vboxArrayRelease(&networkInterfaces); VBOX_RELEASE(host); @@ -7667,54 +7619,48 @@ static virStoragePoolPtr vboxStoragePoolLookupByName(virConnectPtr conn, const c static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool) { VBOX_OBJECT_CHECK(pool->conn, int, -1); - IHardDisk **hardDisks = NULL; - PRUint32 hardDiskCount = 0; + vboxArray hardDisks = VBOX_ARRAY_INITIALIZER; PRUint32 hardDiskAccessible = 0; nsresult rc; int i; - rc = data->vboxObj->vtbl->GetHardDisks(data->vboxObj, &hardDiskCount, &hardDisks); + rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks); if (NS_SUCCEEDED(rc)) { - for (i = 0; i < hardDiskCount; ++i) { - IHardDisk *hardDisk = hardDisks[i]; + for (i = 0; i < hardDisks.count; ++i) { + IHardDisk *hardDisk = hardDisks.items[i]; if (hardDisk) { PRUint32 hddstate; VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) hardDiskAccessible++; - - VBOX_MEDIUM_RELEASE(hardDisk); } } - hardDiskCount = 0; + + vboxArrayRelease(&hardDisks); + + ret = hardDiskAccessible; } else { - hardDiskCount = -1; + ret = -1; vboxError(VIR_ERR_INTERNAL_ERROR, _("could not get number of volumes in the pool: %s, rc=%08x"), pool->name, (unsigned)rc); } - if (hardDiskAccessible) - ret = hardDiskAccessible; - else - ret = hardDiskCount; - return ret; } static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) { VBOX_OBJECT_CHECK(pool->conn, int, -1); - IHardDisk **hardDisks = NULL; - PRUint32 hardDiskCount = 0; + vboxArray hardDisks = VBOX_ARRAY_INITIALIZER; PRUint32 numActive = 0; nsresult rc; int i; - rc = data->vboxObj->vtbl->GetHardDisks(data->vboxObj, &hardDiskCount, &hardDisks); + rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks); if (NS_SUCCEEDED(rc)) { - for (i = 0; i < hardDiskCount && numActive < nnames; ++i) { - IHardDisk *hardDisk = hardDisks[i]; + for (i = 0; i < hardDisks.count && numActive < nnames; ++i) { + IHardDisk *hardDisk = hardDisks.items[i]; if (hardDisk) { PRUint32 hddstate; @@ -7740,39 +7686,35 @@ static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names VBOX_UTF8_FREE(nameUtf8); } } - VBOX_MEDIUM_RELEASE(hardDisk); } } - hardDiskCount = 0; + + vboxArrayRelease(&hardDisks); + + ret = numActive; } else { - hardDiskCount = -1; + ret = -1; vboxError(VIR_ERR_INTERNAL_ERROR, _("could not get the volume list in the pool: %s, rc=%08x"), pool->name, (unsigned)rc); } - if (numActive) - ret = numActive; - else - ret = hardDiskCount; - return ret; } static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name) { VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL); - IHardDisk **hardDisks = NULL; - PRUint32 hardDiskCount = 0; + vboxArray hardDisks = VBOX_ARRAY_INITIALIZER; nsresult rc; int i; if(!name) return ret; - rc = data->vboxObj->vtbl->GetHardDisks(data->vboxObj, &hardDiskCount, &hardDisks); + rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks); if (NS_SUCCEEDED(rc)) { - for (i = 0; i < hardDiskCount; ++i) { - IHardDisk *hardDisk = hardDisks[i]; + for (i = 0; i < hardDisks.count; ++i) { + IHardDisk *hardDisk = hardDisks.items[i]; if (hardDisk) { PRUint32 hddstate; @@ -7821,8 +7763,7 @@ static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const } } - for (i = 0; i < hardDiskCount; ++i) - VBOX_MEDIUM_RELEASE(hardDisks[i]); + vboxArrayRelease(&hardDisks); } return ret; @@ -8081,28 +8022,36 @@ static int vboxStorageVolDelete(virStorageVolPtr vol, VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate); if (hddstate != MediaState_Inaccessible) { PRUint32 machineIdsSize = 0; - vboxIID **machineIds = NULL; + vboxArray machineIds = VBOX_ARRAY_INITIALIZER; + +#if VBOX_API_VERSION < 3001 + vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds); +#else /* VBOX_API_VERSION >= 3001 */ + vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds); +#endif /* VBOX_API_VERSION >= 3001 */ - VBOX_MEDIUM_FUNC_ARG2(hardDisk, GetMachineIds, &machineIdsSize, &machineIds); + machineIdsSize = machineIds.count; - for (i = 0; i < machineIdsSize; i++) { + for (i = 0; i < machineIds.count; i++) { IMachine *machine = NULL; + vboxIID *machineId = machineIds.items[i]; - rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, machineIds[i]); + rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, machineId); if (NS_SUCCEEDED(rc)) { rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine); if (NS_SUCCEEDED(rc)) { - PRUint32 hddAttachSize = 0; - IHardDiskAttachment **hddAttachments = NULL; + vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER; #if VBOX_API_VERSION < 3001 - machine->vtbl->GetHardDiskAttachments(machine, &hddAttachSize, &hddAttachments); + vboxArrayGet(&hddAttachments, machine, + machine->vtbl->GetHardDiskAttachments); #else /* VBOX_API_VERSION >= 3001 */ - machine->vtbl->GetMediumAttachments(machine, &hddAttachSize, &hddAttachments); + vboxArrayGet(&hddAttachments, machine, + machine->vtbl->GetMediumAttachments); #endif /* VBOX_API_VERSION >= 3001 */ - for (j = 0; j < hddAttachSize; j++) { - IHardDiskAttachment *hddAttachment = hddAttachments[j]; + for (j = 0; j < hddAttachments.count; j++) { + IHardDiskAttachment *hddAttachment = hddAttachments.items[j]; if (hddAttachment) { IHardDisk *hdd = NULL; @@ -8154,18 +8103,16 @@ static int vboxStorageVolDelete(virStorageVolPtr vol, } VBOX_MEDIUM_RELEASE(hdd); } - VBOX_RELEASE(hddAttachment); } } + vboxArrayRelease(&hddAttachments); VBOX_RELEASE(machine); } data->vboxSession->vtbl->Close(data->vboxSession); } } - for (i = 0; i < machineIdsSize; i++) - if (machineIds[i]) - vboxIIDUnalloc(machineIds[i]); + vboxArrayUnalloc(&machineIds); if (machineIdsSize == 0 || machineIdsSize == deregister) { IProgress *progress = NULL; -- 1.7.0.4

On 12/17/2010 11:56 AM, Matthias Bolte wrote:
Add a vboxArray to hide the details from the general driver code. --- src/vbox/vbox_MSCOMGlue.c | 107 +++++++++++ src/vbox/vbox_MSCOMGlue.h | 15 ++ src/vbox/vbox_XPCOMCGlue.c | 115 ++++++++++++ src/vbox/vbox_XPCOMCGlue.h | 14 ++ src/vbox/vbox_tmpl.c | 445 +++++++++++++++++++------------------------- 5 files changed, 447 insertions(+), 249 deletions(-)
diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index 81a2c99..ded1275 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -647,3 +647,110 @@ 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 get's invalid. Finally the
s/get's/becomes/
+ * 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 (*SaveArrayGetter)(void *self, SAFEARRAY **array); +typedef HRESULT __stdcall (*SaveArrayGetterWithArg)(void *self, void *arg, SAFEARRAY **array);
Perhaps s/SaveArrayGetter/SafeArrayGetter/g? But it looks like a good wrapper, as well as a mechanical change to implement its use. ACK. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2010/12/17 Eric Blake <eblake@redhat.com>:
On 12/17/2010 11:56 AM, Matthias Bolte wrote:
Add a vboxArray to hide the details from the general driver code. --- src/vbox/vbox_MSCOMGlue.c | 107 +++++++++++ src/vbox/vbox_MSCOMGlue.h | 15 ++ src/vbox/vbox_XPCOMCGlue.c | 115 ++++++++++++ src/vbox/vbox_XPCOMCGlue.h | 14 ++ src/vbox/vbox_tmpl.c | 445 +++++++++++++++++++------------------------- 5 files changed, 447 insertions(+), 249 deletions(-)
diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index 81a2c99..ded1275 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -647,3 +647,110 @@ 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 get's invalid. Finally the
s/get's/becomes/
+ * 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 (*SaveArrayGetter)(void *self, SAFEARRAY **array); +typedef HRESULT __stdcall (*SaveArrayGetterWithArg)(void *self, void *arg, SAFEARRAY **array);
Perhaps s/SaveArrayGetter/SafeArrayGetter/g?
But it looks like a good wrapper, as well as a mechanical change to implement its use.
ACK.
I addressed the two comments and pushed it, thanks. Matthias

XPCOM returns an array as a pointer to an array of pointers to the actual items. When the array isn't needed anymore the items are released, but the actual array containing the pointers to the items was not freed and leaked. Free the actual array using ComUnallocMem. This doesn't affect MSCOM as SafeArrayDestroy releases all items and frees the array. --- src/vbox/vbox_XPCOMCGlue.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 5992350..dcaf682 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -339,6 +339,8 @@ vboxArrayRelease(vboxArray *array) } } + pVBoxFuncs_v2_2->pfnComUnallocMem(array->items); + array->items = NULL; array->count = 0; } @@ -365,6 +367,8 @@ vboxArrayUnalloc(vboxArray *array) } } + pVBoxFuncs_v2_2->pfnComUnallocMem(array->items); + array->items = NULL; array->count = 0; } -- 1.7.0.4

On 12/17/2010 11:56 AM, Matthias Bolte wrote:
XPCOM returns an array as a pointer to an array of pointers to the actual items. When the array isn't needed anymore the items are released, but the actual array containing the pointers to the items was not freed and leaked.
Free the actual array using ComUnallocMem.
This doesn't affect MSCOM as SafeArrayDestroy releases all items and frees the array. --- src/vbox/vbox_XPCOMCGlue.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 5992350..dcaf682 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -339,6 +339,8 @@ vboxArrayRelease(vboxArray *array) } }
+ pVBoxFuncs_v2_2->pfnComUnallocMem(array->items); +
ACK. Was this the leak you were telling me on IRC that exists even in the XPCOM example code? And certainly easier to plug given the wrapper function you created in 4/6 than to plug at every call site. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2010/12/17 Eric Blake <eblake@redhat.com>:
On 12/17/2010 11:56 AM, Matthias Bolte wrote:
XPCOM returns an array as a pointer to an array of pointers to the actual items. When the array isn't needed anymore the items are released, but the actual array containing the pointers to the items was not freed and leaked.
Free the actual array using ComUnallocMem.
This doesn't affect MSCOM as SafeArrayDestroy releases all items and frees the array. --- src/vbox/vbox_XPCOMCGlue.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 5992350..dcaf682 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -339,6 +339,8 @@ vboxArrayRelease(vboxArray *array) } }
+ pVBoxFuncs_v2_2->pfnComUnallocMem(array->items); +
ACK. Was this the leak you were telling me on IRC that exists even in the XPCOM example code? And certainly easier to plug given the wrapper function you created in 4/6 than to plug at every call site.
Yes, that's the leak that's also in the XPCOM example code in the VirtualBox SDK. Thanks, pushed. Matthias

--- src/vbox/vbox_tmpl.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index c283609..728c501 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -3112,13 +3112,17 @@ static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int m || (state > MachineState_LastOnline) ) { machine->vtbl->GetName(machine, &machineNameUtf16); VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); - if (!(names[j++] = strdup(machineName))) { + names[j] = strdup(machineName); + VBOX_UTF16_FREE(machineNameUtf16); + VBOX_UTF8_FREE(machineName); + if (!names[j]) { virReportOOMError(); for ( ; j >= 0 ; j--) VIR_FREE(names[j]); ret = -1; goto cleanup; } + j++; ret++; } } @@ -3126,8 +3130,6 @@ static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int m } cleanup: - VBOX_UTF8_FREE(machineName); - VBOX_UTF16_FREE(machineNameUtf16); vboxArrayRelease(&machines); return ret; } -- 1.7.0.4

On 12/17/2010 11:56 AM, Matthias Bolte wrote:
--- src/vbox/vbox_tmpl.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index c283609..728c501 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -3112,13 +3112,17 @@ static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int m || (state > MachineState_LastOnline) ) { machine->vtbl->GetName(machine, &machineNameUtf16); VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); - if (!(names[j++] = strdup(machineName))) { + names[j] = strdup(machineName); + VBOX_UTF16_FREE(machineNameUtf16); + VBOX_UTF8_FREE(machineName); + if (!names[j]) { virReportOOMError(); for ( ; j >= 0 ; j--) VIR_FREE(names[j]); ret = -1; goto cleanup; } + j++;
ACK - since machineName is reused each iteration of the loop, it has to be freed each iteration rather than once at the end. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2010/12/17 Eric Blake <eblake@redhat.com>:
On 12/17/2010 11:56 AM, Matthias Bolte wrote:
--- src/vbox/vbox_tmpl.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index c283609..728c501 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -3112,13 +3112,17 @@ static int vboxListDefinedDomains(virConnectPtr conn, char ** const names, int m || (state > MachineState_LastOnline) ) { machine->vtbl->GetName(machine, &machineNameUtf16); VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); - if (!(names[j++] = strdup(machineName))) { + names[j] = strdup(machineName); + VBOX_UTF16_FREE(machineNameUtf16); + VBOX_UTF8_FREE(machineName); + if (!names[j]) { virReportOOMError(); for ( ; j >= 0 ; j--) VIR_FREE(names[j]); ret = -1; goto cleanup; } + j++;
ACK - since machineName is reused each iteration of the loop, it has to be freed each iteration rather than once at the end.
Thanks, pushed. Matthias

2010/12/17 Matthias Bolte <matthias.bolte@googlemail.com>:
This series makes the VirtualBox driver work on Windows.
On non-Windows systems VirtualBox uses XPCOM, on Windows it uses MSCOM (Microsoft COM). XPCOM and MSCOM are slightly different. This series adds a new glue layer for MSCOM.
The main difference is the representation of arrays. A new vboxArray type hides the differences from the general driver code.
I've tested this with the 3.x series of VirtualBox. Testing with 2.x revealed that 2.x and 3.x represent IIDs differently. This problem is not fixed by this series and will need some additional work. Therefore, the VirtualBox driver only works with the 3.x series on Windows for now.
VirtualBox 4.x seems to stay in line with the 3.x COM API. I expect it to work properly on Windows once we've added general support for it.
Matthias
I've pushed the whole series now. Thanks again to Eric for his fast review :) Matthias

On 18/12/2010, at 9:25 AM, Matthias Bolte wrote:
2010/12/17 Matthias Bolte <matthias.bolte@googlemail.com>:
This series makes the VirtualBox driver work on Windows.
On non-Windows systems VirtualBox uses XPCOM, on Windows it uses MSCOM (Microsoft COM). XPCOM and MSCOM are slightly different. This series adds a new glue layer for MSCOM.
The main difference is the representation of arrays. A new vboxArray type hides the differences from the general driver code.
I've tested this with the 3.x series of VirtualBox. Testing with 2.x revealed that 2.x and 3.x represent IIDs differently. This problem is not fixed by this series and will need some additional work. Therefore, the VirtualBox driver only works with the 3.x series on Windows for now.
VirtualBox 4.x seems to stay in line with the 3.x COM API. I expect it to work properly on Windows once we've added general support for it.
Matthias
I've pushed the whole series now. Thanks again to Eric for his fast review :)
Hey good work. People have asked about VBox support on Windows now that we're putting together a windows installer. I was thinking it might take a while, so this is very welcome. :)
participants (4)
-
Eric Blake
-
Justin Clift
-
Matthias Bolte
-
Paolo Bonzini