Index: /trunk/include/VBox/com/array.h
===================================================================
--- /trunk/include/VBox/com/array.h	(revision 6851)
+++ /trunk/include/VBox/com/array.h	(revision 6851)
@@ -0,0 +1,705 @@
+/** @file
+ * MS COM / XPCOM Abstraction Layer:
+ * Safe array helper class declaration
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_com_array_h
+#define ___VBox_com_array_h
+
+/** @defgroup   grp_COM_arrays    COM/XPCOM Arrays
+ * @{
+ *
+ * The COM/XPCOM array support layer provides a cross-platform way to pass
+ * arrays to and from COM interface methods and consists of the com::SafeArray
+ * template and a set of ComSafeArray* macros part of which is defined in
+ * VBox/com/defs.h.
+ *
+ * This layer works with interface attributes and method parameters that have
+ * the 'safearray="yes"' attribute in the XIDL definition:
+ * @code
+
+    <interface name="ISomething" ...>
+
+      <method name="testArrays">
+        <param name="inArr" type="long" dir="in" safearray="yes"/>
+        <param name="outArr" type="long" dir="out" safearray="yes"/>
+        <param name="retArr" type="long" dir="return" safearray="yes"/>
+      </method>
+
+    </interface>
+
+ * @endcode
+ *
+ * Methods generated from this and similar definitions are implemented in
+ * component classes using the following declarations:
+ * @code
+
+    STDMETHOD(TestArrays) (ComSafeArrayIn (LONG, aIn),
+                           ComSafeArrayOut (LONG, aOut),
+                           ComSafeArrayOut (LONG, aRet));
+
+ * @endcode
+ *
+ * And the following function bodies:
+ * @code
+
+    STDMETHODIMP Component::TestArrays (ComSafeArrayIn (LONG, aIn),
+                                        ComSafeArrayOut (LONG, aOut),
+                                        ComSafeArrayOut (LONG, aRet))
+    {
+        if (ComSafeArrayInIsNull (aIn))
+            return E_INVALIDARG;
+        if (ComSafeArrayOutIsNull (aOut))
+            return E_POINTER;
+        if (ComSafeArrayOutIsNull (aRet))
+            return E_POINTER;
+
+        // Use SafeArray to access the input array parameter
+
+        com::SafeArray <LONG> in (ComSafeArrayInArg (aIn));
+
+        for (size_t i = 0; i < in.size(); ++ i)
+            LogFlow (("*** in[%u]=%d\n", i, in [i]));
+
+        // Use SafeArray to create the return array (the same technique is used
+        // for output array paramters)
+
+        SafeArray <LONG> ret (in.size() * 2);
+        for (size_t i = 0; i < in.size(); ++ i)
+        {
+            ret [i] = in [i];
+            ret [i + in.size()] = in [i] * 10;
+        }
+
+        ret.detachTo (ComSafeArrayOutArg (aRet));
+
+        return S_OK;
+    }
+
+ * @endcode
+ *
+ * Such methods can be called from the client code using the following pattern:
+ * @code
+
+    ComPtr <ISomething> component;
+
+    // ...
+
+    com::SafeArray <LONG> in (3);
+    in [0] = -1;
+    in [1] = -2;
+    in [2] = -3;
+
+    com::SafeArray <LONG> out;
+    com::SafeArray <LONG> ret;
+
+    HRESULT rc = component->TestArrays (ComSafeArrayAsInParam (in),
+                                        ComSafeArrayAsOutParam (out),
+                                        ComSafeArrayAsOutParam (ret));
+
+    if (SUCCEEDED (rc))
+        for (size_t i = 0; i < ret.size(); ++ i)
+            printf ("*** ret[%u]=%d\n", i, ret [i]);
+
+ * @endcode
+ *
+ * Implementation declarations and function bodies of attribute getters and
+ * setters are very similar to the examples shown above and therefore not
+ * explained separately.
+ *
+ * The current implementation of the SafeArray layer supports all types normally
+ * allowed in XIDL as array element types (including 'wstring', 'uuid' types and
+ * interface pointers). However 'pointer-to' types (e.g. 'long *', 'wstrig *',
+ * 'IUnknown **') are not supported and therefore cannot be used as element
+ * types.
+ */
+
+#if defined (VBOX_WITH_XPCOM)
+#include <nsMemory.h>
+#endif
+
+#include "VBox/com/defs.h"
+#include "VBox/com/assert.h"
+
+#include "iprt/cpputils.h"
+
+#if defined (VBOX_WITH_XPCOM)
+
+/**
+ * Wraps the given com::SafeArray instance to generate an expression that is
+ * suitable for passing it to functions that take input safearray parameters
+ * declared using the ComSafeArrayIn marco.
+ *
+ * @param aArray    com::SafeArray instance to pass as an input parameter.
+ */
+#define ComSafeArrayAsInParam(aArray)   \
+    (aArray).size(), (aArray).__asInParam_Arr (aArray.raw())
+
+/**
+ * Wraps the given com::SafeArray instance to generate an expression that is
+ * suitable for passing it to functions that take output safearray parameters
+ * declared using the ComSafeArrayOut marco.
+ *
+ * @param aArray    com::SafeArray instance to pass as an output parameter.
+ */
+#define ComSafeArrayAsOutParam(aArray)  \
+    (aArray).__asOutParam_Size(), (aArray).__asOutParam_Arr()
+
+#else /* defined (VBOX_WITH_XPCOM) */
+
+#define ComSafeArrayAsInParam(aArray)   (aArray).__asInParam()
+
+#define ComSafeArrayAsOutParam(aArray)  (aArray).__asOutParam()
+
+#endif /* defined (VBOX_WITH_XPCOM) */
+
+/**
+ *
+ */
+namespace com
+{
+
+#if defined (VBOX_WITH_XPCOM)
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Contains various helper constants for SafeArray.
+ */
+template <typename T>
+struct SafeArrayTraits
+{
+    static void Init (T &aElem) { aElem = 0; }
+    static void Uninit (T &aElem) { aElem = 0; }
+
+    /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard.
+     * Then initial reason for this magic is that XPIDL declares input strings
+     * (char/PRUnichar pointers) as const but doesn't do so for pointers to
+     * arrays. */
+    static T *__asInParam_Arr (T *aArr) { return aArr; }
+    static T *__asInParam_Arr (const T *aArr) { return const_cast <T *> (aArr); }
+};
+
+template<>
+struct SafeArrayTraits <PRUnichar *>
+{
+    static void Init (PRUnichar * &aElem) { aElem = NULL; }
+    static void Uninit (PRUnichar * &aElem)
+    {
+        if (aElem)
+        {
+            ::SysFreeString (aElem);
+            aElem = NULL;
+        }
+    }
+
+    /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */
+    static const PRUnichar **__asInParam_Arr (PRUnichar **aArr)
+    {
+        return const_cast <const PRUnichar **> (aArr);
+    }
+    static const PRUnichar **__asInParam_Arr (const PRUnichar **aArr) { return aArr; }
+};
+
+#else /* defined (VBOX_WITH_XPCOM) */
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Contains various helper constants for SafeArray.
+ */
+template <typename T>
+struct SafeArrayTraits
+{
+    static VARTYPE VarType() { AssertMsgFailedReturn ("Not supported", VT_EMPTY) }
+};
+
+template<>
+struct SafeArrayTraits <LONG>
+{
+    static VARTYPE VarType() { return VT_I4; }
+};
+
+template<>
+struct SafeArrayTraits <ULONG>
+{
+    static VARTYPE VarType() { return VT_UI4; }
+};
+
+template<>
+struct SafeArrayTraits <BSTR>
+{
+    static VARTYPE VarType() { return VT_BSTR; }
+};
+
+#endif /* defined (VBOX_WITH_XPCOM) */
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The SafeArray class represents the safe array type used in COM to pass arrays
+ * to/from interface methods.
+ *
+ * This helper class hides all MSCOM/XPCOM specific implementation details and,
+ * together with ComSafeArrayIn, ComSafeArrayOut and ComSafeArrayRet macros,
+ * provides a platform-neutral way to handle safe arrays in the method
+ * implementation.
+ *
+ * When an instance of this class is destroyed, it automatically frees all
+ * resources occupied by individual elements of the array as well as by the
+ * array itself. However, when the value of an element is manually changed
+ * using #operator[] or by acessing array data through the #raw() pointer, it is
+ * the caller's responsibility to free resources occupied by the previous
+ * element's value.
+ *
+ * Also, objects of this class do not support copy and assignment operations and
+ * therefore cannot be returned from functions by value. In other words, this
+ * class is just a temporary storage for handling interface method calls and not
+ * intended to be used to store arrays as data members and such -- you should
+ * use normal list/vector classes for that.
+ *
+ * @note The current implementation supports only one-dimentional arrays.
+ *
+ * @note This class is not thread-safe.
+ */
+template  <typename T>
+class SafeArray : public SafeArrayTraits <T>
+{
+public:
+
+    /**
+     * Creates a null array.
+     */
+    SafeArray() {}
+
+    /**
+     * Creates a new array of the given size. All elements of the newly created
+     * array initialized with null values.
+     *
+     * @param aSize     Initial number of elements in the array. Must be greater
+     *                  than 0.
+     *
+     * @note If this object remains null after construction it means that there
+     *       was not enough memory for creating an array of the requested size.
+     *       The constructor will also assert in this case.
+     */
+    SafeArray (size_t aSize) { reset (aSize); }
+
+    /**
+     * Weakly attaches this instance to the existing array passed in a method
+     * parameter declared using the ComSafeArrayIn macro. When using this call,
+     * always wrap the parameter name in the ComSafeArrayOutArg macro call like
+     * this:
+     * <pre>
+     *  SafeArray safeArray (ComSafeArrayInArg (aArg));
+     * </pre>
+     *
+     * Note that this constructor doesn't take the ownership of the array. In
+     * particular, it means that operations that operate on the ownership (e.g.
+     * #detachTo()) are forbidden and will assert.
+     *
+     * @param aArg  Input method parameter to attach to.
+     */
+    SafeArray (ComSafeArrayIn (T, aArg))
+    {
+#if defined (VBOX_WITH_XPCOM)
+
+        AssertReturnVoid (aArg != NULL);
+
+        m.size = aArgSize;
+        m.arr = aArg;
+        m.isWeak = true;
+
+#else /* defined (VBOX_WITH_XPCOM) */
+
+        AssertReturnVoid (aArg != NULL);
+        SAFEARRAY *arg = *aArg;
+
+        if (arg)
+        {
+            AssertReturnVoid (arg->cDims == 1);
+
+            VARTYPE vt;
+            HRESULT rc = SafeArrayGetVartype (arg, &vt);
+            AssertComRCReturnVoid (rc);
+            AssertMsgReturnVoid (vt == VarType(),
+                                 ("Expected vartype %d, got %d.\n",
+                                  VarType(), vt));
+        }
+
+        m.arr = arg;
+        m.isWeak = true;
+
+        AssertReturnVoid (accessRaw() != NULL);
+
+#endif /* defined (VBOX_WITH_XPCOM) */
+    }
+
+    /**
+     * Destroys this instance after calling #setNull() to release allocated
+     * resources. See #setNull() for more details.
+     */
+    ~SafeArray() { setNull(); }
+
+    /**
+     * Returns @c true if this instance represents a null array.
+     */
+    bool isNull() const { return m.arr == NULL; }
+
+    /**
+     * Resets this instance to null and, if this instance is not a weak one,
+     * releases any resources ocuppied by the array data.
+     *
+     * @note This method destroys (cleans up) all elements of the array using
+     *       the corresponding cleanup routine for the element type before the
+     *       array itself is destroyed.
+     */
+    void setNull() { m.uninit(); }
+
+    /**
+     * Returns @c true if this instance is weak. A weak instance doesn't own the
+     * array data and therefore operations manipulating the ownership (e.g.
+     * #detachTo()) are forbidden and will assert.
+     */
+    bool isWeak() const { return m.isWeak; }
+
+    /** Number of elements in the array. */
+    size_t size() const
+    {
+#if defined (VBOX_WITH_XPCOM)
+        if (m.arr)
+            return m.size;
+        return 0;
+#else
+        if (m.arr)
+            return m.arr->rgsabound [0].cElements;
+        return 0;
+#endif
+    }
+
+    /**
+     * Resizes the array preserving its contents when possible. If the new size
+     * is bigger than the old size, new elements are initialized with null
+     * values. If the new size is smaller than the old size, the contents of the
+     * array above the new size is lost.
+     *
+     * @param aNewSize  New number of elements in the array.
+     * @return          @c true on success and false if there is not enough
+     *                  memory for resizing.
+     */
+    bool resize (size_t aNewSize)
+    {
+        /// @todo Implement me!
+        AssertFailedReturn (false);
+    }
+
+    /**
+     * Reinitializes this instance by preallocating space for the given number
+     * of elements. The previous array contents is lost.
+     *
+     * @param aNewSize  New number of elements in the array.
+     * @return          @c true on success and false if there is not enough
+     *                  memory for resizing.
+     */
+    bool reset (size_t aNewSize)
+    {
+        m.uninit();
+
+#if defined (VBOX_WITH_XPCOM)
+
+        AssertReturn (aNewSize > 0, false);
+
+        m.arr = (T *) nsMemory::Alloc (aNewSize * sizeof (T));
+        AssertReturn (m.arr != NULL, false);
+
+        m.size = aNewSize;
+
+        for (size_t i = 0; i < m.size; ++ i)
+            Init (m.arr [i]);
+
+#else
+
+        AssertReturn (aNewSize > 0, false);
+
+        SAFEARRAYBOUND bound = { aNewSize, 0 };
+        m.arr = SafeArrayCreate (VarType(), 1, &bound);
+        AssertReturn (m.arr != NULL, false);
+
+        AssertReturn (accessRaw() != NULL, false);
+
+#endif
+        return true;
+    }
+
+    /**
+     * Returns a pointer to the raw array data. Use this raw pointer with care
+     * as no type or bound checking is done for you in this case.
+     *
+     * @note This method returns @c NULL when this instance is null.
+     * @see #operator[]
+     */
+    T *raw()
+    {
+#if defined (VBOX_WITH_XPCOM)
+        return m.arr;
+#else
+        return accessRaw();
+#endif
+    }
+
+    /**
+     * Const version of #raw().
+     */
+    const T *raw() const
+    {
+#if defined (VBOX_WITH_XPCOM)
+        return m.arr;
+#else
+        return accessRaw();
+#endif
+    }
+
+    /**
+     * Array access operator that returns an array element by reference. A bit
+     * safer than #raw(): asserts and returns an invalid reference if this
+     * instance is null or if the index is out of bounds.
+     *
+     * @note For weak instances, this call will succeed but the beiavior of
+     *       changing the contents of an element of the weak array instance is
+     *       undefined and may lead to a program crash on some platforms.
+     */
+    T &operator[] (size_t aIdx)
+    {
+        AssertReturn (m.arr != NULL,  *((T *) NULL));
+        AssertReturn (aIdx < size(), *((T *) NULL));
+#if defined (VBOX_WITH_XPCOM)
+        return m.arr [aIdx];
+#else
+
+        AssertReturn (accessRaw() != NULL,  *((T *) NULL));
+        return m.raw [aIdx];
+#endif
+    }
+
+    /**
+     * Const version of #operator[] that returns an array element by value.
+     */
+    const T operator[] (size_t aIdx) const
+    {
+        AssertReturn (m.arr != NULL,  *((T *) NULL));
+        AssertReturn (aIdx < size(), *((T *) NULL));
+#if defined (VBOX_WITH_XPCOM)
+        return m.arr [aIdx];
+#else
+        AssertReturn (unconst (this)->accessRaw() != NULL,  *((T *) NULL));
+        return m.raw [aIdx];
+#endif
+    }
+
+    /**
+     * Creates a copy of this array and stores it in a method parameter declared
+     * using the ComSafeArrayOut macro. When using this call, always wrap the
+     * parameter name in the ComSafeArrayOutArg macro call like this:
+     * <pre>
+     *  safeArray.cloneTo (ComSafeArrayOutArg (aArg));
+     * </pre>
+     *
+     * @note It is assumed that the ownership of the returned copy is
+     * transferred to the caller of the method and he is responsible to free the
+     * array data when it is no more necessary.
+     *
+     * @param aArg  Output method parameter to clone to.
+     */
+    const SafeArray &cloneTo (ComSafeArrayOut (T, aArg)) const
+    {
+        /// @todo Implement me!
+        AssertFailedReturn (*this);
+    }
+
+    /**
+     * Transfers the ownership of this array's data to a method parameter
+     * declared using the ComSafeArrayOut macro and makes this array a null
+     * array. When using this call, always wrap the parameter name in the
+     * ComSafeArrayOutArg macro call like this:
+     * <pre>
+     *  safeArray.detachTo (ComSafeArrayOutArg (aArg));
+     * </pre>
+     *
+     * @note Since the ownership of the array data is transferred to the
+     * caller of the method, he is responsible to free the array data when it is
+     * no more necessary.
+     *
+     * @param aArg  Output method parameter to detach to.
+     */
+    SafeArray &detachTo (ComSafeArrayOut (T, aArg))
+    {
+        AssertReturn (m.isWeak == false, *this);
+
+#if defined (VBOX_WITH_XPCOM)
+
+        AssertReturn (aArgSize != NULL, *this);
+        AssertReturn (aArg != NULL, *this);
+
+        *aArgSize = m.size;
+        *aArg = m.arr;
+
+        m.isWeak = false;
+        m.size = 0;
+        m.arr = NULL;
+
+#else /* defined (VBOX_WITH_XPCOM) */
+
+        AssertReturn (aArg != NULL, *this);
+        *aArg = m.arr;
+
+        if (m.raw)
+        {
+            HRESULT rc = SafeArrayUnaccessData (m.arr);
+            AssertComRCReturn (rc, *this);
+            m.raw = NULL;
+        }
+
+        m.isWeak = false;
+        m.arr = NULL;
+
+#endif /* defined (VBOX_WITH_XPCOM) */
+
+        return *this;
+    }
+
+    // public methods for internal purposes only
+
+#if defined (VBOX_WITH_XPCOM)
+
+    /** Internal funciton. Never call it directly. */
+    PRUint32 *__asOutParam_Size() { setNull(); return &m.size; }
+
+    /** Internal funciton. Never call it directly. */
+    T **__asOutParam_Arr() { Assert (isNull()); return &m.arr; }
+
+#else /* defined (VBOX_WITH_XPCOM) */
+
+    /** Internal funciton. Never call it directly. */
+    SAFEARRAY ** __asInParam() { return &m.arr; }
+
+    /** Internal funciton. Never call it directly. */
+    SAFEARRAY ** __asOutParam() { setNull(); return &m.arr; }
+
+#endif /* defined (VBOX_WITH_XPCOM) */
+
+    static const SafeArray Null;
+
+private:
+
+    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeArray)
+
+#if defined (VBOX_WITH_XPCOM)
+#else /* defined (VBOX_WITH_XPCOM) */
+
+    /** Requests access to the raw data pointer. */
+    T *accessRaw()
+    {
+        if (m.arr && m.raw == NULL)
+        {
+            HRESULT rc = SafeArrayAccessData (m.arr, (void HUGEP **) &m.raw);
+            AssertComRCReturn (rc, NULL);
+        }
+        return m.raw;
+    }
+
+#endif /* defined (VBOX_WITH_XPCOM) */
+
+    struct Data
+    {
+        Data()
+            : isWeak (false)
+#if defined (VBOX_WITH_XPCOM)
+            , size (0), arr (NULL)
+#else
+            , arr (NULL), raw (NULL)
+#endif
+        {}
+
+        ~Data() { uninit(); }
+
+        void uninit()
+        {
+#if defined (VBOX_WITH_XPCOM)
+
+            if (arr)
+            {
+                if (!isWeak)
+                {
+                    for (size_t i = 0; i < size; ++ i)
+                        Uninit (arr [i]);
+
+                    nsMemory::Free ((void *) arr);
+
+                    isWeak = false;
+                }
+                arr = NULL;
+            }
+
+#else /* defined (VBOX_WITH_XPCOM) */
+
+            if (arr)
+            {
+                if (raw)
+                {
+                    SafeArrayUnaccessData (arr);
+                    raw = NULL;
+                }
+
+                if (!isWeak)
+                {
+                    HRESULT rc = SafeArrayDestroy (arr);
+                    AssertComRCReturnVoid (rc);
+
+                    isWeak = false;
+                }
+                arr = NULL;
+            }
+
+#endif /* defined (VBOX_WITH_XPCOM) */
+        }
+
+        bool isWeak : 1;
+
+#if defined (VBOX_WITH_XPCOM)
+        PRUint32 size;
+        T *arr;
+#else
+        SAFEARRAY *arr;
+        T *raw;
+#endif
+    };
+
+    Data m;
+};
+
+} /* namespace com */
+
+/** @} */
+
+#endif /* ___VBox_com_array_h */
Index: /trunk/include/VBox/com/defs.h
===================================================================
--- /trunk/include/VBox/com/defs.h	(revision 6850)
+++ /trunk/include/VBox/com/defs.h	(revision 6851)
@@ -70,4 +70,73 @@
 
 /**
+ * Declares an input safearray parameter in the COM method implementation. Also 
+ * used to declare the COM attribute setter parameter. Corresponds to either of 
+ * the following XIDL definitions: 
+ * <pre>
+ *  <param name="arg" ... dir="in" safearray="yes"/>
+ *  ...
+ *  <attribute name="arg" ... safearray="yes"/>
+ * </pre> 
+ * 
+ * The method implementation should use the com::SafeArray helper class to work 
+ * with parameters declared using this define. 
+ *  
+ * @param aType Array element type.
+ * @param aArg  Parameter/attribute name.
+ */
+#define ComSafeArrayIn(aType, aArg)     SAFEARRAY **aArg
+
+/** 
+ * Expands to @true if the given input safearray parameter is a "null pointer" 
+ * which makes it impossible to use it for reading safearray data. 
+ */ 
+#define ComSafeArrayInIsNull(aArg)      (aArg == NULL)
+
+/** 
+ * Wraps the given parameter name to generate an expression that is suitable for
+ * passing the parameter to functions that take input safearray parameters 
+ * declared using the ComSafeArrayIn marco. 
+ *  
+ * @param aArg  Parameter name to wrap. The given parameter must be declared 
+ *              within the calling function using the ComSafeArrayIn macro.
+ */
+#define ComSafeArrayInArg(aArg)         aArg
+
+/**
+ * Declares an output safearray parameter in the COM method implementation. Also 
+ * used to declare the COM attribute getter parameter. Corresponds to either of 
+ * the following XIDL definitions:
+ * <pre>
+ *  <param name="arg" ... dir="out" safearray="yes"/>
+ *  <param name="arg" ... dir="return" safearray="yes"/>
+ *  ...
+ *  <attribute name="arg" ... safearray="yes"/>
+ * </pre> 
+ *  
+ * The method implementation should use the com::SafeArray helper class to work 
+ * with parameters declared using this define. 
+ *  
+ * @param aType Array element type.
+ * @param aArg  Parameter/attribute name.
+ */
+#define ComSafeArrayOut(aType, aArg)    SAFEARRAY **aArg
+
+/** 
+ * Expands to @true if the given output safearray parameter is a "null pointer" 
+ * which makes it impossible to use it for returning a safearray.
+ */ 
+#define ComSafeArrayOutIsNull(aArg)     (aArg == NULL)
+
+/** 
+ * Wraps the given parameter name to generate an expression that is suitable for
+ * passing the parameter to functions that take output safearray parameters 
+ * declared using the ComSafeArrayOut marco. 
+ *  
+ * @param aArg  Parameter name to wrap. The given parameter must be declared 
+ *              within the calling function using the ComSafeArrayOut macro.
+ */
+#define ComSafeArrayOutArg(aArg)        aArg
+
+/**
  *  Returns the const reference to the IID (i.e., |const GUID &|) of the given
  *  interface.
@@ -79,5 +148,5 @@
 #else /* defined (RT_OS_WINDOWS) */
 
-#error "VBOX_WITH_XPCOM is not defined!"
+#error "VBOX_WITH_XPCOM must be defined on a platform other than Windows!"
 
 #endif /* defined (RT_OS_WINDOWS) */
@@ -156,4 +225,14 @@
 /* a type for an output GUID parameter in the interface method declaration */
 #define GUIDPARAMOUT        nsID **
+
+/* safearray input parameter macros */
+#define ComSafeArrayIn(aType, aArg)         PRUint32 aArg##Size, aType *aArg
+#define ComSafeArrayInIsNull(aArg)          (aArg == NULL)
+#define ComSafeArrayInArg(aArg)             aArg##Size, aArg
+
+/* safearray output parameter macros */
+#define ComSafeArrayOut(aType, aArg)        PRUint32 *aArg##Size, aType **aArg
+#define ComSafeArrayOutIsNull(aArg)         (aArg == NULL)
+#define ComSafeArrayOutArg(aArg)            aArg##Size, aArg
 
 /* CLSID and IID for compatibility with Win32 */
Index: /trunk/include/VBox/com/string.h
===================================================================
--- /trunk/include/VBox/com/string.h	(revision 6850)
+++ /trunk/include/VBox/com/string.h	(revision 6851)
@@ -184,7 +184,7 @@
 
     /**
-     *  Intended to assign instances to |BSTR| out parameters from within the
-     *  interface method. Transfers the ownership of the duplicated string to
-     *  the caller.
+     *  Intended to assign copies of instances to |BSTR| out parameters from
+     *  within the interface method. Transfers the ownership of the duplicated
+     *  string to the caller.
      */
     const Bstr &cloneTo (BSTR *pstr) const
@@ -199,7 +199,22 @@
 
     /**
-     *  Intended to assign instances to |char *| out parameters from within the
-     *  interface method. Transfers the ownership of the duplicated string to
-     *  the caller.
+     *  Intended to assign instances to |BSTR| out parameters from within the
+     *  interface method. Transfers the ownership of the original string to the
+     *  caller and resets the instance to null.
+     *
+     *  As opposed to cloneTo(), this method doesn't create a copy of the
+     *  string.
+     */
+    Bstr &detachTo (BSTR *pstr)
+    {
+        *pstr = bstr;
+        bstr = NULL;
+        return *this;
+    }
+
+    /**
+     *  Intended to assign copies of instances to |char *| out parameters from
+     *  within the interface method. Transfers the ownership of the duplicated
+     *  string to the caller.
      */
     const Bstr &cloneTo (char **pstr) const;
@@ -211,5 +226,5 @@
     BSTR *asOutParam() { setNull(); return &bstr; }
 
-    /** 
+    /**
      *  Static immutable null object. May be used for comparison purposes.
      */
@@ -405,4 +420,19 @@
 
     /**
+     *  Intended to assign instances to |char *| out parameters from within the
+     *  interface method. Transfers the ownership of the original string to the
+     *  caller and resets the instance to null.
+     *
+     *  As opposed to cloneTo(), this method doesn't create a copy of the
+     *  string.
+     */
+    Utf8Str &detachTo (char **pstr)
+    {
+        *pstr = str;
+        str = NULL;
+        return *this;
+    }
+
+    /**
      *  Intended to assign instances to |BSTR| out parameters from within the
      *  interface method. Transfers the ownership of the duplicated string to the
@@ -425,5 +455,5 @@
     char **asOutParam() { setNull(); return &str; }
 
-    /** 
+    /**
      *  Static immutable null object. May be used for comparison purposes.
      */
Index: /trunk/src/VBox/Frontends/VirtualBox/include/COMDefs.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/include/COMDefs.h	(revision 6850)
+++ /trunk/src/VBox/Frontends/VirtualBox/include/COMDefs.h	(revision 6851)
@@ -24,4 +24,45 @@
 #define __COMDefs_h__
 
+/** @defgroup   grp_QT_COM  Qt-COM Support Layer
+ * @{
+ *
+ * The Qt-COM support layer provides a set of defintions and smart classes for
+ * writing simple, clean and platform-independent code to access COM/XPCOM
+ * components through exposed COM interfaces. This layer is based on the
+ * COM/XPCOM Abstarction Layer library (the VBoxCOM glue library defined in
+ * include/VBox/com and implemented in src/VBox/Main/glue).
+ *
+ * ...
+ *
+ * @defgroup   grp_QT_COM_arrays    Arrays
+ * @{
+ *
+ * COM/XPCOM arrays are mapped to QValueVector objects. QValueVector templates
+ * declared with a type that corresponds to the COM type of elements in the
+ * array using normal Qt-COM type mapping rules. Here is a code example that
+ * demonstrates how to call interface methods that take and return arrays (this
+ * example is based on examples given in @ref grp_COM_arrays):
+ * @code
+
+    CSomething component;
+
+    // ...
+
+    QValueVector <LONG> in (3);
+    in [0] = -1;
+    in [1] = -2;
+    in [2] = -3;
+
+    QValueVector <LONG> out;
+    QValueVector <LONG> ret;
+
+    ret = component.TestArrays (in, out);
+
+    for (size_t i = 0; i < ret.size(); ++ i)
+        LogFlow (("*** ret[%u]=%d\n", i, ret [i]));
+
+ * @endcode
+ * @}
+ */
 
 /* Both VBox/com/assert.h and qglobal.h contain a definition of ASSERT.
@@ -30,4 +71,5 @@
 
 #include <VBox/com/com.h>
+#include <VBox/com/array.h>
 #include <VBox/com/assert.h>
 
@@ -37,4 +79,5 @@
 #include <qstring.h>
 #include <quuid.h>
+#include <qvaluevector.h>
 
 #include <iprt/memory> // for auto_copy_ptr
@@ -139,28 +182,6 @@
 public:
 
-    static HRESULT initializeCOM();
-    static HRESULT cleanupCOM();
-
-#if !defined (VBOX_WITH_XPCOM)
-
-    /** Converts a GUID value to QUuid */
-    static QUuid toQUuid (const GUID &id)
-    {
-        return QUuid (id.Data1, id.Data2, id.Data3,
-                      id.Data4[0], id.Data4[1], id.Data4[2], id.Data4[3],
-                      id.Data4[4], id.Data4[5], id.Data4[6], id.Data4[7]);
-    }
-
-#else /* !defined (VBOX_WITH_XPCOM) */
-
-    /** Converts a GUID value to QUuid */
-    static QUuid toQUuid (const nsID &id)
-    {
-        return QUuid (id.m0, id.m1, id.m2,
-                      id.m3[0], id.m3[1], id.m3[2], id.m3[3],
-                      id.m3[4], id.m3[5], id.m3[6], id.m3[7]);
-    }
-
-#endif /* !defined (VBOX_WITH_XPCOM) */
+    static HRESULT InitializeCOM();
+    static HRESULT CleanupCOM();
 
     /**
@@ -178,4 +199,109 @@
     virtual COMErrorInfo errorInfo() const { return COMErrorInfo(); }
 
+#if !defined (VBOX_WITH_XPCOM)
+
+    /** Converts a GUID value to QUuid */
+    static QUuid ToQUuid (const GUID &id)
+    {
+        return QUuid (id.Data1, id.Data2, id.Data3,
+                      id.Data4[0], id.Data4[1], id.Data4[2], id.Data4[3],
+                      id.Data4[4], id.Data4[5], id.Data4[6], id.Data4[7]);
+    }
+
+#else /* !defined (VBOX_WITH_XPCOM) */
+
+    /** Converts a GUID value to QUuid */
+    static QUuid ToQUuid (const nsID &id)
+    {
+        return QUuid (id.m0, id.m1, id.m2,
+                      id.m3[0], id.m3[1], id.m3[2], id.m3[3],
+                      id.m3[4], id.m3[5], id.m3[6], id.m3[7]);
+    }
+
+#endif /* !defined (VBOX_WITH_XPCOM) */
+
+    /* Arrays of arbitrary types */
+
+    template <typename QT, typename CT>
+    static void ToSafeArray (const QValueVector <QT> &aVec, com::SafeArray <CT> &aArr)
+    {
+        AssertMsgFailedReturnVoid (("No conversion!\n"));
+    }
+
+    template <typename CT, typename QT>
+    static void FromSafeArray (const com::SafeArray <CT> &aArr, QValueVector <QT> &aVec)
+    {
+        AssertMsgFailedReturnVoid (("No conversion!\n"));
+    }
+
+    template <typename QT, typename CT>
+    static void ToSafeArray (const QValueVector <QT *> &aVec, com::SafeArray <CT *> &aArr)
+    {
+        AssertMsgFailedReturnVoid (("No conversion!\n"));
+    }
+
+    template <typename CT, typename QT>
+    static void FromSafeArray (const com::SafeArray <CT *> &aArr, QValueVector <QT *> &aVec)
+    {
+        AssertMsgFailedReturnVoid (("No conversion!\n"));
+    }
+
+    /* Arrays of equal types */
+
+    template <typename T>
+    static void ToSafeArray (const QValueVector <T> &aVec, com::SafeArray <T> &aArr)
+    {
+        aArr.reset (aVec.size());
+        size_t i = 0;
+        for (typename QValueVector <T>::const_iterator it = aVec.begin();
+             it != aVec.end(); ++ it, ++ i)
+            aArr [i] = *it;
+    }
+
+    template <typename T>
+    static void FromSafeArray (const com::SafeArray <T> &aArr, QValueVector <T> &aVec)
+    {
+        aVec = QValueVector <T> (aArr.size());
+        size_t i = 0;
+        for (typename QValueVector <T>::iterator it = aVec.begin();
+             it != aVec.end(); ++ it, ++ i)
+            *it = aArr [i];
+    }
+
+    /* Arrays of interface pointers */
+
+    template <class CI, class I>
+    static void ToSafeArray (const QValueVector <CI> &aVec,
+                             com::SafeArray <I *> &aArr)
+    {
+        aArr.reset (aVec.size());
+        size_t i = 0;
+        for (typename QValueVector <CI>::const_iterator it = aVec.begin();
+             it != aVec.end(); ++ it, ++ i)
+        {
+            aArr [i] = (*it).iface();
+            if (aArr [i])
+                aArr [i]->AddRef();
+        }
+    }
+
+    template <class I, class CI>
+    void FromSafeArray (const com::SafeArray <I *> &aArr,
+                        QValueVector <CI> &aVec)
+    {
+        aVec = QValueVector <CI> (aArr.size());
+        size_t i = 0;
+        for (typename QValueVector <CI>::iterator it = aVec.begin();
+             it != aVec.end(); ++ it, ++ i)
+            (*it).attach (aArr [i]);
+    }
+
+    /* Arrays of strings */
+
+    static void ToSafeArray (const QValueVector <QString> &aVec,
+                             com::SafeArray <BSTR> &aArr);
+    static void FromSafeArray (const com::SafeArray <BSTR> &aArr,
+                               QValueVector <QString> &aVec);
+
 protected:
 
@@ -230,18 +356,23 @@
     };
 
-    /** Adapter to pass CEnums enums as output VirtualBox enum params (*_T) */
-    template <typename CE, typename VE>
+    /**
+     * Adapter to pass CEnums enums as output COM enum params (*_T).
+     *
+     * @param QE    CEnums enum.
+     * @param CE    COM enum.
+     */
+    template <typename QE, typename CE>
     class ENUMOut
     {
     public:
 
-        ENUMOut (CE &e) : ce (e), ve ((VE) 0) {}
-        ~ENUMOut() { ce = (CE) ve; }
-        operator VE *() { return &ve; }
+        ENUMOut (QE &e) : qe (e), ce ((CE) 0) {}
+        ~ENUMOut() { qe = (QE) ce; }
+        operator CE *() { return &ce; }
 
     private:
 
-        CE &ce;
-        VE ve;
+        QE &qe;
+        CE ce;
     };
 
@@ -605,3 +736,5 @@
 #include "COMWrappers.h"
 
+/** @} */
+
 #endif // __COMDefs_h__
Index: /trunk/src/VBox/Frontends/VirtualBox/include/COMWrappers.xsl
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/include/COMWrappers.xsl	(revision 6850)
+++ /trunk/src/VBox/Frontends/VirtualBox/include/COMWrappers.xsl	(revision 6851)
@@ -12,5 +12,5 @@
 /*
      Copyright (C) 2006-2007 innotek GmbH
-    
+
      This file is part of VirtualBox Open Source Edition (OSE), as
      available from http://www.virtualbox.org. This file is free software;
@@ -126,5 +126,5 @@
         <xsl:text>    enum </xsl:text>
         <xsl:value-of select="@name"/>
-        <xsl:text> {&#x0A;</xsl:text>
+        <xsl:text>&#x0A;    {&#x0A;</xsl:text>
         <xsl:for-each select="const">
             <xsl:text>        </xsl:text>
@@ -360,5 +360,5 @@
     <xsl:text>    C</xsl:text>
     <xsl:value-of select="substring(@name,2)"/>
-    <xsl:text> &amp; operator = (const CUnknown &amp; that) {&#x0A;        return (C</xsl:text>
+    <xsl:text> &amp; operator = (const CUnknown &amp; that)&#x0A;    {&#x0A;        return (C</xsl:text>
     <xsl:value-of select="substring(@name,2)"/>
     <xsl:text> &amp;) Base::operator = (that);&#x0A;    }&#x0A;&#x0A;</xsl:text>
@@ -431,5 +431,12 @@
 </xsl:template>
 
+<!-- attribute declarations -->
 <xsl:template match="interface//attribute | collection//attribute" mode="declare">
+    <xsl:if test="@array">
+        <xsl:message terminate="yes">
+            <xsl:value-of select="concat(../../@name,'::',../@name,'::',@name,': ')"/>
+            <xsl:text>'array' attributes are not supported, use 'safearray="yes"' instead.</xsl:text>
+        </xsl:message>
+    </xsl:if>
     <xsl:apply-templates select="parent::node()" mode="begin"/>
     <xsl:apply-templates select="@if" mode="begin"/>
@@ -446,4 +453,5 @@
 </xsl:template>
 
+<!-- method declarations -->
 <xsl:template match="interface//method | collection//method" mode="declare">
     <xsl:apply-templates select="parent::node()" mode="begin"/>
@@ -468,5 +476,5 @@
         <xsl:text>inline ULONG C</xsl:text>
         <xsl:value-of select="substring(@name,2)"/>
-        <xsl:text>::GetCount () const {&#x0A;</xsl:text>
+        <xsl:text>::GetCount () const&#x0A;{&#x0A;</xsl:text>
         <xsl:text>    ULONG count = 0;&#x0A;</xsl:text>
         <xsl:text>    Assert (mIface);&#x0A;</xsl:text>
@@ -481,5 +489,5 @@
         <xsl:text> C</xsl:text>
         <xsl:value-of select="substring(@name,2)"/>
-        <xsl:text>::GetItemAt (ULONG index) const {&#x0A;</xsl:text>
+        <xsl:text>::GetItemAt (ULONG index) const&#x0A;{&#x0A;</xsl:text>
         <xsl:text>    </xsl:text><xsl:apply-templates select="@type"/>
         <xsl:text> item;&#x0A;</xsl:text>
@@ -495,5 +503,5 @@
         <xsl:text> C</xsl:text>
         <xsl:value-of select="substring(@name,2)"/>
-        <xsl:text>::Enumerate () const {&#x0A;</xsl:text>
+        <xsl:text>::Enumerate () const&#x0A;{&#x0A;</xsl:text>
         <xsl:text>    </xsl:text><xsl:apply-templates select="@enumerator"/>
         <xsl:text> enumerator;&#x0A;</xsl:text>
@@ -510,5 +518,5 @@
         <xsl:text>inline BOOL C</xsl:text>
         <xsl:value-of select="substring(@name,2)"/>
-        <xsl:text>::HasMore () const {&#x0A;</xsl:text>
+        <xsl:text>::HasMore () const&#x0A;{&#x0A;</xsl:text>
         <xsl:text>    BOOL more = FALSE;&#x0A;</xsl:text>
         <xsl:text>    Assert (mIface);&#x0A;</xsl:text>
@@ -523,5 +531,5 @@
         <xsl:text> C</xsl:text>
         <xsl:value-of select="substring(@name,2)"/>
-        <xsl:text>::GetNext () const {&#x0A;</xsl:text>
+        <xsl:text>::GetNext () const&#x0A;{&#x0A;</xsl:text>
         <xsl:text>    </xsl:text><xsl:apply-templates select="@type"/>
         <xsl:text> next;&#x0A;</xsl:text>
@@ -545,4 +553,5 @@
 </xsl:template>
 
+<!-- attribute definitions -->
 <xsl:template match="interface//attribute | collection//attribute" mode="define">
     <xsl:apply-templates select="parent::node()" mode="begin"/>
@@ -563,4 +572,5 @@
 </xsl:template>
 
+<!-- method definitions -->
 <xsl:template match="interface//method | collection//method" mode="define">
     <xsl:apply-templates select="parent::node()" mode="begin"/>
@@ -625,5 +635,5 @@
             </xsl:call-template>
             <xsl:if test="$define">
-                <xsl:text> {&#x0A;</xsl:text>
+                <xsl:text>&#x0A;{&#x0A;</xsl:text>
                 <!-- iface assertion -->
                 <xsl:text>    Assert (mIface);&#x0A;</xsl:text>
@@ -658,33 +668,26 @@
             <xsl:call-template name="composeMethodDecl"/>
             <xsl:if test="$define">
-                <xsl:text> {&#x0A;    </xsl:text>
+                <xsl:text>&#x0A;{&#x0A;    </xsl:text>
                 <xsl:apply-templates select="$return/@type"/>
-                <xsl:text> a_</xsl:text>
-                <!-- ### xsl:call-template name="capitalize">
+                <xsl:text> a</xsl:text>
+                <xsl:call-template name="capitalize">
                     <xsl:with-param name="str" select="$return/@name"/>
-                </xsl:call-template-->
-                <!--
-                    using one of the blocks marked with ### causes sabcmd on RedHat
-                    to stupidly fail, so we use <value-of> instead.
-                -->
-                <xsl:value-of select="$return/@name"/>
+                </xsl:call-template>
                 <xsl:apply-templates select="$return/@type" mode="initializer"/>
                 <xsl:text>;&#x0A;</xsl:text>
                 <!-- iface assertion -->
                 <xsl:text>    Assert (mIface);&#x0A;</xsl:text>
-                <xsl:text>    if (!mIface)&#x0A;        return a_</xsl:text>
-                <!-- ### xsl:call-template name="capitalize">
+                <xsl:text>    if (!mIface)&#x0A;        return a</xsl:text>
+                <xsl:call-template name="capitalize">
                     <xsl:with-param name="str" select="$return/@name"/>
-                </xsl:call-template-->
-                <xsl:value-of select="$return/@name"/>
+                </xsl:call-template>
                 <xsl:text>;&#x0A;</xsl:text>
                 <!-- method call -->
                 <xsl:call-template name="composeMethodCall"/>
                 <!-- return statement -->
-                <xsl:text>    return a_</xsl:text>
-                <!-- ### xsl:call-template name="capitalize">
+                <xsl:text>    return a</xsl:text>
+                <xsl:call-template name="capitalize">
                     <xsl:with-param name="str" select="$return/@name"/>
-                </xsl:call-template -->
-                <xsl:value-of select="$return/@name"/>
+                </xsl:call-template>
                 <xsl:text>;&#x0A;}&#x0A;</xsl:text>
             </xsl:if>
@@ -720,9 +723,8 @@
                     <!-- parameter -->
                     <xsl:apply-templates select="@type" mode="param"/>
-                    <xsl:text> a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text> a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:text>)</xsl:text>
                 </xsl:when>
@@ -749,9 +751,8 @@
             <xsl:for-each select="param[@dir!='return']">
                 <xsl:apply-templates select="@type" mode="param"/>
-                <xsl:text> a_</xsl:text>
-                <!-- ###  xsl:call-template name="capitalize">
+                <xsl:text> a</xsl:text>
+                <xsl:call-template name="capitalize">
                     <xsl:with-param name="str" select="@name"/>
-                </xsl:call-template -->
-                <xsl:value-of select="@name"/>
+                </xsl:call-template>
                 <xsl:if test="position() != last()">
                     <xsl:text>, </xsl:text>
@@ -767,4 +768,21 @@
 <xsl:template name="composeMethodCall">
     <xsl:param name="isSetter" select="''"/>
+    <!-- apply 'pre-call' hooks -->
+    <xsl:choose>
+        <xsl:when test="name()='attribute'">
+            <xsl:call-template name="hooks">
+                <xsl:with-param name="when" select="'pre-call'"/>
+                <xsl:with-param name="isSetter" select="$isSetter"/>
+            </xsl:call-template>
+        </xsl:when>
+        <xsl:when test="name()='method'">
+            <xsl:for-each select="param">
+                <xsl:call-template name="hooks">
+                    <xsl:with-param name="when" select="'pre-call'"/>
+                </xsl:call-template>
+            </xsl:for-each>
+        </xsl:when>
+    </xsl:choose>
+    <!-- start the call -->
     <xsl:text>    mRC = mIface-></xsl:text>
     <xsl:choose>
@@ -807,4 +825,21 @@
     </xsl:choose>
     <xsl:text>);&#x0A;</xsl:text>
+    <!-- apply 'post-call' hooks -->
+    <xsl:choose>
+        <xsl:when test="name()='attribute'">
+            <xsl:call-template name="hooks">
+                <xsl:with-param name="when" select="'post-call'"/>
+                <xsl:with-param name="isSetter" select="$isSetter"/>
+            </xsl:call-template>
+        </xsl:when>
+        <xsl:when test="name()='method'">
+            <xsl:for-each select="param">
+                <xsl:call-template name="hooks">
+                    <xsl:with-param name="when" select="'post-call'"/>
+                </xsl:call-template>
+            </xsl:for-each>
+        </xsl:when>
+    </xsl:choose>
+    <!-- -->
     <xsl:call-template name="tryComposeFetchErrorInfo"/>
 </xsl:template>
@@ -855,5 +890,5 @@
         <xsl:otherwise>
             <xsl:if test="$supports='strict' or $supports='yes'">
-                <xsl:text>    if (FAILED (mRC)) {&#x0A;</xsl:text>
+                <xsl:text>    if (FAILED (mRC))&#x0A;    {&#x0A;</xsl:text>
                 <xsl:text>        fetchErrorInfo (mIface, &amp;COM_IIDOF (Base::Iface));&#x0A;</xsl:text>
                 <xsl:if test="$supports='strict'">
@@ -868,4 +903,5 @@
 
 <xsl:template name="composeMethodCallParam">
+
     <xsl:param name="isIn" select="@dir='in'"/>
     <xsl:param name="isOut" select="@dir='out' or @dir='return'"/>
@@ -874,21 +910,34 @@
 
     <xsl:choose>
+        <!-- safearrays -->
+        <xsl:when test="@safearray='yes'">
+            <xsl:choose>
+                <xsl:when test="$isIn">
+                    <xsl:text>ComSafeArrayAsInParam (</xsl:text>
+                    <xsl:value-of select="@name"/>
+                    <xsl:text>)</xsl:text>
+                </xsl:when>
+                <xsl:when test="$isOut">
+                    <xsl:text>ComSafeArrayAsOutParam (</xsl:text>
+                    <xsl:value-of select="@name"/>
+                    <xsl:text>)</xsl:text>
+                </xsl:when>
+            </xsl:choose>
+        </xsl:when>
         <!-- string types -->
         <xsl:when test="@type = 'wstring'">
             <xsl:choose>
                 <xsl:when test="$isIn">
-                    <xsl:text>BSTRIn (a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>BSTRIn (a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:text>)</xsl:text>
                 </xsl:when>
                 <xsl:when test="$isOut">
-                    <xsl:text>BSTROut (a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>BSTROut (a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:text>)</xsl:text>
                 </xsl:when>
@@ -899,17 +948,15 @@
             <xsl:choose>
                 <xsl:when test="$isIn">
-                    <xsl:text>GUIDIn (a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>GUIDIn (a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:text>)</xsl:text>
                 </xsl:when>
                 <xsl:when test="$isOut">
-                    <xsl:text>GUIDOut (a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>GUIDOut (a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:text>)</xsl:text>
                 </xsl:when>
@@ -925,9 +972,8 @@
                     <xsl:text>(</xsl:text>
                     <xsl:value-of select="@type"/>
-                    <xsl:text>_T) a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>_T) a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                 </xsl:when>
                 <xsl:when test="$isOut">
@@ -936,9 +982,8 @@
                     <xsl:text>, </xsl:text>
                     <xsl:value-of select="@type"/>
-                    <xsl:text>_T&gt; (a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>_T&gt; (a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:text>)</xsl:text>
                 </xsl:when>
@@ -960,9 +1005,8 @@
             <xsl:choose>
                 <xsl:when test="$isIn">
-                    <xsl:text>a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:choose>
                         <xsl:when test="@type='$unknown'">
@@ -975,9 +1019,8 @@
                 </xsl:when>
                 <xsl:when test="$isOut">
-                    <xsl:text>&amp;a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>&amp;a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                     <xsl:choose>
                         <xsl:when test="@type='$unknown'">
@@ -1003,16 +1046,14 @@
             <xsl:choose>
                 <xsl:when test="$isIn">
-                    <xsl:text>a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                 </xsl:when>
                 <xsl:when test="$isOut">
-                    <xsl:text>&amp;a_</xsl:text>
-                    <!-- ### xsl:call-template name="capitalize">
+                    <xsl:text>&amp;a</xsl:text>
+                    <xsl:call-template name="capitalize">
                         <xsl:with-param name="str" select="@name"/>
-                    </xsl:call-template -->
-                    <xsl:value-of select="@name"/>
+                    </xsl:call-template>
                 </xsl:when>
             </xsl:choose>
@@ -1023,5 +1064,5 @@
 
 <!--
- *  attribute/parameter type conversion (plain type name)
+ *  attribute/parameter type conversion (returns plain Qt type name)
 -->
 <xsl:template match="
@@ -1031,8 +1072,15 @@
     <xsl:variable name="self_target" select="current()/ancestor::if/@target"/>
 
-    <xsl:if test="name(..)='param' and ../@array and ../@dir='return'">
+    <xsl:if test="../@array and ../@safearray='yes'">
+        <xsl:message terminate="yes">
+                <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
+            <xsl:text>either 'array' or 'safearray="yes"' attribute is allowed, but not both!</xsl:text>
+        </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="../@array and ((name(..)='param' and ../@dir='return') or (name(..)='attribute'))">
         <xsl:message terminate="yes">
             <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
-            <xsl:text>return array parameters are not currently supported</xsl:text>
+            <xsl:text>return 'array' parameters and 'array' attributes are not supported, use 'safearray="yes"' instead.</xsl:text>
         </xsl:message>
     </xsl:if>
@@ -1041,7 +1089,13 @@
         <!-- modifiers (ignored for 'enumeration' attributes)-->
         <xsl:when test="name(current())='type' and ../@mod">
+            <xsl:if test="../@safearray">
+                <xsl:message terminate="yes">
+                      <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
+                    <xsl:text>either 'safearray' or 'mod' attribute is allowed, but not both!</xsl:text>
+                </xsl:message>
+            </xsl:if>
             <xsl:if test="../@array">
                 <xsl:message terminate="yes">
-                        <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
+                    <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
                     <xsl:text>either 'array' or 'mod' attribute is allowed, but not both!</xsl:text>
                 </xsl:message>
@@ -1079,5 +1133,5 @@
                         <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
                         <xsl:value-of select="concat('value &quot;',../@mod,'&quot; ')"/>
-                        <xsl:text>of attibute 'mod' is invalid!</xsl:text>
+                        <xsl:text>of attribute 'mod' is invalid!</xsl:text>
                     </xsl:message>
                 </xsl:otherwise>
@@ -1086,4 +1140,7 @@
         <!-- no modifiers -->
         <xsl:otherwise>
+            <xsl:if test="../@safearray">
+                <xsl:text>QValueVector &lt;</xsl:text>
+            </xsl:if>
             <xsl:choose>
                 <!-- standard types -->
@@ -1139,4 +1196,7 @@
                 </xsl:otherwise>
             </xsl:choose>
+            <xsl:if test="../@safearray">
+                <xsl:text>&gt;</xsl:text>
+            </xsl:if>
         </xsl:otherwise>
     </xsl:choose>
@@ -1157,12 +1217,9 @@
 
     <xsl:choose>
+        <!-- safearrays don't need initializers -->
+        <xsl:when test="../@safearray">
+        </xsl:when>
         <!-- modifiers (ignored for 'enumeration' attributes)-->
         <xsl:when test="name(current())='type' and ../@mod">
-            <xsl:if test="../@array">
-                <xsl:message terminate="yes">
-                        <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
-                    <xsl:text>either 'array' or 'mod' attribute is allowed, but not both!</xsl:text>
-                </xsl:message>
-            </xsl:if>
             <xsl:choose>
                 <xsl:when test="../@mod='ptr'">
@@ -1197,5 +1254,5 @@
                         <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
                         <xsl:value-of select="concat('value &quot;',../@mod,'&quot; ')"/>
-                        <xsl:text>of attibute 'mod' is invalid!</xsl:text>
+                        <xsl:text>of attribute 'mod' is invalid!</xsl:text>
                     </xsl:message>
                 </xsl:otherwise>
@@ -1247,4 +1304,5 @@
             .='string' or
             .='wstring' or
+            ../@safearray='yes' or
             ((ancestor::library/enum[@name=current()]) or
              (ancestor::library/if[@target=$self_target]/enum[@name=current()])
@@ -1270,10 +1328,4 @@
                 <!-- <param> context -->
                 <xsl:when test="name(..)='param'">
-                    <xsl:if test="../@array">
-                        <xsl:message terminate="yes">
-                            <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
-                            <xsl:text>arrays of non-scalar types are not currently supported</xsl:text>
-                        </xsl:message>
-                    </xsl:if>
                     <xsl:choose>
                         <xsl:when test="../@dir='in'">
@@ -1324,4 +1376,185 @@
 
 
+<!--
+ *  attribute/parameter type conversion (returns plain COM type name)
+ *  (basically, copied from midl.xsl)
+-->
+<xsl:template match="
+    attribute/@type | param/@type |
+    enumerator/@type | collection/@type | collection/@enumerator
+" mode="com">
+
+    <xsl:variable name="self_target" select="current()/ancestor::if/@target"/>
+
+    <xsl:choose>
+        <!-- modifiers (ignored for 'enumeration' attributes)-->
+        <xsl:when test="name(current())='type' and ../@mod">
+            <xsl:choose>
+                <xsl:when test="../@mod='ptr'">
+                    <xsl:choose>
+                        <!-- standard types -->
+                        <!--xsl:when test=".='result'">??</xsl:when-->
+                        <xsl:when test=".='boolean'">BOOL *</xsl:when>
+                        <xsl:when test=".='octet'">BYTE *</xsl:when>
+                        <xsl:when test=".='short'">SHORT *</xsl:when>
+                        <xsl:when test=".='unsigned short'">USHORT *</xsl:when>
+                        <xsl:when test=".='long'">LONG *</xsl:when>
+                        <xsl:when test=".='long long'">LONG64 *</xsl:when>
+                        <xsl:when test=".='unsigned long'">ULONG *</xsl:when>
+                        <xsl:when test=".='unsigned long long'">ULONG64 *</xsl:when>
+                        <xsl:when test=".='char'">CHAR *</xsl:when>
+                        <!--xsl:when test=".='string'">??</xsl:when-->
+                        <xsl:when test=".='wchar'">OLECHAR *</xsl:when>
+                        <!--xsl:when test=".='wstring'">??</xsl:when-->
+                        <xsl:otherwise>
+                            <xsl:message terminate="yes">
+                                <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
+                                <xsl:text>attribute 'mod=</xsl:text>
+                                <xsl:value-of select="concat('&quot;',../@mod,'&quot;')"/>
+                                <xsl:text>' cannot be used with type </xsl:text>
+                                <xsl:value-of select="concat('&quot;',current(),'&quot;!')"/>
+                            </xsl:message>
+                        </xsl:otherwise>
+                    </xsl:choose>
+                </xsl:when>
+                <xsl:otherwise>
+                    <xsl:message terminate="yes">
+                        <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
+                        <xsl:value-of select="concat('value &quot;',../@mod,'&quot; ')"/>
+                        <xsl:text>of attribute 'mod' is invalid!</xsl:text>
+                    </xsl:message>
+                </xsl:otherwise>
+            </xsl:choose>
+        </xsl:when>
+        <!-- no modifiers -->
+        <xsl:otherwise>
+            <xsl:choose>
+                <!-- standard types -->
+                <xsl:when test=".='result'">HRESULT</xsl:when>
+                <xsl:when test=".='boolean'">BOOL</xsl:when>
+                <xsl:when test=".='octet'">BYTE</xsl:when>
+                <xsl:when test=".='short'">SHORT</xsl:when>
+                <xsl:when test=".='unsigned short'">USHORT</xsl:when>
+                <xsl:when test=".='long'">LONG</xsl:when>
+                <xsl:when test=".='long long'">LONG64</xsl:when>
+                <xsl:when test=".='unsigned long'">ULONG</xsl:when>
+                <xsl:when test=".='unsigned long long'">ULONG64</xsl:when>
+                <xsl:when test=".='char'">CHAR</xsl:when>
+                <xsl:when test=".='string'">CHAR *</xsl:when>
+                <xsl:when test=".='wchar'">OLECHAR</xsl:when>
+                <xsl:when test=".='wstring'">BSTR</xsl:when>
+                <!-- UUID type -->
+                <xsl:when test=".='uuid'">GUID</xsl:when>
+                <!-- system interface types -->
+                <xsl:when test=".='$unknown'">IUnknown *</xsl:when>
+                <xsl:otherwise>
+                    <xsl:choose>
+                        <!-- enum types -->
+                        <xsl:when test="
+                            (ancestor::library/enum[@name=current()]) or
+                            (ancestor::library/if[@target=$self_target]/enum[@name=current()])
+                        ">
+                            <xsl:value-of select="."/>
+                        </xsl:when>
+                        <!-- custom interface types -->
+                        <xsl:when test="
+                            (name(current())='enumerator' and
+                             ((ancestor::library/enumerator[@name=current()]) or
+                              (ancestor::library/if[@target=$self_target]/enumerator[@name=current()]))
+                            ) or
+                            ((ancestor::library/interface[@name=current()]) or
+                             (ancestor::library/if[@target=$self_target]/interface[@name=current()])
+                            ) or
+                            ((ancestor::library/collection[@name=current()]) or
+                             (ancestor::library/if[@target=$self_target]/collection[@name=current()])
+                            )
+                        ">
+                            <xsl:value-of select="."/><xsl:text> *</xsl:text>
+                        </xsl:when>
+                        <!-- other types -->
+                        <xsl:otherwise>
+                            <xsl:message terminate="yes">
+                                <xsl:text>Unknown parameter type: </xsl:text>
+                                <xsl:value-of select="."/>
+                            </xsl:message>
+                        </xsl:otherwise>
+                    </xsl:choose>
+                </xsl:otherwise>
+            </xsl:choose>
+        </xsl:otherwise>
+    </xsl:choose>
+</xsl:template>
+
+
+<!--
+ *  attribute/parameter type additional hooks.
+ *
+ *  Called in the context of <attribute> or <param> elements.
+ *
+ *  @param when     When the hook is being called:
+ *                  'pre-call'  - right before the method call
+ *                  'post-call' - right after the method call
+ *  @param isSetter Non-empty if called in the cotext of the attribute setter
+ *                  call.
+-->
+<xsl:template name="hooks">
+
+    <xsl:param name="when" select="''"/>
+    <xsl:param name="isSetter" select="''"/>
+
+    <xsl:choose>
+        <xsl:when test="$when='pre-call'">
+            <xsl:choose>
+                <xsl:when test="@safearray='yes'">
+                    <!-- declare a SafeArray variable -->
+                    <xsl:text>    com::SafeArray &lt;</xsl:text>
+                    <xsl:apply-templates select="@type" mode="com"/>
+                    <xsl:text>&gt; </xsl:text>
+                    <xsl:value-of select="@name"/>
+                    <xsl:text>;&#x0A;</xsl:text>
+                    <xsl:if test="(name()='attribute' and $isSetter) or
+                                  (name()='param' and @dir='in')">
+                        <!-- convert QValueVector to SafeArray -->
+                        <xsl:text>    ToSafeArray (</xsl:text>
+                        <xsl:text>a</xsl:text>
+                        <xsl:call-template name="capitalize">
+                            <xsl:with-param name="str" select="@name"/>
+                        </xsl:call-template>
+                        <xsl:text>, </xsl:text>
+                        <xsl:value-of select="@name"/>
+                        <xsl:text>);&#x0A;</xsl:text>
+                    </xsl:if>
+                </xsl:when>
+            </xsl:choose>
+        </xsl:when>
+        <xsl:when test="$when='post-call'">
+            <xsl:choose>
+                <xsl:when test="@safearray='yes'">
+                    <xsl:if test="(name()='attribute' and not($isSetter)) or
+                                  (name()='param' and (@dir='out' or @dir='return'))">
+                        <!-- convert SafeArray to QValueVector -->
+                        <xsl:text>    FromSafeArray (</xsl:text>
+                        <xsl:value-of select="@name"/>
+                        <xsl:text>, </xsl:text>
+                        <xsl:text>a</xsl:text>
+                        <xsl:call-template name="capitalize">
+                            <xsl:with-param name="str" select="@name"/>
+                        </xsl:call-template>
+                        <xsl:text>);&#x0A;</xsl:text>
+                    </xsl:if>
+                </xsl:when>
+            </xsl:choose>
+        </xsl:when>
+      <xsl:otherwise>
+          <xsl:message terminate="yes">
+              <xsl:text>Invalid when value: </xsl:text>
+              <xsl:value-of select="$when"/>
+          </xsl:message>
+      </xsl:otherwise>
+    </xsl:choose>
+
+</xsl:template>
+
+
 </xsl:stylesheet>
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/COMDefs.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/COMDefs.cpp	(revision 6850)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/COMDefs.cpp	(revision 6851)
@@ -86,5 +86,5 @@
  *  Initializes COM/XPCOM.
  */
-HRESULT COMBase::initializeCOM()
+HRESULT COMBase::InitializeCOM()
 {
     LogFlowFuncEnter();
@@ -126,5 +126,5 @@
 
     if (FAILED (rc))
-        cleanupCOM();
+        CleanupCOM();
 
     AssertComRC (rc);
@@ -139,5 +139,5 @@
  *  Cleans up COM/XPCOM.
  */
-HRESULT COMBase::cleanupCOM()
+HRESULT COMBase::CleanupCOM()
 {
     LogFlowFuncEnter();
@@ -182,4 +182,26 @@
 }
 
+/* static */
+void COMBase::ToSafeArray (const QValueVector <QString> &aVec,
+                           com::SafeArray <BSTR> &aArr)
+{
+    aArr.reset (aVec.size());
+    size_t i = 0;
+    for (QValueVector <QString>::const_iterator it = aVec.begin();
+         it != aVec.end(); ++ it, ++ i)
+        aArr [i] = SysAllocString ((const OLECHAR *) (*it).ucs2());
+}
+
+/* static */
+void COMBase::FromSafeArray (const com::SafeArray <BSTR> &aArr,
+                             QValueVector <QString> &aVec)
+{
+    aVec = QValueVector <QString> (aArr.size());
+    size_t i = 0;
+    for (QValueVector <QString>::iterator it = aVec.begin();
+         it != aVec.end(); ++ it, ++ i)
+        *it = QString::fromUcs2 (aArr [i]);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -351,5 +373,5 @@
     if (callee && calleeIID && mIsBasicAvailable)
     {
-        mCalleeIID = COMBase::toQUuid (*calleeIID);
+        mCalleeIID = COMBase::ToQUuid (*calleeIID);
         mCalleeName = getInterfaceNameFromIID (mCalleeIID);
     }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/VBoxGlobal.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/VBoxGlobal.cpp	(revision 6850)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/VBoxGlobal.cpp	(revision 6851)
@@ -190,5 +190,5 @@
     STDMETHOD(OnMachineStateChange) (IN_GUIDPARAM id, MachineState_T state)
     {
-        postEvent (new VBoxMachineStateChangeEvent (COMBase::toQUuid (id),
+        postEvent (new VBoxMachineStateChangeEvent (COMBase::ToQUuid (id),
                                                     (CEnums::MachineState) state));
         return S_OK;
@@ -197,5 +197,5 @@
     STDMETHOD(OnMachineDataChange) (IN_GUIDPARAM id)
     {
-        postEvent (new VBoxMachineDataChangeEvent (COMBase::toQUuid (id)));
+        postEvent (new VBoxMachineDataChangeEvent (COMBase::ToQUuid (id)));
         return S_OK;
     }
@@ -208,5 +208,5 @@
             return E_INVALIDARG;
 
-        if (COMBase::toQUuid (id).isNull())
+        if (COMBase::ToQUuid (id).isNull())
         {
             /* it's a global extra data key someone wants to change */
@@ -257,5 +257,5 @@
                                   IN_BSTRPARAM key, IN_BSTRPARAM value)
     {
-        if (COMBase::toQUuid (id).isNull())
+        if (COMBase::ToQUuid (id).isNull())
         {
             QString sKey = QString::fromUcs2 (key);
@@ -300,5 +300,5 @@
     STDMETHOD(OnMachineRegistered) (IN_GUIDPARAM id, BOOL registered)
     {
-        postEvent (new VBoxMachineRegisteredEvent (COMBase::toQUuid (id),
+        postEvent (new VBoxMachineRegisteredEvent (COMBase::ToQUuid (id),
                                                    registered));
         return S_OK;
@@ -307,5 +307,5 @@
     STDMETHOD(OnSessionStateChange) (IN_GUIDPARAM id, SessionState_T state)
     {
-        postEvent (new VBoxSessionStateChangeEvent (COMBase::toQUuid (id),
+        postEvent (new VBoxSessionStateChangeEvent (COMBase::ToQUuid (id),
                                                     (CEnums::SessionState) state));
         return S_OK;
@@ -314,6 +314,6 @@
     STDMETHOD(OnSnapshotTaken) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
     {
-        postEvent (new VBoxSnapshotEvent (COMBase::toQUuid (aMachineId),
-                                          COMBase::toQUuid (aSnapshotId),
+        postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
+                                          COMBase::ToQUuid (aSnapshotId),
                                           VBoxSnapshotEvent::Taken));
         return S_OK;
@@ -322,6 +322,6 @@
     STDMETHOD(OnSnapshotDiscarded) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
     {
-        postEvent (new VBoxSnapshotEvent (COMBase::toQUuid (aMachineId),
-                                          COMBase::toQUuid (aSnapshotId),
+        postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
+                                          COMBase::ToQUuid (aSnapshotId),
                                           VBoxSnapshotEvent::Discarded));
         return S_OK;
@@ -330,6 +330,6 @@
     STDMETHOD(OnSnapshotChange) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
     {
-        postEvent (new VBoxSnapshotEvent (COMBase::toQUuid (aMachineId),
-                                          COMBase::toQUuid (aSnapshotId),
+        postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
+                                          COMBase::ToQUuid (aSnapshotId),
                                           VBoxSnapshotEvent::Changed));
         return S_OK;
@@ -1934,5 +1934,5 @@
         {
             LogFlow (("MediaEnumThread started.\n"));
-            COMBase::initializeCOM();
+            COMBase::InitializeCOM();
 
             CVirtualBox mVBox = vboxGlobal().virtualBox();
@@ -2010,5 +2010,5 @@
                 QApplication::postEvent (target, new VBoxEnumerateMediaEvent());
 
-            COMBase::cleanupCOM();
+            COMBase::CleanupCOM();
             LogFlow (("MediaEnumThread finished.\n"));
         }
@@ -3770,5 +3770,5 @@
     /* COM for the main thread is initialized in main() */
 #else
-    HRESULT rc = COMBase::initializeCOM();
+    HRESULT rc = COMBase::InitializeCOM();
     if (FAILED (rc))
     {
@@ -4030,5 +4030,5 @@
     /* COM for the main thread is shutdown in main() */
 #else
-    COMBase::cleanupCOM();
+    COMBase::CleanupCOM();
 #endif
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/main.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/main.cpp	(revision 6850)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/main.cpp	(revision 6851)
@@ -138,5 +138,5 @@
      * for some unknown reason), see also src/VBox/Main/glue/initterm.cpp. */
     /// @todo find a proper solution that satisfies both OLE and VBox
-    HRESULT hrc = COMBase::initializeCOM();
+    HRESULT hrc = COMBase::InitializeCOM();
 #endif
 
@@ -267,5 +267,5 @@
     /* See COMBase::initializeCOM() above */
     if (SUCCEEDED (hrc))
-        COMBase::cleanupCOM();
+        COMBase::CleanupCOM();
 #endif
 
Index: /trunk/src/VBox/Main/Doxyfile.Main
===================================================================
--- /trunk/src/VBox/Main/Doxyfile.Main	(revision 6850)
+++ /trunk/src/VBox/Main/Doxyfile.Main	(revision 6851)
@@ -86,5 +86,5 @@
 # "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
 
-ABBREVIATE_BRIEF       = "The $name interface" "represents" "a" "an" "the"
+ABBREVIATE_BRIEF       = "The $name class" "The $name interface" "is" "provides" "represents" "a" "an" "the"
 
 # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 6850)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 6851)
@@ -394,5 +394,5 @@
 ConsoleImpl.cpp_DEFS = VBOX_BUILD_TARGET=\"$(BUILD_TARGET).$(BUILD_TARGET_ARCH)\"
 
-win32/VBoxC.rc_DEPS = $(PATH_TARGET)/VBoxC.rgs
+win32/VBoxC.rc_DEPS = $(PATH_TARGET)/VBoxC.rgs $(PATH_VBoxCOM)/VirtualBox.tlb
 
 
Index: /trunk/src/VBox/Main/VirtualBoxBase.cpp
===================================================================
--- /trunk/src/VBox/Main/VirtualBoxBase.cpp	(revision 6850)
+++ /trunk/src/VBox/Main/VirtualBoxBase.cpp	(revision 6851)
@@ -932,8 +932,197 @@
 }
 
-#if defined VBOX_MAIN_SETTINGS_ADDONS
+// VirtualBoxBaseWithChildrenNEXT methods
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Uninitializes all dependent children registered with #addDependentChild().
+ * 
+ * Typically called from the uninit() method. Note that this method will call 
+ * uninit() methods of child objects. If these methods need to call the parent 
+ * object during initialization, uninitDependentChildren() must be called before 
+ * the relevant part of the parent is uninitialized, usually at the begnning of 
+ * the parent uninitialization sequence. 
+ */
+void VirtualBoxBaseWithChildrenNEXT::uninitDependentChildren()
+{
+    LogFlowThisFuncEnter();
+
+    AutoLock mapLock (mMapLock);
+
+    LogFlowThisFunc (("count=%u...\n", mDependentChildren.size()));
+
+    if (mDependentChildren.size())
+    {
+        /* We keep the lock until we have enumerated all children.
+         * Those ones that will try to call removeDependentChild() from a
+         * different thread will have to wait */
+
+        Assert (mUninitDoneSem == NIL_RTSEMEVENT);
+        int vrc = RTSemEventCreate (&mUninitDoneSem);
+        AssertRC (vrc);
+
+        Assert (mChildrenLeft == 0);
+        mChildrenLeft = mDependentChildren.size();
+
+        for (DependentChildren::iterator it = mDependentChildren.begin();
+            it != mDependentChildren.end(); ++ it)
+        {
+            VirtualBoxBase *child = (*it).second;
+            Assert (child);
+            if (child)
+                child->uninit();
+        }
+
+        mDependentChildren.clear();
+    }
+
+    /* Wait until all children that called uninit() on their own on other
+     * threads but stuck waiting for the map lock in removeDependentChild() have
+     * finished uninitialization. */
+
+    if (mUninitDoneSem != NIL_RTSEMEVENT)
+    {
+        /* let stuck children run */
+        mapLock.leave();
+
+        LogFlowThisFunc (("Waiting for uninitialization of all children...\n"));
+
+        RTSemEventWait (mUninitDoneSem, RT_INDEFINITE_WAIT);
+
+        mapLock.enter();
+
+        RTSemEventDestroy (mUninitDoneSem);
+        mUninitDoneSem = NIL_RTSEMEVENT;
+        Assert (mChildrenLeft == 0);
+    }
+
+    LogFlowThisFuncLeave();
+}
+
+/**
+ * Returns a pointer to the dependent child corresponding to the given
+ * interface pointer (used as a key in the map of dependent children) or NULL
+ * if the interface pointer doesn't correspond to any child registered using 
+ * #addDependentChild(). 
+ *  
+ * Note that ComPtr <IUnknown> is used as an argument instead of IUnknown * in 
+ * order to guarantee IUnknown identity and disambiguation by doing 
+ * QueryInterface (IUnknown) rather than a regular C cast. 
+ *
+ * @param aUnk  Pointer to map to the dependent child object.
+ * @return      Pointer to the dependent child object.
+ */
+VirtualBoxBaseNEXT *
+VirtualBoxBaseWithChildrenNEXT::getDependentChild (const ComPtr <IUnknown> &aUnk)
+{
+    AssertReturn (!!aUnk, NULL);
+
+    AutoLock alock (mMapLock);
+
+    /* return NULL if uninitDependentChildren() is in action */
+    if (mUninitDoneSem != NIL_RTSEMEVENT)
+        return NULL;
+
+    DependentChildren::const_iterator it = mDependentChildren.find (aUnk);
+    if (it == mDependentChildren.end())
+        return NULL;
+    return (*it).second;
+}
+
+void VirtualBoxBaseWithChildrenNEXT::doAddDependentChild (
+    IUnknown *aUnk, VirtualBoxBaseNEXT *aChild)
+{
+    AssertReturnVoid (aUnk && aChild);
+
+    AutoLock alock (mMapLock);
+
+    if (mUninitDoneSem != NIL_RTSEMEVENT)
+    {
+        /* uninitDependentChildren() is being run. For this very unlikely case,
+         * we have to increase the number of children left, for symmetry with
+         * a later #removeDependentChild() call. */
+        ++ mChildrenLeft;
+        return;
+    }
+
+    std::pair <DependentChildren::iterator, bool> result =
+        mDependentChildren.insert (DependentChildren::value_type (aUnk, aChild));
+    AssertMsg (result.second, ("Failed to insert a child to the map\n"));
+}
+
+void VirtualBoxBaseWithChildrenNEXT::doRemoveDependentChild (IUnknown *aUnk)
+{
+    AssertReturnVoid (aUnk);
+
+    AutoLock alock (mMapLock);
+
+    if (mUninitDoneSem != NIL_RTSEMEVENT)
+    {
+        /* uninitDependentChildren() is being run. Just decrease the number of
+         * children left and signal a semaphore if it reaches zero. */
+        Assert (mChildrenLeft != 0);
+        -- mChildrenLeft;
+        if (mChildrenLeft == 0)
+        {
+            int vrc = RTSemEventSignal (mUninitDoneSem);
+            AssertRC (vrc);
+        }
+        return;
+    }
+
+    DependentChildren::size_type result = mDependentChildren.erase (aUnk);
+    AssertMsg (result == 1, ("Failed to remove the child %p from the map\n",
+                             aUnk));
+    NOREF (result);
+}
+
+// VirtualBoxBaseWithTypedChildrenNEXT methods
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Uninitializes all dependent children registered with 
+ * #addDependentChild(). 
+ *
+ * @note This method will call uninit() methods of children. If these 
+ *       methods access the parent object, uninitDependentChildren() must be
+ *       called either at the beginning of the parent uninitialization
+ *       sequence (when it is still operational) or after setReady(false) is
+ *       called to indicate the parent is out of action.
+ */
+template <class C>
+void VirtualBoxBaseWithTypedChildrenNEXT <C>::uninitDependentChildren()
+{
+    AutoLock mapLock (mMapLock);
+
+    if (mDependentChildren.size())
+    {
+        /* set flag to ignore #removeDependentChild() called from
+         * child->uninit() */
+        mInUninit = true;
+
+        /* leave the locks to let children waiting for
+         * #removeDependentChild() run */
+        mapLock.leave();
+
+        for (typename DependentChildren::iterator it = mDependentChildren.begin();
+            it != mDependentChildren.end(); ++ it)
+        {
+            C *child = (*it);
+            Assert (child);
+            if (child)
+                child->uninit();
+        }
+        mDependentChildren.clear();
+
+        mapLock.enter();
+
+        mInUninit = false;
+    }
+}
 
 // Settings API additions
 ////////////////////////////////////////////////////////////////////////////////
+
+#if defined VBOX_MAIN_SETTINGS_ADDONS
 
 namespace settings
Index: /trunk/src/VBox/Main/idl/midl.xsl
===================================================================
--- /trunk/src/VBox/Main/idl/midl.xsl	(revision 6850)
+++ /trunk/src/VBox/Main/idl/midl.xsl	(revision 6851)
@@ -6,5 +6,5 @@
 
      Copyright (C) 2006-2007 innotek GmbH
-    
+
      This file is part of VirtualBox Open Source Edition (OSE), as
      available from http://www.virtualbox.org. This file is free software;
@@ -199,4 +199,11 @@
 <xsl:template match="interface//attribute | collection//attribute">
     <xsl:apply-templates select="@if" mode="begin"/>
+    <xsl:if test="@array">
+        <xsl:message terminate="yes">
+            <xsl:value-of select="concat(../@name,'::',@name,': ')"/>
+            <xsl:text>'array' attributes are not supported, use 'safearray="yes"' instead.</xsl:text>
+        </xsl:message>
+    </xsl:if>
+    <!-- getter -->
     <xsl:text>    [propget] HRESULT </xsl:text>
     <xsl:call-template name="capitalize">
@@ -204,5 +211,11 @@
     </xsl:call-template>
     <xsl:text> ([out, retval] </xsl:text>
+    <xsl:if test="@safearray='yes'">
+        <xsl:text>SAFEARRAY(</xsl:text>
+    </xsl:if>
     <xsl:apply-templates select="@type"/>
+    <xsl:if test="@safearray='yes'">
+        <xsl:text>)</xsl:text>
+    </xsl:if>
     <xsl:text> * a</xsl:text>
     <xsl:call-template name="capitalize">
@@ -210,4 +223,5 @@
     </xsl:call-template>
     <xsl:text>);&#x0A;</xsl:text>
+    <!-- setter -->
     <xsl:if test="not(@readonly='yes')">
         <xsl:text>    [propput] HRESULT </xsl:text>
@@ -215,6 +229,17 @@
             <xsl:with-param name="str" select="@name"/>
         </xsl:call-template>
-        <xsl:text> ([in] </xsl:text>
+        <xsl:text> ([in</xsl:text>
+        <xsl:if test="@safearray='yes'">
+            <!-- VB supports only [in, out], [out] and [out, retval] arrays -->
+            <xsl:text>, out</xsl:text>
+        </xsl:if>
+        <xsl:text>] </xsl:text>
+        <xsl:if test="@safearray='yes'">
+            <xsl:text>SAFEARRAY(</xsl:text>
+        </xsl:if>
         <xsl:apply-templates select="@type"/>
+        <xsl:if test="@safearray='yes'">
+            <xsl:text>) *</xsl:text>
+        </xsl:if>
         <xsl:text> a</xsl:text>
         <xsl:call-template name="capitalize">
@@ -392,9 +417,13 @@
         <xsl:otherwise>in</xsl:otherwise>
     </xsl:choose>
+    <xsl:if test="@safearray='yes'">
+        <!-- VB supports only [in, out], [out] and [out, retval] arrays -->
+        <xsl:if test="@dir='in'">, out</xsl:if>
+    </xsl:if>
     <xsl:if test="@array">
         <xsl:if test="@dir='return'">
             <xsl:message terminate="yes">
                 <xsl:value-of select="concat(../../@name,'::',../@name,'::',@name,': ')"/>
-                <xsl:text>return array parameters are not currently supported</xsl:text>
+                <xsl:text>return 'array' parameters are not supported, use 'safearray="yes"' instead.</xsl:text>
             </xsl:message>
         </xsl:if>
@@ -410,10 +439,6 @@
                 <xsl:text>, size_is(</xsl:text>
                     <xsl:if test="@dir='out'">
-                        <xsl:text>, </xsl:text>
+                        <xsl:text>, *</xsl:text>
                     </xsl:if>
-                    <xsl:if test="../param[@name=current()/@array]/@dir='out'">
-                        <xsl:text>*</xsl:text>
-                    </xsl:if>
-                    <!--xsl:value-of select="@array"/-->
                     <xsl:text>a</xsl:text>
                     <xsl:call-template name="capitalize">
@@ -432,14 +457,18 @@
     </xsl:if>
     <xsl:text>] </xsl:text>
+    <xsl:if test="@safearray='yes'">
+        <xsl:text>SAFEARRAY(</xsl:text>
+    </xsl:if>
     <xsl:apply-templates select="@type"/>
-    <xsl:text> </xsl:text>
+    <xsl:if test="@safearray='yes'">
+        <xsl:text>)</xsl:text>
+    </xsl:if>
     <xsl:if test="@array">
-        <xsl:text>* </xsl:text>
-    </xsl:if>
-    <xsl:if test="@dir='out' or @dir='return'">
-        <xsl:text>* </xsl:text>
-    </xsl:if>
-    <!--xsl:value-of select="@name"/-->
-    <xsl:text>a</xsl:text>
+        <xsl:text> *</xsl:text>
+    </xsl:if>
+    <xsl:if test="@dir='out' or @dir='return' or @safearray='yes'">
+        <xsl:text> *</xsl:text>
+    </xsl:if>
+    <xsl:text> a</xsl:text>
     <xsl:call-template name="capitalize">
         <xsl:with-param name="str" select="@name"/>
@@ -457,13 +486,14 @@
     <xsl:variable name="self_target" select="current()/ancestor::if/@target"/>
 
+    <xsl:if test="../@array and ../@safearray='yes'">
+        <xsl:message terminate="yes">
+            <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
+            <xsl:text>either 'array' or 'safearray="yes"' attribute is allowed, but not both!</xsl:text>
+        </xsl:message>
+    </xsl:if>
+
     <xsl:choose>
         <!-- modifiers (ignored for 'enumeration' attributes)-->
         <xsl:when test="name(current())='type' and ../@mod">
-            <xsl:if test="../@array">
-                <xsl:message terminate="yes">
-                        <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
-                    <xsl:text>either 'array' or 'mod' attribute is allowed, but not both!</xsl:text>
-                </xsl:message>
-            </xsl:if>
             <xsl:choose>
                 <xsl:when test="../@mod='ptr'">
@@ -498,5 +528,5 @@
                         <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
                         <xsl:value-of select="concat('value &quot;',../@mod,'&quot; ')"/>
-                        <xsl:text>of attibute 'mod' is invalid!</xsl:text>
+                        <xsl:text>of attribute 'mod' is invalid!</xsl:text>
                     </xsl:message>
                 </xsl:otherwise>
Index: /trunk/src/VBox/Main/idl/xpidl.xsl
===================================================================
--- /trunk/src/VBox/Main/idl/xpidl.xsl	(revision 6850)
+++ /trunk/src/VBox/Main/idl/xpidl.xsl	(revision 6851)
@@ -26,4 +26,17 @@
 /////////////////////////////////////////////////////////////////////////////
 -->
+
+<!--
+ *  capitalizes the first letter
+-->
+<xsl:template name="capitalize">
+    <xsl:param name="str" select="."/>
+    <xsl:value-of select="
+        concat(
+            translate(substring($str,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+            substring($str,2)
+        )
+    "/>
+</xsl:template>
 
 <!--
@@ -214,4 +227,10 @@
 -->
 <xsl:template match="interface//attribute | collection//attribute">
+    <xsl:if test="@array">
+        <xsl:message terminate="yes">
+            <xsl:value-of select="concat(../../@name,'::',../@name,'::',@name,': ')"/>
+            <xsl:text>'array' attributes are not supported, use 'safearray="yes"' instead.</xsl:text>
+        </xsl:message>
+    </xsl:if>
     <xsl:apply-templates select="@if" mode="begin"/>
     <xsl:if test="@mod='ptr'">
@@ -219,13 +238,59 @@
         <xsl:text>    [noscript]&#x0A;</xsl:text>
     </xsl:if>
-    <xsl:text>    </xsl:text>
-    <xsl:if test="@readonly='yes'">
-        <xsl:text>readonly </xsl:text>
-    </xsl:if>
-    <xsl:text>attribute </xsl:text>
-    <xsl:apply-templates select="@type"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="@name"/>
-    <xsl:text>;&#x0A;</xsl:text>
+    <xsl:choose>
+        <!-- safearray pseudo attribute -->
+        <xsl:when test="@safearray='yes'">
+            <!-- getter -->
+            <xsl:text>    void get</xsl:text>
+            <xsl:call-template name="capitalize">
+                <xsl:with-param name="str" select="@name"/>
+            </xsl:call-template>
+            <xsl:text> (&#x0A;</xsl:text>
+            <!-- array size -->
+            <xsl:text>        out unsigned long </xsl:text>
+            <xsl:value-of select="@name"/>
+            <xsl:text>Size,&#x0A;</xsl:text>
+            <!-- array pointer -->
+            <xsl:text>        [array, size_is(</xsl:text>
+            <xsl:value-of select="@name"/>
+            <xsl:text>Size), retval] out </xsl:text>
+            <xsl:apply-templates select="@type"/>
+            <xsl:text> </xsl:text>
+            <xsl:value-of select="@name"/>
+            <xsl:text>&#x0A;    );&#x0A;</xsl:text>
+            <!-- setter -->
+            <xsl:if test="not(@readonly='yes')">
+                <xsl:text>    void set</xsl:text>
+                <xsl:call-template name="capitalize">
+                    <xsl:with-param name="str" select="@name"/>
+                </xsl:call-template>
+                <xsl:text> (&#x0A;</xsl:text>
+                <!-- array size -->
+                <xsl:text>        in unsigned long </xsl:text>
+                <xsl:value-of select="@name"/>
+                <xsl:text>Size,&#x0A;</xsl:text>
+                <!-- array pointer -->
+                <xsl:text>        [array, size_is(</xsl:text>
+                <xsl:value-of select="@name"/>
+                <xsl:text>Size)] in </xsl:text>
+                <xsl:apply-templates select="@type"/>
+                <xsl:text> </xsl:text>
+                <xsl:value-of select="@name"/>
+                <xsl:text>&#x0A;    );&#x0A;</xsl:text>
+            </xsl:if>
+        </xsl:when>
+        <!-- normal attribute -->
+        <xsl:otherwise>
+            <xsl:text>    </xsl:text>
+            <xsl:if test="@readonly='yes'">
+                <xsl:text>readonly </xsl:text>
+            </xsl:if>
+            <xsl:text>attribute </xsl:text>
+            <xsl:apply-templates select="@type"/>
+            <xsl:text> </xsl:text>
+            <xsl:value-of select="@name"/>
+            <xsl:text>;&#x0A;</xsl:text>
+        </xsl:otherwise>
+    </xsl:choose>
     <xsl:apply-templates select="@if" mode="end"/>
     <xsl:text>&#x0A;</xsl:text>
@@ -408,50 +473,75 @@
 -->
 <xsl:template match="method/param">
-    <xsl:if test="@array">
-        <xsl:if test="@dir='return'">
-            <xsl:message terminate="yes">
-                <xsl:value-of select="concat(../../@name,'::',../@name,'::',@name,': ')"/>
-                <xsl:text>return array parameters are not currently supported</xsl:text>
-            </xsl:message>
-        </xsl:if>
-        <xsl:text>[array, </xsl:text>
-        <xsl:choose>
-            <xsl:when test="../param[@name=current()/@array]">
-                <xsl:if test="../param[@name=current()/@array]/@dir != @dir">
+    <xsl:choose>
+        <!-- safearray parameters -->
+        <xsl:when test="@safearray='yes'">
+            <!-- array size -->
+            <xsl:choose>
+                <xsl:when test="@dir='in'">in </xsl:when>
+                <xsl:when test="@dir='out'">out </xsl:when>
+                <xsl:when test="@dir='return'">out </xsl:when>
+                <xsl:otherwise>in </xsl:otherwise>
+            </xsl:choose>
+            <xsl:text>unsigned long </xsl:text>
+            <xsl:value-of select="@name"/>
+            <xsl:text>Size,&#x0A;</xsl:text>
+            <!-- array pointer -->
+            <xsl:text>        [array, size_is(</xsl:text>
+            <xsl:value-of select="@name"/>
+            <xsl:text>Size)</xsl:text>
+            <xsl:choose>
+                <xsl:when test="@dir='in'">] in </xsl:when>
+                <xsl:when test="@dir='out'">] out </xsl:when>
+                <xsl:when test="@dir='return'"> , retval] out </xsl:when>
+                <xsl:otherwise>] in </xsl:otherwise>
+            </xsl:choose>
+            <xsl:apply-templates select="@type"/>
+            <xsl:text> </xsl:text>
+            <xsl:value-of select="@name"/>
+        </xsl:when>
+        <!-- normal and array parameters -->
+        <xsl:otherwise>
+            <xsl:if test="@array">
+                <xsl:if test="@dir='return'">
                     <xsl:message terminate="yes">
-                        <xsl:value-of select="concat(../../@name,'::',../@name,': ')"/>
-                        <xsl:value-of select="concat(@name,' and ',../param[@name=current()/@array]/@name)"/>
-                        <xsl:text> must have the same direction</xsl:text>
+                        <xsl:value-of select="concat(../../@name,'::',../@name,'::',@name,': ')"/>
+                        <xsl:text>return 'array' parameters are not supported, use 'safearray="yes"' instead.</xsl:text>
                     </xsl:message>
                 </xsl:if>
-                <xsl:text>size_is(</xsl:text>
-                    <xsl:if test="@dir='out'">
-                        <xsl:text>, </xsl:text>
-                    </xsl:if>
-                    <xsl:if test="../param[@name=current()/@array]/@dir='out'">
-                        <xsl:text>*</xsl:text>
-                    </xsl:if>
-                    <xsl:value-of select="@array"/>
-                <xsl:text>)</xsl:text>
-            </xsl:when>
-            <xsl:otherwise>
-                <xsl:message terminate="yes">
-                    <xsl:value-of select="concat(../../@name,'::',../@name,'::',@name,': ')"/>
-                    <xsl:text>array attribute refers to non-existent param: </xsl:text>
-                    <xsl:value-of select="@array"/>
-                </xsl:message>
-            </xsl:otherwise>
-        </xsl:choose>
-        <xsl:text>] </xsl:text>
-    </xsl:if>
-    <xsl:choose>
-        <xsl:when test="@dir='in'">in </xsl:when>
-        <xsl:when test="@dir='out'">out </xsl:when>
-        <xsl:when test="@dir='return'">[retval] out </xsl:when>
-        <xsl:otherwise>in</xsl:otherwise>
+                <xsl:text>[array, </xsl:text>
+                <xsl:choose>
+                    <xsl:when test="../param[@name=current()/@array]">
+                        <xsl:if test="../param[@name=current()/@array]/@dir != @dir">
+                            <xsl:message terminate="yes">
+                                <xsl:value-of select="concat(../../@name,'::',../@name,': ')"/>
+                                <xsl:value-of select="concat(@name,' and ',../param[@name=current()/@array]/@name)"/>
+                                <xsl:text> must have the same direction</xsl:text>
+                            </xsl:message>
+                        </xsl:if>
+                        <xsl:text>size_is(</xsl:text>
+                            <xsl:value-of select="@array"/>
+                        <xsl:text>)</xsl:text>
+                    </xsl:when>
+                    <xsl:otherwise>
+                        <xsl:message terminate="yes">
+                            <xsl:value-of select="concat(../../@name,'::',../@name,'::',@name,': ')"/>
+                            <xsl:text>array attribute refers to non-existent param: </xsl:text>
+                            <xsl:value-of select="@array"/>
+                        </xsl:message>
+                    </xsl:otherwise>
+                </xsl:choose>
+                <xsl:text>] </xsl:text>
+            </xsl:if>
+            <xsl:choose>
+                <xsl:when test="@dir='in'">in </xsl:when>
+                <xsl:when test="@dir='out'">out </xsl:when>
+                <xsl:when test="@dir='return'">[retval] out </xsl:when>
+                <xsl:otherwise>in </xsl:otherwise>
+            </xsl:choose>
+            <xsl:apply-templates select="@type"/>
+            <xsl:text> </xsl:text>
+            <xsl:value-of select="@name"/>
+        </xsl:otherwise>
     </xsl:choose>
-    <xsl:apply-templates select="@type"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="@name"/>
 </xsl:template>
 
@@ -466,13 +556,14 @@
     <xsl:variable name="self_target" select="current()/ancestor::if/@target"/>
 
+    <xsl:if test="../@array and ../@safearray='yes'">
+        <xsl:message terminate="yes">
+            <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
+            <xsl:text>either 'array' or 'safearray="yes"' attribute is allowed, but not both!</xsl:text>
+        </xsl:message>
+    </xsl:if>
+
     <xsl:choose>
         <!-- modifiers (ignored for 'enumeration' attributes)-->
         <xsl:when test="name(current())='type' and ../@mod">
-            <xsl:if test="../@array">
-                <xsl:message terminate="yes">
-                        <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
-                    <xsl:text>either 'array' or 'mod' attribute is allowed, but not both!</xsl:text>
-                </xsl:message>
-            </xsl:if>
             <xsl:choose>
                 <xsl:when test="../@mod='ptr'">
@@ -507,5 +598,5 @@
                         <xsl:value-of select="concat(../../../@name,'::',../../@name,'::',../@name,': ')"/>
                         <xsl:value-of select="concat('value &quot;',../@mod,'&quot; ')"/>
-                        <xsl:text>of attibute 'mod' is invalid!</xsl:text>
+                        <xsl:text>of attribute 'mod' is invalid!</xsl:text>
                     </xsl:message>
                 </xsl:otherwise>
Index: /trunk/src/VBox/Main/include/USBControllerImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/USBControllerImpl.h	(revision 6850)
+++ /trunk/src/VBox/Main/include/USBControllerImpl.h	(revision 6851)
@@ -137,5 +137,5 @@
     ComObjPtr <USBDeviceFilter> getDependentChild (IUSBDeviceFilter *aFilter)
     {
-        VirtualBoxBase *child = VirtualBoxBaseWithChildren::
+        VirtualBoxBase *child = VirtualBoxBaseWithChildrenNEXT::
                                 getDependentChild (ComPtr <IUnknown> (aFilter));
         return child ? static_cast <USBDeviceFilter *> (child)
Index: /trunk/src/VBox/Main/include/VirtualBoxBase.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 6850)
+++ /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 6851)
@@ -1446,5 +1446,5 @@
  *      VirtualBoxBase::uninit() implementations). This is done simply by
  *      calling the #uninitDependentChildren() method.
- *  </li><ol>
+ *  </li></ol>
  *
  *  In order to let the above work, the following must be done:
@@ -1459,5 +1459,5 @@
  *      uninit() implementation must do is to check for readiness after acquiring
  *      the object's lock and return immediately if not ready.
- *  </li><ol>
+ *  </li></ol>
  *
  *  Children added by #addDependentChild() are <b>weakly</b> referenced
@@ -1471,4 +1471,6 @@
  *  if #addDependentChild() or #removeDependentChild() are used incorrectly
  *  (called at inappropriate times). Check the above rules once more.
+ *  
+ *  @deprecated Use VirtualBoxBaseWithChildrenNEXT for new classes.
  */
 class VirtualBoxBaseWithChildren : public VirtualBoxBase
@@ -1544,19 +1546,145 @@
 };
 
-/**
- *  Temporary class to disable deprecated methods of VirtualBoxBase.
- *  Can be used as a base for components that are completely switched to
- *  the new locking scheme (VirtualBoxBaseNEXT_base).
- *
- *  @todo remove after we switch to VirtualBoxBaseNEXT completely.
- */
-class VirtualBoxBaseWithChildrenNEXT : public VirtualBoxBaseWithChildren
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  
+ * Base class to track VirtualBoxBaseNEXT chlidren of the component.
+ *  
+ * This class is a preferrable VirtualBoxBase replacement for components that 
+ * operate with collections of child components. It gives two useful 
+ * possibilities: 
+ *
+ * <ol><li> 
+ *      Given an IUnknown instance, it's possible to quickly determine 
+ *      whether this instance represents a child object created by the given
+ *      component, and if so, get a valid VirtualBoxBase pointer to the child
+ *      object. The returned pointer can be then safely casted to the
+ *      actual class of the child object (to get access to its "internal"
+ *      non-interface methods) provided that no other child components implement
+ *      the same initial interface IUnknown is queried from.
+ * </li><li>
+ *      When the parent object uninitializes itself, it can easily unintialize
+ *      all its VirtualBoxBase derived children (using their
+ *      VirtualBoxBase::uninit() implementations). This is done simply by
+ *      calling the #uninitDependentChildren() method.
+ * </li></ol>
+ *
+ * In order to let the above work, the following must be done:
+ * <ol><li>
+ *      When a child object is initialized, it calls #addDependentChild() of
+ *      its parent to register itself within the list of dependent children.
+ * </li><li>
+ *      When a child object it is uninitialized, it calls
+ *      #removeDependentChild() to unregister itself. Since the child's
+ *      uninitialization may originate both from this method and from the child
+ *      itself calling its uninit() on another thread at the same time, please
+ *      make sure that #removeDependentChild() is called:
+ *      <ul><li>
+ *          after the child has successfully entered AutoUninitSpan -- to make
+ *          sure this method is called only once for the given child object
+ *          transitioning from Ready to NotReady. A failure to do so will at
+ *          least likely cause an assertion ("Failed to remove the child from
+ *          the map").
+ *      </li><li>
+ *          outside the child object's lock -- to avoid guaranteed deadlocks
+ *          caused by different lock order: (child_lock, map_lock) in uninit()
+ *          and (map_lock, child_lock) in this method.
+ *      </li></ul>
+ * </li></ol>
+ *
+ * Note that children added by #addDependentChild() are <b>weakly</b> referenced
+ * (i.e. AddRef() is not called), so when a child object is deleted externally 
+ * (because it's reference count goes to zero), it will automatically remove 
+ * itself from the map of dependent children provided that it follows the rules
+ * described here. 
+ *
+ * @note Once again: because of weak referencing, deadlocks and assertions are 
+ *       very likely if #addDependentChild() or #removeDependentChild() are used
+ *       incorrectly (called at inappropriate times). Check the above rules once
+ *       more.
+ *  
+ * @todo This is a VirtualBoxBaseWithChildren equivalent that uses the 
+ *       VirtualBoxBaseNEXT implementation. Will completely supercede
+ *       VirtualBoxBaseWithChildren after the old VirtualBoxBase implementation
+ *       has gone.
+ */
+class VirtualBoxBaseWithChildrenNEXT : public VirtualBoxBaseNEXT
 {
+public:
+
+    VirtualBoxBaseWithChildrenNEXT()
+        : mUninitDoneSem (NIL_RTSEMEVENT), mChildrenLeft (0)
+    {}
+
+    virtual ~VirtualBoxBaseWithChildrenNEXT()
+    {}
+
+    /**
+     * Adds the given child to the map of dependent children. 
+     *
+     * Typically called from the child's init() method, from within the
+     * AutoInitSpan scope.  Otherwise, VirtualBoxBase::AutoCaller must be
+     * used on @a aChild to make sure it is not uninitialized during this 
+     * method's call.
+     *
+     * @param aChild    Child object to add (must inherit VirtualBoxBase AND 
+     *                  implement some interface).
+     */
+    template <class C>
+    void addDependentChild (C *aChild)
+    {
+        AssertReturnVoid (aChild);
+        doAddDependentChild (ComPtr <IUnknown> (aChild), aChild);
+    }
+
+    /**
+     * Removes the given child from the map of dependent children. 
+     *  
+     * Make sure this method is called after the child has successfully entered 
+     * AutoUninitSpan and outside the child lock. 
+     *  
+     * If called not from within the AutoUninitSpan scope, 
+     * VirtualBoxBase::AutoCaller must be used on @a aChild to make sure it is 
+     * not uninitialized during this method's call. 
+     *
+     * @param aChild    Child object to remove (must inherit VirtualBoxBase AND
+     *                  implement some interface).
+     */
+    template <class C>
+    void removeDependentChild (C *aChild)
+    {
+        AssertReturnVoid (aChild);
+        Assert (!aChild->isLockedOnCurrentThread());
+        doRemoveDependentChild (ComPtr <IUnknown> (aChild));
+    }
+
+protected:
+
+    void uninitDependentChildren();
+
+    VirtualBoxBaseNEXT *getDependentChild (const ComPtr <IUnknown> &aUnk);
+
 private:
 
-    void lock();
-    void unlock();
-    void setReady (bool isReady);
-    bool isReady();
+    /// @todo temporarily reinterpret VirtualBoxBase * as VirtualBoxBaseNEXT *
+    //  until ported HardDisk and Progress to the new scheme.
+    void doAddDependentChild (IUnknown *aUnk, VirtualBoxBase *aChild)
+    {
+        doAddDependentChild (aUnk,
+                             reinterpret_cast <VirtualBoxBaseNEXT *> (aChild));
+    }
+
+    void doAddDependentChild (IUnknown *aUnk, VirtualBoxBaseNEXT *aChild);
+    void doRemoveDependentChild (IUnknown *aUnk);
+
+    typedef std::map <IUnknown *, VirtualBoxBaseNEXT *> DependentChildren;
+    DependentChildren mDependentChildren;
+
+    RTSEMEVENT mUninitDoneSem;
+    size_t mChildrenLeft;
+
+    /* Protects all the fields above */
+    AutoLock::Handle mMapLock;
 };
 
@@ -1579,4 +1707,6 @@
  *  @param C    type of child objects (must inherit VirtualBoxBase AND
  *              implement some interface)
+ *  
+ *  @deprecated Use VirtualBoxBaseWithTypedChildrenNEXT for new classes.
  */
 template <class C>
@@ -1709,25 +1839,124 @@
 };
 
-/**
- *  Temporary class to disable deprecated methods of VirtualBoxBase.
- *  Can be used as a base for components that are completely switched to
- *  the new locking scheme (VirtualBoxBaseNEXT_base).
- *
- *  @todo remove after we switch to VirtualBoxBaseNEXT completely.
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Base class to track component's chlidren of the particular type.
+ *
+ * This class is similar to VirtualBoxBaseWithChildren, with the exception that 
+ * all children must be of the same type. For this reason, it's not necessary to 
+ * use a map to store children, so a list is used instead. 
+ *
+ * As opposed to VirtualBoxBaseWithChildren, children added by
+ * #addDependentChild() are <b>strongly</b> referenced, so that they cannot be 
+ * externally deleted until #removeDependentChild() is called. For this 
+ * reason, strict rules of calling #removeDependentChild() don't apply to 
+ * instances of this class -- it can be called anywhere in the child's uninit() 
+ * implementation. 
+ *
+ * @param C Type of child objects (must inherit VirtualBoxBase AND implementsome 
+ *          interface).
+ *  
+ * @todo This is a VirtualBoxBaseWithChildren equivalent that uses the 
+ *       VirtualBoxBaseNEXT implementation. Will completely supercede
+ *       VirtualBoxBaseWithChildren after the old VirtualBoxBase implementation
+ *       has gone.
  */
 template <class C>
-class VirtualBoxBaseWithTypedChildrenNEXT : public VirtualBoxBaseWithTypedChildren <C>
+class VirtualBoxBaseWithTypedChildrenNEXT : public VirtualBoxBaseNEXT
 {
 public:
 
-    typedef util::AutoLock AutoLock;
+    typedef std::list <ComObjPtr <C> > DependentChildren;
+
+    VirtualBoxBaseWithTypedChildrenNEXT() : mInUninit (false) {}
+
+    virtual ~VirtualBoxBaseWithTypedChildrenNEXT() {}
+
+    /**
+     * Adds the given child to the list of dependent children. 
+     * 
+     * VirtualBoxBase::AutoCaller must be used on @a aChild to make sure it is 
+     * not uninitialized during this method's call.
+     *
+     *  @param aChild   Child object to add (must inherit VirtualBoxBase AND
+     *                  implement some interface).
+     */
+    void addDependentChild (C *aChild)
+    {
+        AssertReturnVoid (aChild);
+
+        AutoLock alock (mMapLock);
+        if (mInUninit)
+            return;
+
+        mDependentChildren.push_back (aChild);
+    }
+
+    /**
+     * Removes the given child from the list of dependent children. 
+     * 
+     * VirtualBoxBase::AutoCaller must be used on @a aChild to make sure it is 
+     * not uninitialized during this method's call. 
+     *
+     *  @param aChild   the child object to remove (must inherit VirtualBoxBase
+     *                  AND implement some interface).
+     */
+    void removeDependentChild (C *aChild)
+    {
+        AssertReturnVoid (aChild);
+
+        AutoLock alock (mMapLock);
+        if (mInUninit)
+            return;
+
+        mDependentChildren.remove (aChild);
+    }
+
+protected:
+
+    /**
+     * Returns an internal lock handle used to lock the list of children 
+     * returned by #dependentChildren(). This lock is to be used by AutoLock as 
+     * follows: 
+     * <code> 
+     *      AutoLock alock (dependentChildrenLock());
+     * </code>
+     */
+    AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }
+
+    /**
+     * Returns the read-only list of all dependent children. 
+     *  
+     * @note Access the returned list (iterate, get size etc.) only after doing 
+     *       AutoLock alock (dependentChildrenLock())!
+     */
+    const DependentChildren &dependentChildren() const { return mDependentChildren; }
+
+    void uninitDependentChildren();
+
+    /**
+     * Removes (detaches) all dependent children registered with
+     * #addDependentChild(), without uninitializing them.
+     *
+     * @note This method must be called from under the main object's lock.
+     */
+    void removeDependentChildren()
+    {
+        /// @todo why?..
+        AssertReturnVoid (isLockedOnCurrentThread());
+
+        AutoLock alock (mMapLock);
+        mDependentChildren.clear();
+    }
 
 private:
 
-    void lock();
-    void unlock();
-    bool isLockedOnCurrentThread();
-    void setReady (bool isReady);
-    bool isReady();
+    DependentChildren mDependentChildren;
+
+    bool mInUninit;
+
+    /* Protects the two fields above */
+    mutable AutoLock::Handle mMapLock;
 };
 
