Index: /trunk/include/VBox/HostServices/GuestControlSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/GuestControlSvc.h	(revision 39417)
+++ /trunk/include/VBox/HostServices/GuestControlSvc.h	(revision 39418)
@@ -75,4 +75,15 @@
 #define INPUT_FLAG_NONE             0
 #define INPUT_FLAG_EOF              RT_BIT(0)
+
+/**
+ * Execution flags.
+ * Note: Has to match Main's ExecuteProcessFlag_* flags!
+ */
+#define EXECUTEPROCESSFLAG_NONE             0x0
+#define EXECUTEPROCESSFLAG_WAIT_START       RT_BIT(1)
+#define EXECUTEPROCESSFLAG_HIDDEN           RT_BIT(2)
+#define EXECUTEPROCESSFLAG_NO_PROFILE       RT_BIT(3)
+#define EXECUTEPROCESSFLAG_WAIT_STDOUT      RT_BIT(4)
+#define EXECUTEPROCESSFLAG_WAIT_STDERR      RT_BIT(5)
 
 /**
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp	(revision 39417)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp	(revision 39418)
@@ -314,5 +314,6 @@
             /* Tell the host. */
             rc = VbglR3GuestCtrlExecReportStatus(uClientID, uContextID, 0 /* PID, invalid. */,
-                                                 PROC_STS_ERROR, VERR_MAX_PROCS_REACHED,
+                                                 PROC_STS_ERROR,
+                                                 !fAllowed ? VERR_MAX_PROCS_REACHED : rc,
                                                  NULL /* pvData */, 0 /* cbData */);
         }
@@ -335,5 +336,6 @@
  * @param   pcbRead                 Pointer to number of bytes read.  Optional.
  */
-int VBoxServiceControlExecGetOutput(uint32_t uPID, uint32_t uHandleId, uint32_t uTimeout,
+int VBoxServiceControlExecGetOutput(uint32_t uPID, uint32_t uCID,
+                                    uint32_t uHandleId, uint32_t uTimeout,
                                     void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
 {
@@ -345,4 +347,5 @@
 
     VBOXSERVICECTRLREQUEST ctrlRequest;
+    ctrlRequest.uCID   = uCID;
     ctrlRequest.cbData = cbBuf;
     ctrlRequest.pvData = (uint8_t*)pvBuf;
@@ -389,5 +392,6 @@
  * @param   pcbWritten              Pointer to number of bytes written to the process.  Optional.
  */
-int VBoxServiceControlSetInput(uint32_t uPID, bool fPendingClose,
+int VBoxServiceControlSetInput(uint32_t uPID, uint32_t uCID,
+                               bool fPendingClose,
                                void *pvBuf, uint32_t cbBuf,
                                uint32_t *pcbWritten)
@@ -400,4 +404,5 @@
 
     VBOXSERVICECTRLREQUEST ctrlRequest;
+    ctrlRequest.uCID    = uCID;
     ctrlRequest.cbData  = cbBuf;
     ctrlRequest.pvData  = pvBuf;
@@ -470,8 +475,8 @@
         }
 
-        rc = VBoxServiceControlSetInput(uPID, fPendingClose, pabBuffer,
+        rc = VBoxServiceControlSetInput(uPID, uContextID, fPendingClose, pabBuffer,
                                         cbSize, &cbWritten);
-        VBoxServiceVerbose(4, "Control: [PID %u]: Written input, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",
-                           uPID, rc, uFlags, fPendingClose, cbSize, cbWritten);
+        VBoxServiceVerbose(4, "Control: [PID %u]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",
+                           uPID, uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten);
         if (RT_SUCCESS(rc))
         {
@@ -543,11 +548,18 @@
         if (pBuf)
         {
-            rc = VBoxServiceControlExecGetOutput(uPID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,
+            rc = VBoxServiceControlExecGetOutput(uPID, uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,
                                                  pBuf, _64K /* cbSize */, &cbRead);
+
+            /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary
+             *        data which the host needs to work with -- so just pass through all data unfiltered! */
+
             if (RT_SUCCESS(rc))
-                VBoxServiceVerbose(3, "Control: [PID %u]: Got output, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",
+                VBoxServiceVerbose(2, "Control: Got output, PID=%u, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",
                                    uPID, uContextID, cbRead, uHandleID, uFlags);
+            else if (rc == VERR_NOT_FOUND)
+                VBoxServiceVerbose(2, "Control: PID=%u not found, CID=%u, uHandle=%u\n",
+                                   uPID, uContextID, uHandleID, rc);
             else
-                VBoxServiceError("Control: [PID %u]: Failed to retrieve output, CID=%u, uHandle=%u, rc=%Rrc\n",
+                VBoxServiceError("Control: Failed to retrieve output for PID=%u, CID=%u, uHandle=%u, rc=%Rrc\n",
                                  uPID, uContextID, uHandleID, rc);
             /* Note: Since the context ID is unique the request *has* to be completed here,
@@ -598,7 +610,10 @@
 
 
+/**
+ * Destroys all guest process threads which are still active.
+ */
 static void VBoxServiceControlDestroyThreads(void)
 {
-    VBoxServiceVerbose(3, "Control: Destroying threads ...\n");
+    VBoxServiceVerbose(2, "Control: Destroying threads ...\n");
 
     /* Signal all threads that we want to shutdown. */
@@ -625,4 +640,11 @@
     }
 
+#ifdef DEBUG
+        PVBOXSERVICECTRLTHREAD pThreadCur;
+        uint32_t cThreads = 0;
+        RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
+            cThreads++;
+        VBoxServiceVerbose(4, "Control: Guest process threads left=%u\n", cThreads);
+#endif
     AssertMsg(RTListIsEmpty(&g_GuestControlThreads),
               ("Guest process thread list still contains children when it should not\n"));
@@ -680,9 +702,8 @@
             RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node)
             {
-    // THREAD LOCKING!!
-                Assert(pThread->fStarted != pThread->fStopped);
-                if (pThread->fStarted)
+                VBOXSERVICECTRLTHREADSTATUS enmStatus = VBoxServiceControlThreadGetStatus(pThread);
+                if (enmStatus == VBOXSERVICECTRLTHREADSTATUS_STARTED)
                     uProcsRunning++;
-                else if (pThread->fStopped)
+                else if (enmStatus == VBOXSERVICECTRLTHREADSTATUS_STOPPED)
                     uProcsStopped++;
                 else
@@ -690,5 +711,5 @@
             }
 
-            VBoxServiceVerbose(2, "Control: Maximum served guest processes set to %u, running=%u, stopped=%u\n",
+            VBoxServiceVerbose(3, "Control: Maximum served guest processes set to %u, running=%u, stopped=%u\n",
                                g_GuestControlProcsMaxKept, uProcsRunning, uProcsStopped);
 
@@ -714,10 +735,11 @@
 
 /**
- * Finds a (formerly) started process given by its PID.
+ * Finds a (formerly) started process given by its PID and locks it. Must be unlocked
+ * by the caller with VBoxServiceControlThreadUnlock().
  *
  * @return  PVBOXSERVICECTRLTHREAD      Process structure if found, otherwise NULL.
  * @param   uPID                        PID to search for.
  */
-PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadByPID(uint32_t uPID)
+const PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadLocked(uint32_t uPID)
 {
     PVBOXSERVICECTRLTHREAD pThread = NULL;
@@ -730,5 +752,7 @@
             if (pThreadCur->uPID == uPID)
             {
-                pThread = pThreadCur;
+                rc = RTCritSectEnter(&pThreadCur->CritSect);
+                if (RT_SUCCESS(rc))
+                    pThread = pThreadCur;
                 break;
             }
@@ -745,4 +769,62 @@
 
 /**
+ * Unlocks a previously locked guest process thread.
+ *
+ * @param   pThread                 Thread to unlock.
+ */
+void VBoxServiceControlThreadUnlock(const PVBOXSERVICECTRLTHREAD pThread)
+{
+    AssertPtr(pThread);
+
+    int rc = RTCritSectLeave(&pThread->CritSect);
+    AssertRC(rc);
+}
+
+
+/**
+ * Assigns a valid PID to a guest control thread and also checks if there already was
+ * another (stale) guest process which was using that PID before and destroys it.
+ *
+ * @return  IPRT status code.
+ * @param   pThread        Thread to assign PID to.
+ * @param   uPID           PID to assign to the specified guest control execution thread.
+ */
+int VBoxServiceControlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)
+{
+    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
+    AssertReturn(uPID, VERR_INVALID_PARAMETER);
+
+    int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect);
+    if (RT_SUCCESS(rc))
+    {
+        /* Search old threads using the desired PID and shut them down completely -- it's
+         * not used anymore. */
+        PVBOXSERVICECTRLTHREAD pThreadCur;
+        RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
+        {
+            if (   pThreadCur->uPID == uPID
+                && pThreadCur       != pThread)
+            {
+                VBoxServiceVerbose(2, "ControlThread: PID %u was used before, shutting down stale exec thread ...\n",
+                                   uPID);
+                rc = VBoxServiceControlThreadSignalShutdown(pThreadCur);
+                if (RT_SUCCESS(rc))
+                    rc = VBoxServiceControlThreadWaitForShutdown(pThreadCur,
+                                                                 30 * 1000 /* Wait 30 seconds max. */);
+            }
+        }
+
+        /* Assign PID to current thread. */
+        pThread->uPID = uPID;
+
+        rc = RTCritSectLeave(&g_GuestControlThreadsCritSect);
+        AssertRC(rc);
+    }
+
+    return rc;
+}
+
+
+/**
  * Removes the specified guest process thread from the global thread
  * list.
@@ -751,5 +833,5 @@
  * @param   pThread             Thread to remove.
  */
-void VBoxServiceControlRemoveThread(PVBOXSERVICECTRLTHREAD pThread)
+void VBoxServiceControlRemoveThread(const PVBOXSERVICECTRLTHREAD pThread)
 {
     if (!pThread)
@@ -763,6 +845,13 @@
         RTListNodeRemove(&pThread->Node);
 
-        int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect);
-        AssertRC(rc2);
+#ifdef DEBUG
+        PVBOXSERVICECTRLTHREAD pThreadCur;
+        uint32_t cThreads = 0;
+        RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
+            cThreads++;
+        VBoxServiceVerbose(4, "Control: Guest process threads left=%u\n", cThreads);
+#endif
+        rc = RTCritSectLeave(&g_GuestControlThreadsCritSect);
+        AssertRC(rc);
     }
 }
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp	(revision 39417)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp	(revision 39418)
@@ -42,7 +42,5 @@
 
 /* Internal functions. */
-static int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pData, uint32_t uPID);
-static void vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pData);
-static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread);
+static int vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pThread);
 
 /**
@@ -154,4 +152,69 @@
 
 /**
+ * Frees a guest thread.
+ *
+ * @return  IPRT status code.
+ * @param   pThread                 Thread to shut down.
+ */
+static int vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pThread)
+{
+    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
+
+    VBoxServiceVerbose(1, "ControlThread: [PID %u]: Shutting down ...\n",
+                       pThread->uPID);
+
+    /* Signal the request event to unblock potential waiters. */
+    int rc = RTSemEventMultiSignal(pThread->RequestEvent);
+    if (RT_FAILURE(rc))
+        VBoxServiceError("ControlThread: [PID %u]: Signalling request event failed, rc=%Rrc\n",
+                         pThread->uPID, rc);
+
+    rc = RTCritSectEnter(&pThread->CritSect);
+    if (RT_SUCCESS(rc))
+    {
+        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Freeing thread data ...\n",
+                           pThread->uPID);
+
+        RTStrFree(pThread->pszCmd);
+        if (pThread->uNumEnvVars)
+        {
+            for (uint32_t i = 0; i < pThread->uNumEnvVars; i++)
+                RTStrFree(pThread->papszEnv[i]);
+            RTMemFree(pThread->papszEnv);
+        }
+        RTGetOptArgvFree(pThread->papszArgs);
+        RTStrFree(pThread->pszUser);
+        RTStrFree(pThread->pszPassword);
+
+        rc = RTSemEventMultiDestroy(pThread->RequestEvent);
+        AssertRC(rc);
+
+        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Cleaning up ...\n",
+                           pThread->uPID);
+
+        /* Set stopped status. */
+        ASMAtomicXchgBool(&pThread->fStopped, true);
+
+        rc = RTCritSectLeave(&pThread->CritSect);
+        AssertRC(rc);
+    }
+
+    /*
+     * Destroy other thread data.
+     */
+    if (RTCritSectIsInitialized(&pThread->CritSect))
+        RTCritSectDelete(&pThread->CritSect);
+
+    /*
+     * Destroy thread structure as final step.
+     */
+    RTMemFree(pThread);
+    pThread = NULL;
+
+    return rc;
+}
+
+
+/**
  * Signals a guest process thread that we want it to shut down in
  * a gentle way.
@@ -164,5 +227,5 @@
     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
 
-    VBoxServiceVerbose(3, "ControlThead: [PID %u]: Signalling shutdown ...\n",
+    VBoxServiceVerbose(3, "ControlThread: [PID %u]: Signalling shutdown ...\n",
                        pThread->uPID);
 
@@ -176,5 +239,5 @@
     int rc = VBoxServiceControlThreadPerform(pThread->uPID, &ctrlRequest);
     if (RT_FAILURE(rc))
-        VBoxServiceVerbose(3, "ControlThead: [PID %u]: Sending quit request failed with rc=%Rrc\n",
+        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Sending quit request failed with rc=%Rrc\n",
                            pThread->uPID, rc);
     return rc;
@@ -197,5 +260,5 @@
         && !ASMAtomicReadBool(&pThread->fStopped)) /* Only shutdown threads which aren't yet. */
     {
-        VBoxServiceVerbose(3, "ControlThead: [PID %u]: Waiting for shutdown ...\n",
+        VBoxServiceVerbose(2, "ControlThread: [PID %u]: Waiting for shutdown ...\n",
                            pThread->uPID);
 
@@ -205,5 +268,5 @@
         if (RT_FAILURE(rcThread))
         {
-            VBoxServiceError("ControlThead: [PID %u]: Shutdown returned error rc=%Rrc\n",
+            VBoxServiceError("ControlThread: [PID %u]: Shutdown returned error rc=%Rrc\n",
                              pThread->uPID, rcThread);
             if (RT_SUCCESS(rc))
@@ -216,32 +279,35 @@
 
 /**
- * Frees an allocated thread data structure along with all its allocated parameters.
- *
- * @param   pThread             Pointer to thread data to free.
- */
-static void vboxServiceControlThreadFree(const PVBOXSERVICECTRLTHREAD pThread)
-{
-    if (!pThread)
-        return;
-
-    VBoxServiceVerbose(3, "ControlThead: [PID %u]: Freeing thread data ...\n",
-                       pThread->uPID);
-
-    RTStrFree(pThread->pszCmd);
-    if (pThread->uNumEnvVars)
-    {
-        for (uint32_t i = 0; i < pThread->uNumEnvVars; i++)
-            RTStrFree(pThread->papszEnv[i]);
-        RTMemFree(pThread->papszEnv);
-    }
-    RTGetOptArgvFree(pThread->papszArgs);
-    RTStrFree(pThread->pszUser);
-    RTStrFree(pThread->pszPassword);
-
-    if (pThread->RequestEvent != NIL_RTSEMEVENTMULTI)
-    {
-        int rc2 = RTSemEventMultiDestroy(pThread->RequestEvent);
-        AssertRC(rc2);
-    }
+ * Returns the guest process thread's current status.
+ *
+ * @return  VBOXSERVICECTRLTHREADSTATUS
+ * @param   pThread             Thread to determine current status for.
+ */
+VBOXSERVICECTRLTHREADSTATUS VBoxServiceControlThreadGetStatus(const PVBOXSERVICECTRLTHREAD pThread)
+{
+    AssertPtrReturn(pThread, VBOXSERVICECTRLTHREADSTATUS_UNKNOWN);
+
+    int rc = RTCritSectEnter(&pThread->CritSect);
+    if (RT_SUCCESS(rc))
+    {
+        Assert(pThread->fStarted != pThread->fStopped);
+
+        VBOXSERVICECTRLTHREADSTATUS enmStatus = VBOXSERVICECTRLTHREADSTATUS_UNKNOWN;
+        /** @todo Add more logic here. */
+        /** @todo Remove fStarted/fStopped and just use this VBOXSERVICECTRLTHREADSTATUS. */
+        if (pThread->fStarted)
+            enmStatus = VBOXSERVICECTRLTHREADSTATUS_STARTED;
+        else if (pThread->fStopped)
+            enmStatus = VBOXSERVICECTRLTHREADSTATUS_STOPPED;
+        else
+            AssertMsgFailed(("ControlThread: Uknown thread status (0x%x)\n"));
+
+        rc = RTCritSectLeave(&pThread->CritSect);
+        AssertRC(rc);
+
+        return enmStatus;
+    }
+
+    return VBOXSERVICECTRLTHREADSTATUS_UNKNOWN;
 }
 
@@ -294,53 +360,71 @@
  *
  */
+static int VBoxServiceControlThreadHandleOutputError(RTPOLLSET hPollSet, uint32_t fPollEvt,
+                                                     PRTPIPE phPipeR, uint32_t idPollHnd)
+{
+    int rc = VINF_SUCCESS;
+
+    rc = RTPollSetRemove(hPollSet, idPollHnd);
+    AssertRC(rc);
+
+    rc = RTPipeClose(*phPipeR);
+    AssertRC(rc);
+    *phPipeR = NIL_RTPIPE;
+
+    return rc;
+}
+
+
+/**
+ * Handle pending output data or error on standard out or standard error.
+ *
+ * @returns IPRT status code from client send.
+ * @param   hPollSet            The polling set.
+ * @param   fPollEvt            The event mask returned by RTPollNoResume.
+ * @param   phPipeR             The pipe handle.
+ * @param   idPollHnd           The pipe ID to handle.
+ *
+ */
 static int VBoxServiceControlThreadHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt,
                                                      PRTPIPE phPipeR, uint32_t idPollHnd)
 {
     int rc = VINF_SUCCESS;
-
-#if 0
-    if (fPollEvt & RTPOLL_EVT_READ)
-    {
-        /** @todo Later: Notify the host about the read operation! */
-
-        /* Make sure we go another poll round in case there was too much data
-           for the buffer to hold. */
-        fPollEvt &= RTPOLL_EVT_ERROR;
-
-        /* Remove read event from poll set and just poll for errors from now on.
-         * This is necessary for doing a RTPipeRead. */
-        rc = RTPollSetEventsChange(hPollSet, idPollHnd, RTPOLL_EVT_ERROR);
-        AssertRC(rc);
-    }
+    if (fPollEvt == RTPOLL_EVT_READ)
+    {
+        char abBuf[_64K];
+        size_t cbRead;
+        int rc = RTPipeRead(*phPipeR, abBuf, sizeof(abBuf), &cbRead);
+        if (RT_SUCCESS(rc) && cbRead)
+        {
+#ifdef DEBUG
+            VBoxServiceVerbose(4, "ControlThread: Drain idPollHnd=%u, abBuf=0x%p, cbRead=%u\n",
+                               idPollHnd, abBuf, cbRead);
 #endif
-
+            /* Goes to bit bucket ... */
+
+            /* Make sure we go another poll round in case there was too much data
+               for the buffer to hold. */
+            fPollEvt &= RTPOLL_EVT_ERROR;
+        }
+        else if (RT_FAILURE(rc))
+        {
+            fPollEvt |= RTPOLL_EVT_ERROR;
+            AssertMsg(rc == VERR_BROKEN_PIPE, ("%Rrc\n", rc));
+        }
+    }
+
+    if (fPollEvt & RTPOLL_EVT_ERROR)
+        rc = VBoxServiceControlThreadHandleOutputError(hPollSet, fPollEvt,
+                                                       phPipeR, idPollHnd);
+    return rc;
+}
+
+
+static int VBoxServiceControlThreadHandleRequest(RTPOLLSET hPollSet, uint32_t fPollEvt,
+                                                 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR,
+                                                 PVBOXSERVICECTRLTHREAD pThread)
+{
 #ifdef DEBUG_andy
-    VBoxServiceVerbose(4, "ControlThead: HandleOutputEvent fPollEvt=0x%x, idPollHnd=%u\n",
-                       fPollEvt, idPollHnd);
-#endif
-
-    /*
-     * If an error was raised signalled
-     */
-    if (fPollEvt & RTPOLL_EVT_ERROR)
-    {
-        rc = RTPollSetRemove(hPollSet, idPollHnd);
-        AssertRC(rc);
-
-        rc = RTPipeClose(*phPipeR);
-        AssertRC(rc);
-        *phPipeR = NIL_RTPIPE;
-    }
-
-    return rc;
-}
-
-
-static int VBoxServiceControlThreadHandleIPCRequest(RTPOLLSET hPollSet, uint32_t fPollEvt,
-                                                    PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR,
-                                                    PVBOXSERVICECTRLTHREAD pThread)
-{
-#ifdef DEBUG_andy
-    VBoxServiceVerbose(4, "ControlThead: HandleIPCRequest\n");
+    VBoxServiceVerbose(4, "ControlThread: HandleIPCRequest\n");
 #endif
 
@@ -350,7 +434,7 @@
     AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER);
 
-    int rc = RTCritSectEnter(&pThread->CritSect);
+    /*int rc = RTCritSectEnter(&pThread->CritSect);
     if (RT_SUCCESS(rc))
-    {
+    {*/
         /* Drain the notification pipe. */
         uint8_t abBuf[8];
@@ -358,5 +442,5 @@
         rc = RTPipeRead(pThread->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);
         if (RT_FAILURE(rc))
-            VBoxServiceError("ControlThead: Draining IPC notification pipe failed with rc=%Rrc\n", rc);
+            VBoxServiceError("ControlThread: Draining IPC notification pipe failed with rc=%Rrc\n", rc);
 
         int rcReq = VINF_SUCCESS; /* Actual request result. */
@@ -438,6 +522,6 @@
                      ? rcReq : rc;
 
-        VBoxServiceVerbose(4, "ControlThead: Handled IPC request with rcReq=%Rrc, enmType=%u, cbData=%u\n",
-                           rcReq, pRequest->enmType, pRequest->cbData);
+        VBoxServiceVerbose(2, "ControlThread: [PID %u]: Handled req=%u, CID=%u, rcReq=%Rrc, cbData=%u\n",
+                           pThread->uPID, pRequest->enmType, pRequest->uCID, rcReq, pRequest->cbData);
 
         /* In any case, regardless of the result, we notify
@@ -448,7 +532,7 @@
          * or modified already! */
 
-        rc2 = RTCritSectLeave(&pThread->CritSect);
+        /*rc2 = RTCritSectLeave(&pThread->CritSect);
         AssertRC(rc2);
-    }
+    }*/
 
     return rc;
@@ -475,6 +559,5 @@
     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     AssertPtrReturn(phStdInW, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(phStdOutR, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(phStdErrR, VERR_INVALID_PARAMETER);
+    /* Rest is optional. */
 
     int                         rc;
@@ -495,8 +578,9 @@
      * the first (stale) entry will be found and we get really weird results!
      */
-    rc = vboxServiceControlThreadAssignPID(pThread, hProcess);
+    rc = VBoxServiceControlAssignPID(pThread, hProcess);
     if (RT_FAILURE(rc))
     {
-        VBoxServiceError("ControlThead: Unable to assign PID to new thread, rc=%Rrc\n", rc);
+        VBoxServiceError("ControlThread: Unable to assign PID=%u, to new thread, rc=%Rrc\n",
+                         hProcess, rc);
         return rc;
     }
@@ -506,6 +590,6 @@
      * and that it's now OK to send input to the process.
      */
-    VBoxServiceVerbose(3, "ControlThead: [PID %u]: Process started, CID=%u, User=%s\n",
-                       pThread->uPID, pThread->uContextID, pThread->pszUser);
+    VBoxServiceVerbose(2, "ControlThread: [PID %u]: Process \"%s\" started, CID=%u, User=%s\n",
+                       pThread->uPID, pThread->pszCmd, pThread->uContextID, pThread->pszUser);
     rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
                                          pThread->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
@@ -531,5 +615,5 @@
         if (RT_SUCCESS(rc2))
         {
-            /*VBoxServiceVerbose(4, "ControlThead: [PID %u}: RTPollNoResume idPollHnd=%u\n",
+            /*VBoxServiceVerbose(4, "ControlThread: [PID %u}: RTPollNoResume idPollHnd=%u\n",
                                  pThread->uPID, idPollHnd);*/
             switch (idPollHnd)
@@ -550,6 +634,6 @@
 
                 case VBOXSERVICECTRLPIPEID_IPC_NOTIFY:
-                    rc = VBoxServiceControlThreadHandleIPCRequest(hPollSet, fPollEvt,
-                                                                  phStdInW,phStdOutR,phStdErrR, pThread);
+                    rc = VBoxServiceControlThreadHandleRequest(hPollSet, fPollEvt,
+                                                               phStdInW, phStdOutR, phStdErrR, pThread);
                     break;
             }
@@ -608,5 +692,5 @@
             if (cMsElapsed >= cMsTimeout)
             {
-                VBoxServiceVerbose(3, "ControlThead: [PID %u]: Timed out (%ums elapsed > %ums timeout), killing ...",
+                VBoxServiceVerbose(3, "ControlThread: [PID %u]: Timed out (%ums elapsed > %ums timeout), killing ...",
                                    pThread->uPID, cMsElapsed, cMsTimeout);
 
@@ -644,5 +728,5 @@
         if (MsProcessKilled == UINT64_MAX)
         {
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Is still alive and not killed yet\n",
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Is still alive and not killed yet\n",
                                pThread->uPID);
 
@@ -654,10 +738,10 @@
         for (size_t i = 0; i < 10; i++)
         {
-            VBoxServiceVerbose(4, "ControlThead: [PID %u]: Kill attempt %d/10: Waiting to exit ...\n",
+            VBoxServiceVerbose(4, "ControlThread: [PID %u]: Kill attempt %d/10: Waiting to exit ...\n",
                                pThread->uPID, i + 1);
             rc2 = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
             if (RT_SUCCESS(rc2))
             {
-                VBoxServiceVerbose(4, "ControlThead: [PID %u]: Kill attempt %d/10: Exited\n",
+                VBoxServiceVerbose(4, "ControlThread: [PID %u]: Kill attempt %d/10: Exited\n",
                                    pThread->uPID, i + 1);
                 fProcessAlive = false;
@@ -666,5 +750,5 @@
             if (i >= 5)
             {
-                VBoxServiceVerbose(4, "ControlThead: [PID %u]: Kill attempt %d/10: Trying to terminate ...\n",
+                VBoxServiceVerbose(4, "ControlThread: [PID %u]: Kill attempt %d/10: Trying to terminate ...\n",
                                    pThread->uPID, i + 1);
                 RTProcTerminate(hProcess);
@@ -674,5 +758,5 @@
 
         if (fProcessAlive)
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Could not be killed\n", pThread->uPID);
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Could not be killed\n", pThread->uPID);
     }
 
@@ -688,5 +772,5 @@
         if (     fProcessTimedOut  && !fProcessAlive && MsProcessKilled != UINT64_MAX)
         {
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Timed out and got killed\n",
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Timed out and got killed\n",
                                pThread->uPID);
             uStatus = PROC_STS_TOK;
@@ -694,5 +778,5 @@
         else if (fProcessTimedOut  &&  fProcessAlive && MsProcessKilled != UINT64_MAX)
         {
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Timed out and did *not* get killed\n",
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Timed out and did *not* get killed\n",
                                pThread->uPID);
             uStatus = PROC_STS_TOA;
@@ -700,5 +784,5 @@
         else if (pThread->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))
         {
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Got terminated because system/service is about to shutdown\n",
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Got terminated because system/service is about to shutdown\n",
                                pThread->uPID);
             uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */
@@ -707,15 +791,15 @@
         else if (fProcessAlive)
         {
-            VBoxServiceError("ControlThead: [PID %u]: Is alive when it should not!\n",
+            VBoxServiceError("ControlThread: [PID %u]: Is alive when it should not!\n",
                              pThread->uPID);
         }
         else if (MsProcessKilled != UINT64_MAX)
         {
-            VBoxServiceError("ControlThead: [PID %u]: Has been killed when it should not!\n",
+            VBoxServiceError("ControlThread: [PID %u]: Has been killed when it should not!\n",
                              pThread->uPID);
         }
         else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
         {
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Ended with RTPROCEXITREASON_NORMAL (%u)\n",
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_NORMAL (%u)\n",
                                pThread->uPID, ProcessStatus.iStatus);
 
@@ -725,5 +809,5 @@
         else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL)
         {
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Ended with RTPROCEXITREASON_SIGNAL (%u)\n",
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_SIGNAL (%u)\n",
                                pThread->uPID, ProcessStatus.iStatus);
 
@@ -733,5 +817,5 @@
         else if (ProcessStatus.enmReason == RTPROCEXITREASON_ABEND)
         {
-            VBoxServiceVerbose(3, "ControlThead: [PID %u]: Ended with RTPROCEXITREASON_ABEND (%u)\n",
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_ABEND (%u)\n",
                                pThread->uPID, ProcessStatus.iStatus);
 
@@ -740,8 +824,8 @@
         }
         else
-            VBoxServiceVerbose(1, "ControlThead: [PID %u]: Handling process status %u not implemented\n",
+            VBoxServiceVerbose(1, "ControlThread: [PID %u]: Handling process status %u not implemented\n",
                                pThread->uPID, ProcessStatus.enmReason);
 
-        VBoxServiceVerbose(3, "ControlThead: [PID %u]: Sending final status, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",
+        VBoxServiceVerbose(2, "ControlThread: [PID %u]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",
                            pThread->uPID, pThread->uClientID, pThread->uContextID, uStatus, uFlags);
         rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
@@ -749,14 +833,27 @@
                                              NULL /* pvData */, 0 /* cbData */);
         if (RT_FAILURE(rc))
-            VBoxServiceError("ControlThead: [PID %u]: Error reporting final status to host; rc=%Rrc\n",
+            VBoxServiceError("ControlThread: [PID %u]: Error reporting final status to host; rc=%Rrc\n",
                              pThread->uPID, rc);
 
-        VBoxServiceVerbose(3, "ControlThead: [PID %u]: Process loop ended with rc=%Rrc\n",
+        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Process loop ended with rc=%Rrc\n",
                            pThread->uPID, rc);
     }
     else
-        VBoxServiceError("ControlThead: [PID %u]: Loop failed with rc=%Rrc\n",
+        VBoxServiceError("ControlThread: [PID %u]: Loop failed with rc=%Rrc\n",
                          pThread->uPID, rc);
     return rc;
+}
+
+
+static int vboxServiceControlThreadInitPipe(PRTHANDLE ph, PRTPIPE phPipe)
+{
+    AssertPtrReturn(ph, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(phPipe, VERR_INVALID_PARAMETER);
+
+    ph->enmType = RTHANDLETYPE_PIPE;
+    ph->u.hPipe = NIL_RTPIPE;
+    *phPipe     = NIL_RTPIPE;
+
+    return VINF_SUCCESS;
 }
 
@@ -781,9 +878,4 @@
     AssertPtrReturn(phPipe, VERR_INVALID_PARAMETER);
 
-    ph->enmType = RTHANDLETYPE_PIPE;
-    ph->u.hPipe = NIL_RTPIPE;
-    *pph        = NULL;
-    *phPipe     = NIL_RTPIPE;
-
     int rc;
 
@@ -833,5 +925,5 @@
 #endif
 #ifdef DEBUG
-    VBoxServiceVerbose(3, "ControlThead: VBoxServiceControlExecMakeFullPath: %s -> %s\n",
+    VBoxServiceVerbose(3, "ControlThread: VBoxServiceControlExecMakeFullPath: %s -> %s\n",
                        pszPath, pszExpanded);
 #endif
@@ -870,5 +962,5 @@
         rc = VBoxServiceControlThreadMakeFullPath(pszExecResolved, pszResolved, cbResolved);
 #ifdef DEBUG
-        VBoxServiceVerbose(3, "ControlThead: VBoxServiceControlExecResolveExecutable: %s -> %s\n",
+        VBoxServiceVerbose(3, "ControlThread: VBoxServiceControlExecResolveExecutable: %s -> %s\n",
                            pszFileName, pszResolved);
 #endif
@@ -1024,9 +1116,7 @@
             if (fFlags)
             {
-                /* Process Main flag "ExecuteProcessFlag_Hidden". */
-                if (fFlags & RT_BIT(2))
+                if (fFlags & EXECUTEPROCESSFLAG_HIDDEN)
                     uProcFlags |= RTPROC_FLAGS_HIDDEN;
-                /* Process Main flag "ExecuteProcessFlag_NoProfile". */
-                if (fFlags & RT_BIT(3))
+                if (fFlags & EXECUTEPROCESSFLAG_NO_PROFILE)
                     uProcFlags |= RTPROC_FLAGS_NO_PROFILE;
             }
@@ -1041,7 +1131,7 @@
                 uProcFlags |= RTPROC_FLAGS_SERVICE;
 #ifdef DEBUG
-            VBoxServiceVerbose(3, "ControlThead: Command: %s\n", szExecExp);
+            VBoxServiceVerbose(3, "ControlThread: Command: %s\n", szExecExp);
             for (size_t i = 0; papszArgsExp[i]; i++)
-                VBoxServiceVerbose(3, "ControlThead:\targv[%ld]: %s\n", i, papszArgsExp[i]);
+                VBoxServiceVerbose(3, "ControlThread:\targv[%ld]: %s\n", i, papszArgsExp[i]);
 #endif
             /* Do normal execution. */
@@ -1066,15 +1156,15 @@
 {
     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
-    VBoxServiceVerbose(3, "ControlThead: Thread of process \"%s\" started\n", pThread->pszCmd);
+    VBoxServiceVerbose(3, "ControlThread: Thread of process \"%s\" started\n", pThread->pszCmd);
 
     int rc = VbglR3GuestCtrlConnect(&pThread->uClientID);
     if (RT_FAILURE(rc))
     {
-        VBoxServiceError("ControlThead: Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc);
+        VBoxServiceError("ControlThread: Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc);
         RTThreadUserSignal(RTThreadSelf());
         return rc;
     }
-    VBoxServiceVerbose(3, "ControlThead: Guest process \"%s\" got client ID=%u\n",
-                       pThread->pszCmd, pThread->uClientID);
+    VBoxServiceVerbose(3, "ControlThread: Guest process \"%s\" got client ID=%u, flags=0x%x\n",
+                       pThread->pszCmd, pThread->uClientID, pThread->uFlags);
 
     bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */
@@ -1130,8 +1220,26 @@
                             /* Stdout. */
                             if (RT_SUCCESS(rc))
-                                rc = RTPollSetAddPipe(hPollSet, hStdOutR, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDOUT);
+                            {
+                                uint32_t uFlags = RTPOLL_EVT_ERROR;
+                                if (!(pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT))
+                                {
+                                    uFlags |= RTPOLL_EVT_READ;
+                                    VBoxServiceVerbose(3, "ControlThread: Host is not interested in getting stdout for \"%s\", poll flags=0x%x\n",
+                                                        pThread->pszCmd, uFlags);
+                                }
+                                rc = RTPollSetAddPipe(hPollSet, hStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT);
+                            }
                             /* Stderr. */
                             if (RT_SUCCESS(rc))
-                                rc = RTPollSetAddPipe(hPollSet, hStdErrR, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDERR);
+                            {
+                                uint32_t uFlags = RTPOLL_EVT_ERROR;
+                                if (!(pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR))
+                                {
+                                    uFlags |= RTPOLL_EVT_READ;
+                                    VBoxServiceVerbose(3, "ControlThread: Host is not interested in getting stderr for \"%s\", poll flags=0x%x\n",
+                                                        pThread->pszCmd, uFlags);
+                                }
+                                rc = RTPollSetAddPipe(hPollSet, hStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR);
+                            }
                             /* IPC notification pipe. */
                             if (RT_SUCCESS(rc))
@@ -1148,5 +1256,5 @@
                                                                            &hProcess);
                                 if (RT_FAILURE(rc))
-                                    VBoxServiceError("ControlThead: Error starting process, rc=%Rrc\n", rc);
+                                    VBoxServiceError("ControlThread: Error starting process, rc=%Rrc\n", rc);
                                 /*
                                  * Tell the control thread that it can continue
@@ -1176,11 +1284,4 @@
                                                                           hProcess, pThread->uTimeLimitMS, hPollSet,
                                                                           &pThread->pipeStdInW, &hStdOutR, &hStdErrR);
-
-                                    /*
-                                     * Remove thread from global thread list. After this it's safe to shutdown
-                                     * and deallocate this thread.
-                                     */
-                                    VBoxServiceControlRemoveThread(pThread);
-
                                     /*
                                      * The handles that are no longer in the set have
@@ -1203,5 +1304,5 @@
                                 else /* Something went wrong; report error! */
                                 {
-                                    VBoxServiceError("ControlThead: Could not start process '%s' (CID: %u)! Error: %Rrc\n",
+                                    VBoxServiceError("ControlThread: Could not start process '%s' (CID: %u)! Error: %Rrc\n",
                                                      pThread->pszCmd, pThread->uContextID, rc);
 
@@ -1210,5 +1311,5 @@
                                                                           NULL /* pvData */, 0 /* cbData */);
                                     if (RT_FAILURE(rc2))
-                                        VBoxServiceError("ControlThead: Could not report process start error! Error: %Rrc (process error %Rrc)\n",
+                                        VBoxServiceError("ControlThread: Could not report process start error! Error: %Rrc (process error %Rrc)\n",
                                                          rc2, rc);
                                 }
@@ -1238,10 +1339,10 @@
     if (pThread->uClientID)
     {
-        VBoxServiceVerbose(3, "ControlThead: [PID %u]: Cancelling pending waits (client ID=%u)\n",
+        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Cancelling pending waits (client ID=%u)\n",
                            pThread->uPID, pThread->uClientID);
         int rc2 = VbglR3GuestCtrlCancelPendingWaits(pThread->uClientID);
         if (RT_FAILURE(rc2))
         {
-            VBoxServiceError("ControlThead: [PID %u]: Cancelling pending waits failed; rc=%Rrc\n",
+            VBoxServiceError("ControlThread: [PID %u]: Cancelling pending waits failed; rc=%Rrc\n",
                              pThread->uPID, rc2);
             if (RT_SUCCESS(rc))
@@ -1250,11 +1351,11 @@
 
         /* Disconnect from guest control service. */
-        VBoxServiceError("ControlThead: [PID %u]: Disconnecting (client ID=%u) ...\n",
-                         pThread->uPID, pThread->uClientID);
+        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Disconnecting (client ID=%u) ...\n",
+                           pThread->uPID, pThread->uClientID);
         VbglR3GuestCtrlDisconnect(pThread->uClientID);
         pThread->uClientID = 0;
     }
 
-    VBoxServiceVerbose(3, "ControlThead: [PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n",
+    VBoxServiceVerbose(3, "ControlThread: [PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n",
                        pThread->uPID, pThread->pszCmd, rc);
 
@@ -1268,5 +1369,11 @@
         RTThreadUserSignal(RTThreadSelf());
 
-    int rc2 = vboxServiceControlThreadShutdown(pThread);
+    /*
+     * Remove thread from global thread list. After this it's safe to shutdown
+     * and deallocate this thread.
+     */
+    VBoxServiceControlRemoveThread(pThread);
+
+    int rc2 = vboxServiceControlThreadFree(pThread);
     if (RT_SUCCESS(rc))
         rc = rc2;
@@ -1348,10 +1455,10 @@
         if (RT_FAILURE(rc))
         {
-            VBoxServiceError("ControlThead: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
+            VBoxServiceError("ControlThread: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
                              rc, pThread);
         }
         else
         {
-            VBoxServiceVerbose(4, "ControlThead: Waiting for thread to initialize ...\n");
+            VBoxServiceVerbose(4, "ControlThread: Waiting for thread to initialize ...\n");
 
             /* Wait for the thread to initialize. */
@@ -1359,5 +1466,5 @@
             if (ASMAtomicReadBool(&pThread->fShutdown))
             {
-                VBoxServiceError("ControlThead: Thread for process \"%s\" failed to start!\n", pszCmd);
+                VBoxServiceError("ControlThread: Thread for process \"%s\" failed to start!\n", pszCmd);
                 rc = VERR_GENERAL_FAILURE;
             }
@@ -1380,44 +1487,4 @@
 
 /**
- * Assigns a valid PID to a guest control thread and also checks if there already was
- * another (stale) guest process which was using that PID before and destroys it.
- *
- * @return  IPRT status code.
- * @param   pData          Pointer to guest control execution thread data.
- * @param   uPID           PID to assign to the specified guest control execution thread.
- */
-int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)
-{
-    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
-    AssertReturn(uPID, VERR_INVALID_PARAMETER);
-
-    int rc = VINF_SUCCESS;
-
-    /* Search an old thread using the desired PID and shut it down completely -- it's
-     * not used anymore. */
-    PVBOXSERVICECTRLTHREAD pOldThread = VBoxServiceControlGetThreadByPID(uPID);
-    if (   pOldThread
-        && pOldThread != pThread)
-    {
-        PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pOldThread->Node, VBOXSERVICECTRLTHREAD, Node);
-
-        VBoxServiceVerbose(3, "ControlThead: PID %u was used before, shutting down stale exec thread ...\n",
-                           uPID);
-        rc = vboxServiceControlThreadShutdown(pOldThread);
-        if (RT_FAILURE(rc))
-        {
-            VBoxServiceVerbose(3, "ControlThead: Unable to shut down stale exec thread, rc=%Rrc\n", rc);
-            /* Keep going. */
-        }
-    }
-
-    /* Assign PID to current thread. */
-    pThread->uPID = uPID;
-
-    return rc;
-}
-
-
-/**
  * Performs a request to a specific (formerly started) guest process and waits
  * for its response.
@@ -1433,111 +1500,60 @@
     /* Rest in pRequest is optional (based on the request type). */
 
-    VBoxServiceVerbose(4, "ControlThead: Performing PID=%u, enmType=%u, pvData=0x%p, cbData=%u ...\n",
-                       uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
-
-    int rc;
-    const PVBOXSERVICECTRLTHREAD pThread = VBoxServiceControlGetThreadByPID(uPID);
-    if (   pThread
-        && !ASMAtomicReadBool(&pThread->fStopped))
-    {
-        rc = RTCritSectEnter(&pThread->CritSect);
+    int rc = VINF_SUCCESS;
+    const PVBOXSERVICECTRLTHREAD pThread = VBoxServiceControlGetThreadLocked(uPID);
+    if (pThread)
+    {
+        /* Set request result to some defined state in case
+         * it got cancelled. */
+        pRequest->rc = VERR_CANCELLED;
+
+        /* Set request structure pointer. */
+        pThread->pRequest = pRequest;
+
+        /** @todo To speed up simultaneous guest process handling we could add a worker threads
+         *        or queue in order to wait for the request to happen. Later. */
+
+        /* Wake up guest thrad by sending a wakeup byte to the notification pipe so
+         * that RTPoll unblocks (returns) and we then can do our requested operation. */
+        if (pThread->hNotificationPipeW == NIL_RTPIPE)
+            rc = VERR_BROKEN_PIPE;
+        size_t cbWritten;
         if (RT_SUCCESS(rc))
-        {
-            /* Set request structure pointer. */
-            pThread->pRequest = pRequest;
-
-            /** @todo To speed up simultaneous guest process handling we could add a worker threads
-             *        or queue in order to wait for the request to happen. Later. */
-
-            /* Wake up guest thrad by sending a wakeup byte to the notification pipe so
-             * that RTPoll unblocks (returns) and we then can do our requested operation. */
-            if (pThread->hNotificationPipeW == NIL_RTPIPE)
-                rc = VERR_BROKEN_PIPE;
-            size_t cbWritten;
+            rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten);
+
+        if (   RT_SUCCESS(rc)
+            && cbWritten)
+        {
+            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n",
+                               uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
+            /* Wait on the request to get completed (or we are asked to abort/shutdown). */
+            rc = RTSemEventMultiWait(pThread->RequestEvent, RT_INDEFINITE_WAIT);
             if (RT_SUCCESS(rc))
-                rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten);
-
-            /* Make sure we leave the critical section before doing the wait. */
-            int rc2 = RTCritSectLeave(&pThread->CritSect);
-            AssertRCReturn(rc2, rc2);
-
-            if (RT_SUCCESS(rc) && cbWritten)
             {
-                VBoxServiceVerbose(4, "ControlThead: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n",
-                                   uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
-                /* Wait on the request to get completed (or we are asked to abort/shutdown). */
-                rc = RTSemEventMultiWait(pThread->RequestEvent, RT_INDEFINITE_WAIT);
-                if (RT_SUCCESS(rc))
-                {
-                    VBoxServiceVerbose(4, "ControlThead: [PID %u]: Performed with rc=%Rrc, cbData=%u\n",
-                                       uPID, pRequest->rc, pRequest->cbData);
-
-                    rc = RTCritSectEnter(&pThread->CritSect);
-                    if (RT_SUCCESS(rc))
-                    {
-                        /* Give back overall request result. */
-                        rc = pRequest->rc;
-
-                        /* Reset the semaphore. */
-                        rc2 = RTSemEventMultiReset(pThread->RequestEvent);
-                        if (RT_FAILURE(rc2))
-                            VBoxServiceError("ControlThead: Unable to reset request event, rc=%Rrc\n", rc2);
-
-                        rc2 = RTCritSectLeave(&pThread->CritSect);
-                        AssertRCReturn(rc2, rc2);
-                    }
-                }
+                VBoxServiceVerbose(4, "ControlThread: [PID %u]: Performed with rc=%Rrc, cbData=%u\n",
+                                   uPID, pRequest->rc, pRequest->cbData);
+
+                /* Give back overall request result. */
+                rc = pRequest->rc;
+
+                /* Reset the semaphore. */
+                int rc2 = RTSemEventMultiReset(pThread->RequestEvent);
+                if (RT_FAILURE(rc2))
+                    VBoxServiceError("ControlThread: [PID %u]: Unable to reset request event, rc=%Rrc\n",
+                                     uPID, rc2);
             }
-        }
+            else
+                VBoxServiceError("ControlThread: [PID %u]: Wait failed, rc=%Rrc\n",
+                                 uPID, rc);
+        }
+
+        VBoxServiceControlThreadUnlock(pThread);
     }
     else /* PID not found! */
         rc = VERR_NOT_FOUND;
 
-    VBoxServiceVerbose(4, "ControlThead: Performed PID=%u, enmType=%u, pvData=0x%p, cbData=%u with rc=%Rrc\n",
-                       uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData, rc);
-    return rc;
-}
-
-
-/**
- * Shuts down a guest thread.
- *
- * @return  IPRT status code.
- * @param   pThread                 Thread to shut down.
- */
-static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread)
-{
-    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
-
-    int rc = RTCritSectEnter(&pThread->CritSect);
-    if (RT_SUCCESS(rc))
-    {
-        VBoxServiceVerbose(3, "ControlThead: [PID %u]: Shutting down ...\n",
-                           pThread->uPID);
-
-        /*
-         * Destroy thread-specific data.
-         */
-        vboxServiceControlThreadFree(pThread);
-
-        /* Set stopped status. */
-        ASMAtomicXchgBool(&pThread->fStopped, true);
-
-        rc = RTCritSectLeave(&pThread->CritSect);
-    }
-
-    /*
-     * Destroy other thread data.
-     */
-    if (RTCritSectIsInitialized(&pThread->CritSect))
-        RTCritSectDelete(&pThread->CritSect);
-
-    /*
-     * Destroy thread structure as final step.
-     */
-    RTMemFree(pThread);
-    pThread = NULL;
-
-    return rc;
-}
-
+    VBoxServiceVerbose(3, "ControlThread: [PID %u]: Performed enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n",
+                       uPID, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);
+    return rc;
+}
+
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h	(revision 39417)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h	(revision 39418)
@@ -171,4 +171,7 @@
     /** Payload data; a pre-allocated data buffer for input/output. */
     void                      *pvData;
+    /** The context ID which is required to complete the
+     *  request. */
+    uint32_t                   uCID;
     /** The overall result of the operation. */
     int                        rc;
@@ -230,4 +233,15 @@
 /** Pointer to thread data. */
 typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD;
+
+/**
+ * Request types to perform on a started guest process.
+ */
+typedef enum VBOXSERVICECTRLTHREADSTATUS
+{
+    /** Unknown status. Do not use / should not happen. */
+    VBOXSERVICECTRLTHREADSTATUS_UNKNOWN          = 0,
+    VBOXSERVICECTRLTHREADSTATUS_STARTED          = 100,
+    VBOXSERVICECTRLTHREADSTATUS_STOPPED          = 200
+} VBOXSERVICECTRLTHREADSTATUS;
 #endif /* VBOX_WITH_GUEST_CONTROL */
 #ifdef VBOX_WITH_GUEST_PROPS
@@ -329,7 +343,10 @@
 extern int          VBoxServiceControlHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms, size_t cbMaxBufSize);
 extern int          VBoxServiceControlHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms);
-extern PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadByPID(uint32_t uPID);
-extern void         VBoxServiceControlRemoveThread(PVBOXSERVICECTRLTHREAD pThread);
+extern const PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadLocked(uint32_t uPID);
+extern void         VBoxServiceControlThreadUnlock(const PVBOXSERVICECTRLTHREAD pThread);
+extern int          VBoxServiceControlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID);
+extern void         VBoxServiceControlRemoveThread(const PVBOXSERVICECTRLTHREAD pThread);
 /* Guest process functions. */
+extern VBOXSERVICECTRLTHREADSTATUS VBoxServiceControlThreadGetStatus(const PVBOXSERVICECTRLTHREAD pThread);
 extern int          VBoxServiceControlThreadStart(uint32_t uClientID, uint32_t uContext,
                                                   const char *pszCmd, uint32_t uFlags,
@@ -338,5 +355,5 @@
                                                   const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS,
                                                   PRTLISTNODE *ppNode);
-int                 VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);
+extern int          VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);
 extern int          VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread);
 extern int          VBoxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread, RTMSINTERVAL msTimeout);
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 39417)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 39418)
@@ -570,9 +570,10 @@
 
             case GETOPTDEF_EXEC_WAITFORSTDOUT:
-                fWaitForExit = true;
-                fWaitForStdOut = true;
+                fExecFlags |= ExecuteProcessFlag_WaitForStdOut;
+                fWaitForExit = fWaitForStdOut = true;
                 break;
 
             case GETOPTDEF_EXEC_WAITFORSTDERR:
+                fExecFlags |= ExecuteProcessFlag_WaitForStdErr;
                 fWaitForExit = (fOutputFlags |= ProcessOutputFlag_StdErr) ? true : false;
                 break;
@@ -662,4 +663,8 @@
         if (fCancelable)
             ctrlSignalHandlerInstall();
+
+        vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */);
+        if (RT_FAILURE(vrc))
+            RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc);
 
         /* Wait for process to exit ... */
@@ -711,4 +716,8 @@
                     if (cbOutputData > 0)
                     {
+                        BYTE *pBuf = aOutputData.raw();
+                        AssertPtr(pBuf);
+                        pBuf[cbOutputData - 1] = 0; /* Properly terminate buffer. */
+
                         /** @todo r=bird: Use a VFS I/O stream filter for doing this, it's a
                         *        generic problem and the new VFS APIs will handle it more
@@ -721,19 +730,34 @@
                          * Windows. Otherwise we end up with CR/CR/LF on Windows.
                          */
-                        ULONG cbOutputDataPrint = cbOutputData;
-                        for (BYTE *s = aOutputData.raw(), *d = s;
-                             s - aOutputData.raw() < (ssize_t)cbOutputData;
-                             s++, d++)
+
+                        char *pszBufUTF8;
+                        vrc = RTStrCurrentCPToUtf8(&pszBufUTF8, (const char*)aOutputData.raw());
+                        if (RT_SUCCESS(vrc))
                         {
-                            if (*s == '\r')
+                            cbOutputData = strlen(pszBufUTF8);
+
+                            ULONG cbOutputDataPrint = cbOutputData;
+                            for (char *s = pszBufUTF8, *d = s;
+                                 s - pszBufUTF8 < (ssize_t)cbOutputData;
+                                 s++, d++)
                             {
-                                /* skip over CR, adjust destination */
-                                d--;
-                                cbOutputDataPrint--;
+                                if (*s == '\r')
+                                {
+                                    /* skip over CR, adjust destination */
+                                    d--;
+                                    cbOutputDataPrint--;
+                                }
+                                else if (s != d)
+                                    *d = *s;
                             }
-                            else if (s != d)
-                                *d = *s;
+
+                            vrc = RTStrmWrite(g_pStdOut, pszBufUTF8, cbOutputDataPrint);
+                            if (RT_FAILURE(vrc))
+                                RTMsgError("Unable to write output, rc=%Rrc\n", vrc);
+
+                            RTStrFree(pszBufUTF8);
                         }
-                        RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);
+                        else
+                            RTMsgError("Unable to convert output, rc=%Rrc\n", vrc);
                     }
                 }
@@ -2240,5 +2264,5 @@
     AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
 
-#ifdef DEBUG_andy
+#ifdef DEBUG_andy_disabled
     if (RT_FAILURE(tstTranslatePath()))
         return RTEXITCODE_FAILURE;
@@ -2290,5 +2314,5 @@
 
         ctrlUninitVM(pArg);
-        return rcExit;
+        return RT_FAILURE(rcExit) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
     }
     return RTEXITCODE_FAILURE;
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 39417)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 39418)
@@ -8438,5 +8438,5 @@
   <enum
     name="ExecuteProcessFlag"
-    uuid="286ceb91-5f66-4c96-9845-4483e90e00ae"
+    uuid="1c49b831-b2c7-4a30-97dd-999a2e2cbf90"
     >
     <desc>
@@ -8455,8 +8455,14 @@
     </const>
     <const name="Hidden"                  value="4">
-      <desc>Don't show the started process according to the guest OS guidelines.</desc>
+      <desc>Do not show the started process according to the guest OS guidelines.</desc>
     </const>
     <const name="NoProfile"               value="8">
       <desc>Do not use the user's profile data when exeuting a process. Only available for Windows guests.</desc>
+    </const>
+    <const name="WaitForStdOut"           value="16">
+      <desc>The guest process waits until all data from stdout is read out.</desc>
+    </const>
+    <const name="WaitForStdErr"           value="32">
+      <desc>The guest process waits until all data from stderr is read out.</desc>
     </const>
   </enum>
Index: /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 39417)
+++ /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 39418)
@@ -121,4 +121,6 @@
     uint32_t GetOffset();
 
+    uint32_t GetSize();
+
     int ParseBlock(GuestProcessStreamBlock &streamBlock);
 
Index: /trunk/src/VBox/Main/include/GuestImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestImpl.h	(revision 39417)
+++ /trunk/src/VBox/Main/include/GuestImpl.h	(revision 39418)
@@ -153,4 +153,6 @@
                                   ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
                                   IN_BSTR aUsername, IN_BSTR aPassword,
+                                  ULONG uFlagsToAdd,
+                                  GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr,
                                   IProgress **aProgress, ULONG *aPID);
     HRESULT executeProcessInternal(IN_BSTR aCommand, ULONG aFlags,
@@ -158,9 +160,12 @@
                                    IN_BSTR aUsername, IN_BSTR aPassword,
                                    ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress, int *pRC);
+    HRESULT getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS,
+                                     LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC);
     HRESULT executeProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID);
     HRESULT executeStreamQueryFsObjInfo(IN_BSTR aObjName,GuestProcessStreamBlock &streamBlock, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttribs);
-    int     executeStreamDrain(ULONG aPID, GuestProcessStream &stream);
-    int     executeStreamGetNextBlock(ULONG aPID, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
-    HRESULT executeStreamParse(ULONG aPID, GuestCtrlStreamObjects &streamObjects);
+    int     executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream &stream);
+    int     executeStreamGetNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
+    int     executeStreamParseNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
+    HRESULT executeStreamParse(ULONG ulPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects);
     HRESULT executeWaitForStatusChange(ULONG uPID, ULONG uTimeoutMS, ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode);
     // Internal guest file functions
@@ -229,7 +234,6 @@
     typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS >::const_iterator GuestProcessMapIterConst;
 
-    int processAdd(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
-    int processGetByPID(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess);
-    int processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
+    int  processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess);
+    int  processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
 
     // Internal guest directory representation.
Index: /trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp	(revision 39417)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp	(revision 39418)
@@ -318,4 +318,9 @@
 }
 
+uint32_t GuestProcessStream::GetSize()
+{
+    return m_cbSize;
+}
+
 /**
  * Tries to parse the next upcoming pair block within the internal
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 39417)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 39418)
@@ -162,16 +162,12 @@
     AssertReturnVoid(uContextID);
 
-    LogFlowFunc(("Destroying callback with CID=%u ...\n", uContextID));
-
-    /* Notify callback (if necessary). */
-    int rc = callbackNotifyEx(uContextID, VERR_CANCELLED,
-                              Guest::tr("VM is shutting down, canceling uncompleted guest requests ..."));
-    AssertRC(rc);
-
     CallbackMapIter it = mCallbackMap.find(uContextID);
     if (it != mCallbackMap.end())
     {
+        LogFlowFunc(("Callback with CID=%u found\n", uContextID));
         if (it->second.pvData)
         {
+            LogFlowFunc(("Destroying callback with CID=%u ...\n", uContextID));
+
             callbackFreeUserData(it->second.pvData);
             it->second.cbData = 0;
@@ -385,5 +381,5 @@
 
 /**
- * TODO
+ * Notifies a specified callback about its final status.
  *
  * @return  IPRT status code.
@@ -395,6 +391,8 @@
 {
     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
-
-    LogFlowFunc(("Notifying callback with CID=%u, iRC=%d, pszMsg=%s ...\n",
+    if (RT_FAILURE(iRC))
+        AssertReturn(pszMessage, VERR_INVALID_PARAMETER);
+
+    LogFlowFunc(("Checking whether callback (CID=%u) needs notification iRC=%Rrc, pszMsg=%s\n",
                  uContextID, iRC, pszMessage ? pszMessage : "<No message given>"));
 
@@ -430,4 +428,7 @@
             && !fCompleted)
         {
+            LogFlowFunc(("Notifying callback with CID=%u, iRC=%Rrc, pszMsg=%s\n",
+                         uContextID, iRC, pszMessage ? pszMessage : "<No message given>"));
+
             /*
              * To get waitForCompletion completed (unblocked) we have to notify it if necessary (only
@@ -437,6 +438,5 @@
              * progress object to become signalled.
              */
-            if (   RT_SUCCESS(iRC)
-                && !pszMessage)
+            if (RT_SUCCESS(iRC))
             {
                 hRC = pProgress->notifyComplete(S_OK);
@@ -444,5 +444,5 @@
             else
             {
-                AssertPtrReturn(pszMessage, VERR_INVALID_PARAMETER);
+
                 hRC = pProgress->notifyComplete(VBOX_E_IPRT_ERROR /* Must not be S_OK. */,
                                                 COM_IIDOF(IGuest),
@@ -450,6 +450,10 @@
                                                 pszMessage);
             }
-        }
-        ComAssertComRC(hRC);
+
+            LogFlowFunc(("Notified callback with CID=%u returned %Rhrc (0x%x)\n",
+                         uContextID, hRC, hRC));
+        }
+        else
+            LogFlowFunc(("Callback with CID=%u already notified\n", uContextID));
 
         /*
@@ -564,4 +568,6 @@
     if (RT_SUCCESS(vrc))
     {
+        LogFlowFunc(("Waiting for callback completion (CID=%u, Stage=%RI32, timeout=%RI32ms) ...\n",
+                     uContextID, lStage, lTimeout));
         HRESULT rc;
         if (lStage < 0)
@@ -579,4 +585,6 @@
     }
 
+    LogFlowFunc(("Callback (CID=%u) completed with rc=%Rrc\n",
+                 uContextID, vrc));
     return vrc;
 }
@@ -603,5 +611,5 @@
      */
 #ifdef DEBUG_andy
-    LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
+    LogFlowFunc(("pvExtension=%p, u32Function=%d, pvParms=%p, cbParms=%d\n",
                  pvExtension, u32Function, pvParms, cbParms));
 #endif
@@ -686,4 +694,7 @@
         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
+        LogFlowFunc(("Execution status (CID=%u, pData=0x%p)\n",
+                     uContextID, pData));
+
         PCALLBACKDATAEXECSTATUS pCallbackData =
             (PCALLBACKDATAEXECSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
@@ -695,16 +706,43 @@
             /** @todo Copy void* buffer contents? */
         }
-        else
-            AssertReleaseMsgFailed(("Process status (PID=%u, CID=%u) does not have allocated callback data!\n",
-                                    pData->u32PID, uContextID));
-    }
-
-    int vrc = VINF_SUCCESS;
+        /* If pCallbackData is NULL this might be an old request for which no user data
+         * might exist anymore. */
+    }
+
+    int vrc = VINF_SUCCESS; /* Function result. */
+    int rcCallback = VINF_SUCCESS; /* Callback result. */
     Utf8Str errMsg;
 
     /* Was progress canceled before? */
-    bool fCbCanceled = callbackIsCanceled(uContextID);
-    if (!fCbCanceled)
-    {
+    bool fCanceled = callbackIsCanceled(uContextID);
+    if (!fCanceled)
+    {
+        /* Handle process map. This needs to be done first in order to have a valid
+         * map in case some callback gets notified a bit below. */
+
+        /* Note: PIDs never get removed here in case the guest process signalled its
+         *       end; instead the next call of GetProcessStatus() will remove the PID
+         *       from the process map after we got the process' final (exit) status.
+         *       See waitpid() for an example. */
+        if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */
+        {
+            switch (pData->u32Status)
+            {
+                /* Interprete u32Flags as the guest process' exit code. */
+                case PROC_STS_TES:
+                case PROC_STS_TOK:
+                    vrc = processSetStatus(pData->u32PID,
+                                           (ExecuteProcessStatus_T)pData->u32Status,
+                                           pData->u32Flags /* Exit code. */, 0 /* Flags. */);
+                    break;
+                /* Just reach through flags. */
+                default:
+                    vrc = processSetStatus(pData->u32PID,
+                                           (ExecuteProcessStatus_T)pData->u32Status,
+                                           0 /* Exit code. */, pData->u32Flags);
+                    break;
+            }
+        }
+
         /* Do progress handling. */
         switch (pData->u32Status)
@@ -725,4 +763,5 @@
                 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
                                     pData->u32Flags);
+                rcCallback = VERR_GENERAL_FAILURE; /** @todo */
                 break;
 
@@ -732,4 +771,5 @@
                 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
                                     pData->u32Flags);
+                rcCallback = VERR_GENERAL_FAILURE; /** @todo */
                 break;
 
@@ -737,4 +777,5 @@
                 LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
                 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
+                rcCallback = VERR_TIMEOUT;
                 break;
 
@@ -742,4 +783,5 @@
                 LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
                 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
+                rcCallback = VERR_TIMEOUT;
                 break;
 
@@ -758,11 +800,32 @@
                 }
                 else
+                {
                     errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
+                    rcCallback = VERR_CANCELLED;
+                }
                 break;
 
             case PROC_STS_ERROR:
-                LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n",
-                        pData->u32PID, pData->u32Flags)); /** @todo Add process name */
+                if (pData->u32PID)
+                {
+                    LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n",
+                            pData->u32PID, pData->u32Flags)); /** @todo Add process name */
+                }
+                else
+                {
+                    switch (pData->u32Flags)
+                    {
+                        case VERR_MAX_PROCS_REACHED:
+                            LogRel(("Guest process could not be started because maximum number of parallel guest processes has been reached\n"));
+                            break;
+
+                        default:
+                            LogRel(("Guest process could not be started because of rc=%Rrc\n",
+                                    pData->u32Flags));
+                    }
+
+                }
                 errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pData->u32Flags);
+                rcCallback = pData->u32Flags; /* Report back rc. */
                 break;
 
@@ -771,67 +834,44 @@
                 break;
         }
-
-        /* Handle process map. */
-        /** @todo What happens on/deal with PID reuse? */
-        /** @todo How to deal with multiple updates at once? */
+    }
+    else
+    {
+        errMsg = Utf8StrFmt(Guest::tr("Process execution canceled"));
+        rcCallback = VERR_CANCELLED;
+    }
+
+    /* Do we need to handle the callback error? */
+    if (RT_FAILURE(rcCallback))
+    {
+        AssertMsg(!errMsg.isEmpty(), ("Error message must not be empty!\n"));
+
+        /* Notify all callbacks which are still waiting on something
+         * which is related to the current PID. */
         if (pData->u32PID)
         {
-            VBOXGUESTCTRL_PROCESS process;
-            vrc = processGetByPID(pData->u32PID, &process);
-            if (vrc == VERR_NOT_FOUND)
-            {
-                /* Not found, add to map. */
-                vrc = processAdd(pData->u32PID,
-                                 (ExecuteProcessStatus_T)pData->u32Status,
-                                 pData->u32Flags /* Contains exit code. */,
-                                 0 /*Flags. */);
-                AssertRC(vrc);
-            }
-            else if (RT_SUCCESS(vrc))
-            {
-                /* Process found, update process map. */
-                vrc = processSetStatus(pData->u32PID,
-                                       (ExecuteProcessStatus_T)pData->u32Status,
-                                       pData->u32Flags /* Contains exit code. */,
-                                       0 /*Flags. */);
-                AssertRC(vrc);
-            }
-            else
-                AssertReleaseMsgFailed(("Process was neither found nor absent!?\n"));
-        }
-    }
-    else
-        errMsg = Utf8StrFmt(Guest::tr("Process execution canceled"));
-
-    if (!callbackIsComplete(uContextID))
-    {
-        if (   errMsg.length()
-            || fCbCanceled) /* If canceled we have to report E_FAIL! */
-        {
-            /* Notify all callbacks which are still waiting on something
-             * which is related to the current PID. */
-            if (pData->u32PID)
-            {
-                vrc = callbackNotifyAllForPID(pData->u32PID, VERR_GENERAL_FAILURE, errMsg.c_str());
-                if (RT_FAILURE(vrc))
-                    LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
-                                 pData->u32PID));
-            }
-
-            /* Let the caller know what went wrong ... */
-            int rc2 = callbackNotifyEx(uContextID, VERR_GENERAL_FAILURE, errMsg.c_str());
+            int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
             if (RT_FAILURE(rc2))
             {
-                LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
-                             uContextID, pData->u32PID));
-
+                LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
+                             pData->u32PID));
                 if (RT_SUCCESS(vrc))
                     vrc = rc2;
             }
-            LogFlowFunc(("Process (CID=%u, status=%u) reported error: %s\n",
-                         uContextID, pData->u32Status, errMsg.c_str()));
-        }
-    }
-    LogFlowFunc(("Returned with rc=%Rrc\n", vrc));
+        }
+
+        /* Let the caller know what went wrong ... */
+        int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
+        if (RT_FAILURE(rc2))
+        {
+            LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
+                         uContextID, pData->u32PID));
+            if (RT_SUCCESS(vrc))
+                vrc = rc2;
+        }
+        LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n",
+                     uContextID, pData->u32Status, errMsg.c_str()));
+    }
+    LogFlowFunc(("Returned with rc=%Rrc, rcCallback=%Rrc\n",
+                 vrc, rcCallback));
     return vrc;
 }
@@ -851,4 +891,7 @@
         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
+        LogFlowFunc(("Output status (CID=%u, pData=0x%p)\n",
+                     uContextID, pData));
+
         PCALLBACKDATAEXECOUT pCallbackData =
             (PCALLBACKDATAEXECOUT)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
@@ -878,7 +921,6 @@
             }
         }
-        else
-            AssertReleaseMsgFailed(("Process output status (PID=%u, CID=%u) does not have allocated callback data!\n",
-                                    pData->u32PID, uContextID));
+        /* If pCallbackData is NULL this might be an old request for which no user data
+         * might exist anymore. */
     }
 
@@ -909,4 +951,7 @@
         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
+        LogFlowFunc(("Input status (CID=%u, pData=0x%p)\n",
+                     uContextID, pData));
+
         PCALLBACKDATAEXECINSTATUS pCallbackData =
             (PCALLBACKDATAEXECINSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
@@ -915,11 +960,10 @@
             /* Save bytes processed. */
             pCallbackData->cbProcessed = pData->cbProcessed;
-            pCallbackData->u32Status = pData->u32Status;
-            pCallbackData->u32Flags = pData->u32Flags;
-            pCallbackData->u32PID = pData->u32PID;
-        }
-        else
-            AssertReleaseMsgFailed(("Process input status (PID=%u, CID=%u) does not have allocated callback data!\n",
-                                    pData->u32PID, uContextID));
+            pCallbackData->u32Status   = pData->u32Status;
+            pCallbackData->u32Flags    = pData->u32Flags;
+            pCallbackData->u32PID      = pData->u32PID;
+        }
+        /* If pCallbackData is NULL this might be an old request for which no user data
+         * might exist anymore. */
     }
 
@@ -936,17 +980,59 @@
     Assert(uContextID);
 
-    return callbackNotifyEx(uContextID, S_OK,
+    LogFlowFunc(("Client disconnected (CID=%u)\n,", uContextID));
+
+    return callbackNotifyEx(uContextID, VERR_CANCELLED,
                             Guest::tr("Client disconnected"));
 }
 
-int Guest::processAdd(uint32_t u32PID, ExecuteProcessStatus_T enmStatus,
-                      uint32_t uExitCode, uint32_t uFlags)
+/**
+ * Gets guest process information. Removes the process from the map
+ * after the process was marked as exited/terminated.
+ *
+ * @return  IPRT status code.
+ * @param   u32PID
+ * @param   pProcess
+ */
+int Guest::processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess)
 {
     AssertReturn(u32PID, VERR_INVALID_PARAMETER);
 
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
+    if (it != mGuestProcessMap.end())
+    {
+        if (pProcess)
+        {
+            pProcess->mStatus   = it->second.mStatus;
+            pProcess->mExitCode = it->second.mExitCode;
+            pProcess->mFlags    = it->second.mFlags;
+        }
+
+        /* If the is marked as stopped/terminated
+         * remove it from the map. */
+        if (it->second.mStatus != ExecuteProcessStatus_Started)
+            mGuestProcessMap.erase(it);
+
+        return VINF_SUCCESS;
+    }
+
+    return VERR_NOT_FOUND;
+}
+
+int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
+{
+    AssertReturn(u32PID, VERR_INVALID_PARAMETER);
+
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    GuestProcessMapIterConst it = mGuestProcessMap.find(u32PID);
-    if (it == mGuestProcessMap.end())
+    GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
+    if (it != mGuestProcessMap.end())
+    {
+        it->second.mStatus = enmStatus;
+        it->second.mExitCode = uExitCode;
+        it->second.mFlags = uFlags;
+    }
+    else
     {
         VBOXGUESTCTRL_PROCESS process;
@@ -957,48 +1043,7 @@
 
         mGuestProcessMap[u32PID] = process;
-
-        return VINF_SUCCESS;
-    }
-
-    return VERR_ALREADY_EXISTS;
-}
-
-int Guest::processGetByPID(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess)
-{
-    AssertReturn(u32PID, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pProcess, VERR_INVALID_PARAMETER);
-
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    GuestProcessMapIterConst it = mGuestProcessMap.find(u32PID);
-    if (it != mGuestProcessMap.end())
-    {
-        pProcess->mStatus = it->second.mStatus;
-        pProcess->mExitCode = it->second.mExitCode;
-        pProcess->mFlags = it->second.mFlags;
-
-        return VINF_SUCCESS;
-    }
-
-    return VERR_NOT_FOUND;
-}
-
-int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
-{
-    AssertReturn(u32PID, VERR_INVALID_PARAMETER);
-
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
-    if (it != mGuestProcessMap.end())
-    {
-        it->second.mStatus = enmStatus;
-        it->second.mExitCode = uExitCode;
-        it->second.mFlags = uFlags;
-
-        return VINF_SUCCESS;
-    }
-
-    return VERR_NOT_FOUND;
+    }
+
+    return VINF_SUCCESS;
 }
 
@@ -1080,4 +1125,5 @@
  * @param   aUsername               Username to execute tool under.
  * @param   aPassword               The user's password.
+ * @param   uFlagsToAdd             ExecuteProcessFlag flags to add to the execution operation.
  * @param   aProgress               Pointer which receives the tool's progress object. Optional.
  * @param   aPID                    Pointer which receives the tool's PID. Optional.
@@ -1086,4 +1132,6 @@
                                      ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
                                      IN_BSTR aUsername, IN_BSTR aPassword,
+                                     ULONG uFlagsToAdd,
+                                     GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr,
                                      IProgress **aProgress, ULONG *aPID)
 {
@@ -1091,60 +1139,69 @@
     ULONG uPID;
 
+    ULONG uFlags =   ExecuteProcessFlag_Hidden
+                   | ExecuteProcessFlag_WaitForProcessStartOnly;
+    if (uFlagsToAdd)
+        uFlags |= uFlagsToAdd;
+
+    bool fWaitForOutput = false;
+    if (   (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
+            && pObjStdOut)
+        || (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
+            && pObjStdErr))
+    {
+        fWaitForOutput = true;
+    }
+
     HRESULT rc = ExecuteProcess(aTool,
-                                ExecuteProcessFlag_Hidden,
+                                uFlags,
                                 ComSafeArrayInArg(aArguments),
                                 ComSafeArrayInArg(aEnvironment),
                                 aUsername, aPassword,
-                                5 * 1000 /* Wait 5s for getting the process started. */,
+                                0 /* No timeout. */,
                                 &uPID, progressTool.asOutParam());
+    if (   SUCCEEDED(rc)
+        && fWaitForOutput)
+    {
+        BOOL fCompleted;
+        while (   SUCCEEDED(progressTool->COMGETTER(Completed)(&fCompleted))
+               && !fCompleted)
+        {
+            BOOL fCanceled;
+            rc = progressTool->COMGETTER(Canceled)(&fCanceled);
+            ComAssertRC(rc);
+            if (fCanceled)
+            {
+                rc = setError(VBOX_E_IPRT_ERROR,
+                              tr("%s was cancelled"), Utf8Str(aDescription));
+                break;
+            }
+
+            if (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
+                && pObjStdOut)
+            {
+                rc = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
+            }
+
+            if (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
+                && pObjStdErr)
+            {
+                rc = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
+            }
+
+            if (FAILED(rc))
+                break;
+        }
+    }
+
     if (SUCCEEDED(rc))
     {
-        /* Wait for process to exit ... */
-        rc = progressTool->WaitForCompletion(-1);
-        if (FAILED(rc)) return rc;
-
-        BOOL fCompleted = FALSE;
-        BOOL fCanceled = FALSE;
-        progressTool->COMGETTER(Completed)(&fCompleted);
-        if (!fCompleted)
-            progressTool->COMGETTER(Canceled)(&fCanceled);
-
-        if (fCompleted)
-        {
-            ExecuteProcessStatus_T retStatus;
-            ULONG uRetExitCode, uRetFlags;
-            if (SUCCEEDED(rc))
-            {
-                rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
-                if (SUCCEEDED(rc))
-                {
-                    if (uRetExitCode != 0) /* Not equal 0 means some error occured. */
-                    {
-                        /** @todo IPRT exit code to string! */
-                        rc = setError(VBOX_E_IPRT_ERROR,
-                                      tr("%s: Error %u occured"),
-                                      Utf8Str(aDescription).c_str(), uRetExitCode);
-                    }
-                    else /* Return code 0, success. */
-                    {
-                        if (aProgress)
-                        {
-                            /* Return the progress to the caller. */
-                            progressTool.queryInterfaceTo(aProgress);
-                        }
-                        if (aPID)
-                            *aPID = uPID;
-                    }
-                }
-            }
-        }
-        else if (fCanceled)
-        {
-            rc = setError(VBOX_E_IPRT_ERROR,
-                          tr("%s was aborted"), aDescription);
-        }
-        else
-            AssertReleaseMsgFailed(("%s: Operation neither completed nor canceled!?\n",
-                                    Utf8Str(aDescription).c_str()));
+        if (aProgress)
+        {
+            /* Return the progress to the caller. */
+            progressTool.queryInterfaceTo(aProgress);
+        }
+
+        if (aPID)
+            *aPID = uPID;
     }
 
@@ -1267,34 +1324,112 @@
 
 /**
- * Tries to drain the guest's output (from stdout) and fill it into
+ * Tries to drain the guest's output and fill it into
  * a guest process stream object for later usage.
  *
+ * @todo    What's about specifying stderr?
  * @return  IPRT status code.
  * @param   aPID                    PID of process to get the output from.
+ * @param   aFlags                  Which stream to drain (stdout or stderr).
  * @param   stream                  Reference to guest process stream to fill.
  */
-int Guest::executeStreamDrain(ULONG aPID, GuestProcessStream &stream)
+int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream &stream)
 {
     AssertReturn(aPID, VERR_INVALID_PARAMETER);
-
-    /** @todo Should we try to drain the stream harder? */
 
     int rc = VINF_SUCCESS;
     for (;;)
     {
-        SafeArray<BYTE> aOutputData;
-        HRESULT hr = GetProcessOutput(aPID, ProcessOutputFlag_None /* Stdout */,
-                                      10 * 1000 /* Timeout in ms */,
-                                      _64K, ComSafeArrayAsOutParam(aOutputData));
-        if (   SUCCEEDED(hr)
-            && aOutputData.size())
-        {
-            rc = stream.AddData(aOutputData.raw(), aOutputData.size());
-            if (RT_UNLIKELY(RT_FAILURE(rc)))
+        SafeArray<BYTE> aData;
+        HRESULT hr = getProcessOutputInternal(aPID, aFlags,
+                                              0 /* Infinite timeout */,
+                                              _64K, ComSafeArrayAsOutParam(aData), &rc);
+        if (SUCCEEDED(hr))
+        {
+            if (aData.size())
+            {
+                rc = stream.AddData(aData.raw(), aData.size());
+                if (RT_UNLIKELY(RT_FAILURE(rc)))
+                    break;
+            }
+
+            continue; /* Try one more time. */
+        }
+        else /* No more output and/or error! */
+        {
+            if (rc == VERR_NOT_FOUND)
+                rc = VINF_SUCCESS;
+            break;
+        }
+    }
+
+    return rc;
+}
+
+/**
+ * Tries to retrieve the next stream block of a given stream and
+ * drains the process output only as much as needed to get this next
+ * stream block.
+ *
+ * @return  IPRT status code.
+ * @param   ulPID
+ * @param   ulFlags
+ * @param   stream
+ * @param   streamBlock
+ */
+int Guest::executeStreamGetNextBlock(ULONG ulPID,
+                                     ULONG ulFlags,
+                                     GuestProcessStream &stream,
+                                     GuestProcessStreamBlock &streamBlock)
+{
+    AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER);
+
+    bool fDrainStream = true;
+    int rc;
+    do
+    {
+        rc = stream.ParseBlock(streamBlock);
+        if (RT_FAILURE(rc)) /* More data needed or empty buffer? */
+        {
+            if (fDrainStream)
+            {
+                SafeArray<BYTE> aData;
+                HRESULT hr = getProcessOutputInternal(ulPID, ulFlags,
+                                                      0 /* Infinite timeout */,
+                                                      _64K, ComSafeArrayAsOutParam(aData), &rc);
+                if (SUCCEEDED(hr))
+                {
+                    if (aData.size())
+                    {
+                        rc = stream.AddData(aData.raw(), aData.size());
+                        if (RT_UNLIKELY(RT_FAILURE(rc)))
+                            break;
+                    }
+
+                    continue; /* Try one more time. */
+                }
+                else
+                {
+                    /* No more output to drain from stream. */
+                    if (rc == VERR_NOT_FOUND)
+                    {
+                        fDrainStream = false;
+                        continue;
+                    }
+
+                    break;
+                }
+            }
+            else
+            {
+                /* We haved drained the stream as much as we can and reached the
+                 * end of our stream buffer -- that means that there simply is no
+                 * stream block anymore, which is ok. */
+                if (rc == VERR_NO_DATA)
+                    rc = VINF_SUCCESS;
                 break;
-        }
-        else /* No more output and/or error! */
-            break;
-    }
+            }
+        }
+    }
+    while (!streamBlock.GetCount());
 
     return rc;
@@ -1306,30 +1441,25 @@
  *
  * @return  IPRT status code.
- * @param   aPID                    PID of process to get/parse the output from.
+ * @param   ulPID                   PID of process to get/parse the output from.
+ * @param   ulFlags                 ?
  * @param   stream                  Reference to process stream object to use.
  * @param   streamBlock             Reference that receives the next stream block data.
  *
  */
-int Guest::executeStreamGetNextBlock(ULONG aPID, GuestProcessStream &stream,
-                                     GuestProcessStreamBlock &streamBlock)
-{
-    int rc = executeStreamDrain(aPID, stream);
-    if (RT_SUCCESS(rc))
-    {
-        do
-        {
-            rc = stream.ParseBlock(streamBlock);
-            if (streamBlock.GetCount())
-                break; /* We got a block, bail out! */
-        } while (RT_SUCCESS(rc));
-
-        /* In case this was the last block, VERR_NO_DATA is returned.
-         * Overwrite this to get a proper return value for the last block. */
-        if(    streamBlock.GetCount()
-            && rc == VERR_NO_DATA)
-        {
-            rc = VINF_SUCCESS;
-        }
-    }
+int Guest::executeStreamParseNextBlock(ULONG ulPID,
+                                       ULONG ulFlags,
+                                       GuestProcessStream &stream,
+                                       GuestProcessStreamBlock &streamBlock)
+{
+    AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER);
+
+    int rc;
+    do
+    {
+        rc = stream.ParseBlock(streamBlock);
+        if (RT_FAILURE(rc))
+            break;
+    }
+    while (!streamBlock.GetCount());
 
     return rc;
@@ -1342,38 +1472,33 @@
  *
  * @return  HRESULT
- * @param   aPID                    PID of process to get/parse the output from.
+ * @param   ulPID                   PID of process to get/parse the output from.
+ * @param   ulFlags                 ?
  * @param   streamObjects           Reference to a guest stream object structure for
  *                                  storing the parsed data.
  */
-HRESULT Guest::executeStreamParse(ULONG aPID, GuestCtrlStreamObjects &streamObjects)
-{
-    GuestProcessStream guestStream;
-    HRESULT hr = executeStreamDrain(aPID, guestStream);
-    if (SUCCEEDED(hr))
-    {
-        for (;;)
+HRESULT Guest::executeStreamParse(ULONG ulPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects)
+{
+    GuestProcessStream stream;
+    int rc = executeStreamDrain(ulPID, ulFlags, stream);
+    if (RT_SUCCESS(rc))
+    {
+        do
         {
             /* Try to parse the stream output we gathered until now. If we still need more
              * data the parsing routine will tell us and we just do another poll round. */
             GuestProcessStreamBlock curBlock;
-            int vrc = guestStream.ParseBlock(curBlock);
-            if (RT_SUCCESS(vrc))
-            {
-                if (curBlock.GetCount())
-                {
-                    streamObjects.push_back(curBlock);
-                }
-                else
-                    break; /* No more data. */
-            }
-            else /* Everything else would be an error! */
-                hr = setError(VBOX_E_IPRT_ERROR,
-                              tr("Error while parsing guest output (%Rrc)"), vrc);
-        }
-    }
-
-    /** @todo Add check if there now are any sream objects at all! */
-
-    return hr;
+            rc = executeStreamParseNextBlock(ulPID, ulFlags, stream, curBlock);
+            if (RT_SUCCESS(rc))
+                streamObjects.push_back(curBlock);
+        } while (RT_SUCCESS(rc));
+
+        if (rc == VERR_NO_DATA) /* End of data reached. */
+            rc = VINF_SUCCESS;
+    }
+
+    if (RT_FAILURE(rc))
+        return setError(VBOX_E_IPRT_ERROR,
+                        tr("Error while parsing guest output (%Rrc)"), rc);
+    return rc;
 }
 
@@ -1461,5 +1586,7 @@
             && !(aFlags & ExecuteProcessFlag_WaitForProcessStartOnly)
             && !(aFlags & ExecuteProcessFlag_Hidden)
-            && !(aFlags & ExecuteProcessFlag_NoProfile))
+            && !(aFlags & ExecuteProcessFlag_NoProfile)
+            && !(aFlags & ExecuteProcessFlag_WaitForStdOut)
+            && !(aFlags & ExecuteProcessFlag_WaitForStdErr))
         {
             if (pRC)
@@ -1619,5 +1746,5 @@
             if (RT_SUCCESS(vrc))
             {
-                LogFlowFunc(("Waiting for HGCM callback (timeout=%dms) ...\n", aTimeoutMS));
+                LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));
 
                 /*
@@ -1629,5 +1756,5 @@
                 PCALLBACKDATAEXECSTATUS pExecStatus = NULL;
 
-                 /*
+                /*
                  * Wait for the first stage (=0) to complete (that is starting the process).
                  */
@@ -1713,5 +1840,5 @@
     {
         VBOXGUESTCTRL_PROCESS process;
-        int vrc = processGetByPID(aPID, &process);
+        int vrc = processGetStatus(aPID, &process);
         if (RT_SUCCESS(vrc))
         {
@@ -1871,4 +1998,17 @@
 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
 {
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else  /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    return getProcessOutputInternal(aPID, aFlags, aTimeoutMS,
+                                    aSize, ComSafeArrayOutArg(aData), NULL /* rc */);
+#endif
+}
+
+HRESULT Guest::getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS,
+                                        LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC)
+{
 /** @todo r=bird: Eventually we should clean up all the timeout parameters
  *        in the API and have the same way of specifying infinite waits!  */
@@ -1898,11 +2038,12 @@
     try
     {
-        VBOXGUESTCTRL_PROCESS process;
-        int vrc = processGetByPID(aPID, &process);
+        VBOXGUESTCTRL_PROCESS proc;
+        int vrc = processGetStatus(aPID, &proc);
         if (RT_FAILURE(vrc))
+        {
             rc = setError(VBOX_E_IPRT_ERROR,
-                          Guest::tr("Cannot get output from non-existent guest process (PID %u)"), aPID);
-
-        if (SUCCEEDED(rc))
+                          Guest::tr("Guest process (PID %u) does not exist"), aPID);
+        }
+        else
         {
             uint32_t uContextID = 0;
@@ -1979,5 +2120,5 @@
             if (RT_SUCCESS(vrc))
             {
-                LogFlowFunc(("Waiting for HGCM callback (timeout=%dms) ...\n", aTimeoutMS));
+                LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));
 
                 /*
@@ -1987,12 +2128,11 @@
                  */
 
-                PCALLBACKDATAEXECOUT pExecOut = NULL;
-
                 /*
                  * Wait for the first output callback notification to arrive.
                  */
-                vrc = callbackWaitForCompletion(uContextID, -1 /* No staging */, aTimeoutMS);
+                vrc = callbackWaitForCompletion(uContextID, -1 /* No staging required */, aTimeoutMS);
                 if (RT_SUCCESS(vrc))
                 {
+                    PCALLBACKDATAEXECOUT pExecOut = NULL;
                     vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
                                               (void**)&pExecOut, NULL /* Don't need the size. */);
@@ -2042,4 +2182,7 @@
             pProgress.setNull();
         }
+
+        if (pRC)
+            *pRC = vrc;
     }
     catch (std::bad_alloc &)
@@ -2068,5 +2211,5 @@
     {
         VBOXGUESTCTRL_PROCESS process;
-        int vrc = processGetByPID(aPID, &process);
+        int vrc = processGetStatus(aPID, &process);
         if (RT_SUCCESS(vrc))
         {
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp	(revision 39417)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp	(revision 39418)
@@ -126,4 +126,6 @@
                                    ComSafeArrayAsInParam(env),
                                    aUsername, aPassword,
+                                   ExecuteProcessFlag_None,
+                                   NULL, NULL,
                                    NULL /* Progress */, NULL /* PID */);
     }
@@ -301,4 +303,5 @@
     {
         return executeStreamGetNextBlock(it->second.mPID,
+                                         ProcessOutputFlag_None /* StdOut */,
                                          it->second.mStream, streamBlock);
     }
@@ -405,9 +408,12 @@
 
         ULONG uPID;
-        /** @todo Don't wait for tool to finish! Might take a lot of time! */
+        /* We only start the directory listing and requesting stdout data but don't get its
+         * data here; this is done in sequential IGuest::DirectoryRead calls then. */
         hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_LS).raw(), Bstr("Opening directory").raw(),
                                    ComSafeArrayAsInParam(args),
                                    ComSafeArrayAsInParam(env),
                                    aUsername, aPassword,
+                                   ExecuteProcessFlag_WaitForStdOut,
+                                   NULL, NULL,
                                    NULL /* Progress */, &uPID);
         if (SUCCEEDED(hr))
@@ -477,38 +483,36 @@
          */
         ULONG uPID;
+        GuestCtrlStreamObjects stdOut;
         hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying directory information").raw(),
                                    ComSafeArrayAsInParam(args),
                                    ComSafeArrayAsInParam(env),
                                    aUsername, aPassword,
+                                   ExecuteProcessFlag_WaitForStdOut,
+                                   &stdOut, NULL /* stdErr */,
                                    NULL /* Progress */, &uPID);
         if (SUCCEEDED(hr))
         {
-            GuestCtrlStreamObjects streamObjs;
-            hr = executeStreamParse(uPID, streamObjs);
-            if (SUCCEEDED(hr))
+            int rc = VINF_SUCCESS;
+
+            Assert(stdOut.size());
+            const char *pszFsType = stdOut[0].GetString("ftype");
+            if (!pszFsType) /* Attribute missing? */
+                 rc = VERR_NOT_FOUND;
+            if (   RT_SUCCESS(rc)
+                && strcmp(pszFsType, "d")) /* Directory? */
             {
-                int rc = VINF_SUCCESS;
-
-                Assert(streamObjs.size());
-                const char *pszFsType = streamObjs[0].GetString("ftype");
-                if (!pszFsType) /* Attribute missing? */
-                     rc = VERR_NOT_FOUND;
-                if (   RT_SUCCESS(rc)
-                    && strcmp(pszFsType, "d")) /* Directory? */
-                {
-                     rc = VERR_FILE_NOT_FOUND;
-                     /* This is not critical for Main, so don't set hr --
-                      * we will take care of rc then. */
-                }
-                if (   RT_SUCCESS(rc)
-                    && aObjInfo) /* Do we want object details? */
-                {
-                    hr = executeStreamQueryFsObjInfo(aDirectory, streamObjs[0],
-                                                     aObjInfo, enmAddAttribs);
-                }
-
-                if (pRC)
-                    *pRC = rc;
+                 rc = VERR_FILE_NOT_FOUND;
+                 /* This is not critical for Main, so don't set hr --
+                  * we will take care of rc then. */
             }
+            if (   RT_SUCCESS(rc)
+                && aObjInfo) /* Do we want object details? */
+            {
+                hr = executeStreamQueryFsObjInfo(aDirectory, stdOut[0],
+                                                 aObjInfo, enmAddAttribs);
+            }
+
+            if (pRC)
+                *pRC = rc;
         }
     }
@@ -540,22 +544,25 @@
         if (RT_SUCCESS(rc))
         {
-            ComObjPtr <GuestDirEntry> pDirEntry;
-            hr = pDirEntry.createObject();
-            ComAssertComRC(hr);
-
-            Assert(streamBlock.GetCount());
-            hr = pDirEntry->init(this, streamBlock);
-            if (SUCCEEDED(hr))
+            if (streamBlock.GetCount())
             {
-                pDirEntry.queryInterfaceTo(aDirEntry);
+                ComObjPtr <GuestDirEntry> pDirEntry;
+                hr = pDirEntry.createObject();
+                ComAssertComRC(hr);
+
+                Assert(streamBlock.GetCount());
+                hr = pDirEntry->init(this, streamBlock);
+                if (SUCCEEDED(hr))
+                {
+                    pDirEntry.queryInterfaceTo(aDirEntry);
+                }
+                else
+                    hr = setError(VBOX_E_IPRT_ERROR,
+                                  Guest::tr("Failed to init guest directory entry"));
             }
             else
-                hr = setError(VBOX_E_IPRT_ERROR,
-                              Guest::tr("Failed to init guest directory entry"));
-        }
-        else if (rc == VERR_NO_DATA)
-        {
-            /* No more directory entries to read. That's fine. */
-            hr = E_ABORT; /** @todo Find/define a better rc! */
+            {
+                /* No more directory entries to read. That's fine. */
+                hr = E_ABORT; /** @todo Find/define a better rc! */
+            }
         }
         else
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp	(revision 39417)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp	(revision 39418)
@@ -135,36 +135,34 @@
          */
         ULONG uPID;
+        GuestCtrlStreamObjects stdOut;
         hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying file information").raw(),
                                    ComSafeArrayAsInParam(args),
                                    ComSafeArrayAsInParam(env),
                                    aUsername, aPassword,
+                                   ExecuteProcessFlag_WaitForStdOut,
+                                   &stdOut, NULL,
                                    NULL /* Progress */, &uPID);
         if (SUCCEEDED(hr))
         {
-            GuestCtrlStreamObjects streamObjs;
-            hr = executeStreamParse(uPID, streamObjs);
-            if (SUCCEEDED(hr))
+            int rc = VINF_SUCCESS;
+            const char *pszFsType = stdOut[0].GetString("ftype");
+            if (!pszFsType) /* Attribute missing? */
+                rc = VERR_NOT_FOUND;
+            if (   RT_SUCCESS(rc)
+                && strcmp(pszFsType, "-")) /* Regular file? */
             {
-                int rc = VINF_SUCCESS;
-                const char *pszFsType = streamObjs[0].GetString("ftype");
-                if (!pszFsType) /* Attribute missing? */
-                     rc = VERR_NOT_FOUND;
-                if (   RT_SUCCESS(rc)
-                    && strcmp(pszFsType, "-")) /* Regular file? */
-                {
-                     rc = VERR_FILE_NOT_FOUND;
-                     /* This is not critical for Main, so don't set hr --
-                      * we will take care of rc then. */
-                }
-                if (   RT_SUCCESS(rc)
-                    && aObjInfo) /* Do we want object details? */
-                {
-                    hr = executeStreamQueryFsObjInfo(aFile, streamObjs[0],
-                                                     aObjInfo, enmAddAttribs);
-                }
-
-                if (pRC)
-                    *pRC = rc;
+                rc = VERR_FILE_NOT_FOUND;
+                /* This is not critical for Main, so don't set hr --
+                 * we will take care of rc then. */
             }
+            if (   RT_SUCCESS(rc)
+                && aObjInfo) /* Do we want object details? */
+            {
+                hr = executeStreamQueryFsObjInfo(aFile, stdOut[0],
+                                                 aObjInfo, enmAddAttribs);
+            }
+
+            if (pRC)
+                *pRC = rc;
         }
     }
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp	(revision 39417)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp	(revision 39418)
@@ -522,12 +522,13 @@
                  * actual copying, start the guest part now.
                  */
-                rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
-                                            ExecuteProcessFlag_Hidden,
-                                            ComSafeArrayAsInParam(args),
-                                            ComSafeArrayAsInParam(env),
-                                            Bstr(aTask->strUserName).raw(),
-                                            Bstr(aTask->strPassword).raw(),
-                                            5 * 1000 /* Wait 5s for getting the process started. */,
-                                            &uPID, execProgress.asOutParam());
+                rc = pGuest->executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
+                                                   Bstr("Copying file to host").raw(),
+                                                   ComSafeArrayAsInParam(args),
+                                                   ComSafeArrayAsInParam(env),
+                                                   Bstr(aTask->strUserName).raw(),
+                                                   Bstr(aTask->strPassword).raw(),
+                                                   ExecuteProcessFlag_WaitForStdOut,
+                                                   NULL, NULL,
+                                                   execProgress.asOutParam(), &uPID);
                 if (FAILED(rc))
                     rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest);
@@ -551,41 +552,31 @@
                     size_t cbTransfered = 0;
                     SafeArray<BYTE> aOutputData(_64K);
-                    while (SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))))
-                    {
-                        rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
-                                                    10 * 1000 /* Timeout in ms */,
-                                                    _64K, ComSafeArrayAsOutParam(aOutputData));
+                    while (   SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))
+                           && !fCompleted)
+                    {
+                        rc = pGuest->GetProcessOutput(uPID, ProcessOutputFlag_None /* StdOut */,
+                                                      0 /* No timeout. */,
+                                                      _64K, ComSafeArrayAsOutParam(aOutputData));
                         if (SUCCEEDED(rc))
                         {
-                            if (!aOutputData.size())
-                            {
-                                /*
-                                 * Only bitch about an unexpected end of a file when there already
-                                 * was data read from that file. If this was the very first read we can
-                                 * be (almost) sure that this file is not meant to be read by the specified user.
-                                 */
-                                if (   cbTransfered
-                                    && cbToRead)
+                            if (aOutputData.size())
+                            {
+                                vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */);
+                                if (RT_FAILURE(vrc))
                                 {
                                     rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                         Guest::tr("Unexpected end of file \"%s\" (%u bytes left, %u bytes written)"),
-                                                                         aTask->strSource.c_str(), cbToRead, cbTransfered);
+                                                                         Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"),
+                                                                         aTask->strSource.c_str(), cbToRead, vrc);
+                                    break;
                                 }
-                                break;
-                            }
-
-                            vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */);
-                            if (RT_FAILURE(vrc))
-                            {
-                                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
-                                                                     Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"),
-                                                                     aTask->strSource.c_str(), cbToRead, vrc);
-                                break;
-                            }
-
-                            cbToRead -= aOutputData.size();
-                            cbTransfered += aOutputData.size();
-
-                            aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0));
+
+                                cbToRead -= aOutputData.size();
+                                Assert(cbToRead >= 0);
+                                cbTransfered += aOutputData.size();
+
+                                aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0));
+                            }
+
+                            /* Nothing read this time; try next round. */
                         }
                         else
@@ -596,8 +587,21 @@
                     }
 
+                    RTFileClose(hFileDest);
+
+                    if (   cbTransfered
+                        && (cbTransfered != lFileSize))
+                    {
+                        /*
+                         * Only bitch about an unexpected end of a file when there already
+                         * was data read from that file. If this was the very first read we can
+                         * be (almost) sure that this file is not meant to be read by the specified user.
+                         */
+                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
+                                                             Guest::tr("Unexpected end of file \"%s\" (%u bytes total, %u bytes transferred)"),
+                                                             aTask->strSource.c_str(), lFileSize, cbTransfered);
+                    }
+
                     if (SUCCEEDED(rc))
                         aTask->progress->notifyComplete(S_OK);
-
-                    RTFileClose(hFileDest);
                 }
             }
Index: /trunk/src/VBox/Main/src-client/GuestImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 39417)
+++ /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 39418)
@@ -120,6 +120,14 @@
         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-        /* Clean up callback data. */
+        /* Notify left over callbacks that we are about to shutdown ... */
         CallbackMapIter it;
+        for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
+        {
+            int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
+                                       Guest::tr("VM is shutting down, canceling uncompleted guest requests ..."));
+            AssertRC(rc2);
+        }
+
+        /* Destroy left over callback data. */
         for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
             callbackDestroy(it->first);
