Index: /trunk/include/VBox/settings.h
===================================================================
--- /trunk/include/VBox/settings.h	(revision 42128)
+++ /trunk/include/VBox/settings.h	(revision 42129)
@@ -18,5 +18,5 @@
 
 /*
- * Copyright (C) 2007-2011 Oracle Corporation
+ * Copyright (C) 2007-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -100,4 +100,5 @@
 
 typedef std::map<com::Utf8Str, com::Utf8Str> StringsMap;
+typedef std::list<com::Utf8Str> StringsList;
 
 // ExtraDataItem (used by both VirtualBox.xml and machines XML)
@@ -1015,5 +1016,7 @@
           uFaultToleranceInterval(0),
           fRTCUseUTC(false)
-    { }
+    {
+        llGroups.push_back("/");
+    }
 
     bool operator==(const MachineUserData &c) const
@@ -1039,4 +1042,5 @@
     bool                    fNameSync;
     com::Utf8Str            strDescription;
+    StringsList             llGroups;
     com::Utf8Str            strOsType;
     com::Utf8Str            strSnapshotFolder;
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp	(revision 42128)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp	(revision 42129)
@@ -815,4 +815,6 @@
     if (rc == VERR_GETOPT_UNKNOWN_OPTION)
         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option: %s", pValueUnion->psz);
+    if (rc == VERR_GETOPT_INVALID_ARGUMENT_FORMAT)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid argument format: %s", pValueUnion->psz);
     if (pValueUnion->pDef)
         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "%s: %Rrs", pValueUnion->pDef->pszLong, rc);
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 42128)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 42129)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -382,4 +382,23 @@
     } while (0)
 
+#define SHOW_STRINGARRAY_PROP(a_pObj, a_Prop, a_szMachine, a_szHuman) \
+    do \
+    { \
+        SafeArray<BSTR> array; \
+        CHECK_ERROR2_RET(a_pObj, COMGETTER(a_Prop)(ComSafeArrayAsOutParam(array)), hrcCheck); \
+        Utf8Str str; \
+        for (size_t i = 0; i < array.size(); i++) \
+        { \
+            if (i != 0) \
+                str.append(","); \
+            str.append(Utf8Str(array[i]).c_str()); \
+        } \
+        Bstr bstr(str); \
+        if (details == VMINFO_MACHINEREADABLE) \
+            outputMachineReadableString(a_szMachine, &bstr); \
+        else \
+            RTPrintf("%-16s %ls\n", a_szHuman ":", bstr.raw()); \
+    } while (0)
+
 #define SHOW_UUID_PROP(a_pObj, a_Prop, a_szMachine, a_szHuman) \
     SHOW_STRING_PROP(a_pObj, a_Prop, a_szMachine, a_szHuman)
@@ -470,4 +489,5 @@
     ComPtr<IGuestOSType> osType;
     CHECK_ERROR2_RET(virtualBox, GetGuestOSType(osTypeId.raw(), osType.asOutParam()), hrcCheck);
+    SHOW_STRINGARRAY_PROP( machine, Groups,                     "groups",               "Groups");
     SHOW_STRING_PROP(       osType, Description,                "ostype",               "Guest OS");
     SHOW_UUID_PROP(        machine, Id,                         "UUID",                 "UUID");
@@ -1320,7 +1340,5 @@
             {
                 ULONG ulIRQ, ulIOBase;
-                PortMode_T HostMode;
                 Bstr path;
-                BOOL fServer;
                 lpt->COMGETTER(IRQ)(&ulIRQ);
                 lpt->COMGETTER(IOBase)(&ulIOBase);
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 42128)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 42129)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -171,60 +171,71 @@
 }
 
+static const RTGETOPTDEF g_aCreateVMOptions[] =
+{
+    { "--name",           'n', RTGETOPT_REQ_STRING },
+    { "-name",            'n', RTGETOPT_REQ_STRING },
+    { "--groups",         'g', RTGETOPT_REQ_STRING },
+    { "--basefolder",     'p', RTGETOPT_REQ_STRING },
+    { "-basefolder",      'p', RTGETOPT_REQ_STRING },
+    { "--ostype",         'o', RTGETOPT_REQ_STRING },
+    { "-ostype",          'o', RTGETOPT_REQ_STRING },
+    { "--uuid",           'u', RTGETOPT_REQ_UUID },
+    { "-uuid",            'u', RTGETOPT_REQ_UUID },
+    { "--register",       'r', RTGETOPT_REQ_NOTHING },
+    { "-register",        'r', RTGETOPT_REQ_NOTHING },
+};
+
 int handleCreateVM(HandlerArg *a)
 {
     HRESULT rc;
-    Bstr baseFolder;
-    Bstr name;
-    Bstr osTypeId;
-    RTUUID id;
+    Bstr bstrBaseFolder;
+    Bstr bstrName;
+    Bstr bstrGroups;
+    Bstr bstrOsTypeId;
+    Bstr bstrUuid;
     bool fRegister = false;
 
-    RTUuidClear(&id);
-    for (int i = 0; i < a->argc; i++)
-    {
-        if (   !strcmp(a->argv[i], "--basefolder")
-            || !strcmp(a->argv[i], "-basefolder"))
-        {
-            if (a->argc <= i + 1)
-                return errorArgument("Missing argument to '%s'", a->argv[i]);
-            i++;
-            baseFolder = a->argv[i];
-        }
-        else if (   !strcmp(a->argv[i], "--name")
-                 || !strcmp(a->argv[i], "-name"))
-        {
-            if (a->argc <= i + 1)
-                return errorArgument("Missing argument to '%s'", a->argv[i]);
-            i++;
-            name = a->argv[i];
-        }
-        else if (   !strcmp(a->argv[i], "--ostype")
-                 || !strcmp(a->argv[i], "-ostype"))
-        {
-            if (a->argc <= i + 1)
-                return errorArgument("Missing argument to '%s'", a->argv[i]);
-            i++;
-            osTypeId = a->argv[i];
-        }
-        else if (   !strcmp(a->argv[i], "--uuid")
-                 || !strcmp(a->argv[i], "-uuid"))
-        {
-            if (a->argc <= i + 1)
-                return errorArgument("Missing argument to '%s'", a->argv[i]);
-            i++;
-            if (RT_FAILURE(RTUuidFromStr(&id, a->argv[i])))
-                return errorArgument("Invalid UUID format %s\n", a->argv[i]);
-        }
-        else if (   !strcmp(a->argv[i], "--register")
-                 || !strcmp(a->argv[i], "-register"))
-        {
-            fRegister = true;
-        }
-        else
-            return errorSyntax(USAGE_CREATEVM, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
+    int c;
+    RTGETOPTUNION ValueUnion;
+    RTGETOPTSTATE GetState;
+    // start at 0 because main() has hacked both the argc and argv given to us
+    RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateVMOptions, RT_ELEMENTS(g_aCreateVMOptions),
+                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
+    while ((c = RTGetOpt(&GetState, &ValueUnion)))
+    {
+        switch (c)
+        {
+            case 'n':   // --name
+                bstrName = ValueUnion.psz;
+                break;
+
+            case 'g':   // --groups
+                bstrGroups = ValueUnion.psz;
+                /// @todo implement group string parsing to safearray
+                break;
+
+            case 'p':   // --basefolder
+                bstrBaseFolder = ValueUnion.psz;
+                break;
+
+            case 'o':   // --ostype
+                bstrOsTypeId = ValueUnion.psz;
+                break;
+
+            case 'u':   // --uuid
+                bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
+                break;
+
+            case 'r':   // --register
+                fRegister = true;
+                break;
+
+            default:
+                return errorGetOpt(USAGE_CREATEVM, c, &ValueUnion);
+        }
     }
 
     /* check for required options */
-    if (name.isEmpty())
+    if (bstrName.isEmpty())
         return errorSyntax(USAGE_CREATEVM, "Parameter --name is required");
 
@@ -233,13 +244,15 @@
         Bstr bstrSettingsFile;
         CHECK_ERROR_BREAK(a->virtualBox,
-                          ComposeMachineFilename(name.raw(),
-                                                 baseFolder.raw(),
+                          ComposeMachineFilename(bstrName.raw(),
+                                                 NULL /* aGroup */,
+                                                 bstrBaseFolder.raw(),
                                                  bstrSettingsFile.asOutParam()));
         ComPtr<IMachine> machine;
         CHECK_ERROR_BREAK(a->virtualBox,
                           CreateMachine(bstrSettingsFile.raw(),
-                                        name.raw(),
-                                        osTypeId.raw(),
-                                        Guid(id).toUtf16().raw(),
+                                        bstrName.raw(),
+                                        NULL /* aGroups */,
+                                        bstrOsTypeId.raw(),
+                                        bstrUuid.raw(),
                                         FALSE /* forceOverwrite */,
                                         machine.asOutParam()));
@@ -257,5 +270,5 @@
                  "UUID: %s\n"
                  "Settings file: '%ls'\n",
-                 name.raw(), fRegister ? " and registered" : "",
+                 bstrName.raw(), fRegister ? " and registered" : "",
                  Utf8Str(uuid).c_str(), settingsFile.raw());
     }
@@ -269,9 +282,10 @@
     { "--snapshot",       's', RTGETOPT_REQ_STRING },
     { "--name",           'n', RTGETOPT_REQ_STRING },
+    { "--groups",         'g', RTGETOPT_REQ_STRING },
     { "--mode",           'm', RTGETOPT_REQ_STRING },
     { "--options",        'o', RTGETOPT_REQ_STRING },
     { "--register",       'r', RTGETOPT_REQ_NOTHING },
     { "--basefolder",     'p', RTGETOPT_REQ_STRING },
-    { "--uuid",           'u', RTGETOPT_REQ_STRING },
+    { "--uuid",           'u', RTGETOPT_REQ_UUID },
 };
 
@@ -332,4 +346,5 @@
     com::SafeArray<CloneOptions_T> options;
     const char                    *pszTrgName       = NULL;
+    const char                    *pszTrgGroups     = NULL;
     const char                    *pszTrgBaseFolder = NULL;
     bool                           fRegister        = false;
@@ -350,4 +365,17 @@
                 break;
 
+            case 'n':   // --name
+                pszTrgName = ValueUnion.psz;
+                break;
+
+            case 'g':   // --groups
+                pszTrgGroups = ValueUnion.psz;
+                /// @todo implement group string parsing to safearray
+                break;
+
+            case 'p':   // --basefolder
+                pszTrgBaseFolder = ValueUnion.psz;
+                break;
+
             case 'm':   // --mode
                 if (RT_FAILURE(parseCloneMode(ValueUnion.psz, &mode)))
@@ -360,18 +388,6 @@
                 break;
 
-            case 'n':   // --name
-                pszTrgName = ValueUnion.psz;
-                break;
-
-            case 'p':   // --basefolder
-                pszTrgBaseFolder = ValueUnion.psz;
-                break;
-
             case 'u':   // --uuid
-                RTUUID trgUuid;
-                if (RT_FAILURE(RTUuidFromStr(&trgUuid, ValueUnion.psz)))
-                    return errorArgument("Invalid UUID format %s\n", ValueUnion.psz);
-                else
-                    bstrUuid = Guid(trgUuid).toUtf16().raw();
+                bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
                 break;
 
@@ -421,4 +437,5 @@
     CHECK_ERROR_RET(a->virtualBox,
                     ComposeMachineFilename(Bstr(pszTrgName).raw(),
+                                           NULL /* aGroup */,
                                            Bstr(pszTrgBaseFolder).raw(),
                                            bstrSettingsFile.asOutParam()),
@@ -428,4 +445,5 @@
     CHECK_ERROR_RET(a->virtualBox, CreateMachine(bstrSettingsFile.raw(),
                                                  Bstr(pszTrgName).raw(),
+                                                 NULL /* aGroups */,
                                                  NULL,
                                                  bstrUuid.raw(),
Index: /trunk/src/VBox/Frontends/VirtualBox/src/wizards/clonevm/UIWizardCloneVM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/wizards/clonevm/UIWizardCloneVM.cpp	(revision 42128)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/wizards/clonevm/UIWizardCloneVM.cpp	(revision 42129)
@@ -113,6 +113,6 @@
 
     /* Create a new machine object. */
-    const QString &strSettingsFile = vbox.ComposeMachineFilename(strName, QString::null);
-    CMachine cloneMachine = vbox.CreateMachine(strSettingsFile, strName, QString::null, QString::null, false);
+    const QString &strSettingsFile = vbox.ComposeMachineFilename(strName, QString::null /**< @todo group support */, QString::null);
+    CMachine cloneMachine = vbox.CreateMachine(strSettingsFile, strName, QVector<QString>(), QString::null, QString::null, false);
     if (!vbox.isOk())
     {
Index: /trunk/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVM.cpp	(revision 42128)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVM.cpp	(revision 42129)
@@ -62,5 +62,5 @@
     if (m_machine.isNull())
     {
-        m_machine = vbox.CreateMachine(QString(), field("name").toString(), strTypeId, QString(), false);
+        m_machine = vbox.CreateMachine(QString(), field("name").toString(), QVector<QString>() /**< @todo group support */, strTypeId, QString(), false);
         if (!vbox.isOk())
         {
Index: /trunk/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVMPageBasic1.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVMPageBasic1.cpp	(revision 42128)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVMPageBasic1.cpp	(revision 42129)
@@ -183,5 +183,5 @@
     QString strDefaultMachinesFolder = vbox.GetSystemProperties().GetDefaultMachineFolder();
     /* Compose machine filename: */
-    QString strMachineFilename = vbox.ComposeMachineFilename(m_pNameAndSystemEditor->name(), strDefaultMachinesFolder);
+    QString strMachineFilename = vbox.ComposeMachineFilename(m_pNameAndSystemEditor->name(), QString::null /**< @todo group support */, strDefaultMachinesFolder);
     /* Compose machine folder/basename: */
     QFileInfo fileInfo(strMachineFilename);
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42128)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42129)
@@ -1398,5 +1398,5 @@
   <interface
     name="IVirtualBox" extends="$unknown"
-    uuid="867664ba-41ce-4099-a10d-b7a8e34057c7"
+    uuid="53789455-fad2-425a-94c8-eb6dc4ceaa05"
     wsmap="managed"
     >
@@ -1495,4 +1495,13 @@
     </attribute>
 
+    <attribute name="machineGroups" type="wstring" readonly="yes" safearray="yes">
+      <desc>
+        Array of all machine group names which are used by the machines which
+        are accessible. Each group is only listed once, however they are listed
+        in no particular order and there is no guarantee that there are no gaps
+        in the group hierarchy (i.e. "/", "/group/subgroup" is a valid result).
+      </desc>
+    </attribute>
+
     <attribute name="hardDisks" type="IMedium" readonly="yes" safearray="yes">
       <desc>
@@ -1582,7 +1591,8 @@
 
         <ul>
-          <li>It gets called by <link to="#createMachine" /> if NULL is specified
-          for the @a settingsFile argument there, which means that API should use
-          a recommended default file name.</li>
+          <li>It gets called by <link to="#createMachine" /> if @c null or
+            empty string (which is recommended) is specified for the
+            @a settingsFile argument there, which means that API should use
+            a recommended default file name.</li>
 
           <li>It can be called manually by a client software before creating a machine,
@@ -1597,4 +1607,9 @@
         details about the machine name.
 
+        @a groupName defines which additional subdirectory levels should be
+        included. It must be either a valid group name or @c null or empty
+        string which designates that the machine will not be related to a
+        machine group.
+
         If @a baseFolder is a @c null or empty string (which is recommended), the
         default machine settings folder
@@ -1605,8 +1620,12 @@
 
         This method does not access the host disks. In particular, it does not check
-        for whether a machine of this name already exists.
+        for whether a machine with this name already exists.
       </desc>
       <param name="name" type="wstring" dir="in">
         <desc>Suggested machine name.</desc>
+      </param>
+      <param name="group" type="wstring" dir="in">
+        <desc>Machine group name for the new machine or machine group. It is
+        used to determine the right subdirectory.</desc>
       </param>
       <param name="baseFolder" type="wstring" dir="in">
@@ -1627,10 +1646,11 @@
         and machine files can be created at arbitrary locations.
 
-        However, it is is recommended that machines be created in the default
+        However, it is recommended that machines are created in the default
         machine folder (e.g. "/home/user/VirtualBox VMs/name/name.vbox"; see
         <link to="ISystemProperties::defaultMachineFolder" />). If you specify
-        NULL for the @a settingsFile argument, <link to="#composeMachineFilename" />
-        is called automatically to have such a recommended name composed based
-        on the machine name given in the @a name argument.
+        @c null or empty string (which is recommended) for the @a settingsFile
+        argument, <link to="#composeMachineFilename" /> is called automatically
+        to have such a recommended name composed based on the machine name
+        given in the @a name argument and the primary group.
 
         If the resulting settings file already exists, this method will fail,
@@ -1693,9 +1713,15 @@
       <param name="settingsFile" type="wstring" dir="in">
         <desc>Fully qualified path where the settings file should be created,
-        or NULL for a default folder and file based on the @a name argument
+          empty string or @c null for a default folder and file based on the
+          @a name argument and the primary group.
         (see <link to="#composeMachineFilename" />).</desc>
       </param>
       <param name="name" type="wstring" dir="in">
         <desc>Machine name.</desc>
+      </param>
+      <param name="groups" type="wstring" safearray="yes" dir="in">
+        <desc>Array of group names. @c null or an empty array have the same
+          meaning as an array with just the empty string or "/", i.e. create a
+          machine without group association.</desc>
       </param>
       <param name="osTypeId" type="wstring" dir="in">
@@ -3711,5 +3737,5 @@
   <interface
     name="IMachine" extends="$unknown"
-    uuid="019d7a7b-1e2d-4008-b954-4b5d72d103b8"
+    uuid="1d03031a-ce63-4641-9d67-3a16e03778d5"
     wsmap="managed"
     >
@@ -3865,4 +3891,14 @@
     </attribute>
 
+    <attribute name="groups" type="wstring" safearray="yes">
+      <desc>
+        Array of machine group names of which this machine is a member. "" and
+        "/" are synonyms for the toplevel group. Each group is only listed
+        once, however they are listed in no particular order and there is no
+        guarantee that there are no gaps in the group hierarchy
+        (i.e. "/group", "/group/subgroup/subsubgroup" is a valid result).
+      </desc>
+    </attribute>
+
     <attribute name="OSTypeId" type="wstring">
       <desc>
@@ -3888,5 +3924,5 @@
         properties.  For most VMs this is the same as the @a id, but for VMs
         which have been cloned or teleported it may be the same as the source
-        VM.  This latter is because the guest shouldn't notice that it was
+        VM. The latter is because the guest shouldn't notice that it was
         cloned or teleported.
       </desc>
@@ -4354,6 +4390,6 @@
         Enables tracepoints in PDM devices and drivers to use the VMCPU or VM
         structures when firing off trace points.  This is especially useful
-        with DTrace tracepoints, as it allow you to use the VMCPU or VM pointer
-        to obtail useful information such as guest register state.
+        with DTrace tracepoints, as it allows you to use the VMCPU or VM
+        pointer to obtain useful information such as guest register state.
 
         This is disabled by default because devices and drivers normally has no
@@ -4574,7 +4610,7 @@
             <li><tt>"emergencystop"</tt>: reserved value, used for aborting
               the currently running VM or session owner. In this case the
-              @a session parameter may be @c NULL (if it is non-null it isn't
+              @a session parameter may be @c null (if it is non-null it isn't
               used in any way), and the @a progress return value will be always
-              NULL. The operation completes immediately.</li>
+              @c null. The operation completes immediately.</li>
           </ul>
         </desc>
@@ -4745,5 +4781,5 @@
       </param>
       <param name="medium" type="IMedium" dir="in">
-        <desc>Medium to mount or NULL for an empty drive.</desc>
+        <desc>Medium to mount or @c null for an empty drive.</desc>
       </param>
     </method>
@@ -4975,5 +5011,5 @@
       </param>
       <param name="bandwidthGroup" type="IBandwidthGroup" dir="in">
-        <desc>New value for the bandwidth group or NULL for no group.</desc>
+        <desc>New value for the bandwidth group or @c null for no group.</desc>
       </param>
     </method>
@@ -5025,5 +5061,5 @@
       </param>
       <param name="medium" type="IMedium" dir="in">
-        <desc>Medium to mount or NULL for an empty drive.</desc>
+        <desc>Medium to mount or @c null for an empty drive.</desc>
       </param>
       <param name="force" type="boolean" dir="in">
@@ -7063,5 +7099,5 @@
         Paused virtual machine. When the machine is PoweredOff, an
         offline snapshot is created. When the machine is Running a live
-        snapshot is created, and an online snapshot is is created when Paused.
+        snapshot is created, and an online snapshot is created when Paused.
 
         The taken snapshot is always based on the
@@ -11531,5 +11567,5 @@
 
               When deleting the current snapshot, the <link to="IMachine::currentSnapshot" />
-              attribute is set to the current snapshot's parent or NULL if it
+              attribute is set to the current snapshot's parent or @c null if it
               has no parent. Otherwise the attribute is unchanged.
           </li>
@@ -11736,5 +11772,5 @@
     <const name="MultiAttach"       value="5">
       <desc>
-        A medium which is is indirectly attached, so that one base medium can
+        A medium which is indirectly attached, so that one base medium can
         be used for several VMs which have their own differencing medium to
         store their modifications. In some sense a variant of Immutable
Index: /trunk/src/VBox/Main/idl/midl.xsl
===================================================================
--- /trunk/src/VBox/Main/idl/midl.xsl	(revision 42128)
+++ /trunk/src/VBox/Main/idl/midl.xsl	(revision 42129)
@@ -6,5 +6,5 @@
  *  from the generic interface definition expressed in XML.
 
-     Copyright (C) 2006-2010 Oracle Corporation
+     Copyright (C) 2006-2012 Oracle Corporation
 
      This file is part of VirtualBox Open Source Edition (OSE), as
@@ -288,10 +288,5 @@
       <xsl:with-param name="str" select="@name"/>
     </xsl:call-template>
-    <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:text> ([in] </xsl:text>
     <xsl:if test="@safearray='yes'">
       <xsl:text>SAFEARRAY(</xsl:text>
@@ -299,5 +294,5 @@
     <xsl:apply-templates select="@type"/>
     <xsl:if test="@safearray='yes'">
-      <xsl:text>) *</xsl:text>
+      <xsl:text>)</xsl:text>
     </xsl:if>
     <xsl:text> a</xsl:text>
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 42128)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 42129)
@@ -342,4 +342,5 @@
                  const Utf8Str &strConfigFile,
                  const Utf8Str &strName,
+                 const StringsList &llGroups,
                  GuestOSType *aOsType,
                  const Guid &aId,
@@ -381,4 +382,6 @@
     STDMETHOD(COMSETTER(Description))(IN_BSTR aDescription);
     STDMETHOD(COMGETTER(Id))(BSTR *aId);
+    STDMETHOD(COMGETTER(Groups))(ComSafeArrayOut(BSTR, aGroups));
+    STDMETHOD(COMSETTER(Groups))(ComSafeArrayIn(IN_BSTR, aGroups));
     STDMETHOD(COMGETTER(OSTypeId))(BSTR *aOSTypeId);
     STDMETHOD(COMSETTER(OSTypeId))(IN_BSTR aOSTypeId);
Index: /trunk/src/VBox/Main/include/VirtualBoxBase.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 42128)
+++ /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 42129)
@@ -52,5 +52,6 @@
 class Medium;
 class Host;
-typedef std::list< ComObjPtr<Medium> > MediaList;
+typedef std::list<ComObjPtr<Medium> > MediaList;
+typedef std::list<Utf8Str> StringsList;
 
 ////////////////////////////////////////////////////////////////////////////////
Index: /trunk/src/VBox/Main/include/VirtualBoxImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 42128)
+++ /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 42129)
@@ -45,5 +45,5 @@
 class AutostartDb;
 
-typedef std::list< ComObjPtr<SessionMachine> > SessionMachinesList;
+typedef std::list<ComObjPtr<SessionMachine> > SessionMachinesList;
 
 #ifdef RT_OS_WINDOWS
@@ -68,5 +68,5 @@
 public:
 
-    typedef std::list< ComPtr<IInternalSessionControl> > InternalControlList;
+    typedef std::list<ComPtr<IInternalSessionControl> > InternalControlList;
 
     class CallbackEvent;
@@ -111,4 +111,5 @@
     STDMETHOD(COMGETTER(SystemProperties))(ISystemProperties **aSystemProperties);
     STDMETHOD(COMGETTER(Machines))(ComSafeArrayOut(IMachine *, aMachines));
+    STDMETHOD(COMGETTER(MachineGroups))(ComSafeArrayOut(BSTR, aMachineGroups));
     STDMETHOD(COMGETTER(HardDisks))(ComSafeArrayOut(IMedium *, aHardDisks));
     STDMETHOD(COMGETTER(DVDImages))(ComSafeArrayOut(IMedium *, aDVDImages));
@@ -125,7 +126,8 @@
 
     /* IVirtualBox methods */
-    STDMETHOD(ComposeMachineFilename)(IN_BSTR aName, IN_BSTR aBaseFolder, BSTR *aFilename);
+    STDMETHOD(ComposeMachineFilename)(IN_BSTR aName, IN_BSTR aGroup, IN_BSTR aBaseFolder, BSTR *aFilename);
     STDMETHOD(CreateMachine)(IN_BSTR aSettingsFile,
                              IN_BSTR aName,
+                             ComSafeArrayIn(IN_BSTR, aGroups),
                              IN_BSTR aOsTypeId,
                              IN_BSTR aId,
@@ -219,4 +221,6 @@
                         bool aSetError,
                         ComObjPtr<Machine> *machine = NULL);
+
+    HRESULT convertMachineGroups(ComSafeArrayIn(IN_BSTR, aMachineGroups), StringsList *pllMachineGroups);
 
     HRESULT findHardDiskById(const Guid &id,
Index: /trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp	(revision 42128)
+++ /trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp	(revision 42129)
@@ -205,5 +205,6 @@
             Bstr bstrMachineFilename;
             rc = mVirtualBox->ComposeMachineFilename(Bstr(nameVBox).raw(),
-                                                     NULL,
+                                                     NULL /* aGroup */,
+                                                     NULL /* aBaseFolder */,
                                                      bstrMachineFilename.asOutParam());
             if (FAILED(rc)) throw rc;
@@ -1950,4 +1951,5 @@
     rc = mVirtualBox->CreateMachine(NULL, /* machine name: use default */
                                     Bstr(stack.strNameVBox).raw(),
+                                    NULL, /* no groups */
                                     Bstr(stack.strOsTypeVBox).raw(),
                                     NULL, /* uuid */
@@ -2864,5 +2866,6 @@
         Bstr bstrMachineFilename;
         rc = mVirtualBox->ComposeMachineFilename(Bstr(stack.strNameVBox).raw(),
-                                                 NULL,
+                                                 NULL /* aGroup */,
+                                                 NULL /* aBaseFolder */,
                                                  bstrMachineFilename.asOutParam());
         if (FAILED(rc)) throw rc;
Index: /trunk/src/VBox/Main/src-server/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 42128)
+++ /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 42129)
@@ -271,6 +271,7 @@
  *                      be relative to the VirtualBox config directory).
  *  @param strName      name for the machine
+ *  @param llGroups     list of groups for the machine
+ *  @param aOsType      OS Type of this machine or NULL.
  *  @param aId          UUID for the new machine.
- *  @param aOsType      OS Type of this machine or NULL.
  *  @param fForceOverwrite Whether to overwrite an existing machine settings file.
  *
@@ -280,4 +281,5 @@
                       const Utf8Str &strConfigFile,
                       const Utf8Str &strName,
+                      const StringsList &llGroups,
                       GuestOSType *aOsType,
                       const Guid &aId,
@@ -313,4 +315,6 @@
 
         mUserData->s.strName = strName;
+        
+        mUserData->s.llGroups = llGroups;
 
         // the "name sync" flag determines whether the machine directory gets renamed along
@@ -1048,4 +1052,48 @@
 }
 
+STDMETHODIMP Machine::COMGETTER(Groups)(ComSafeArrayOut(BSTR, aGroups))
+{
+    CheckComArgOutSafeArrayPointerValid(aGroups);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    SafeArray<BSTR> groups(mUserData->s.llGroups.size());
+    size_t i = 0;
+    for (StringsList::const_iterator it = mUserData->s.llGroups.begin();
+         it != mUserData->s.llGroups.end();
+         ++it, i++)
+    {
+        Bstr tmp = *it;
+        tmp.cloneTo(&groups[i]);
+    }
+    groups.detachTo(ComSafeArrayOutArg(aGroups));
+
+    return S_OK;
+}
+
+STDMETHODIMP Machine::COMSETTER(Groups)(ComSafeArrayIn(IN_BSTR, aGroups))
+{
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    StringsList llGroups;
+    HRESULT rc = mParent->convertMachineGroups(ComSafeArrayInArg(aGroups), &llGroups);
+    if (FAILED(rc))
+        return rc;
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    rc = checkStateDependency(MutableStateDep);
+    if (FAILED(rc)) return rc;
+
+    setModified(IsModified_MachineData);
+    mUserData.backup();
+    mUserData->s.llGroups = llGroups;
+
+    return S_OK;
+}
+
 STDMETHODIMP Machine::COMGETTER(OSTypeId)(BSTR *aOSTypeId)
 {
@@ -1113,5 +1161,5 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    int rc = checkStateDependency(MutableStateDep);
+    HRESULT rc = checkStateDependency(MutableStateDep);
     if (FAILED(rc)) return rc;
 
@@ -1143,5 +1191,5 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    int rc = checkStateDependency(MutableStateDep);
+    HRESULT rc = checkStateDependency(MutableStateDep);
     if (FAILED(rc)) return rc;
 
@@ -1173,5 +1221,5 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    int rc = checkStateDependency(MutableStateDep);
+    HRESULT rc = checkStateDependency(MutableStateDep);
     if (FAILED(rc)) return rc;
 
@@ -1203,5 +1251,5 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    int rc = checkStateDependency(MutableStateDep);
+    HRESULT rc = checkStateDependency(MutableStateDep);
     if (FAILED(rc)) return rc;
 
@@ -1233,6 +1281,5 @@
 STDMETHODIMP Machine::COMGETTER(HardwareVersion)(BSTR *aHWVersion)
 {
-    if (!aHWVersion)
-        return E_POINTER;
+    CheckComArgOutPointerValid(aHWVersion);
 
     AutoCaller autoCaller(this);
@@ -1313,6 +1360,5 @@
 STDMETHODIMP Machine::COMGETTER(MemorySize)(ULONG *memorySize)
 {
-    if (!memorySize)
-        return E_POINTER;
+    CheckComArgOutPointerValid(memorySize);
 
     AutoCaller autoCaller(this);
@@ -1353,6 +1399,5 @@
 STDMETHODIMP Machine::COMGETTER(CPUCount)(ULONG *CPUCount)
 {
-    if (!CPUCount)
-        return E_POINTER;
+    CheckComArgOutPointerValid(CPUCount);
 
     AutoCaller autoCaller(this);
@@ -1406,6 +1451,5 @@
 STDMETHODIMP Machine::COMGETTER(CPUExecutionCap)(ULONG *aExecutionCap)
 {
-    if (!aExecutionCap)
-        return E_POINTER;
+    CheckComArgOutPointerValid(aExecutionCap);
 
     AutoCaller autoCaller(this);
@@ -1455,6 +1499,5 @@
 STDMETHODIMP Machine::COMGETTER(CPUHotPlugEnabled)(BOOL *enabled)
 {
-    if (!enabled)
-        return E_POINTER;
+    CheckComArgOutPointerValid(enabled);
 
     AutoCaller autoCaller(this);
@@ -1552,5 +1595,5 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    int rc = checkStateDependency(MutableStateDep);
+    HRESULT rc = checkStateDependency(MutableStateDep);
     if (FAILED(rc)) return rc;
 
@@ -1612,6 +1655,5 @@
 STDMETHODIMP Machine::COMGETTER(VRAMSize)(ULONG *memorySize)
 {
-    if (!memorySize)
-        return E_POINTER;
+    CheckComArgOutPointerValid(memorySize);
 
     AutoCaller autoCaller(this);
@@ -1652,6 +1694,5 @@
 STDMETHODIMP Machine::COMGETTER(MemoryBalloonSize)(ULONG *memoryBalloonSize)
 {
-    if (!memoryBalloonSize)
-        return E_POINTER;
+    CheckComArgOutPointerValid(memoryBalloonSize);
 
     AutoCaller autoCaller(this);
@@ -1699,6 +1740,5 @@
 STDMETHODIMP Machine::COMGETTER(PageFusionEnabled) (BOOL *enabled)
 {
-    if (!enabled)
-        return E_POINTER;
+    CheckComArgOutPointerValid(enabled);
 
     AutoCaller autoCaller(this);
@@ -1732,6 +1772,5 @@
 STDMETHODIMP Machine::COMGETTER(Accelerate3DEnabled)(BOOL *enabled)
 {
-    if (!enabled)
-        return E_POINTER;
+    CheckComArgOutPointerValid(enabled);
 
     AutoCaller autoCaller(this);
@@ -1767,6 +1806,5 @@
 STDMETHODIMP Machine::COMGETTER(Accelerate2DVideoEnabled)(BOOL *enabled)
 {
-    if (!enabled)
-        return E_POINTER;
+    CheckComArgOutPointerValid(enabled);
 
     AutoCaller autoCaller(this);
@@ -1801,6 +1839,5 @@
 STDMETHODIMP Machine::COMGETTER(MonitorCount)(ULONG *monitorCount)
 {
-    if (!monitorCount)
-        return E_POINTER;
+    CheckComArgOutPointerValid(monitorCount);
 
     AutoCaller autoCaller(this);
@@ -1839,6 +1876,5 @@
 STDMETHODIMP Machine::COMGETTER(BIOSSettings)(IBIOSSettings **biosSettings)
 {
-    if (!biosSettings)
-        return E_POINTER;
+    CheckComArgOutPointerValid(biosSettings);
 
     AutoCaller autoCaller(this);
@@ -1853,6 +1889,5 @@
 STDMETHODIMP Machine::GetCPUProperty(CPUPropertyType_T property, BOOL *aVal)
 {
-    if (!aVal)
-        return E_POINTER;
+    CheckComArgOutPointerValid(aVal);
 
     AutoCaller autoCaller(this);
@@ -2111,6 +2146,5 @@
 STDMETHODIMP Machine::GetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL *aVal)
 {
-    if (!aVal)
-        return E_POINTER;
+    CheckComArgOutPointerValid(aVal);
 
     AutoCaller autoCaller(this);
@@ -2269,6 +2303,5 @@
 STDMETHODIMP Machine::COMGETTER(MediumAttachments)(ComSafeArrayOut(IMediumAttachment*, aAttachments))
 {
-    if (ComSafeArrayOutIsNull(aAttachments))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aAttachments);
 
     AutoCaller autoCaller(this);
@@ -2285,6 +2318,5 @@
 STDMETHODIMP Machine::COMGETTER(VRDEServer)(IVRDEServer **vrdeServer)
 {
-    if (!vrdeServer)
-        return E_POINTER;
+    CheckComArgOutPointerValid(vrdeServer);
 
     AutoCaller autoCaller(this);
@@ -2301,6 +2333,5 @@
 STDMETHODIMP Machine::COMGETTER(AudioAdapter)(IAudioAdapter **audioAdapter)
 {
-    if (!audioAdapter)
-        return E_POINTER;
+    CheckComArgOutPointerValid(audioAdapter);
 
     AutoCaller autoCaller(this);
@@ -2419,6 +2450,5 @@
 STDMETHODIMP Machine::COMGETTER(State)(MachineState_T *machineState)
 {
-    if (!machineState)
-        return E_POINTER;
+    CheckComArgOutPointerValid(machineState);
 
     AutoCaller autoCaller(this);
@@ -4481,6 +4511,5 @@
 STDMETHODIMP Machine::GetExtraDataKeys(ComSafeArrayOut(BSTR, aKeys))
 {
-    if (ComSafeArrayOutIsNull(aKeys))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aKeys);
 
     AutoCaller autoCaller(this);
@@ -4803,6 +4832,6 @@
 {
     ComObjPtr<Machine>          pMachine;
-    RTCList< ComPtr<IMedium> >  llMediums;
-    std::list<Utf8Str>          llFilesToDelete;
+    RTCList<ComPtr<IMedium> >   llMediums;
+    StringsList                 llFilesToDelete;
     ComObjPtr<Progress>         pProgress;
 };
@@ -4969,5 +4998,5 @@
         // medium storage files from the IMedium list passed in, and the
         // machine XML file)
-        std::list<Utf8Str>::const_iterator it = task.llFilesToDelete.begin();
+        StringsList::const_iterator it = task.llFilesToDelete.begin();
         while (it != task.llFilesToDelete.end())
         {
@@ -6589,5 +6618,5 @@
         hrc = checkStateDependency(MutableStateDep);
         if (   SUCCEEDED(hrc)
-            && mHWData->mAutostart.fAutostartEnabled != fEnabled)
+            && mHWData->mAutostart.fAutostartEnabled != !!fEnabled)
         {
             AutostartDb *autostartDb = mParent->getAutostartDb();
@@ -8907,4 +8936,6 @@
 
     bool fSettingsFileIsNew = !mData->pMachineConfigFile->fileExists();
+
+    /// @todo need to handle primary group change, too
 
     /* attempt to rename the settings file if machine name is changed */
@@ -12228,8 +12259,8 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    AssertReturn(!ComSafeArrayOutIsNull(aNames), E_POINTER);
-    AssertReturn(!ComSafeArrayOutIsNull(aValues), E_POINTER);
-    AssertReturn(!ComSafeArrayOutIsNull(aTimestamps), E_POINTER);
-    AssertReturn(!ComSafeArrayOutIsNull(aFlags), E_POINTER);
+    CheckComArgOutSafeArrayPointerValid(aNames);
+    CheckComArgOutSafeArrayPointerValid(aValues);
+    CheckComArgOutSafeArrayPointerValid(aTimestamps);
+    CheckComArgOutSafeArrayPointerValid(aFlags);
 
     size_t cEntries = mHWData->mGuestProperties.size();
@@ -12596,5 +12627,5 @@
      */
 
-    mParent->onNatRedirectChange(getId(), ulSlot, RT_BOOL(aNatRuleRemove), aRuleName, aProto, aHostIp, aHostPort, aGuestIp, aGuestPort);
+    mParent->onNatRedirectChange(getId(), ulSlot, RT_BOOL(aNatRuleRemove), aRuleName, aProto, aHostIp, (uint16_t)aHostPort, aGuestIp, (uint16_t)aGuestPort);
     return S_OK;
 }
Index: /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp	(revision 42128)
+++ /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp	(revision 42129)
@@ -930,6 +930,5 @@
 VirtualBox::COMGETTER(Machines)(ComSafeArrayOut(IMachine *, aMachines))
 {
-    if (ComSafeArrayOutIsNull(aMachines))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aMachines);
 
     AutoCaller autoCaller(this);
@@ -943,8 +942,62 @@
 }
 
+STDMETHODIMP
+VirtualBox::COMGETTER(MachineGroups)(ComSafeArrayOut(BSTR, aMachineGroups))
+{
+    CheckComArgOutSafeArrayPointerValid(aMachineGroups);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    std::list<Bstr> allGroups;
+
+    /* get copy of all machine references, to avoid holding the list lock */
+    MachinesOList::MyList allMachines;
+    {
+        AutoReadLock al(m->allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+        allMachines = m->allMachines.getList();
+    }
+    for (MachinesOList::MyList::const_iterator it = allMachines.begin();
+         it != allMachines.end();
+         ++it)
+    {
+        const ComObjPtr<Machine> &pMachine = *it;
+        AutoCaller autoMachineCaller(pMachine);
+        if (FAILED(autoMachineCaller.rc()))
+            continue;
+        AutoReadLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
+
+        if (pMachine->isAccessible())
+        {
+            SafeArray<BSTR> thisGroups;
+            HRESULT rc = pMachine->COMGETTER(Groups)(ComSafeArrayAsOutParam(thisGroups));
+            if (FAILED(rc))
+                continue;
+
+            for (size_t i = 0; i < thisGroups.size(); i++)
+                allGroups.push_back(thisGroups[i]);
+        }
+    }
+
+    /* throw out any duplicates */
+    allGroups.sort();
+    allGroups.unique();
+    com::SafeArray<BSTR> machineGroups(allGroups.size());
+    size_t i = 0;
+    for (std::list<Bstr>::const_iterator it = allGroups.begin();
+         it != allGroups.end();
+         ++it, i++)
+    {
+        const Bstr &tmp = *it;
+        tmp.cloneTo(&machineGroups[i]);
+    }
+    machineGroups.detachTo(ComSafeArrayOutArg(aMachineGroups));
+
+    return S_OK;
+}
+
 STDMETHODIMP VirtualBox::COMGETTER(HardDisks)(ComSafeArrayOut(IMedium *, aHardDisks))
 {
-    if (ComSafeArrayOutIsNull(aHardDisks))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aHardDisks);
 
     AutoCaller autoCaller(this);
@@ -960,6 +1013,5 @@
 STDMETHODIMP VirtualBox::COMGETTER(DVDImages)(ComSafeArrayOut(IMedium *, aDVDImages))
 {
-    if (ComSafeArrayOutIsNull(aDVDImages))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aDVDImages);
 
     AutoCaller autoCaller(this);
@@ -975,6 +1027,5 @@
 STDMETHODIMP VirtualBox::COMGETTER(FloppyImages)(ComSafeArrayOut(IMedium *, aFloppyImages))
 {
-    if (ComSafeArrayOutIsNull(aFloppyImages))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aFloppyImages);
 
     AutoCaller autoCaller(this);
@@ -1052,6 +1103,5 @@
 VirtualBox::COMGETTER(DHCPServers)(ComSafeArrayOut(IDHCPServer *, aDHCPServers))
 {
-    if (ComSafeArrayOutIsNull(aDHCPServers))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aDHCPServers);
 
     AutoCaller autoCaller(this);
@@ -1101,6 +1151,5 @@
 STDMETHODIMP VirtualBox::COMGETTER(InternalNetworks)(ComSafeArrayOut(BSTR, aInternalNetworks))
 {
-    if (ComSafeArrayOutIsNull(aInternalNetworks))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aInternalNetworks);
 
     AutoCaller autoCaller(this);
@@ -1163,6 +1212,5 @@
 STDMETHODIMP VirtualBox::COMGETTER(GenericNetworkDrivers)(ComSafeArrayOut(BSTR, aGenericNetworkDrivers))
 {
-    if (ComSafeArrayOutIsNull(aGenericNetworkDrivers))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aGenericNetworkDrivers);
 
     AutoCaller autoCaller(this);
@@ -1323,7 +1371,10 @@
 
 STDMETHODIMP VirtualBox::ComposeMachineFilename(IN_BSTR aName,
+                                                IN_BSTR aGroup,
                                                 IN_BSTR aBaseFolder,
                                                 BSTR *aFilename)
 {
+    /// @todo implement aGroup
+    NOREF(aGroup);
     LogFlowThisFuncEnter();
     LogFlowThisFunc(("aName=\"%ls\",aBaseFolder=\"%ls\"\n", aName, aBaseFolder));
@@ -1465,4 +1516,5 @@
 STDMETHODIMP VirtualBox::CreateMachine(IN_BSTR aSettingsFile,
                                        IN_BSTR aName,
+                                       ComSafeArrayIn(IN_BSTR, aGroups),
                                        IN_BSTR aOsTypeId,
                                        IN_BSTR aId,
@@ -1480,11 +1532,16 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
+    StringsList llGroups;
+    HRESULT rc = convertMachineGroups(ComSafeArrayInArg(aGroups), &llGroups);
+    if (FAILED(rc))
+        return rc;
+
     /* NULL settings file means compose automatically */
-    HRESULT rc;
     Bstr bstrSettingsFile(aSettingsFile);
     if (bstrSettingsFile.isEmpty())
     {
         rc = ComposeMachineFilename(aName,
-                                    NULL,
+                                    Bstr(llGroups.front()).raw(),
+                                    NULL /* aBaseFolder */,
                                     bstrSettingsFile.asOutParam());
         if (FAILED(rc)) return rc;
@@ -1509,4 +1566,5 @@
                        Utf8Str(bstrSettingsFile),
                        Utf8Str(aName),
+                       llGroups,
                        osType,
                        id,
@@ -1850,6 +1908,5 @@
     using namespace settings;
 
-    if (ComSafeArrayOutIsNull(aKeys))
-        return E_POINTER;
+    CheckComArgOutSafeArrayPointerValid(aKeys);
 
     AutoCaller autoCaller(this);
@@ -2963,4 +3020,56 @@
 
     return rc;
+}
+
+/**
+ * Takes a list of machine groups, and sanitizes/validates it.
+ *
+ * @param aMachineGroups    Safearray with the machine groups.
+ * @param pllMachineGroups  Pointer to list of strings for the result.
+ *
+ * @return S_OK or E_INVALIDARG
+ */
+
+HRESULT VirtualBox::convertMachineGroups(ComSafeArrayIn(IN_BSTR, aMachineGroups), StringsList *pllMachineGroups)
+{
+    pllMachineGroups->clear();
+    if (aMachineGroups)
+    {
+        com::SafeArray<BSTR> machineGroups(ComSafeArrayInArg(aMachineGroups));
+        for (size_t i = 0; i < machineGroups.size(); i++)
+            pllMachineGroups->push_back(machineGroups[i]);
+        pllMachineGroups->sort();
+        pllMachineGroups->unique();
+        if (pllMachineGroups->size() > 0)
+            pllMachineGroups->push_back("/");
+        else if (pllMachineGroups->front().equals(""))
+        {
+            pllMachineGroups->pop_front();
+            if (pllMachineGroups->size() == 0 || !pllMachineGroups->front().equals("/"))
+                pllMachineGroups->push_front("/");
+        }
+    }
+    else
+        pllMachineGroups->push_back("/");
+
+    for (StringsList::const_iterator it = pllMachineGroups->begin();
+         it != pllMachineGroups->end();
+         ++it)
+    {
+        const Utf8Str &str = *it;
+        /* no empty strings (shouldn't happen after the translation above) */
+        if (str.length() == 0)
+            return E_INVALIDARG;
+        /* must start with a slash */
+        if (str.c_str()[0] != '/')
+            return E_INVALIDARG;
+        /* must not end with a slash */
+        if (str.c_str()[str.length() - 1] != '/')
+            return E_INVALIDARG;
+
+        /** @todo validate each component of the group hierarchy */
+    }
+
+    return S_OK;
 }
 
Index: /trunk/src/VBox/Main/webservice/websrv-cpp.xsl
===================================================================
--- /trunk/src/VBox/Main/webservice/websrv-cpp.xsl	(revision 42128)
+++ /trunk/src/VBox/Main/webservice/websrv-cpp.xsl	(revision 42129)
@@ -534,5 +534,5 @@
   <xsl:param name="safearray" />
 
-  <xsl:value-of select="concat('        // convert input arg ', $name)" />
+  <xsl:value-of select="concat('        // convert input arg ', $name, '(safearray: ', $safearray, ')')" />
   <xsl:call-template name="emitNewlineIndent8" />
 
@@ -709,4 +709,28 @@
 
 <!--
+    emitInParam:
+-->
+<xsl:template name="emitInParam">
+  <xsl:param name="name" />
+  <xsl:param name="type" />
+  <xsl:param name="safearray" />
+  <xsl:param name="varprefix" />      <!-- only with nested set-attribute calls -->
+
+  <xsl:variable name="varname" select="concat('comcall_', $varprefix, $name)" />
+
+  <xsl:choose>
+    <xsl:when test="@safearray='yes'">
+      <xsl:value-of select="concat('ComSafeArrayAsInParam(', $varname, ')')" />
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="$varname" />
+      <xsl:if test="@type='wstring' or @type='uuid'">
+        <xsl:text>.raw()</xsl:text>
+      </xsl:if>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!--
     emitOutParam:
 -->
@@ -768,8 +792,10 @@
     <xsl:choose>
       <xsl:when test="$attrdir='in'">
-        <xsl:value-of select="concat('comcall_', $varprefix, @name)" />
-        <xsl:if test="$attrtype='wstring' or $attrtype='uuid'">
-          <xsl:text>.raw()</xsl:text>
-        </xsl:if>
+        <xsl:call-template name="emitInParam">
+          <xsl:with-param name="name" select="$attrname" />
+          <xsl:with-param name="type" select="$attrtype" />
+          <xsl:with-param name="safearray" select="$attrsafearray" />
+          <xsl:with-param name="varprefix" select="$varprefix" />
+        </xsl:call-template>
       </xsl:when>
       <xsl:when test="$attrdir='return'">
@@ -794,15 +820,10 @@
     <xsl:choose>
       <xsl:when test="@dir='in'">
-        <xsl:choose>
-          <xsl:when test="@safearray='yes'">
-            <xsl:value-of select="concat('ComSafeArrayAsInParam(comcall_', $varprefix, @name, ')')" />
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:value-of select="concat('comcall_', $varprefix, @name)" />
-            <xsl:if test="@type='wstring' or @type='uuid'">
-              <xsl:text>.raw()</xsl:text>
-            </xsl:if>
-          </xsl:otherwise>
-        </xsl:choose>
+        <xsl:call-template name="emitInParam">
+          <xsl:with-param name="name" select="@name" />
+          <xsl:with-param name="type" select="@type" />
+          <xsl:with-param name="safearray" select="@safearray" />
+          <xsl:with-param name="varprefix" select="$varprefix" />
+        </xsl:call-template>
       </xsl:when>
       <xsl:when test="@dir='out'">
@@ -1204,4 +1225,5 @@
   <xsl:param name="attrtype" select="$attrtype" />
   <xsl:param name="attrreadonly" select="$attrreadonly" />
+  <xsl:param name="attrsafearray" select="$attrsafearray" />
 
   <xsl:variable name="settername"><xsl:call-template name="makeSetterName"><xsl:with-param name="attrname" select="$attrname" /></xsl:call-template></xsl:variable>
@@ -1244,4 +1266,5 @@
         <xsl:with-param name="attrname"><xsl:value-of select="$attrname" /></xsl:with-param>
         <xsl:with-param name="attrtype"><xsl:value-of select="$attrtype" /></xsl:with-param>
+        <xsl:with-param name="attrsafearray"><xsl:value-of select="$attrsafearray" /></xsl:with-param>
       </xsl:call-template>
     <!-- </xsl:otherwise>
@@ -1316,4 +1339,5 @@
               <xsl:with-param name="attrtype" select="$attrtype" />
               <xsl:with-param name="attrreadonly" select="$attrreadonly" />
+              <xsl:with-param name="attrsafearray" select="$attrsafearray" />
             </xsl:call-template>
           </xsl:if>
Index: /trunk/src/VBox/Runtime/common/misc/getopt.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/misc/getopt.cpp	(revision 42128)
+++ /trunk/src/VBox/Runtime/common/misc/getopt.cpp	(revision 42129)
@@ -791,4 +791,7 @@
     else if (ch == VERR_GETOPT_UNKNOWN_OPTION)
         RTMsgError("Unknown option: '%s'", pValueUnion->psz);
+    else if (ch == VERR_GETOPT_INVALID_ARGUMENT_FORMAT)
+        /** @todo r=klaus not really ideal, as the option isn't available */
+        RTMsgError("Invalid argument format: '%s'", pValueUnion->psz);
     else if (pValueUnion->pDef)
         RTMsgError("%s: %Rrs\n", pValueUnion->pDef->pszLong, ch);
