Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp	(revision 55534)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp	(revision 55535)
@@ -1500,4 +1500,6 @@
      * Prepare environment variables list.
      */
+/** @todo r=bird: you don't need to prepare this, do you? Why don't you replace
+ * the brilliant RTStrAPrintf call with RTEnvPutEx and drop the papszEnv related code? */
     char **papszEnv = NULL;
     uint32_t uNumEnvVars = 0; /* Initialize in case of failing ... */
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 55534)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 55535)
@@ -111,19 +111,21 @@
 
 #ifdef VBOX_WITH_GUEST_CONTROL
-# define USAGE_GSTCTRL_EXEC         RT_BIT(0)
-# define USAGE_GSTCTRL_COPYFROM     RT_BIT(1)
-# define USAGE_GSTCTRL_COPYTO       RT_BIT(2)
-# define USAGE_GSTCTRL_CREATEDIR    RT_BIT(3)
-# define USAGE_GSTCTRL_REMOVEDIR    RT_BIT(4)
-# define USAGE_GSTCTRL_REMOVEFILE   RT_BIT(5)
-# define USAGE_GSTCTRL_RENAME       RT_BIT(6)
-# define USAGE_GSTCTRL_CREATETEMP   RT_BIT(7)
-# define USAGE_GSTCTRL_LIST         RT_BIT(8)
-# define USAGE_GSTCTRL_PROCESS      RT_BIT(9)
-# define USAGE_GSTCTRL_KILL         RT_BIT(10)
-# define USAGE_GSTCTRL_SESSION      RT_BIT(11)
-# define USAGE_GSTCTRL_STAT         RT_BIT(12)
-# define USAGE_GSTCTRL_UPDATEADDS   RT_BIT(13)
-# define USAGE_GSTCTRL_WATCH        RT_BIT(14)
+# define USAGE_GSTCTRL_RUN          RT_BIT(0)
+# define USAGE_GSTCTRL_START        RT_BIT(1)
+# define USAGE_GSTCTRL_COPYFROM     RT_BIT(2)
+# define USAGE_GSTCTRL_COPYTO       RT_BIT(3)
+# define USAGE_GSTCTRL_CREATEDIR    RT_BIT(4)
+# define USAGE_GSTCTRL_REMOVEDIR    RT_BIT(5)
+# define USAGE_GSTCTRL_REMOVEFILE   RT_BIT(6)
+# define USAGE_GSTCTRL_RENAME       RT_BIT(7)
+# define USAGE_GSTCTRL_CREATETEMP   RT_BIT(8)
+# define USAGE_GSTCTRL_LIST         RT_BIT(9)
+# define USAGE_GSTCTRL_PROCESS      RT_BIT(10)
+# define USAGE_GSTCTRL_KILL         RT_BIT(11)
+# define USAGE_GSTCTRL_SESSION      RT_BIT(12)
+# define USAGE_GSTCTRL_STAT         RT_BIT(13)
+# define USAGE_GSTCTRL_UPDATEADDS   RT_BIT(14)
+# define USAGE_GSTCTRL_WATCH        RT_BIT(15)
+# define USAGE_GSTCTRL_EXEC         RT_BIT(31) /**< @deprecated Remember to remove. */
 #endif
 
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 55534)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 55535)
@@ -46,4 +46,5 @@
 #include <iprt/process.h> /* For RTProcSelf(). */
 #include <iprt/thread.h>
+#include <iprt/vfs.h>
 
 #include <map>
@@ -218,23 +219,4 @@
 typedef std::map< Utf8Str, std::vector<DESTFILEENTRY> >::iterator DESTDIRMAPITER, *PDESTDIRMAPITER;
 
-/**
- * Special exit codes for returning errors/information of a
- * started guest process to the command line VBoxManage was started from.
- * Useful for e.g. scripting.
- *
- * @note    These are frozen as of 4.1.0.
- */
-enum EXITCODEEXEC
-{
-    EXITCODEEXEC_SUCCESS        = RTEXITCODE_SUCCESS,
-    /* Process exited normally but with an exit code <> 0. */
-    EXITCODEEXEC_CODE           = 16,
-    EXITCODEEXEC_FAILED         = 17,
-    EXITCODEEXEC_TERM_SIGNAL    = 18,
-    EXITCODEEXEC_TERM_ABEND     = 19,
-    EXITCODEEXEC_TIMEOUT        = 20,
-    EXITCODEEXEC_DOWN           = 21,
-    EXITCODEEXEC_CANCELED       = 22
-};
 
 /*
@@ -245,4 +227,19 @@
 {
     GETOPTDEF_COMMON_PASSWORD = 1000
+};
+
+/**
+ * Long option IDs for the guestcontrol run command.
+ */
+enum kGstCtrlRunOpt
+{
+    kGstCtrlRunOpt_IgnoreOrphanedProcesses = 1000,
+    kGstCtrlRunOpt_NoProfile,
+    kGstCtrlRunOpt_Dos2Unix,
+    kGstCtrlRunOpt_Unix2Dos,
+    kGstCtrlRunOpt_WaitForStdOut,
+    kGstCtrlRunOpt_NoWaitForStdOut,
+    kGstCtrlRunOpt_WaitForStdErr,
+    kGstCtrlRunOpt_NoWaitForStdErr
 };
 
@@ -290,9 +287,9 @@
 };
 
-enum OUTPUTTYPE
-{
-    OUTPUTTYPE_UNDEFINED = 0,
-    OUTPUTTYPE_DOS2UNIX  = 10,
-    OUTPUTTYPE_UNIX2DOS  = 20
+enum kStreamTransform
+{
+    kStreamTransform_None = 0,
+    kStreamTransform_Dos2Unix,
+    kStreamTransform_Unix2Dos
 };
 
@@ -307,14 +304,36 @@
                  pcszSep1, pcszSep2,
                  uSubCmd == ~0U ? "\n" : "");
-    if (uSubCmd & USAGE_GSTCTRL_EXEC)
+    if (uSubCmd & USAGE_GSTCTRL_RUN)
         RTStrmPrintf(pStrm,
-                 "                              exec[ute]\n"
-                 "                              --image <path to program> --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
-                 "                              [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n"
-                 "                              [--wait-exit] [--wait-stdout] [--wait-stderr]\n"
-                 "                              [--dos2unix] [--unquoted-args] [--unix2dos]\n"
-                 "                              [-- [<argument1>] ... [<argumentN>]]\n"
+                     "                              run\n"
+                     "                              [--image <path to executable>] --username <name>\n"
+                     "                              [--passwordfile <file> | --password <password>]\n"
+                     "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
+                     "                              [--setenv <NAME>=<VALUE>] [--unset <NAME>]\n"
+                     "                              [--unquoted-args] [--no-wait-stdout|--wait-stdout]\n"
+                     "                              [--no-wait-stderr|--wait-stderr]\n"
+                     "                              [--dos2unix] [--unix2dos]\n"
+                     "                              [--] <program/arg0> [argument1] ... [argumentN]]\n"
+                     "\n");
+    if (uSubCmd & USAGE_GSTCTRL_START)
+        RTStrmPrintf(pStrm,
+                     "                              start\n"
+                     "                              [--image <path to executable>] --username <name>\n"
+                     "                              [--passwordfile <file> | --password <password>]\n"
+                     "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
+                     "                              [--setenv <NAME>=<VALUE>] [--unset <NAME>]\n"
+                     "                              [--unquoted-args] [--dos2unix] [--unix2dos]\n"
+                     "                              [--] <program/arg0> [argument1] ... [argumentN]]\n"
+                 "\n");
+    if (uSubCmd == USAGE_GSTCTRL_EXEC)
+        RTStrmPrintf(pStrm,
+                 "   {DEPRECATED}               exec[ute]\n"
+                 "   {DEPRECATED}               --image <path to program> --username <name>\n"
+                 "   {DEPRECATED}               [--passwordfile <file> | --password <password>]\n"
+                 "   {DEPRECATED}               [--domain <domain>] [--verbose] [--timeout <msec>]\n"
+                 "   {DEPRECATED}               [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n"
+                 "   {DEPRECATED}               [--wait-exit] [--wait-stdout] [--wait-stderr]\n"
+                 "   {DEPRECATED}               [--dos2unix] [--unquoted-args] [--unix2dos]\n"
+                 "   {DEPRECATED}               [-- [<argument1>] ... [<argumentN>]]\n"
                  "\n");
     if (uSubCmd & USAGE_GSTCTRL_COPYFROM)
@@ -537,23 +556,1100 @@
 }
 
-static int ctrlExecProcessStatusToExitCode(ProcessStatus_T enmStatus, ULONG uExitCode)
-{
-    int vrc = EXITCODEEXEC_SUCCESS;
+const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)
+{
+    switch (enmWaitResult)
+    {
+        case ProcessWaitResult_Start:
+            return "started";
+        case ProcessWaitResult_Terminate:
+            return "terminated";
+        case ProcessWaitResult_Status:
+            return "status changed";
+        case ProcessWaitResult_Error:
+            return "error";
+        case ProcessWaitResult_Timeout:
+            return "timed out";
+        case ProcessWaitResult_StdIn:
+            return "stdin ready";
+        case ProcessWaitResult_StdOut:
+            return "data on stdout";
+        case ProcessWaitResult_StdErr:
+            return "data on stderr";
+        case ProcessWaitResult_WaitFlagNotSupported:
+            return "waiting flag not supported";
+        default:
+            break;
+    }
+    return "unknown";
+}
+
+/**
+ * Translates a guest session status to a human readable
+ * string.
+ */
+const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)
+{
     switch (enmStatus)
     {
+        case GuestSessionStatus_Starting:
+            return "starting";
+        case GuestSessionStatus_Started:
+            return "started";
+        case GuestSessionStatus_Terminating:
+            return "terminating";
+        case GuestSessionStatus_Terminated:
+            return "terminated";
+        case GuestSessionStatus_TimedOutKilled:
+            return "timed out";
+        case GuestSessionStatus_TimedOutAbnormally:
+            return "timed out, hanging";
+        case GuestSessionStatus_Down:
+            return "killed";
+        case GuestSessionStatus_Error:
+            return "error";
+        default:
+            break;
+    }
+    return "unknown";
+}
+
+/**
+ * Translates a guest file status to a human readable
+ * string.
+ */
+const char *ctrlFileStatusToText(FileStatus_T enmStatus)
+{
+    switch (enmStatus)
+    {
+        case FileStatus_Opening:
+            return "opening";
+        case FileStatus_Open:
+            return "open";
+        case FileStatus_Closing:
+            return "closing";
+        case FileStatus_Closed:
+            return "closed";
+        case FileStatus_Down:
+            return "killed";
+        case FileStatus_Error:
+            return "error";
+        default:
+            break;
+    }
+    return "unknown";
+}
+
+static int ctrlPrintError(com::ErrorInfo &errorInfo)
+{
+    if (   errorInfo.isFullAvailable()
+        || errorInfo.isBasicAvailable())
+    {
+        /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
+         * because it contains more accurate info about what went wrong. */
+        if (errorInfo.getResultCode() == VBOX_E_IPRT_ERROR)
+            RTMsgError("%ls.", errorInfo.getText().raw());
+        else
+        {
+            RTMsgError("Error details:");
+            GluePrintErrorInfo(errorInfo);
+        }
+        return VERR_GENERAL_FAILURE; /** @todo */
+    }
+    AssertMsgFailedReturn(("Object has indicated no error (%Rhrc)!?\n", errorInfo.getResultCode()),
+                          VERR_INVALID_PARAMETER);
+}
+
+static int ctrlPrintError(IUnknown *pObj, const GUID &aIID)
+{
+    com::ErrorInfo ErrInfo(pObj, aIID);
+    return ctrlPrintError(ErrInfo);
+}
+
+static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)
+{
+    int vrc = VINF_SUCCESS;
+    HRESULT rc;
+
+    do
+    {
+        BOOL fCanceled;
+        CHECK_ERROR_BREAK(pProgress, COMGETTER(Canceled)(&fCanceled));
+        if (!fCanceled)
+        {
+            LONG rcProc;
+            CHECK_ERROR_BREAK(pProgress, COMGETTER(ResultCode)(&rcProc));
+            if (FAILED(rcProc))
+            {
+                com::ProgressErrorInfo ErrInfo(pProgress);
+                vrc = ctrlPrintError(ErrInfo);
+            }
+        }
+
+    } while(0);
+
+    AssertMsgStmt(SUCCEEDED(rc), ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED);
+
+    return vrc;
+}
+
+/**
+ * Un-initializes the VM after guest control usage.
+ * @param   pCmdCtx                 Pointer to command context.
+ * @param   uFlags                  Command context flags.
+ */
+static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags)
+{
+    AssertPtrReturnVoid(pCtx);
+
+    if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
+        ctrlSignalHandlerUninstall();
+
+    HRESULT rc;
+
+    do
+    {
+        if (!pCtx->pGuestSession.isNull())
+        {
+            if (   !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)
+                && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH))
+            {
+                if (pCtx->fVerbose)
+                    RTPrintf("Closing guest session ...\n");
+
+                CHECK_ERROR(pCtx->pGuestSession, Close());
+                /* Keep going - don't break here. Try to unlock the
+                 * machine down below. */
+            }
+            else if (   (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)
+                     && pCtx->fVerbose)
+                RTPrintf("Guest session detached\n");
+
+            pCtx->pGuestSession.setNull();
+        }
+
+        if (pCtx->handlerArg.session)
+            CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine());
+
+    } while (0);
+
+    for (int i = 0; i < pCtx->iArgc; i++)
+        RTStrFree(pCtx->ppaArgv[i]);
+    RTMemFree(pCtx->ppaArgv);
+    pCtx->iArgc = 0;
+}
+
+/**
+ * Initializes the VM for IGuest operations.
+ *
+ * That is, checks whether it's up and running, if it can be locked (shared
+ * only) and returns a valid IGuest pointer on success. Also, it does some
+ * basic command line processing and opens a guest session, if required.
+ *
+ * @return  RTEXITCODE status code.
+ * @param   pArg                    Pointer to command line argument structure.
+ * @param   pCmdCtx                 Pointer to command context.
+ * @param   uFlags                  Command context flags.
+ */
+static RTEXITCODE ctrlInitVM(HandlerArg *pArg,
+                             PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage)
+{
+    AssertPtrReturn(pArg, RTEXITCODE_FAILURE);
+    AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE);
+    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+#ifdef DEBUG_andy
+    RTPrintf("Original argv:\n");
+    for (int i=0; i<pArg->argc;i++)
+        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
+#endif
+
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+
+    const char *pszNameOrId = pArg->argv[0];
+    const char *pszCmd = pArg->argv[1];
+
+    /* Lookup VM. */
+    ComPtr<IMachine> machine;
+    /* Assume it's an UUID. */
+    HRESULT rc;
+    CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(),
+                                              machine.asOutParam()));
+    if (SUCCEEDED(rc))
+    {
+        /* Machine is running? */
+        MachineState_T machineState;
+        CHECK_ERROR(machine, COMGETTER(State)(&machineState));
+        if (   SUCCEEDED(rc)
+            && (machineState != MachineState_Running))
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n",
+                                    pszNameOrId, machineStateToName(machineState, false));
+    }
+    else
+        rcExit = RTEXITCODE_FAILURE;
+
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        /*
+         * Process standard options which are served by all commands.
+         */
+        static const RTGETOPTDEF s_aOptions[] =
+        {
+            { "--username",            'u',                             RTGETOPT_REQ_STRING  },
+            { "--passwordfile",        'p',                             RTGETOPT_REQ_STRING  },
+            { "--password",            GETOPTDEF_COMMON_PASSWORD,       RTGETOPT_REQ_STRING  },
+            { "--domain",              'd',                             RTGETOPT_REQ_STRING  },
+            { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
+        };
+
+
+
+        /** @todo r=bird: This is just SOOOO hackish and fragile, especially wrt to the
+         * exec/run commands. If you don't have the full option syntax, there is no way
+         * you can safely tell an option from an option value. sigh.
+         * The way to do this is by a defines with the above s_aOptions entries, calling
+         * a common function in the default case of each option parser, and a routine to
+         * be called at the end of option parsing to open the session. */
+
+
+
+        /*
+         * Allocate per-command argv. This then only contains the specific arguments
+         * the command needs.
+         */
+        pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1);
+        if (!pCtx->ppaArgv)
+        {
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n");
+        }
+        else
+        {
+            pCtx->iArgc = 0;
+
+            int iArgIdx = 2; /* Skip VM name and guest control command */
+            int ch;
+            RTGETOPTUNION ValueUnion;
+            RTGETOPTSTATE GetState;
+            RTGetOptInit(&GetState, pArg->argc, pArg->argv,
+                         s_aOptions, RT_ELEMENTS(s_aOptions),
+                         iArgIdx, 0);
+
+            while (   (ch = RTGetOpt(&GetState, &ValueUnion))
+                   && (rcExit == RTEXITCODE_SUCCESS))
+            {
+                /* For options that require an argument, ValueUnion has received the value. */
+                switch (ch)
+                {
+                    case 'u': /* User name */
+                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+                            pCtx->strUsername = ValueUnion.psz;
+                        iArgIdx = GetState.iNext;
+                        break;
+
+                    case GETOPTDEF_COMMON_PASSWORD: /* Password */
+                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+                        {
+                            if (pCtx->strPassword.isEmpty())
+                                pCtx->strPassword = ValueUnion.psz;
+                        }
+                        iArgIdx = GetState.iNext;
+                        break;
+
+                    case 'p': /* Password file */
+                    {
+                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+                            rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword);
+                        iArgIdx = GetState.iNext;
+                        break;
+                    }
+
+                    case 'd': /* domain */
+                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+                            pCtx->strDomain = ValueUnion.psz;
+                        iArgIdx = GetState.iNext;
+                        break;
+
+                    case 'v': /* Verbose */
+                        pCtx->fVerbose = true;
+                        iArgIdx = GetState.iNext;
+                        break;
+
+                    case 'h': /* Help */
+                        errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);
+                        return RTEXITCODE_SYNTAX;
+
+                    default:
+                        /* Simply skip; might be handled in a specific command
+                         * handler later. */
+                        break;
+
+                } /* switch */
+
+                int iArgDiff = GetState.iNext - iArgIdx;
+                if (iArgDiff)
+                {
+#ifdef DEBUG_andy
+                    RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx);
+#endif
+                    for (int i = iArgIdx; i < GetState.iNext; i++)
+                    {
+                        char *pszArg = RTStrDup(pArg->argv[i]);
+                        if (!pszArg)
+                        {
+                            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
+                                                    "Not enough memory for command line handling\n");
+                            break;
+                        }
+                        pCtx->ppaArgv[pCtx->iArgc] = pszArg;
+                        pCtx->iArgc++;
+#ifdef DEBUG_andy
+                        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
+#endif
+                    }
+
+                    iArgIdx = GetState.iNext;
+                }
+
+            } /* while RTGetOpt */
+        }
+    }
+
+    /*
+     * Check for mandatory stuff.
+     */
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+#if 0
+        RTPrintf("argc=%d\n", pCtx->iArgc);
+        for (int i = 0; i < pCtx->iArgc; i++)
+            RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]);
+#endif
+        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+        {
+            if (pCtx->strUsername.isEmpty())
+                rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!");
+        }
+    }
+
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        /*
+         * Build up a reasonable guest session name. Useful for identifying
+         * a specific session when listing / searching for them.
+         */
+        char *pszSessionName;
+        if (0 >= RTStrAPrintf(&pszSessionName,
+                              "[%RU32] VBoxManage Guest Control [%s] - %s",
+                              RTProcSelf(), pszNameOrId, pszCmd))
+            return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n");
+
+        do
+        {
+            /* Open a session for the VM. */
+            CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));
+            /* Get the associated console. */
+            ComPtr<IConsole> console;
+            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));
+            /* ... and session machine. */
+            ComPtr<IMachine> sessionMachine;
+            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
+            /* Get IGuest interface. */
+            CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));
+            if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+            {
+                if (pCtx->fVerbose)
+                    RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str());
+
+                /* Open a guest session. */
+                Assert(!pCtx->pGuest.isNull());
+                CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),
+                                                              Bstr(pCtx->strPassword).raw(),
+                                                              Bstr(pCtx->strDomain).raw(),
+                                                              Bstr(pszSessionName).raw(),
+                                                              pCtx->pGuestSession.asOutParam()));
+
+                /*
+                 * Wait for guest session to start.
+                 */
+                if (pCtx->fVerbose)
+                    RTPrintf("Waiting for guest session to start ...\n");
+
+                com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
+                aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
+                GuestSessionWaitResult_T sessionWaitResult;
+                CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),
+                                                                    /** @todo Make session handling timeouts configurable. */
+                                                                    30 * 1000, &sessionWaitResult));
+
+                if (   sessionWaitResult == GuestSessionWaitResult_Start
+                    /* Note: This might happen when Guest Additions < 4.3 are installed which don't
+                     *       support dedicated guest sessions. */
+                    || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
+                {
+                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));
+                    if (pCtx->fVerbose)
+                        RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID);
+                }
+                else
+                {
+                    GuestSessionStatus_T sessionStatus;
+                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus));
+                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n",
+                                            ctrlSessionStatusToText(sessionStatus));
+                    break;
+                }
+            }
+
+            if (   SUCCEEDED(rc)
+                && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
+            {
+                ctrlSignalHandlerInstall();
+            }
+
+        } while (0);
+
+        if (FAILED(rc))
+            rcExit = RTEXITCODE_FAILURE;
+
+        RTStrFree(pszSessionName);
+    }
+
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        pCtx->handlerArg = *pArg;
+        pCtx->uFlags = uFlags;
+    }
+    else /* Clean up on failure. */
+        ctrlUninitVM(pCtx, uFlags);
+
+    return rcExit;
+}
+
+
+/** @name EXITCODEEXEC_XXX - Special run exit codes.
+ *
+ * Special exit codes for returning errors/information of a started guest
+ * process to the command line VBoxManage was started from.  Useful for e.g.
+ * scripting.
+ *
+ * ASSUMING that all platforms have at least 7-bits for the exit code we can do
+ * the following mapping:
+ *  - Guest exit code 0 is mapped to 0 on the host.
+ *  - Guest exit codes 1 thru 93 (0x5d) are displaced by 32, so that 1
+ *    becomes 33 (0x21) on the host and 93 becomes 125 (0x7d) on the host.
+ *  - Guest exit codes 94 (0x5e) and above are mapped to 126 (0x5e).
+ *
+ * We ASSUME that all VBoxManage status codes are in the range 0 thru 32.
+ *
+ * @note    These are frozen as of 4.1.0.
+ * @note    The guest exit code mappings was introduced with 5.0 and the 'run'
+ *          command, they are/was not supported by 'exec'.
+ * @sa      ctrlRunCalculateExitCode
+ */
+/** Process exited normally but with an exit code <> 0. */
+#define EXITCODEEXEC_CODE           ((RTEXITCODE)16)
+#define EXITCODEEXEC_FAILED         ((RTEXITCODE)17)
+#define EXITCODEEXEC_TERM_SIGNAL    ((RTEXITCODE)18)
+#define EXITCODEEXEC_TERM_ABEND     ((RTEXITCODE)19)
+#define EXITCODEEXEC_TIMEOUT        ((RTEXITCODE)20)
+#define EXITCODEEXEC_DOWN           ((RTEXITCODE)21)
+/** Execution was interrupt by user (ctrl-c). */
+#define EXITCODEEXEC_CANCELED       ((RTEXITCODE)22)
+/** The first mapped guest (non-zero) exit code. */
+#define EXITCODEEXEC_MAPPED_FIRST           33
+/** The last mapped guest (non-zero) exit code value (inclusive). */
+#define EXITCODEEXEC_MAPPED_LAST            125
+/** The number of exit codes from EXITCODEEXEC_MAPPED_FIRST to
+ * EXITCODEEXEC_MAPPED_LAST.  This is also the highest guest exit code number
+ * we're able to map. */
+#define EXITCODEEXEC_MAPPED_RANGE           (93)
+/** The guest exit code displacement value. */
+#define EXITCODEEXEC_MAPPED_DISPLACEMENT    32
+/** The guest exit code was too big to be mapped. */
+#define EXITCODEEXEC_MAPPED_BIG             ((RTEXITCODE)126)
+/** @} */
+
+/**
+ * Calculates the exit code of VBoxManage.
+ *
+ * @returns The exit code to return.
+ * @param   enmStatus           The guest process status.
+ * @param   uExitCode           The associated guest process exit code (where
+ *                              applicable).
+ * @param   fReturnExitCodes    Set if we're to use the 32-126 range for guest
+ *                              exit codes.
+ */
+static RTEXITCODE ctrlRunCalculateExitCode(ProcessStatus_T enmStatus, ULONG uExitCode, bool fReturnExitCodes)
+{
+    int vrc = RTEXITCODE_SUCCESS;
+    switch (enmStatus)
+    {
+        case ProcessStatus_TerminatedNormally:
+            if (uExitCode == 0)
+                return RTEXITCODE_SUCCESS;
+            if (!fReturnExitCodes)
+                return EXITCODEEXEC_CODE;
+            if (uExitCode <= EXITCODEEXEC_MAPPED_RANGE)
+                return (RTEXITCODE) (uExitCode + EXITCODEEXEC_MAPPED_DISPLACEMENT);
+            return EXITCODEEXEC_MAPPED_BIG;
+
+        case ProcessStatus_TerminatedAbnormally:
+            return EXITCODEEXEC_TERM_ABEND;
+        case ProcessStatus_TerminatedSignal:
+            return EXITCODEEXEC_TERM_SIGNAL;
+
+#if 0  /* see caller! */
+        case ProcessStatus_TimedOutKilled:
+            return EXITCODEEXEC_TIMEOUT;
+        case ProcessStatus_Down:
+            return EXITCODEEXEC_DOWN;   /* Service/OS is stopping, process was killed. */
+        case ProcessStatus_Error:
+            return EXITCODEEXEC_FAILED;
+
+        /* The following is probably for detached? */
         case ProcessStatus_Starting:
-            vrc = EXITCODEEXEC_SUCCESS;
+            return RTEXITCODE_SUCCESS;
+        case ProcessStatus_Started:
+            return RTEXITCODE_SUCCESS;
+        case ProcessStatus_Paused:
+            return RTEXITCODE_SUCCESS;
+        case ProcessStatus_Terminating:
+            return RTEXITCODE_SUCCESS; /** @todo ???? */
+#endif
+
+        default:
+            AssertMsgFailed(("Unknown exit status (%u/%u) from guest process returned!\n", enmStatus, uExitCode));
+            return RTEXITCODE_FAILURE;
+    }
+}
+
+
+/**
+ * Pumps guest output to the host.
+ *
+ * @return  IPRT status code.
+ * @param   pProcess        Pointer to appropriate process object.
+ * @param   hVfsIosDst      Where to write the data.
+ * @param   uHandle         Handle where to read the data from.
+ * @param   cMsTimeout      Timeout (in ms) to wait for the operation to
+ *                          complete.
+ */
+static int ctrlRunPumpOutput(IProcess *pProcess, RTVFSIOSTREAM hVfsIosDst, ULONG uHandle, RTMSINTERVAL cMsTimeout)
+{
+    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
+    Assert(hVfsIosDst != NIL_RTVFSIOSTREAM);
+
+    int vrc;
+
+    SafeArray<BYTE> aOutputData;
+    HRESULT hrc = pProcess->Read(uHandle, _64K, RT_MAX(cMsTimeout, 1), ComSafeArrayAsOutParam(aOutputData));
+    if (SUCCEEDED(hrc))
+    {
+        size_t cbOutputData = aOutputData.size();
+        if (cbOutputData == 0)
+            vrc = VINF_SUCCESS;
+        else
+        {
+            BYTE const *pbBuf = aOutputData.raw();
+            AssertPtr(pbBuf);
+
+            vrc = RTVfsIoStrmWrite(hVfsIosDst, pbBuf, cbOutputData, true /*fBlocking*/,  NULL);
+            if (RT_FAILURE(vrc))
+                RTMsgError("Unable to write output, rc=%Rrc\n", vrc);
+        }
+    }
+    else
+        vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
+    return vrc;
+}
+
+
+/**
+ * Configures a host handle for pumping guest bits.
+ *
+ * @returns true if enabled and we successfully configured it.
+ * @param   fEnabled            Whether pumping this pipe is configured.
+ * @param   enmHandle           The IPRT standard handle designation.
+ * @param   pszName             The name for user messages.
+ * @param   enmTransformation   The transformation to apply.
+ * @param   phVfsIos            Where to return the resulting I/O stream handle.
+ */
+static bool ctrlRunSetupHandle(bool fEnabled, RTHANDLESTD enmHandle, const char *pszName,
+                               kStreamTransform enmTransformation, PRTVFSIOSTREAM phVfsIos)
+{
+    if (fEnabled)
+    {
+        int vrc = RTVfsIoStrmFromStdHandle(enmHandle, 0, true /*fLeaveOpen*/, phVfsIos);
+        if (RT_SUCCESS(vrc))
+        {
+            if (enmTransformation != kStreamTransform_None)
+            {
+                RTMsgWarning("Unsupported %s line ending conversion", pszName);
+                /** @todo Implement dos2unix and unix2dos stream filters. */
+            }
+            return true;
+        }
+        RTMsgWarning("Error getting %s handle: %Rrc", pszName, vrc);
+    }
+    return false;
+}
+
+
+/**
+ * Returns the remaining time (in ms) based on the start time and a set
+ * timeout value. Returns RT_INDEFINITE_WAIT if no timeout was specified.
+ *
+ * @return  RTMSINTERVAL    Time left (in ms).
+ * @param   u64StartMs      Start time (in ms).
+ * @param   cMsTimeout      Timeout value (in ms).
+ */
+static RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout)
+{
+    if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */
+        return RT_INDEFINITE_WAIT;
+
+    uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
+    if (u64ElapsedMs >= cMsTimeout)
+        return 0;
+
+    return cMsTimeout - (RTMSINTERVAL)u64ElapsedMs;
+}
+
+/**
+ * Common handler for the 'run' and 'start' commands.
+ *
+ * @returns Command exit code.
+ * @param   pCtx        Guest session context.
+ * @param   fRunCmd     Set if it's 'run' clear if 'start'.
+ * @param   fHelp       The help flag for the command.
+ */
+static RTEXITCODE handleCtrlProcessRunCommon(PGCTLCMDCTX pCtx, bool fRunCmd, uint32_t fHelp)
+{
+    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+    /*
+     * Parse arguments.
+     */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--environment",                  'E',                                      RTGETOPT_REQ_STRING  },
+        { "--executable",                   'e',                                      RTGETOPT_REQ_STRING  },
+        { "--timeout",                      't',                                      RTGETOPT_REQ_UINT32  },
+        { "--unquoted-args",                'u',                                      RTGETOPT_REQ_NOTHING },
+        { "--ignore-operhaned-processes",   kGstCtrlRunOpt_IgnoreOrphanedProcesses,   RTGETOPT_REQ_NOTHING },
+        { "--no-profile",                   kGstCtrlRunOpt_NoProfile,                 RTGETOPT_REQ_NOTHING },
+        { "--dos2unix",                     kGstCtrlRunOpt_Dos2Unix,                  RTGETOPT_REQ_NOTHING },
+        { "--unix2dos",                     kGstCtrlRunOpt_Unix2Dos,                  RTGETOPT_REQ_NOTHING },
+        { "--no-wait-stdout",               kGstCtrlRunOpt_NoWaitForStdOut,           RTGETOPT_REQ_NOTHING },
+        { "--wait-stdout",                  kGstCtrlRunOpt_WaitForStdOut,             RTGETOPT_REQ_NOTHING },
+        { "--no-wait-stderr",               kGstCtrlRunOpt_NoWaitForStdErr,           RTGETOPT_REQ_NOTHING },
+        { "--wait-stderr",                  kGstCtrlRunOpt_WaitForStdErr,             RTGETOPT_REQ_NOTHING },
+    };
+
+    int                     ch;
+    RTGETOPTUNION           ValueUnion;
+    RTGETOPTSTATE           GetState;
+    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+    com::SafeArray<ProcessCreateFlag_T>     aCreateFlags;
+    com::SafeArray<ProcessWaitForFlag_T>    aWaitFlags;
+    com::SafeArray<IN_BSTR>                 aArgs;
+    com::SafeArray<IN_BSTR>                 aEnv;
+    const char *                            pszImage            = NULL;
+    bool                                    fDetached           = false;
+    bool                                    fWaitForStdOut      = true;
+    bool                                    fWaitForStdErr      = true;
+    RTVFSIOSTREAM                           hVfsStdOut          = NIL_RTVFSIOSTREAM;
+    RTVFSIOSTREAM                           hVfsStdErr          = NIL_RTVFSIOSTREAM;
+    enum kStreamTransform                   enmStdOutTransform  = kStreamTransform_None;
+    enum kStreamTransform                   enmStdErrTransform  = kStreamTransform_None;
+    RTMSINTERVAL                            cMsTimeout          = 0;
+
+    try
+    {
+        /* Wait for process start in any case. This is useful for scripting VBoxManage
+         * when relying on its overall exit code. */
+        aWaitFlags.push_back(ProcessWaitForFlag_Start);
+
+        while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
+        {
+            /* For options that require an argument, ValueUnion has received the value. */
+            switch (ch)
+            {
+                case 'E':
+                    if (   ValueUnion.psz[0] == '\0'
+                        || ValueUnion.psz[0] == '='
+                        || strchr(ValueUnion.psz, '=') == NULL)
+                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
+                                             "Invalid argument variable=value pair: '%s'", ValueUnion.psz);
+                    aEnv.push_back(Bstr(ValueUnion.psz).raw());
+                    break;
+
+                case kGstCtrlRunOpt_IgnoreOrphanedProcesses:
+                    aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses);
+                    break;
+
+                case kGstCtrlRunOpt_NoProfile:
+                    aCreateFlags.push_back(ProcessCreateFlag_NoProfile);
+                    break;
+
+                case 'i':
+                    pszImage = ValueUnion.psz;
+                    break;
+
+                case 'u':
+                    aCreateFlags.push_back(ProcessCreateFlag_UnquotedArguments);
+                    break;
+
+                /** @todo Add a hidden flag. */
+
+                case 't': /* Timeout */
+                    cMsTimeout = ValueUnion.u32;
+                    break;
+
+                case kGstCtrlRunOpt_Dos2Unix:
+                    enmStdErrTransform = enmStdOutTransform = kStreamTransform_Dos2Unix;
+                    break;
+                case kGstCtrlRunOpt_Unix2Dos:
+                    enmStdErrTransform = enmStdOutTransform = kStreamTransform_Unix2Dos;
+                    break;
+
+                case kGstCtrlRunOpt_WaitForStdOut:
+                    if (!fRunCmd)
+                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stdout");
+                    fWaitForStdOut = true;
+                    break;
+                case kGstCtrlRunOpt_NoWaitForStdOut:
+                    if (!fRunCmd)
+                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --no-wait-for-stdout");
+                    fWaitForStdOut = false;
+                    break;
+
+                case kGstCtrlRunOpt_WaitForStdErr:
+                    if (!fRunCmd)
+                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stderr");
+                    fWaitForStdErr = true;
+                    break;
+                case kGstCtrlRunOpt_NoWaitForStdErr:
+                    if (!fRunCmd)
+                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stderr");
+                    fWaitForStdErr = false;
+                    break;
+
+                case VINF_GETOPT_NOT_OPTION:
+                    aArgs.push_back(Bstr(ValueUnion.psz).raw());
+                    if (!pszImage)
+                    {
+                        Assert(aArgs.size() == 1);
+                        pszImage = ValueUnion.psz;
+                    }
+                    break;
+
+                default:
+                    return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, ch, &ValueUnion);
+
+            } /* switch */
+        } /* while RTGetOpt */
+
+        /* Must have something to execute. */
+        if (!pszImage || *pszImage)
+            return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, "No executable specified!");
+
+        /*
+         * Finalize process creation and wait flags and input/output streams.
+         */
+        if (!fRunCmd)
+        {
+            aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly);
+            Assert(!fWaitForStdOut);
+            Assert(!fWaitForStdErr);
+        }
+        else
+        {
+            aWaitFlags.push_back(ProcessWaitForFlag_Terminate);
+            fWaitForStdOut = ctrlRunSetupHandle(fWaitForStdOut, RTHANDLESTD_OUTPUT, "stdout", enmStdOutTransform, &hVfsStdOut);
+            if (fWaitForStdOut)
+            {
+                aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
+                aWaitFlags.push_back(ProcessWaitForFlag_StdOut);
+            }
+            fWaitForStdErr = ctrlRunSetupHandle(fWaitForStdErr, RTHANDLESTD_ERROR, "stderr", enmStdErrTransform, &hVfsStdErr);
+            if (fWaitForStdErr)
+            {
+                aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
+                aWaitFlags.push_back(ProcessWaitForFlag_StdErr);
+            }
+        }
+    }
+    catch (std::bad_alloc &)
+    {
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "VERR_NO_MEMORY\n");
+    }
+
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    HRESULT rc;
+
+    try
+    {
+        do
+        {
+            /* Get current time stamp to later calculate rest of timeout left. */
+            uint64_t msStart = RTTimeMilliTS();
+
+            /*
+             * Create the process.
+             */
+            if (pCtx->fVerbose)
+            {
+                if (cMsTimeout == 0)
+                    RTPrintf("Starting guest process ...\n");
+                else
+                    RTPrintf("Starting guest process (within %ums)\n", cMsTimeout);
+            }
+            ComPtr<IGuestProcess> pProcess;
+            CHECK_ERROR_BREAK(pCtx->pGuestSession, ProcessCreate(Bstr(pszImage).raw(),
+                                                                 ComSafeArrayAsInParam(aArgs),
+                                                                 ComSafeArrayAsInParam(aEnv),
+                                                                 ComSafeArrayAsInParam(aCreateFlags),
+                                                                 ctrlExecGetRemainingTime(msStart, cMsTimeout),
+                                                                 pProcess.asOutParam()));
+
+            /*
+             * Explicitly wait for the guest process to be in a started state.
+             */
+            com::SafeArray<ProcessWaitForFlag_T> aWaitStartFlags;
+            aWaitStartFlags.push_back(ProcessWaitForFlag_Start);
+            ProcessWaitResult_T waitResult;
+            CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags),
+                                                     ctrlExecGetRemainingTime(msStart, cMsTimeout), &waitResult));
+
+            ULONG uPID = 0;
+            CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
+            if (fRunCmd && pCtx->fVerbose)
+                RTPrintf("Process '%s' (PID %RU32) started\n", pszImage, uPID);
+            else if (!fRunCmd) /** @todo Introduce a --quiet option for not printing this. */
+            {
+                /* Just print plain PID to make it easier for scripts
+                 * invoking VBoxManage. */
+                RTPrintf("[%RU32 - Session %RU32]\n", uPID, pCtx->uSessionID);
+            }
+
+            /*
+             * Wait for process to exit/start...
+             */
+            RTMSINTERVAL    cMsTimeLeft = 1; /* Will be calculated. */
+            bool            fReadStdOut = false;
+            bool            fReadStdErr = false;
+            bool            fCompleted  = false;
+            bool            fCompletedStartCmd = false;
+            int             vrc         = VINF_SUCCESS;
+
+            while (   !fCompleted
+                   && cMsTimeLeft > 0)
+            {
+                cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
+                CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags),
+                                                         RT_MIN(500 /*ms*/, RT_MAX(cMsTimeLeft, 1 /*ms*/)),
+                                                         &waitResult));
+                switch (waitResult)
+                {
+                    case ProcessWaitResult_Start:
+                        fCompletedStartCmd = fCompleted = !fRunCmd; /* Only wait for startup if the 'start' command. */
+                        break;
+                    case ProcessWaitResult_StdOut:
+                        fReadStdOut = true;
+                        break;
+                    case ProcessWaitResult_StdErr:
+                        fReadStdErr = true;
+                        break;
+                    case ProcessWaitResult_Terminate:
+                        if (pCtx->fVerbose)
+                            RTPrintf("Process terminated\n");
+                        /* Process terminated, we're done. */
+                        fCompleted = true;
+                        break;
+                    case ProcessWaitResult_WaitFlagNotSupported:
+                        /* The guest does not support waiting for stdout/err, so
+                         * yield to reduce the CPU load due to busy waiting. */
+                        RTThreadYield();
+                        fReadStdOut = fReadStdErr = true;
+                        break;
+                    case ProcessWaitResult_Timeout:
+                    {
+                        /** @todo It is really unclear whether we will get stuck with the timeout
+                         *        result here if the guest side times out the process and fails to
+                         *        kill the process...  To be on the save side, double the IPC and
+                         *        check the process status every time we time out.  */
+                        ProcessStatus_T enmProcStatus;
+                        CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&enmProcStatus));
+                        if (   enmProcStatus == ProcessStatus_TimedOutKilled
+                            || enmProcStatus == ProcessStatus_TimedOutAbnormally)
+                            fCompleted = true;
+                        fReadStdOut = fReadStdErr = true;
+                        break;
+                    }
+                    case ProcessWaitResult_Status:
+                        /* ignore. */
+                        break;
+                    case ProcessWaitResult_Error:
+                        /* waitFor is dead in the water, I think, so better leave the loop. */
+                        vrc = VERR_CALLBACK_RETURN;
+                        break;
+
+                    case ProcessWaitResult_StdIn:   AssertFailed(); /* did ask for this! */ break;
+                    case ProcessWaitResult_None:    AssertFailed(); /* used. */ break;
+                    default:                        AssertFailed(); /* huh? */ break;
+                }
+
+                if (g_fGuestCtrlCanceled)
+                    break;
+
+                /*
+                 * Pump output as needed.
+                 */
+                if (fReadStdOut)
+                {
+                    cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
+                    int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdOut, 1 /* StdOut */, cMsTimeLeft);
+                    if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc))
+                        vrc = vrc2;
+                    fReadStdOut = false;
+                }
+                if (fReadStdErr)
+                {
+                    cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
+                    int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdErr, 2 /* StdErr */, cMsTimeLeft);
+                    if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc))
+                        vrc = vrc2;
+                    fReadStdErr = false;
+                }
+                if (   RT_FAILURE(vrc)
+                    || g_fGuestCtrlCanceled)
+                    break;
+
+                /*
+                 * Process events before looping.
+                 */
+                NativeEventQueue::getMainEventQueue()->processEventQueue(0);
+            } /* while */
+
+            /*
+             * Report status back to the user.
+             */
+            if (g_fGuestCtrlCanceled)
+            {
+                if (pCtx->fVerbose)
+                    RTPrintf("Process execution aborted!\n");
+                rcExit = EXITCODEEXEC_CANCELED;
+            }
+            else if (fCompletedStartCmd)
+            {
+                if (pCtx->fVerbose)
+                    RTPrintf("Process successfully started!\n");
+                rcExit = RTEXITCODE_SUCCESS;
+            }
+            else if (fCompleted)
+            {
+                ProcessStatus_T procStatus;
+                CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&procStatus));
+                if (   procStatus == ProcessStatus_TerminatedNormally
+                    || procStatus == ProcessStatus_TerminatedAbnormally
+                    || procStatus == ProcessStatus_TerminatedSignal)
+                {
+                    LONG lExitCode;
+                    CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&lExitCode));
+                    if (pCtx->fVerbose)
+                        RTPrintf("Exit code=%u (Status=%u [%s])\n",
+                                 lExitCode, procStatus, ctrlProcessStatusToText(procStatus));
+
+                    rcExit = ctrlRunCalculateExitCode(procStatus, lExitCode, true /*fReturnExitCodes*/);
+                }
+                else if (   procStatus == ProcessStatus_TimedOutKilled
+                         || procStatus == ProcessStatus_TimedOutAbnormally)
+                {
+                    if (pCtx->fVerbose)
+                        RTPrintf("Process timed out (guest side) and\n",
+                                 procStatus == ProcessStatus_TimedOutAbnormally
+                                 ? " failed to terminate so far" : " was terminated");
+                    rcExit = EXITCODEEXEC_TIMEOUT;
+                }
+                else
+                {
+                    if (pCtx->fVerbose)
+                        RTPrintf("Process now is in status [%s] (unexpected)\n", ctrlProcessStatusToText(procStatus));
+                    rcExit = RTEXITCODE_FAILURE;
+                }
+            }
+            else if (RT_FAILURE_NP(vrc))
+            {
+                if (pCtx->fVerbose)
+                    RTPrintf("Process monitor loop quit with vrc=%Rrc\n", vrc);
+                rcExit = RTEXITCODE_FAILURE;
+            }
+            else
+            {
+                if (pCtx->fVerbose)
+                    RTPrintf("Process monitor loop timed out\n");
+                rcExit = EXITCODEEXEC_TIMEOUT;
+            }
+
+        } while (0);
+    }
+    catch (std::bad_alloc)
+    {
+        rc = E_OUTOFMEMORY;
+    }
+
+    /*
+     * Decide what to do with the guest session.
+     *
+     * If it's the 'start' command where detach the guest process after
+     * starting, don't close the guest session it is part of, except on
+     * failure or ctrl-c.
+     *
+     * For the 'run' command the guest process quits with us.
+     */
+    if (!fRunCmd && SUCCEEDED(rc) && !g_fGuestCtrlCanceled)
+        pCtx->uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH;
+
+    /* Make sure we return failure on failure. */
+    if (FAILED(rc) && rcExit == RTEXITCODE_SUCCESS)
+        rcExit = RTEXITCODE_FAILURE;
+    return rcExit;
+}
+
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlProcessRun(PGCTLCMDCTX pCtx)
+{
+    return handleCtrlProcessRunCommon(pCtx, true /*fRunCmd*/, USAGE_GSTCTRL_RUN);
+}
+
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlProcessStart(PGCTLCMDCTX pCtx)
+{
+    return handleCtrlProcessRunCommon(pCtx, false /*fRunCmd*/, USAGE_GSTCTRL_START);
+}
+
+#if 1 /* Old exec code. */
+
+static int ctrlExecProcessStatusToExitCodeDeprecated(ProcessStatus_T enmStatus, ULONG uExitCode)
+{
+    int vrc = RTEXITCODE_SUCCESS;
+    switch (enmStatus)
+    {
+        case ProcessStatus_Starting:
+            vrc = RTEXITCODE_SUCCESS;
             break;
         case ProcessStatus_Started:
-            vrc = EXITCODEEXEC_SUCCESS;
+            vrc = RTEXITCODE_SUCCESS;
             break;
         case ProcessStatus_Paused:
-            vrc = EXITCODEEXEC_SUCCESS;
+            vrc = RTEXITCODE_SUCCESS;
             break;
         case ProcessStatus_Terminating:
-            vrc = EXITCODEEXEC_SUCCESS;
+            vrc = RTEXITCODE_SUCCESS;
             break;
         case ProcessStatus_TerminatedNormally:
-            vrc = !uExitCode ? EXITCODEEXEC_SUCCESS : EXITCODEEXEC_CODE;
+            vrc = !uExitCode ? RTEXITCODE_SUCCESS : EXITCODEEXEC_CODE;
             break;
         case ProcessStatus_TerminatedSignal:
@@ -584,461 +1680,4 @@
 }
 
-const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)
-{
-    switch (enmWaitResult)
-    {
-        case ProcessWaitResult_Start:
-            return "started";
-        case ProcessWaitResult_Terminate:
-            return "terminated";
-        case ProcessWaitResult_Status:
-            return "status changed";
-        case ProcessWaitResult_Error:
-            return "error";
-        case ProcessWaitResult_Timeout:
-            return "timed out";
-        case ProcessWaitResult_StdIn:
-            return "stdin ready";
-        case ProcessWaitResult_StdOut:
-            return "data on stdout";
-        case ProcessWaitResult_StdErr:
-            return "data on stderr";
-        case ProcessWaitResult_WaitFlagNotSupported:
-            return "waiting flag not supported";
-        default:
-            break;
-    }
-    return "unknown";
-}
-
-/**
- * Translates a guest session status to a human readable
- * string.
- */
-const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)
-{
-    switch (enmStatus)
-    {
-        case GuestSessionStatus_Starting:
-            return "starting";
-        case GuestSessionStatus_Started:
-            return "started";
-        case GuestSessionStatus_Terminating:
-            return "terminating";
-        case GuestSessionStatus_Terminated:
-            return "terminated";
-        case GuestSessionStatus_TimedOutKilled:
-            return "timed out";
-        case GuestSessionStatus_TimedOutAbnormally:
-            return "timed out, hanging";
-        case GuestSessionStatus_Down:
-            return "killed";
-        case GuestSessionStatus_Error:
-            return "error";
-        default:
-            break;
-    }
-    return "unknown";
-}
-
-/**
- * Translates a guest file status to a human readable
- * string.
- */
-const char *ctrlFileStatusToText(FileStatus_T enmStatus)
-{
-    switch (enmStatus)
-    {
-        case FileStatus_Opening:
-            return "opening";
-        case FileStatus_Open:
-            return "open";
-        case FileStatus_Closing:
-            return "closing";
-        case FileStatus_Closed:
-            return "closed";
-        case FileStatus_Down:
-            return "killed";
-        case FileStatus_Error:
-            return "error";
-        default:
-            break;
-    }
-    return "unknown";
-}
-
-static int ctrlPrintError(com::ErrorInfo &errorInfo)
-{
-    if (   errorInfo.isFullAvailable()
-        || errorInfo.isBasicAvailable())
-    {
-        /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
-         * because it contains more accurate info about what went wrong. */
-        if (errorInfo.getResultCode() == VBOX_E_IPRT_ERROR)
-            RTMsgError("%ls.", errorInfo.getText().raw());
-        else
-        {
-            RTMsgError("Error details:");
-            GluePrintErrorInfo(errorInfo);
-        }
-        return VERR_GENERAL_FAILURE; /** @todo */
-    }
-    AssertMsgFailedReturn(("Object has indicated no error (%Rhrc)!?\n", errorInfo.getResultCode()),
-                          VERR_INVALID_PARAMETER);
-}
-
-static int ctrlPrintError(IUnknown *pObj, const GUID &aIID)
-{
-    com::ErrorInfo ErrInfo(pObj, aIID);
-    return ctrlPrintError(ErrInfo);
-}
-
-static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)
-{
-    int vrc = VINF_SUCCESS;
-    HRESULT rc;
-
-    do
-    {
-        BOOL fCanceled;
-        CHECK_ERROR_BREAK(pProgress, COMGETTER(Canceled)(&fCanceled));
-        if (!fCanceled)
-        {
-            LONG rcProc;
-            CHECK_ERROR_BREAK(pProgress, COMGETTER(ResultCode)(&rcProc));
-            if (FAILED(rcProc))
-            {
-                com::ProgressErrorInfo ErrInfo(pProgress);
-                vrc = ctrlPrintError(ErrInfo);
-            }
-        }
-
-    } while(0);
-
-    AssertMsgStmt(SUCCEEDED(rc), ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED);
-
-    return vrc;
-}
-
-/**
- * Un-initializes the VM after guest control usage.
- * @param   pCmdCtx                 Pointer to command context.
- * @param   uFlags                  Command context flags.
- */
-static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags)
-{
-    AssertPtrReturnVoid(pCtx);
-
-    if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
-        ctrlSignalHandlerUninstall();
-
-    HRESULT rc;
-
-    do
-    {
-        if (!pCtx->pGuestSession.isNull())
-        {
-            if (   !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)
-                && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH))
-            {
-                if (pCtx->fVerbose)
-                    RTPrintf("Closing guest session ...\n");
-
-                CHECK_ERROR(pCtx->pGuestSession, Close());
-                /* Keep going - don't break here. Try to unlock the
-                 * machine down below. */
-            }
-            else if (   (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)
-                     && pCtx->fVerbose)
-                RTPrintf("Guest session detached\n");
-
-            pCtx->pGuestSession.setNull();
-        }
-
-        if (pCtx->handlerArg.session)
-            CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine());
-
-    } while (0);
-
-    for (int i = 0; i < pCtx->iArgc; i++)
-        RTStrFree(pCtx->ppaArgv[i]);
-    RTMemFree(pCtx->ppaArgv);
-    pCtx->iArgc = 0;
-}
-
-/**
- * Initializes the VM for IGuest operations.
- *
- * That is, checks whether it's up and running, if it can be locked (shared
- * only) and returns a valid IGuest pointer on success. Also, it does some
- * basic command line processing and opens a guest session, if required.
- *
- * @return  RTEXITCODE status code.
- * @param   pArg                    Pointer to command line argument structure.
- * @param   pCmdCtx                 Pointer to command context.
- * @param   uFlags                  Command context flags.
- */
-static RTEXITCODE ctrlInitVM(HandlerArg *pArg,
-                             PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage)
-{
-    AssertPtrReturn(pArg, RTEXITCODE_FAILURE);
-    AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE);
-    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
-
-#ifdef DEBUG_andy
-    RTPrintf("Original argv:\n");
-    for (int i=0; i<pArg->argc;i++)
-        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
-#endif
-
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-
-    const char *pszNameOrId = pArg->argv[0];
-    const char *pszCmd = pArg->argv[1];
-
-    /* Lookup VM. */
-    ComPtr<IMachine> machine;
-    /* Assume it's an UUID. */
-    HRESULT rc;
-    CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(),
-                                              machine.asOutParam()));
-    if (SUCCEEDED(rc))
-    {
-        /* Machine is running? */
-        MachineState_T machineState;
-        CHECK_ERROR(machine, COMGETTER(State)(&machineState));
-        if (   SUCCEEDED(rc)
-            && (machineState != MachineState_Running))
-            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n",
-                                    pszNameOrId, machineStateToName(machineState, false));
-    }
-    else
-        rcExit = RTEXITCODE_FAILURE;
-
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        /*
-         * Process standard options which are served by all commands.
-         */
-        static const RTGETOPTDEF s_aOptions[] =
-        {
-            { "--username",            'u',                             RTGETOPT_REQ_STRING  },
-            { "--passwordfile",        'p',                             RTGETOPT_REQ_STRING  },
-            { "--password",            GETOPTDEF_COMMON_PASSWORD,       RTGETOPT_REQ_STRING  },
-            { "--domain",              'd',                             RTGETOPT_REQ_STRING  },
-            { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
-        };
-
-        /*
-         * Allocate per-command argv. This then only contains the specific arguments
-         * the command needs.
-         */
-        pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1);
-        if (!pCtx->ppaArgv)
-        {
-            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n");
-        }
-        else
-        {
-            pCtx->iArgc = 0;
-
-            int iArgIdx = 2; /* Skip VM name and guest control command */
-            int ch;
-            RTGETOPTUNION ValueUnion;
-            RTGETOPTSTATE GetState;
-            RTGetOptInit(&GetState, pArg->argc, pArg->argv,
-                         s_aOptions, RT_ELEMENTS(s_aOptions),
-                         iArgIdx, 0);
-
-            while (   (ch = RTGetOpt(&GetState, &ValueUnion))
-                   && (rcExit == RTEXITCODE_SUCCESS))
-            {
-                /* For options that require an argument, ValueUnion has received the value. */
-                switch (ch)
-                {
-                    case 'u': /* User name */
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                            pCtx->strUsername = ValueUnion.psz;
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case GETOPTDEF_COMMON_PASSWORD: /* Password */
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                        {
-                            if (pCtx->strPassword.isEmpty())
-                                pCtx->strPassword = ValueUnion.psz;
-                        }
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case 'p': /* Password file */
-                    {
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                            rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword);
-                        iArgIdx = GetState.iNext;
-                        break;
-                    }
-
-                    case 'd': /* domain */
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                            pCtx->strDomain = ValueUnion.psz;
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case 'v': /* Verbose */
-                        pCtx->fVerbose = true;
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case 'h': /* Help */
-                        errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);
-                        return RTEXITCODE_SYNTAX;
-
-                    default:
-                        /* Simply skip; might be handled in a specific command
-                         * handler later. */
-                        break;
-
-                } /* switch */
-
-                int iArgDiff = GetState.iNext - iArgIdx;
-                if (iArgDiff)
-                {
-#ifdef DEBUG_andy
-                    RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx);
-#endif
-                    for (int i = iArgIdx; i < GetState.iNext; i++)
-                    {
-                        char *pszArg = RTStrDup(pArg->argv[i]);
-                        if (!pszArg)
-                        {
-                            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                                    "Not enough memory for command line handling\n");
-                            break;
-                        }
-                        pCtx->ppaArgv[pCtx->iArgc] = pszArg;
-                        pCtx->iArgc++;
-#ifdef DEBUG_andy
-                        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
-#endif
-                    }
-
-                    iArgIdx = GetState.iNext;
-                }
-
-            } /* while RTGetOpt */
-        }
-    }
-
-    /*
-     * Check for mandatory stuff.
-     */
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-#if 0
-        RTPrintf("argc=%d\n", pCtx->iArgc);
-        for (int i = 0; i < pCtx->iArgc; i++)
-            RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]);
-#endif
-        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-        {
-            if (pCtx->strUsername.isEmpty())
-                rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!");
-        }
-    }
-
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        /*
-         * Build up a reasonable guest session name. Useful for identifying
-         * a specific session when listing / searching for them.
-         */
-        char *pszSessionName;
-        if (0 >= RTStrAPrintf(&pszSessionName,
-                              "[%RU32] VBoxManage Guest Control [%s] - %s",
-                              RTProcSelf(), pszNameOrId, pszCmd))
-            return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n");
-
-        do
-        {
-            /* Open a session for the VM. */
-            CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));
-            /* Get the associated console. */
-            ComPtr<IConsole> console;
-            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));
-            /* ... and session machine. */
-            ComPtr<IMachine> sessionMachine;
-            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
-            /* Get IGuest interface. */
-            CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));
-            if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-            {
-                if (pCtx->fVerbose)
-                    RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str());
-
-                /* Open a guest session. */
-                Assert(!pCtx->pGuest.isNull());
-                CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),
-                                                              Bstr(pCtx->strPassword).raw(),
-                                                              Bstr(pCtx->strDomain).raw(),
-                                                              Bstr(pszSessionName).raw(),
-                                                              pCtx->pGuestSession.asOutParam()));
-
-                /*
-                 * Wait for guest session to start.
-                 */
-                if (pCtx->fVerbose)
-                    RTPrintf("Waiting for guest session to start ...\n");
-
-                com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
-                aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
-                GuestSessionWaitResult_T sessionWaitResult;
-                CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),
-                                                                    /** @todo Make session handling timeouts configurable. */
-                                                                    30 * 1000, &sessionWaitResult));
-
-                if (   sessionWaitResult == GuestSessionWaitResult_Start
-                    /* Note: This might happen when Guest Additions < 4.3 are installed which don't
-                     *       support dedicated guest sessions. */
-                    || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
-                {
-                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));
-                    if (pCtx->fVerbose)
-                        RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID);
-                }
-                else
-                {
-                    GuestSessionStatus_T sessionStatus;
-                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus));
-                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n",
-                                            ctrlSessionStatusToText(sessionStatus));
-                    break;
-                }
-            }
-
-            if (   SUCCEEDED(rc)
-                && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
-            {
-                ctrlSignalHandlerInstall();
-            }
-
-        } while (0);
-
-        if (FAILED(rc))
-            rcExit = RTEXITCODE_FAILURE;
-
-        RTStrFree(pszSessionName);
-    }
-
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        pCtx->handlerArg = *pArg;
-        pCtx->uFlags = uFlags;
-    }
-    else /* Clean up on failure. */
-        ctrlUninitVM(pCtx, uFlags);
-
-    return rcExit;
-}
 
 /**
@@ -1049,8 +1688,10 @@
  * @param   pStrmOutput     Where to write the data.
  * @param   uHandle         Handle where to read the data from.
- * @param   uTimeoutMS      Timeout (in ms) to wait for the operation to complete.
+ * @param   cMsTimeout      Timeout (in ms) to wait for the operation to
+ *                          complete.
+ * @remarks Obsolete.
  */
-static int ctrlExecPrintOutput(IProcess *pProcess, PRTSTREAM pStrmOutput,
-                               ULONG uHandle, ULONG uTimeoutMS)
+static int ctrlExecPrintOutputDeprecated(IProcess *pProcess, PRTSTREAM pStrmOutput,
+                                         ULONG uHandle, RTMSINTERVAL cMsTimeout)
 {
     AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
@@ -1060,9 +1701,7 @@
 
     SafeArray<BYTE> aOutputData;
-    HRESULT rc = pProcess->Read(uHandle, _64K, uTimeoutMS,
+    HRESULT rc = pProcess->Read(uHandle, _64K, cMsTimeout,
                                 ComSafeArrayAsOutParam(aOutputData));
-    if (FAILED(rc))
-        vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
-    else
+    if (SUCCEEDED(rc))
     {
         size_t cbOutputData = aOutputData.size();
@@ -1072,6 +1711,4 @@
             AssertPtr(pBuf);
             pBuf[cbOutputData - 1] = 0; /* Properly terminate buffer. */
-
-            /** @todo implement the dos2unix/unix2dos conversions */
 
             /*
@@ -1088,5 +1725,5 @@
                 cbOutputData = strlen(pszBufUTF8);
 
-                ULONG cbOutputDataPrint = cbOutputData;
+                ULONG cbOutputDataPrint = (ULONG)cbOutputData;
                 for (char *s = pszBufUTF8, *d = s;
                      s - pszBufUTF8 < (ssize_t)cbOutputData;
@@ -1113,29 +1750,11 @@
         }
     }
-
+    else
+        vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
     return vrc;
 }
 
-/**
- * Returns the remaining time (in ms) based on the start time and a set
- * timeout value. Returns RT_INDEFINITE_WAIT if no timeout was specified.
- *
- * @return  RTMSINTERVAL    Time left (in ms).
- * @param   u64StartMs      Start time (in ms).
- * @param   cMsTimeout      Timeout value (in ms).
- */
-inline RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout)
-{
-    if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */
-        return RT_INDEFINITE_WAIT;
-
-    uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
-    if (u64ElapsedMs >= cMsTimeout)
-        return 0;
-
-    return cMsTimeout - (RTMSINTERVAL)u64ElapsedMs;
-}
-
-static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExec(PGCTLCMDCTX pCtx)
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExecDeprecated(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -1175,8 +1794,8 @@
     com::SafeArray<ProcessCreateFlag_T>  aCreateFlags;
     com::SafeArray<ProcessWaitForFlag_T> aWaitFlags;
-    com::SafeArray<IN_BSTR>              aArgs;
+    com::SafeArray<IN_BSTR>              aArgsWithout0;
+    com::SafeArray<IN_BSTR>              aArgsWith0;
     com::SafeArray<IN_BSTR>              aEnv;
     RTMSINTERVAL                         cMsTimeout      = 0;
-    OUTPUTTYPE                           eOutputType     = OUTPUTTYPE_UNDEFINED;
     bool                                 fDetached       = true;
     int                                  vrc             = VINF_SUCCESS;
@@ -1194,11 +1813,4 @@
             switch (ch)
             {
-                case GETOPTDEF_EXEC_DOS2UNIX:
-                    if (eOutputType != OUTPUTTYPE_UNDEFINED)
-                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
-                                             "More than one output type (dos2unix/unix2dos) specified!");
-                    eOutputType = OUTPUTTYPE_DOS2UNIX;
-                    break;
-
                 case 'e': /* Environment */
                 {
@@ -1208,5 +1820,5 @@
                     vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL);
                     if (RT_FAILURE(vrc))
-                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
+                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
                                              "Failed to parse environment value, rc=%Rrc", vrc);
                     for (int j = 0; j < cArgs; j++)
@@ -1240,9 +1852,7 @@
 
                 case GETOPTDEF_EXEC_UNIX2DOS:
-                    if (eOutputType != OUTPUTTYPE_UNDEFINED)
-                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
-                                             "More than one output type (dos2unix/unix2dos) specified!");
-                    eOutputType = OUTPUTTYPE_UNIX2DOS;
-                    break;
+                case GETOPTDEF_EXEC_DOS2UNIX:
+                    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
+                                         "Output conversion not implemented yet!");
 
                 case GETOPTDEF_EXEC_WAITFOREXIT:
@@ -1264,8 +1874,8 @@
 
                 case VINF_GETOPT_NOT_OPTION:
-                    if (aArgs.size() == 0 && strCmd.isEmpty())
+                    if (aArgsWithout0.size() == 0 && strCmd.isEmpty())
                         strCmd = ValueUnion.psz;
                     else
-                        aArgs.push_back(Bstr(ValueUnion.psz).raw());
+                        aArgsWithout0.push_back(Bstr(ValueUnion.psz).raw());
                     break;
 
@@ -1274,11 +1884,16 @@
                      *       contain a single dash, e.g. "-- foo.exe -s". */
                     if (GetState.argc == GetState.iNext)
-                        aArgs.push_back(Bstr(ValueUnion.psz).raw());
+                        aArgsWithout0.push_back(Bstr(ValueUnion.psz).raw());
                     else
-                        return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC, ch, &ValueUnion);
+                        return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, ch, &ValueUnion);
                     break;
 
             } /* switch */
         } /* while RTGetOpt */
+
+        /* Create aArgsWith0 from strCmd and aArgsWithout0. */
+        aArgsWith0.push_back(Bstr(strCmd).raw());
+        for (size_t i = 0; i < aArgsWithout0.size(); i++)
+            aArgsWith0.push_back(aArgsWithout0[i]);
     }
     catch (std::bad_alloc &)
@@ -1291,11 +1906,6 @@
 
     if (strCmd.isEmpty())
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
                              "No command to execute specified!");
-
-    /** @todo Any output conversion not supported yet! */
-    if (eOutputType != OUTPUTTYPE_UNDEFINED)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
-                             "Output conversion not implemented yet!");
 
     RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
@@ -1326,5 +1936,5 @@
             ComPtr<IGuestProcess> pProcess;
             CHECK_ERROR_BREAK(pCtx->pGuestSession, ProcessCreate(Bstr(strCmd).raw(),
-                                                                 ComSafeArrayAsInParam(aArgs),
+                                                                 ComSafeArrayAsInParam(aArgsWith0),
                                                                  ComSafeArrayAsInParam(aEnv),
                                                                  ComSafeArrayAsInParam(aCreateFlags),
@@ -1421,6 +2031,6 @@
                 {
                     cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
-                    vrc = ctrlExecPrintOutput(pProcess, g_pStdOut,
-                                              1 /* StdOut */, cMsTimeLeft);
+                    vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdOut,
+                                                        1 /* StdOut */, cMsTimeLeft);
                     fReadStdOut = false;
                 }
@@ -1429,6 +2039,6 @@
                 {
                     cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
-                    vrc = ctrlExecPrintOutput(pProcess, g_pStdErr,
-                                              2 /* StdErr */, cMsTimeLeft);
+                    vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdErr,
+                                                        2 /* StdErr */, cMsTimeLeft);
                     fReadStdErr = false;
                 }
@@ -1467,5 +2077,5 @@
                                          exitCode, procStatus, ctrlProcessStatusToText(procStatus));
 
-                            rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(procStatus, exitCode);
+                            rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCodeDeprecated(procStatus, exitCode);
                         }
                         else if (pCtx->fVerbose)
@@ -1526,4 +2136,6 @@
     return rcExit;
 }
+
+#endif /* Old exec code. */
 
 /**
@@ -2718,5 +3330,5 @@
     }
 
-    uint32_t cDirs = mapDirs.size();
+    size_t cDirs = mapDirs.size();
     if (!cDirs)
         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATEDIR,
@@ -2781,5 +3393,5 @@
     }
 
-    uint32_t cDirs = mapDirs.size();
+    size_t cDirs = mapDirs.size();
     if (!cDirs)
         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEDIR,
@@ -2864,5 +3476,5 @@
     }
 
-    uint32_t cFiles = mapDirs.size();
+    size_t cFiles = mapDirs.size();
     if (!cFiles)
         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE,
@@ -2942,5 +3554,5 @@
         return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize, rc=%Rrc\n", vrc);
 
-    uint32_t cSources = vecSources.size();
+    size_t cSources = vecSources.size();
     if (!cSources)
         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME,
@@ -3179,5 +3791,5 @@
     }
 
-    uint32_t cObjs = mapObjs.size();
+    size_t cObjs = mapObjs.size();
     if (!cObjs)
         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_STAT,
@@ -3948,6 +4560,16 @@
         || !RTStrICmp(pArg->argv[1], "execute"))
     {
-        gctlCmd.pfnHandler = handleCtrlProcessExec;
+        gctlCmd.pfnHandler = handleCtrlProcessExecDeprecated;
         uUsage = USAGE_GSTCTRL_EXEC;
+    }
+    else if (!strcmp(pArg->argv[1], "run"))
+    {
+        gctlCmd.pfnHandler = handleCtrlProcessRun;
+        uUsage = USAGE_GSTCTRL_RUN;
+    }
+    else if (!strcmp(pArg->argv[1], "start"))
+    {
+        gctlCmd.pfnHandler = handleCtrlProcessStart;
+        uUsage = USAGE_GSTCTRL_START;
     }
     else if (!RTStrICmp(pArg->argv[1], "copyfrom"))
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 55534)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 55535)
@@ -10079,5 +10079,5 @@
       To wait for a guest process to terminate after it has been
       created by <link to="IGuestSession::processCreate"/> or <link to="IGuestSession::processCreateEx"/>
-      one would specify ProcessWaitResult_Terminate.
+      one would specify ProcessWaitFor_Terminate.
 
       If a guest process has been started with ProcessCreateFlag_WaitForStdOut
@@ -10107,13 +10107,10 @@
     <const name="Timeout"               value="5">
       <desc>
-        The waiting operation timed out. This also will happen
-        when no event has been occurred matching the
-        current waiting flags in a <link to="IProcess::waitFor"/> call.
+        The waiting operation timed out. Also use if the guest process has
+        timed out on the guest side (kill attempted).
       </desc>
     </const>
     <const name="StdIn"                 value="6">
-      <desc>
-        The process signalled that stdin became available for writing
-        and that the process awaits input now.</desc>
+      <desc>The process signalled that stdin became available for writing.</desc>
     </const>
     <const name="StdOut"                value="7">
@@ -10213,5 +10210,5 @@
   <enum
     name="ProcessCreateFlag"
-    uuid="35192799-bfde-405d-9bea-c735ab9998e4"
+    uuid="be8c8dbd-4a76-e9ac-20df-468e86edf383"
     >
     <desc>
@@ -10786,5 +10783,5 @@
   <interface
     name="IGuestSession" extends="$unknown"
-    uuid="5b28703c-07b6-4fcb-afba-ac199b309752"
+    uuid="c899776d-41f7-7aee-7056-4bac979d58b7"
     wsmap="managed"
     >
@@ -11431,7 +11428,7 @@
           appropriate error message.
 
-          If ProcessCreateFlag_WaitForStdOut and / or respectively ProcessCreateFlag_WaitForStdErr
-          is / are set, the guest process will not exit until all data from the specified
-          stream(s) is / are read out.
+          If ProcessCreateFlag_WaitForStdOut and/or ProcessCreateFlag_WaitForStdErr
+          are set, the guest process will not exit until all data from the specified
+          streams are read out.
         </note>
 
@@ -11440,22 +11437,30 @@
         </result>
       </desc>
-      <param name="command" type="wstring" dir="in">
-        <desc>
-          Full path name of the command to execute on the guest; the
-          commands has to exists in the guest VM in order to be executed.
+      <param name="executable" type="wstring" dir="in">
+        <desc>
+          Full path name of the file to execute on the guest.  The file has to
+          exists in the guest VM with executable right to the session user in
+          order to be executed. If empty/null, the first entry in the
+          @a arguments array will be used in stead (i.e. argv[0]).
         </desc>
       </param>
       <param name="arguments" type="wstring" dir="in" safearray="yes">
-        <desc>Array of arguments passed to the execution command.</desc>
+        <desc>Array of arguments passed to the new process.
+          <note>
+            Starting with VirtualBox 5.0 this array starts with argument 0
+            instead of argument 1 as in previous versions.  Whether the zeroth
+            argument can be passed to the guest depends on the VBoxService
+            version running there.
+          </note>
+        </desc>
       </param>
       <param name="environment" type="wstring" dir="in" safearray="yes">
         <desc>
-          Environment variables that can be set while the command is being
-          executed, in form of "NAME=VALUE"; one pair per entry. To unset a
-          variable just set its name ("NAME") without a value.
-
-          This parameter can be used to override environment variables set by
-          the guest session, which will be applied to the newly started process
-          in any case.
+          Environment variables to set or unset for the guest process,
+          relative to the environment of the guest session.
+
+          The variables are in the traditional "NAME=VALUE" form with one pair
+          per array entry.  To unset a variable just leave out the equal sign
+          and the value ("NAME").
         </desc>
       </param>
@@ -11486,22 +11491,30 @@
         See <link to="IGuestSession::processCreate"/> for more information.
       </desc>
-      <param name="command" type="wstring" dir="in">
-        <desc>
-          Full path name of the command to execute on the guest; the
-          commands has to exists in the guest VM in order to be executed.
+      <param name="executable" type="wstring" dir="in">
+        <desc>
+          Full path name of the file to execute on the guest.  The file has to
+          exists in the guest VM with executable right to the session user in
+          order to be executed.  If empty/null, the first entry in the
+          @a arguments array will be used in stead (i.e. argv[0]).
         </desc>
       </param>
       <param name="arguments" type="wstring" dir="in" safearray="yes">
-        <desc>Array of arguments passed to the execution command.</desc>
+        <desc>Array of arguments passed to the new process.
+          <note>
+            Starting with VirtualBox 5.0 this array starts with argument 0
+            instead of argument 1 as in previous versions.  Whether the zeroth
+            argument can be passed to the guest depends on the VBoxService
+            version running there.
+          </note>
+        </desc>
       </param>
       <param name="environment" type="wstring" dir="in" safearray="yes">
         <desc>
-          Environment variables that can be set while the command is being
-          executed, in form of "NAME=VALUE"; one pair per entry. To unset a
-          variable just set its name ("NAME") without a value.
-
-          This parameter can be used to override environment variables set by
-          the guest session, which will be applied to the newly started process
-          in any case.
+          Environment variables to set or unset for the guest process,
+          relative to the environment of the guest session.
+
+          The variables are in the traditional "NAME=VALUE" form with one pair
+          per array entry.  To unset a variable just leave out the equal sign
+          and the value ("NAME").
         </desc>
       </param>
Index: /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 55534)
+++ /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 55535)
@@ -221,6 +221,7 @@
     /** The process' friendly name. */
     Utf8Str                     mName;
-    /** The actual command to execute. */
-    Utf8Str                     mCommand;
+    /** The executable. */
+    Utf8Str                     mExecutable;
+    /** Arguments vector (starting with argument \#0). */
     ProcessArguments            mArguments;
     GuestEnvironment            mEnvironment;
Index: /trunk/src/VBox/Main/include/GuestSessionImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 55534)
+++ /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 55535)
@@ -204,5 +204,5 @@
               mProcInfo(startupInfo)
         {
-            mProcInfo.mCommand = strDest;
+            mProcInfo.mExecutable = strDest;
             if (mProcInfo.mName.isEmpty())
                 mProcInfo.mName = strDest;
@@ -432,5 +432,5 @@
                                                  int *pGuestRc);
     int                     i_processRemoveFromList(GuestProcess *pProcess);
-    int                     i_processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProgress);
+    int                     i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProgress);
     inline bool             i_processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess);
     inline int              i_processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess);
Index: /trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp	(revision 55534)
+++ /trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp	(revision 55535)
@@ -91,5 +91,5 @@
         GuestProcessStartupInfo procInfo;
         procInfo.mName      = Utf8StrFmt(tr("Reading directory \"%s\""), openInfo.mPath.c_str());
-        procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_LS);
+        procInfo.mExecutable= Utf8Str(VBOXSERVICE_TOOL_LS);
         procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
         procInfo.mFlags     = ProcessCreateFlag_WaitForStdOut;
Index: /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 55534)
+++ /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 55535)
@@ -266,6 +266,5 @@
 
 #ifdef VBOX_WITH_GUEST_CONTROL
-    LogFlowThisFunc(("mCmd=%s, PID=%RU32\n",
-                     mData.mProcess.mCommand.c_str(), mData.mPID));
+    LogFlowThisFunc(("mExe=%s, PID=%RU32\n", mData.mProcess.mExecutable.c_str(), mData.mPID));
 
     /* Terminate process if not already done yet. */
@@ -334,5 +333,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    aExecutablePath = mData.mProcess.mCommand;
+    aExecutablePath = mData.mProcess.mExecutable;
 
     return S_OK;
@@ -987,6 +986,6 @@
 int GuestProcess::i_startProcess(uint32_t uTimeoutMS, int *pGuestRc)
 {
-    LogFlowThisFunc(("uTimeoutMS=%RU32, procCmd=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n",
-                     uTimeoutMS, mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags,
+    LogFlowThisFunc(("uTimeoutMS=%RU32, procExe=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n",
+                     uTimeoutMS, mData.mProcess.mExecutable.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags,
                      mSession->i_getId()));
 
@@ -1017,6 +1016,8 @@
     GuestSession *pSession = mSession;
     AssertPtr(pSession);
+    uint32_t const uProtocol = pSession->i_getProtocolVersion();
 
     const GuestCredentials &sessionCreds = pSession->i_getCredentials();
+
 
     /* Prepare arguments. */
@@ -1029,25 +1030,20 @@
         && cArgs)
     {
-        char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
+        char const **papszArgv = (char const **)RTMemAlloc((cArgs + 1) * sizeof(papszArgv[0]));
         AssertReturn(papszArgv, VERR_NO_MEMORY);
 
-        for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
-        {
-            const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
-            AssertPtr(pszCurArg);
-            vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
+        for (size_t i = 0; i < cArgs; i++)
+        {
+            papszArgv[i] = mData.mProcess.mArguments[i].c_str();
+            AssertPtr(papszArgv[i]);
         }
         papszArgv[cArgs] = NULL;
 
-        if (RT_SUCCESS(vrc))
+        if (uProtocol < UINT32_C(0xdeadbeef) ) /** @todo implement a way of sending argv[0], best idea is a new command. */
+            vrc = RTGetOptArgvToString(&pszArgs, papszArgv + 1, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
+        else
             vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
 
-        if (papszArgv)
-        {
-            size_t i = 0;
-            while (papszArgv[i])
-                RTStrFree(papszArgv[i++]);
-            RTMemFree(papszArgv);
-        }
+        RTMemFree(papszArgv);
     }
 
@@ -1065,13 +1061,10 @@
     if (RT_SUCCESS(vrc))
     {
-        AssertPtr(mSession);
-        uint32_t uProtocol = mSession->i_getProtocolVersion();
-
         /* Prepare HGCM call. */
         VBOXHGCMSVCPARM paParms[16];
         int i = 0;
         paParms[i++].setUInt32(pEvent->ContextID());
-        paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
-                                (ULONG)mData.mProcess.mCommand.length() + 1);
+        paParms[i++].setPointer((void*)mData.mProcess.mExecutable.c_str(),
+                                (ULONG)mData.mProcess.mExecutable.length() + 1);
         paParms[i++].setUInt32(mData.mProcess.mFlags);
         paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size());
@@ -1764,5 +1757,5 @@
                 hr = setError(VBOX_E_IPRT_ERROR,
                               tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
-                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
+                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
                 break;
         }
@@ -1798,5 +1791,5 @@
                 hr = setError(VBOX_E_IPRT_ERROR,
                               tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
-                              mData.mProcess.mCommand.c_str(), mData.mPID);
+                              mData.mProcess.mExecutable.c_str(), mData.mPID);
                 break;
 
@@ -1804,5 +1797,5 @@
                 hr = setError(VBOX_E_IPRT_ERROR,
                               tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
-                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
+                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
                 break;
         }
@@ -1834,5 +1827,6 @@
     HRESULT hr = S_OK;
 
-    int guestRc; ProcessWaitResult_T waitResult;
+    int guestRc;
+    ProcessWaitResult_T waitResult;
     int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc);
     if (RT_SUCCESS(vrc))
@@ -1855,5 +1849,5 @@
                 hr = setError(VBOX_E_IPRT_ERROR,
                               tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
-                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
+                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
                 break;
         }
@@ -1907,5 +1901,5 @@
                 hr = setError(VBOX_E_IPRT_ERROR,
                               tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
-                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
+                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
                 break;
         }
@@ -1956,6 +1950,6 @@
                            bool fAsync, int *pGuestRc)
 {
-    LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",
-                     pGuestSession, startupInfo.mCommand.c_str(), fAsync));
+    LogFlowThisFunc(("pGuestSession=%p, exe=%s, fAsync=%RTbool\n",
+                     pGuestSession, startupInfo.mExecutable.c_str(), fAsync));
 
     AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
@@ -1967,5 +1961,5 @@
     mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
 
-    int vrc = pSession->i_processCreateExInteral(mStartupInfo, pProcess);
+    int vrc = pSession->i_processCreateExInternal(mStartupInfo, pProcess);
     if (RT_SUCCESS(vrc))
         vrc = fAsync
Index: /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 55534)
+++ /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 55535)
@@ -661,6 +661,6 @@
 
     GuestProcessStartupInfo procInfo;
-    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
-    procInfo.mFlags   = ProcessCreateFlag_Hidden;
+    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
+    procInfo.mFlags      = ProcessCreateFlag_Hidden;
 
     try
@@ -816,6 +816,6 @@
 
     GuestProcessStartupInfo procInfo;
-    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
-    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
+    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
+    procInfo.mFlags      = ProcessCreateFlag_WaitForStdOut;
 
     try
@@ -1217,6 +1217,6 @@
     GuestProcessStream      streamOut;
 
-    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
-    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
+    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_RM);
+    procInfo.mFlags      = ProcessCreateFlag_WaitForStdOut;
 
     try
@@ -1374,6 +1374,6 @@
     /** @todo Merge this with IGuestFile::queryInfo(). */
     GuestProcessStartupInfo procInfo;
-    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
-    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
+    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_STAT);
+    procInfo.mFlags      = ProcessCreateFlag_WaitForStdOut;
 
     try
@@ -1837,6 +1837,8 @@
 
 /**
- * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
- * GuestProcess::startProcessAsync() for that.
+ * Creates but does *not* start the process yet.
+ *
+ * See GuestProcess::startProcess() or GuestProcess::startProcessAsync() for
+ * starting the process.
  *
  * @return  IPRT status code.
@@ -1844,8 +1846,8 @@
  * @param   pProcess
  */
-int GuestSession::i_processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
-{
-    LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
-                 procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
+int GuestSession::i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
+{
+    LogFlowFunc(("mExe=%s, mFlags=%x, mTimeoutMS=%RU32\n",
+                 procInfo.mExecutable.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
 #ifdef DEBUG
     if (procInfo.mArguments.size())
@@ -3308,5 +3310,5 @@
 }
 
-HRESULT GuestSession::processCreate(const com::Utf8Str &aCommand, const std::vector<com::Utf8Str> &aArguments,
+HRESULT GuestSession::processCreate(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
                                     const std::vector<com::Utf8Str> &aEnvironment,
                                     const std::vector<ProcessCreateFlag_T> &aFlags,
@@ -3320,10 +3322,10 @@
     std::vector<LONG> affinityIgnored;
 
-    return processCreateEx(aCommand, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default,
+    return processCreateEx(aExecutable, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default,
                            affinityIgnored, aGuestProcess);
 #endif /* VBOX_WITH_GUEST_CONTROL */
 }
 
-HRESULT GuestSession::processCreateEx(const com::Utf8Str &aCommand, const std::vector<com::Utf8Str> &aArguments,
+HRESULT GuestSession::processCreateEx(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
                                       const std::vector<com::Utf8Str> &aEnvironment,
                                       const std::vector<ProcessCreateFlag_T> &aFlags, ULONG aTimeoutMS,
@@ -3336,19 +3338,34 @@
     LogFlowThisFuncEnter();
 
-    if (RT_UNLIKELY((aCommand.c_str()) == NULL || *(aCommand.c_str()) == '\0'))
-        return setError(E_INVALIDARG, tr("No command to execute specified"));
-
+    /*
+     * Must have an executable to execute.  If none is given, we try use the
+     * zero'th argument.
+     */
+    const char *pszExecutable = aExecutable.c_str();
+    if (RT_UNLIKELY(pszExecutable == NULL || *pszExecutable == '\0'))
+    {
+        if (aArguments.size() > 0)
+            pszExecutable = aArguments[0].c_str();
+        if (pszExecutable == NULL || *pszExecutable == '\0')
+            return setError(E_INVALIDARG, tr("No command to execute specified"));
+    }
+
+    /*
+     * Check the session.
+     */
     HRESULT hr = i_isReadyExternal();
     if (FAILED(hr))
         return hr;
 
+    /*
+     * Build the process startup info.
+     */
     GuestProcessStartupInfo procInfo;
-    procInfo.mCommand = aCommand;
-
+
+    /* Executable and arguments. */
+    procInfo.mExecutable = pszExecutable;
     if (aArguments.size())
         for (size_t i = 0; i < aArguments.size(); i++)
             procInfo.mArguments.push_back(aArguments[i]);
-
-    int rc = VINF_SUCCESS;
 
     /*
@@ -3360,10 +3377,20 @@
     procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
 
+    int rc = VINF_SUCCESS;
     if (aEnvironment.size())
         for (size_t i = 0; i < aEnvironment.size() && RT_SUCCESS(rc); i++)
+        {
+            /** @todo r=bird: What ARE you trying to do here??? The documentation is crystal
+             *        clear on that each entry contains ONE pair, however,
+             *        GuestEnvironment::Set(const Utf8Str &) here will split up the input
+             *        into any number of pairs, from what I can tell.  Such that for e.g.
+             *        "VBOX_LOG_DEST=file=/tmp/foobared.log" becomes "VBOX_LOG_DEST=file"
+             *        and "/tmp/foobared.log" - which I obviously don't want! */
             rc = procInfo.mEnvironment.Set(aEnvironment[i]);
+        }
 
     if (RT_SUCCESS(rc))
     {
+        /* Convert the flag array into a mask. */
         if (aFlags.size())
             for (size_t i = 0; i < aFlags.size(); i++)
@@ -3372,4 +3399,5 @@
         procInfo.mTimeoutMS = aTimeoutMS;
 
+        /** @todo use RTCPUSET instead of archaic 64-bit variables! */
         if (aAffinity.size())
             for (size_t i = 0; i < aAffinity.size(); i++)
@@ -3379,18 +3407,33 @@
         procInfo.mPriority = aPriority;
 
+        /*
+         * Create a guest process object.
+         */
         ComObjPtr<GuestProcess> pProcess;
-        rc = i_processCreateExInteral(procInfo, pProcess);
+        rc = i_processCreateExInternal(procInfo, pProcess);
         if (RT_SUCCESS(rc))
         {
             /* Return guest session to the caller. */
             HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
-            if (FAILED(hr2))
+            if (SUCCEEDED(hr2))
+            {
+                /*
+                 * Start the process.
+                 */
+                rc = pProcess->i_startProcessAsync();
+                if (RT_FAILURE(rc))
+                {
+                    /** @todo r=bird: What happens to the interface that *aGuestProcess points to
+                     *        now?  Looks like a leak or an undocument hack of sorts... */
+                }
+            }
+            else
                 rc = VERR_COM_OBJECT_NOT_FOUND;
-
-            if (RT_SUCCESS(rc))
-                rc = pProcess->i_startProcessAsync();
-        }
-    }
-
+        }
+    }
+
+    /** @todo you're better off doing this is 'else if (rc == xxx') statements,
+     *        since there is just one place where you'll get
+     *        VERR_MAX_PROCS_REACHED in the above code. */
     if (RT_FAILURE(rc))
     {
Index: /trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 55534)
+++ /trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 55535)
@@ -309,6 +309,6 @@
 
     GuestProcessStartupInfo procInfo;
-    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT);
-    procInfo.mFlags   = ProcessCreateFlag_Hidden;
+    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
+    procInfo.mFlags      = ProcessCreateFlag_Hidden;
 
     /* Set arguments.*/
@@ -318,5 +318,5 @@
     ComObjPtr<GuestProcess> pProcess; int guestRc;
     if (RT_SUCCESS(rc))
-        rc = pSession->i_processCreateExInteral(procInfo, pProcess);
+        rc = pSession->i_processCreateExInternal(procInfo, pProcess);
     if (RT_SUCCESS(rc))
     {
@@ -637,6 +637,6 @@
             procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),
                                         mSource.c_str(), mDest.c_str(), objData.mObjectSize);
-            procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_CAT);
-            procInfo.mFlags     = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
+            procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
+            procInfo.mFlags      = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
 
             /* Set arguments.*/
@@ -645,5 +645,5 @@
             /* Startup process. */
             ComObjPtr<GuestProcess> pProcess;
-            rc = pSession->i_processCreateExInteral(procInfo, pProcess);
+            rc = pSession->i_processCreateExInternal(procInfo, pProcess);
             if (RT_SUCCESS(rc))
                 rc = pProcess->i_startProcess(30 * 1000 /* 30s timeout */,
@@ -1040,5 +1040,5 @@
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
                                     Utf8StrFmt(GuestSession::tr("Running update file \"%s\" on guest terminated with exit code %ld"),
-                                               procInfo.mCommand.c_str(), exitCode));
+                                               procInfo.mExecutable.c_str(), exitCode));
                 break;
 
@@ -1051,5 +1051,5 @@
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
                                     Utf8StrFmt(GuestSession::tr("Update file \"%s\" reported invalid running state"),
-                                               procInfo.mCommand.c_str()));
+                                               procInfo.mExecutable.c_str()));
                 break;
 
@@ -1057,5 +1057,5 @@
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
                                     Utf8StrFmt(GuestSession::tr("Error while running update file \"%s\" on guest: %Rrc"),
-                                               procInfo.mCommand.c_str(), vrc));
+                                               procInfo.mExecutable.c_str(), vrc));
                 break;
         }
@@ -1413,5 +1413,5 @@
                  * calculate the specific percentage step of each copied file. */
                 uint8_t uOffset = 20; /* Start at 20%. */
-                uint8_t uStep = 40 / mFiles.size();
+                uint8_t uStep = 40 / (uint8_t)mFiles.size(); Assert(mFiles.size() <= 10);
 
                 LogRel(("Copying over Guest Additions update files to the guest ...\n"));
@@ -1453,5 +1453,5 @@
                  * calculate the specific percentage step of each copied file. */
                 uint8_t uOffset = 60; /* Start at 60%. */
-                uint8_t uStep = 35 / mFiles.size();
+                uint8_t uStep = 35 / (uint8_t)mFiles.size(); Assert(mFiles.size() <= 10);
 
                 LogRel(("Executing Guest Additions update files ...\n"));
Index: /trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py
===================================================================
--- /trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py	(revision 55534)
+++ /trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py	(revision 55535)
@@ -9,5 +9,5 @@
 __copyright__ = \
 """
-Copyright (C) 2010-2014 Oracle Corporation
+Copyright (C) 2010-2015 Oracle Corporation
 
 This file is part of VirtualBox Open Source Edition (OSE), as
@@ -262,5 +262,5 @@
         self.oCreds = tdCtxCreds(sUser, sPassword, sDomain);
         self.sCmd = sCmd;
-        self.aArgs = aArgs;
+        self.aArgs = aArgs if aArgs is not None else [sCmd,];
         self.aEnv = aEnv;
         self.aFlags = aFlags or [];
@@ -998,7 +998,7 @@
                          oTest.aArgs, oTest.aEnv));
         try:
-            curProc = oGuestSession.processCreate(oTest.sCmd, \
-                                                  oTest.aArgs, oTest.aEnv, \
-                                                  oTest.aFlags, oTest.timeoutMS);
+            curProc = oGuestSession.processCreate(oTest.sCmd,
+                                                  oTest.aArgs if self.oTstDrv.fpApiVer >= 5.0 else oTest.aArgs[1:],
+                                                  oTest.aEnv, oTest.aFlags, oTest.timeoutMS);
             if curProc is not None:
                 reporter.log2('Process start requested, waiting for start (%ldms) ...' % (oTest.timeoutMS,));
@@ -1511,5 +1511,5 @@
             sDomain = "";
             sCmd = "C:\\windows\\system32\\cmd.exe";
-            sArgs = [];
+            aArgs = [sCmd,];
 
         # Number of stale guest processes to create.
@@ -1542,6 +1542,6 @@
             for i in range(0, cStaleProcs):
                 try:
-                    oGuestSession.processCreate(sCmd, \
-                                                sArgs, [], \
+                    oGuestSession.processCreate(sCmd,
+                                                aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:], [],
                                                 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], \
                                                 30 * 1000);
@@ -1565,13 +1565,11 @@
                 #
                 if oTestVm.isWindows():
-                    sArgs = [ '/C', 'dir', '/S', 'C:\\Windows\\system'];
+                    aArgs = [ sCmd, '/C', 'dir', '/S', 'C:\\Windows\\system'];
                 reporter.log2('Starting non-stale processes');
                 aaProcs = [];
                 for i in range(0, cStaleProcs):
                     try:
-                        oCurProc = oGuestSession.processCreate(sCmd, \
-                                                               sArgs, [], \
-                                                               [], \
-                                                               0); # Infinite timeout.
+                        oCurProc = oGuestSession.processCreate(sCmd, aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:],
+                                                               [], [], 0); # Infinite timeout.
                         aaProcs.append(oCurProc);
                     except:
@@ -1617,12 +1615,11 @@
                 # Fire off blocking processes which are terminated via terminate().
                 if oTestVm.isWindows():
-                    sArgs = [ '/C', 'dir', '/S', 'C:\\Windows'];
+                    aArgs = [ sCmd, '/C', 'dir', '/S', 'C:\\Windows'];
                 reporter.log2('Starting blocking processes');
                 aaProcs = [];
                 for i in range(0, cStaleProcs):
                     try:
-                        oCurProc = oGuestSession.processCreate(sCmd, \
-                                                               sArgs, [], \
-                                                               [], 30 * 1000);
+                        oCurProc = oGuestSession.processCreate(sCmd, aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:],
+                                                               [],  [], 30 * 1000);
                         # Note: Use a timeout in the call above for not letting the stale processes
                         #       hanging around forever.  This can happen if the installed Guest Additions
@@ -1698,60 +1695,60 @@
 
         if oTestVm.isWindows():
+            sVBoxControl = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe";
             aaExec = [
                 # Basic executon.
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True) ],
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32\\kernel32.dll' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32\\kernel32.dll' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True) ],
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32\\nonexist.dll' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32\\nonexist.dll' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ],
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', '/wrongparam' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ],
                 # Paths with spaces.
                 ## @todo Get path of installed Guest Additions. Later.
-                [ tdTestExec(sCmd = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe",
-                             aArgs = [ 'version' ],
+                [ tdTestExec(sCmd = sVBoxControl, aArgs = [ sVBoxControl, 'version' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True) ],
                 # StdOut.
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True) ],
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stdout-non-existing' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ],
                 # StdErr.
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True) ],
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stderr-non-existing' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ],
                 # StdOut + StdErr.
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True) ],
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stdouterr-non-existing' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ]
                 # FIXME: Failing tests.
                 # Environment variables.
-                # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_NONEXIST' ],
+                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
                 #              sUser = sUser, sPassword = sPassword),
                 #   tdTestResultExec(fRc = True, iExitCode = 1) ]
-                # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'windir' ],
+                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'windir' ],
                 #              sUser = sUser, sPassword = sPassword,
                 #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
                 #   tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
-                # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_FOO' ],
+                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
                 #              sUser = sUser, sPassword = sPassword,
                 #              aEnv = [ 'TEST_FOO=BAR' ],
                 #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
                 #   tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
-                # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_FOO' ],
+                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
                 #              sUser = sUser, sPassword = sPassword,
                 #              aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
@@ -1765,5 +1762,5 @@
             # Manual test, not executed automatically.
             aaManual = [
-                [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir /S C:\\Windows' ],
+                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir /S C:\\Windows' ],
                              sUser = sUser, sPassword = sPassword,
                              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
@@ -1922,62 +1919,62 @@
             aaTests.extend([
                 # Simple.
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'wrongcommand' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'wrongcommand' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'exit', '22' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'exit', '22' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 22) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'set', 'ERRORLEVEL=234' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'set', 'ERRORLEVEL=234' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'echo', '%WINDIR%' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'echo', '%WINDIR%' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'set', 'ERRORLEVEL=0' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'set', 'ERRORLEVEL=0' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32\\kernel32.dll' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32\\kernel32.dll' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ],
-                [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
+                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
                              sUser = sUser, sPassword = sPassword),
                   tdTestResultExec(fRc = True, iExitCode = 1) ]
                 # FIXME: Failing tests.
                 # With stdout.
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
                 #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
                 #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 1) ],
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
                 #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 1) ],
                 # With stderr.
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
                 #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
                 #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 1) ],
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
                 #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 1) ],
                 # With stdout/stderr.
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
                 #              sUser = sUser, sPassword = sPassword,
                 #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 0) ],
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
                 #              sUser = sUser, sPassword = sPassword,
                 #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
                 #   tdTestResultExec(fRc = True, iExitCode = 1) ],
-                # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
+                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
                 #              sUser = sUser, sPassword = sPassword,
                 #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
@@ -2031,5 +2028,5 @@
             # waiting for termination.
             try:
-                curProc = oGuestSession.processCreate(sImage, [], \
+                curProc = oGuestSession.processCreate(sImage, [sImage,] if self.oTstDrv.fpApiVer >= 5.0 else [], \
                                                       [], [], 30 * 1000);
                 reporter.log('Waiting for process 1 being started ...');
@@ -2062,5 +2059,5 @@
             if fRc:
                 try:
-                    curProc = oGuestSession.processCreate(sImage, [], \
+                    curProc = oGuestSession.processCreate(sImage, [sImage,] if self.oTstDrv.fpApiVer >= 5.0 else [], \
                                                           [], [], 5 * 1000);
                     reporter.log('Waiting for process 2 being started ...');
@@ -3282,12 +3279,11 @@
 
         sCmd = 'c:\\windows\\system32\\cmd.exe';
-        aArgs = [ '/C', 'dir', '/S', 'c:\\windows' ];
+        aArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
         aEnv = [];
         aFlags = [];
 
         for _ in range(100):
-            oProc = oGuestSession.processCreate(sCmd,
-                                                aArgs, aEnv,
-                                                aFlags, 30 * 1000);
+            oProc = oGuestSession.processCreate(sCmd, aArgs if self.fpApiVer >= 5.0 else aArgs[1:],
+                                                aEnv, aFlags, 30 * 1000);
 
             aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
