Index: /trunk/src/VBox/Main/include/GuestImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestImpl.h	(revision 40684)
+++ /trunk/src/VBox/Main/include/GuestImpl.h	(revision 40685)
@@ -175,12 +175,11 @@
     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 executeSetResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID);
     int     executeStreamQueryFsObjInfo(IN_BSTR aObjName,GuestProcessStreamBlock &streamBlock, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttribs);
-    int     executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream &stream);
+    int     executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream *pStream);
     int     executeStreamGetNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
     int     executeStreamParseNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
     HRESULT executeStreamParse(ULONG uPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects);
-    HRESULT executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS,
-                               ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode);
+    HRESULT executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS);
     // Internal guest file functions
     HRESULT fileExistsInternal(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists);
@@ -211,4 +210,7 @@
         /** Size of user-supplied data. */
         uint32_t                    cbData;
+        /** The host PID. Needed for translating to
+         *  a guest PID. */
+        uint32_t                    uHostPID;
         /** Pointer to user-supplied IProgress. */
         ComObjPtr<Progress>         pProgress;
@@ -219,8 +221,10 @@
 
     int callbackAdd(const PVBOXGUESTCTRL_CALLBACK pCallbackData, uint32_t *puContextID);
+    int callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID);
     void callbackDestroy(uint32_t uContextID);
     void callbackRemove(uint32_t uContextID);
     bool callbackExists(uint32_t uContextID);
     void callbackFreeUserData(void *pvData);
+    uint32_t callbackGetHostPID(uint32_t uContextID);
     int callbackGetUserData(uint32_t uContextID, eVBoxGuestCtrlCallbackType *pEnmType, void **ppvData, size_t *pcbData);
     void* callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData);
@@ -231,5 +235,5 @@
     int callbackNotifyEx(uint32_t uContextID, int iRC, const char *pszMessage);
     int callbackNotifyComplete(uint32_t uContextID);
-    int callbackNotifyAllForPID(uint32_t uPID, int iRC, const char *pszMessage);
+    int callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage);
     int callbackWaitForCompletion(uint32_t uContextID, LONG lStage, LONG lTimeout);
 
@@ -242,6 +246,12 @@
     typedef struct VBOXGUESTCTRL_PROCESS
     {
+        /** The guest PID -- needed for controlling the actual guest
+         *  process which has its own PID (generated by the guest OS). */
+        uint32_t                    mGuestPID;
+        /** The last reported process status. */
         ExecuteProcessStatus_T      mStatus;
+        /** The process execution flags. */
         uint32_t                    mFlags;
+        /** The process' exit code. */
         uint32_t                    mExitCode;
     } VBOXGUESTCTRL_PROCESS, *PVBOXGUESTCTRL_PROCESS;
@@ -250,6 +260,8 @@
     typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS >::const_iterator GuestProcessMapIterConst;
 
-    int  processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess, bool fRemove);
-    int  processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
+    uint32_t processGetGuestPID(uint32_t uHostPID);
+    int  processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess, bool fRemove);
+    int  processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
+                          ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
 
     // Internal guest directory representation.
@@ -259,14 +271,7 @@
         Bstr                        mFilter;
         ULONG                       mFlags;
-        /** Associated PID of started vbox_ls tool. */
+        /** Associated host PID of started vbox_ls tool. */
         ULONG                       mPID;
         GuestProcessStream          mStream;
-#if 0
-        /** Next enetry in our stream objects vector
-         *  to process. */
-        uint32_t                    mNextEntry;
-        /** The guest stream object containing all */
-        GuestCtrlStreamObjects      mStream;
-#endif
     } VBOXGUESTCTRL_DIRECTORY, *PVBOXGUESTCTRL_DIRECTORY;
     typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY > GuestDirectoryMap;
@@ -280,6 +285,7 @@
      * Handler for guest execution control notifications.
      */
-    HRESULT handleErrorCompletion(int rc);
-    HRESULT handleErrorHGCM(int rc);
+    HRESULT setErrorCompletion(int rc);
+    HRESULT setErrorFromProgress(ComPtr<IProgress> pProgress);
+    HRESULT setErrorHGCM(int rc);
 # endif
 
@@ -319,4 +325,6 @@
     /** Next upcoming context ID. */
     volatile uint32_t mNextContextID;
+    /** Next upcoming host PID */
+    volatile uint32_t mNextHostPID;
     /** Next upcoming directory handle ID. */
     volatile uint32_t mNextDirectoryID;
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 40684)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 40685)
@@ -158,4 +158,27 @@
 
 /**
+ * Assigns a host PID to a specified context.
+ * Does not do locking!
+ *
+ * @param   uContextID
+ * @param   uHostPID
+ */
+int Guest::callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID)
+{
+    AssertReturn(uContextID, VERR_INVALID_PARAMETER);
+    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
+
+    int rc = VINF_SUCCESS;
+
+    CallbackMapIter it = mCallbackMap.find(uContextID);
+    if (it == mCallbackMap.end())
+        return VERR_NOT_FOUND;
+
+    it->second.uHostPID = uHostPID;
+
+    return VINF_SUCCESS;
+}
+
+/**
  * Destroys the formerly allocated callback data. The callback then
  * needs to get removed from the callback map via callbackRemove().
@@ -211,4 +234,10 @@
 }
 
+/**
+ * Frees the user data (actual context data) of a callback.
+ * Does not do locking!
+ *
+ * @param   pvData              Data to free.
+ */
 void Guest::callbackFreeUserData(void *pvData)
 {
@@ -218,4 +247,24 @@
         pvData = NULL;
     }
+}
+
+/**
+ * Retrieves the (generated) host PID of a given callback.
+ *
+ * @return  The host PID, if found, 0 otherwise.
+ * @param   uContextID              Context ID to lookup host PID for.
+ * @param   puHostPID               Where to store the host PID.
+ */
+uint32_t Guest::callbackGetHostPID(uint32_t uContextID)
+{
+    AssertReturn(uContextID, VERR_INVALID_PARAMETER);
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    CallbackMapIterConst it = mCallbackMap.find(uContextID);
+    if (it == mCallbackMap.end())
+        return 0;
+
+    return it->second.uHostPID;
 }
 
@@ -256,5 +305,5 @@
 void* Guest::callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData)
 {
-    AssertReturn(uContextID, NULL);
+    /* uContextID can be 0. */
     /* pcbData is optional. */
 
@@ -326,5 +375,6 @@
 bool Guest::callbackIsCanceled(uint32_t uContextID)
 {
-    AssertReturn(uContextID, true);
+    if (!uContextID)
+        return true; /* If no context ID given then take a shortcut. */
 
     ComPtr<IProgress> pProgress;
@@ -468,5 +518,4 @@
             else
             {
-
                 hRC = pProgress->notifyComplete(VBOX_E_IPRT_ERROR /* Must not be S_OK. */,
                                                 COM_IIDOF(IGuest),
@@ -492,14 +541,15 @@
 
 /**
- * TODO
+ * Notifies all callbacks which are assigned to a certain guest PID to set a certain
+ * return/error code and an optional (error) message.
  *
  * @return  IPRT status code.
- * @param   uPID
- * @param   iRC
- * @param   pszMessage
+ * @param   uGuestPID               Guest PID to find all callbacks for.
+ * @param   iRC                     Return (error) code to set for the found callbacks.
+ * @param   pszMessage              Optional (error) message to set.
  */
-int Guest::callbackNotifyAllForPID(uint32_t uPID, int iRC, const char *pszMessage)
-{
-    AssertReturn(uPID, VERR_INVALID_PARAMETER);
+int Guest::callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage)
+{
+    AssertReturn(uGuestPID, VERR_INVALID_PARAMETER);
 
     int vrc = VINF_SUCCESS;
@@ -522,5 +572,5 @@
                 PCALLBACKDATAEXECOUT pItData = (PCALLBACKDATAEXECOUT)it->second.pvData;
                 AssertPtr(pItData);
-                if (pItData->u32PID == uPID)
+                if (pItData->u32PID == uGuestPID)
                     vrc = callbackNotifyEx(it->first, iRC, pszMessage);
                 break;
@@ -534,5 +584,5 @@
                 PCALLBACKDATAEXECINSTATUS pItData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData;
                 AssertPtr(pItData);
-                if (pItData->u32PID == uPID)
+                if (pItData->u32PID == uGuestPID)
                     vrc = callbackNotifyEx(it->first, iRC, pszMessage);
                 break;
@@ -712,5 +762,6 @@
 
     uint32_t uContextID = pData->hdr.u32ContextID;
-    Assert(uContextID);
+    /* The context ID might be 0 in case the guest was not able to fetch
+     * actual command. So we can't do much now but report an error. */
 
     /* Scope write locks as much as possible. */
@@ -744,4 +795,6 @@
         /* 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. */
+
+        uint32_t uHostPID = 0;
 
         /* Note: PIDs never get removed here in case the guest process signalled its
@@ -751,4 +804,7 @@
         if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */
         {
+            uHostPID = callbackGetHostPID(uContextID);
+            Assert(uHostPID);
+
             switch (pData->u32Status)
             {
@@ -756,106 +812,143 @@
                 case PROC_STS_TES:
                 case PROC_STS_TOK:
-                    vrc = processSetStatus(pData->u32PID,
+                    vrc = processSetStatus(uHostPID, pData->u32PID,
                                            (ExecuteProcessStatus_T)pData->u32Status,
-                                           0 /* Exit code. */, pData->u32Flags);
+                                           0 /* Exit code */, pData->u32Flags);
                     break;
                 /* Interprete u32Flags as the guest process' exit code. */
                 default:
-                    vrc = processSetStatus(pData->u32PID,
+                    vrc = processSetStatus(uHostPID, pData->u32PID,
                                            (ExecuteProcessStatus_T)pData->u32Status,
-                                           pData->u32Flags /* Exit code. */, 0 /* Flags. */);
-
+                                           pData->u32Flags /* Exit code */, 0 /* Flags */);
                     break;
             }
         }
 
-        /* Do progress handling. */
-        switch (pData->u32Status)
-        {
-            case PROC_STS_STARTED:
-                vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
-                LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
-                break;
-
-            case PROC_STS_TEN: /* Terminated normally. */
-                vrc = callbackNotifyComplete(uContextID);
-                LogRel(("Guest process (PID %u) exited normally\n", pData->u32PID)); /** @todo Add process name */
-                break;
-
-            case PROC_STS_TEA: /* Terminated abnormally. */
-                LogRel(("Guest process (PID %u) terminated abnormally with exit code = %u\n",
-                        pData->u32PID, pData->u32Flags)); /** @todo Add process name */
-                errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
-                                    pData->u32Flags);
-                rcCallback = VERR_GENERAL_FAILURE; /** @todo */
-                break;
-
-            case PROC_STS_TES: /* Terminated through signal. */
-                LogRel(("Guest process (PID %u) terminated through signal with exit code = %u\n",
-                        pData->u32PID, pData->u32Flags)); /** @todo Add process name */
-                errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
-                                    pData->u32Flags);
-                rcCallback = VERR_GENERAL_FAILURE; /** @todo */
-                break;
-
-            case PROC_STS_TOK:
-                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;
-
-            case PROC_STS_TOA:
-                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;
-
-            case PROC_STS_DWN:
-                LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
-                /*
-                 * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
-                 * our progress object. This is helpful for waiters which rely on the success of our progress object
-                 * even if the executed process was killed because the system/VBoxService is shutting down.
-                 *
-                 * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
-                 */
-                if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
+        if (RT_SUCCESS(vrc))
+        {
+            /* Do progress handling. */
+            switch (pData->u32Status)
+            {
+                case PROC_STS_STARTED:
+                    vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
+                    LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
+                    break;
+
+                case PROC_STS_TEN: /* Terminated normally. */
+                    vrc = callbackNotifyComplete(uContextID);
+                    LogRel(("Guest process (PID %u) exited normally (exit code: %u)\n",
+                            pData->u32PID, pData->u32Flags)); /** @todo Add process name */
+                    break;
+
+                case PROC_STS_TEA: /* Terminated abnormally. */
+                    LogRel(("Guest process (PID %u) terminated abnormally (exit code: %u)\n",
+                            pData->u32PID, pData->u32Flags)); /** @todo Add process name */
+                    errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
+                                        pData->u32Flags);
+                    rcCallback = VERR_GENERAL_FAILURE; /** @todo */
+                    break;
+
+                case PROC_STS_TES: /* Terminated through signal. */
+                    LogRel(("Guest process (PID %u) terminated through signal (exit code: %u)\n",
+                            pData->u32PID, pData->u32Flags)); /** @todo Add process name */
+                    errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
+                                        pData->u32Flags);
+                    rcCallback = VERR_GENERAL_FAILURE; /** @todo */
+                    break;
+
+                case PROC_STS_TOK:
+                    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;
+
+                case PROC_STS_TOA:
+                    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;
+
+                case PROC_STS_DWN:
+                    LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
+                    /*
+                     * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
+                     * our progress object. This is helpful for waiters which rely on the success of our progress object
+                     * even if the executed process was killed because the system/VBoxService is shutting down.
+                     *
+                     * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
+                     */
+                    if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
+                    {
+                        vrc = callbackNotifyComplete(uContextID);
+                    }
+                    else
+                    {
+                        errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
+                        rcCallback = VERR_CANCELLED;
+                    }
+                    break;
+
+                case PROC_STS_ERROR:
                 {
-                    vrc = callbackNotifyComplete(uContextID);
+                    Utf8Str errDetail;
+                    if (pData->u32PID)
+                    {
+                        errDetail = Utf8StrFmt(Guest::tr("Guest process (PID %u) could not be started because of rc=%Rrc"),
+                                               pData->u32PID, pData->u32Flags);
+                    }
+                    else
+                    {
+                        switch (pData->u32Flags) /* u32Flags member contains the IPRT error code from guest side. */
+                        {
+                            case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
+                                errDetail = Utf8StrFmt(Guest::tr("The specified file was not found on guest"));
+                                break;
+
+                            case VERR_PATH_NOT_FOUND:
+                                errDetail = Utf8StrFmt(Guest::tr("Could not resolve path to specified file was not found on guest"));
+                                break;
+
+                            case VERR_BAD_EXE_FORMAT:
+                                errDetail = Utf8StrFmt(Guest::tr("The specified file is not an executable format on guest"));
+                                break;
+
+                            case VERR_AUTHENTICATION_FAILURE:
+                                errDetail = Utf8StrFmt(Guest::tr("The specified user was not able to logon on guest"));
+                                break;
+
+                            case VERR_TIMEOUT:
+                                errDetail = Utf8StrFmt(Guest::tr("The guest did not respond within time"));
+                                break;
+
+                            case VERR_CANCELLED:
+                                errDetail = Utf8StrFmt(Guest::tr("The execution operation was canceled"));
+                                break;
+
+                            case VERR_PERMISSION_DENIED:
+                                errDetail = Utf8StrFmt(Guest::tr("Invalid user/password credentials"));
+                                break;
+
+                            case VERR_MAX_PROCS_REACHED:
+                                errDetail = Utf8StrFmt(Guest::tr("Guest process could not be started because maximum number of parallel guest processes has been reached"));
+                                break;
+
+                            default:
+                                errDetail = Utf8StrFmt(Guest::tr("Guest process reported error %Rrc"), pData->u32Flags);
+                                break;
+                        }
+                    }
+
+                    errMsg = Utf8StrFmt(Guest::tr("Process execution failed: "), pData->u32Flags) + errDetail;
+                    rcCallback = pData->u32Flags; /* Report back guest rc. */
+
+                    LogRel((errMsg.c_str()));
+
+                    break;
                 }
-                else
-                {
-                    errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
-                    rcCallback = VERR_CANCELLED;
-                }
-                break;
-
-            case PROC_STS_ERROR:
-                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;
-
-            default:
-                vrc = VERR_INVALID_PARAMETER;
-                break;
+
+                default:
+                    vrc = VERR_INVALID_PARAMETER;
+                    break;
+            }
         }
     }
@@ -871,27 +964,47 @@
         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)
-        {
-            int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
+        if (uContextID)
+        {
+            /* Notify all callbacks which are still waiting on something
+             * which is related to the current PID. */
+            if (pData->u32PID)
+            {
+                int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
+                if (RT_FAILURE(rc2))
+                {
+                    LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
+                                 pData->u32PID));
+                    if (RT_SUCCESS(vrc))
+                        vrc = rc2;
+                }
+            }
+
+            /* Let the caller know what went wrong ... */
+            int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
             if (RT_FAILURE(rc2))
             {
-                LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
-                             pData->u32PID));
+                LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
+                             uContextID, pData->u32PID));
                 if (RT_SUCCESS(vrc))
                     vrc = rc2;
             }
         }
-
-        /* 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;
-        }
+        else
+        {
+            /* Since we don't know which context exactly failed all we can do is to shutdown
+             * all contexts ... */
+            errMsg = Utf8StrFmt(Guest::tr("Client reported critical error %Rrc -- shutting down"),
+                                pData->u32Flags);
+
+            /* Cancel all callbacks. */
+            CallbackMapIter it;
+            for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
+            {
+                int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
+                                           errMsg.c_str());
+                AssertRC(rc2);
+            }
+        }
+
         LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n",
                      uContextID, pData->u32Status, errMsg.c_str()));
@@ -1011,4 +1124,17 @@
 }
 
+uint32_t Guest::processGetGuestPID(uint32_t uHostPID)
+{
+    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
+    if (it == mGuestProcessMap.end())
+        return 0;
+
+    return it->second.mGuestPID;
+}
+
 /**
  * Gets guest process information. Removes the process from the map
@@ -1016,5 +1142,5 @@
  *
  * @return  IPRT status code.
- * @param   u32PID                  PID of process to get status for.
+ * @param   uHostPID                Host PID of guest process to get status for.
  * @param   pProcess                Where to store the process information. Optional.
  * @param   fRemove                 Flag indicating whether to remove the
@@ -1022,16 +1148,17 @@
  *                                  exited/terminated.
  */
-int Guest::processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess,
+int Guest::processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess,
                             bool fRemove)
 {
-    AssertReturn(u32PID, VERR_INVALID_PARAMETER);
+    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
 
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
+    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
     if (it != mGuestProcessMap.end())
     {
         if (pProcess)
         {
+            pProcess->mGuestPID = it->second.mGuestPID;
             pProcess->mStatus   = it->second.mStatus;
             pProcess->mExitCode = it->second.mExitCode;
@@ -1039,8 +1166,9 @@
         }
 
-        /* If the is marked as stopped/terminated
-         * remove it from the map. */
+        /* Only remove processes from our map when they signalled their final
+         * status. */
         if (   fRemove
-            && it->second.mStatus != ExecuteProcessStatus_Started)
+            && (   it->second.mStatus != ExecuteProcessStatus_Undefined
+                && it->second.mStatus != ExecuteProcessStatus_Started))
         {
             mGuestProcessMap.erase(it);
@@ -1053,16 +1181,29 @@
 }
 
-int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
-{
-    AssertReturn(u32PID, VERR_INVALID_PARAMETER);
+/**
+ * Sets the current status of a guest process.
+ *
+ * @return  IPRT status code.
+ * @param   uHostPID                Host PID of guest process to set status (and guest PID) for.
+ * @param   uGuestPID               Guest PID to assign to the host PID.
+ * @param   enmStatus               Current status to set.
+ * @param   uExitCode               Exit code (if any).
+ * @param   uFlags                  Additional flags.
+ */
+int Guest::processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
+                            ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
+{
+    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
+    /* Assigning a guest PID is optional. */
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
+    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
     if (it != mGuestProcessMap.end())
     {
-        it->second.mStatus = enmStatus;
+        it->second.mGuestPID = uGuestPID;
+        it->second.mStatus   = enmStatus;
         it->second.mExitCode = uExitCode;
-        it->second.mFlags = uFlags;
+        it->second.mFlags    = uFlags;
     }
     else
@@ -1070,9 +1211,13 @@
         VBOXGUESTCTRL_PROCESS process;
 
-        process.mStatus = enmStatus;
+        /* uGuestPID is optional -- the caller could call this function
+         * before the guest process actually was started and a (valid) guest PID
+         * was returned. */
+        process.mGuestPID = uGuestPID;
+        process.mStatus   = enmStatus;
         process.mExitCode = uExitCode;
-        process.mFlags = uFlags;
-
-        mGuestProcessMap[u32PID] = process;
+        process.mFlags    = uFlags;
+
+        mGuestProcessMap[uHostPID] = process;
     }
 
@@ -1080,5 +1225,5 @@
 }
 
-HRESULT Guest::handleErrorCompletion(int rc)
+HRESULT Guest::setErrorCompletion(int rc)
 {
     HRESULT hRC;
@@ -1098,5 +1243,49 @@
 }
 
-HRESULT Guest::handleErrorHGCM(int rc)
+HRESULT Guest::setErrorFromProgress(ComPtr<IProgress> pProgress)
+{
+    BOOL fCompleted;
+    HRESULT rc = pProgress->COMGETTER(Completed)(&fCompleted);
+    ComAssertComRC(rc);
+
+    HRESULT rcProc = S_OK;
+    Utf8Str strError;
+
+    if (!fCompleted)
+    {
+        BOOL fCanceled;
+        rc = pProgress->COMGETTER(Canceled)(&fCanceled);
+        ComAssertComRC(rc);
+
+        strError = fCanceled ? Utf8StrFmt(Guest::tr("Process execution was canceled"))
+                             : Utf8StrFmt(Guest::tr("Process neither completed nor canceled; this shouldn't happen"));
+    }
+    else
+    {
+        rc = pProgress->COMGETTER(ResultCode)(&rcProc);
+        ComAssertComRC(rc);
+
+        if (FAILED(rcProc))
+        {
+            ProgressErrorInfo info(pProgress);
+            strError = info.getText();
+        }
+    }
+
+    if (FAILED(rcProc))
+    {
+        AssertMsg(!strError.isEmpty(), ("Error message must not be empty!\n"));
+        return setErrorInternal(rcProc,
+                                this->getClassIID(),
+                                this->getComponentName(),
+                                strError,
+                                false /* aWarning */,
+                                false /* aLogIt */);
+    }
+
+    return S_OK;
+}
+
+HRESULT Guest::setErrorHGCM(int rc)
 {
     HRESULT hRC;
@@ -1168,5 +1357,5 @@
                                      IProgress **aProgress, ULONG *aPID)
 {
-    ComPtr<IProgress> progressTool;
+    ComPtr<IProgress> pProgress;
     ULONG uPID;
     ULONG uFlags = ExecuteProcessFlag_Hidden;
@@ -1174,5 +1363,5 @@
         uFlags |= uFlagsToAdd;
 
-    bool fWaitForOutput = false;
+    bool fParseOutput = false;
     if (   (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
             && pObjStdOut)
@@ -1180,55 +1369,75 @@
             && pObjStdErr))
     {
-        fWaitForOutput = true;
-    }
-
-    HRESULT rc = ExecuteProcess(aTool,
+        fParseOutput = true;
+    }
+
+    HRESULT hr = ExecuteProcess(aTool,
                                 uFlags,
                                 ComSafeArrayInArg(aArguments),
                                 ComSafeArrayInArg(aEnvironment),
                                 aUsername, aPassword,
-                                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);
-            AssertComRC(rc);
-            if (fCanceled)
-            {
-                rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                   tr("%s was cancelled"), Utf8Str(aDescription).c_str());
-                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))
+                                0 /* No timeout */,
+                                &uPID, pProgress.asOutParam());
+    if (SUCCEEDED(hr))
+    {
+        /* Wait for tool being started. */
+        hr = pProgress->WaitForOperationCompletion( 0 /* Stage, starting the process */,
+                                                   -1 /* No timeout */);
+    }
+
+    if (   SUCCEEDED(hr)
+        && !(uFlags & ExecuteProcessFlag_WaitForProcessStartOnly))
+    {
+        if (!fParseOutput)
+        {
+            if (   !(uFlags & ExecuteProcessFlag_WaitForStdOut)
+                && !(uFlags & ExecuteProcessFlag_WaitForStdErr))
+            {
+                hr = executeWaitForExit(uPID, pProgress, 0 /* No timeout */);
+            }
+        }
+        else
+        {
+            BOOL fCompleted;
+            while (   SUCCEEDED(pProgress->COMGETTER(Completed)(&fCompleted))
+                   && !fCompleted)
+            {
+                BOOL fCanceled;
+                hr = pProgress->COMGETTER(Canceled)(&fCanceled);
+                AssertComRC(hr);
+                if (fCanceled)
+                {
+                    hr = setErrorNoLog(VBOX_E_IPRT_ERROR,
+                                       tr("%s was cancelled"), Utf8Str(aDescription).c_str());
+                    break;
+                }
+
+                if (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
+                    && pObjStdOut)
+                {
+                    hr = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
+                }
+
+                if (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
+                    && pObjStdErr)
+                {
+                    hr = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
+                }
+
+                if (FAILED(hr))
+                    break;
+            }
+        }
+    }
+
+    if (SUCCEEDED(hr))
     {
         if (aProgress)
         {
             /* Return the progress to the caller. */
-            progressTool.queryInterfaceTo(aProgress);
-        }
+            pProgress.queryInterfaceTo(aProgress);
+        }
+        else if (!pProgress.isNull())
+            pProgress.setNull();
 
         if (aPID)
@@ -1236,90 +1445,5 @@
     }
 
-    return rc;
-}
-
-HRESULT Guest::executeProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout,
-                                    PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID)
-{
-    AssertPtrReturn(pExecStatus, E_INVALIDARG);
-    AssertPtrReturn(puPID, E_INVALIDARG);
-
-    HRESULT rc = S_OK;
-
-    /* Did we get some status? */
-    switch (pExecStatus->u32Status)
-    {
-        case PROC_STS_STARTED:
-            /* Process is (still) running; get PID. */
-            *puPID = pExecStatus->u32PID;
-            break;
-
-        /* In any other case the process either already
-         * terminated or something else went wrong, so no PID ... */
-        case PROC_STS_TEN: /* Terminated normally. */
-        case PROC_STS_TEA: /* Terminated abnormally. */
-        case PROC_STS_TES: /* Terminated through signal. */
-        case PROC_STS_TOK:
-        case PROC_STS_TOA:
-        case PROC_STS_DWN:
-            /*
-             * Process (already) ended, but we want to get the
-             * PID anyway to retrieve the output in a later call.
-             */
-            *puPID = pExecStatus->u32PID;
-            break;
-
-        case PROC_STS_ERROR:
-            {
-                int vrc = pExecStatus->u32Flags; /* u32Flags member contains IPRT error code. */
-                if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("The file '%s' was not found on guest"), pszCommand);
-                else if (vrc == VERR_PATH_NOT_FOUND)
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("The path to file '%s' was not found on guest"), pszCommand);
-                else if (vrc == VERR_BAD_EXE_FORMAT)
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("The file '%s' is not an executable format on guest"), pszCommand);
-                else if (vrc == VERR_AUTHENTICATION_FAILURE)
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("The specified user '%s' was not able to logon on guest"), pszUser);
-                else if (vrc == VERR_TIMEOUT)
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("The guest did not respond within time (%ums)"), ulTimeout);
-                else if (vrc == VERR_CANCELLED)
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("The execution operation was canceled"));
-                else if (vrc == VERR_PERMISSION_DENIED)
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("Invalid user/password credentials"));
-                else if (vrc == VERR_MAX_PROCS_REACHED)
-                    rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                       tr("Concurrent guest process limit is reached"));
-                else
-                {
-                    if (pExecStatus && pExecStatus->u32Status == PROC_STS_ERROR)
-                        rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                           tr("Process could not be started: %Rrc"), pExecStatus->u32Flags);
-                    else
-                        rc = setErrorNoLog(E_UNEXPECTED,
-                                           tr("The service call failed with error %Rrc"), vrc);
-                }
-            }
-            break;
-
-        case PROC_STS_UNDEFINED: /* . */
-            rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                               tr("The operation did not complete within time"));
-            break;
-
-        default:
-            AssertReleaseMsgFailed(("Process (PID %u) reported back an undefined state!\n",
-                                    pExecStatus->u32PID));
-            rc = E_UNEXPECTED;
-            break;
-    }
-
-    return rc;
+    return hr;
 }
 
@@ -1355,9 +1479,11 @@
  * @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.
+ * @param   pStream                 Pointer to guest process stream to fill. If NULL,
+ *                                  data goes to /dev/null.
  */
-int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream &stream)
+int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream *pStream)
 {
     AssertReturn(aPID, VERR_INVALID_PARAMETER);
+    /* pStream is optional. */
 
     int rc = VINF_SUCCESS;
@@ -1370,7 +1496,8 @@
         if (RT_SUCCESS(rc))
         {
-            if (aData.size())
-            {
-                rc = stream.AddData(aData.raw(), aData.size());
+            if (   pStream
+                && aData.size())
+            {
+                rc = pStream->AddData(aData.raw(), aData.size());
                 if (RT_UNLIKELY(RT_FAILURE(rc)))
                     break;
@@ -1387,9 +1514,4 @@
             }
 
-            /* In any case remove the (terminated/broken) process from
-             * the process table. */
-            int rc2 = processGetStatus(aPID, NULL /* PVBOXGUESTCTRL_PROCESS */,
-                                       true /* Remove from table */);
-            AssertRC(rc2);
             break;
         }
@@ -1443,4 +1565,11 @@
                     LogFlowFunc(("Got %ld bytes of additional data\n", aData.size()));
 
+                    if (RT_FAILURE(rc))
+                    {
+                        if (rc == VERR_BROKEN_PIPE)
+                             rc = VINF_SUCCESS; /* No more data because process already ended. */
+                        break;
+                    }
+
                     if (aData.size())
                     {
@@ -1533,5 +1662,5 @@
 {
     GuestProcessStream stream;
-    int rc = executeStreamDrain(ulPID, ulFlags, stream);
+    int rc = executeStreamDrain(ulPID, ulFlags, &stream);
     if (RT_SUCCESS(rc))
     {
@@ -1571,6 +1700,5 @@
  *                                  exit code. Optional.
  */
-HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS,
-                                  ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode)
+HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS)
 {
     HRESULT rc = S_OK;
@@ -1592,21 +1720,5 @@
         if (FAILED(rc))
             rc = setError(VBOX_E_IPRT_ERROR,
-                          tr("Waiting for guest process to end failed (%Rhrc)"),
-                          rc);
-    }
-
-    if (SUCCEEDED(rc))
-    {
-        ULONG uExitCode, uRetFlags;
-        ExecuteProcessStatus_T enmStatus;
-        HRESULT hRC = GetProcessStatus(uPID, &uExitCode, &uRetFlags, &enmStatus);
-        if (FAILED(hRC))
-            return hRC;
-
-        if (pRetStatus)
-            *pRetStatus = enmStatus;
-        if (puRetExitCode)
-            *puRetExitCode = uExitCode;
-        /** @todo Flags? */
+                          tr("Waiting for guest process to end failed (%Rhrc)"), rc);
     }
 
@@ -1707,4 +1819,6 @@
         Utf8Str Utf8UserName(aUsername);
         Utf8Str Utf8Password(aPassword);
+        uint32_t uHostPID = 0;
+
         if (RT_SUCCESS(vrc))
         {
@@ -1795,52 +1909,59 @@
             if (RT_SUCCESS(vrc))
             {
-                LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));
+                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
                 /*
-                 * Wait for the HGCM low level callback until the process
-                 * has been started (or something went wrong). This is necessary to
-                 * get the PID.
+                 * Generate a host-driven PID so that we immediately can return to the caller and
+                 * don't need to wait until the guest started the desired process to return the
+                 * PID generated by the guest OS.
+                 *
+                 * The guest PID will later be mapped to the host PID for later lookup.
                  */
-
-                PCALLBACKDATAEXECSTATUS pExecStatus = NULL;
-
-                /*
-                 * Wait for the first stage (=0) to complete (that is starting the process).
-                 */
-                vrc = callbackWaitForCompletion(uContextID, 0 /* Stage */, aTimeoutMS);
+                vrc = VERR_NOT_FOUND; /* We did not find a host PID yet ... */
+
+                uint32_t uTries = 0;
+                for (;;)
+                {
+                    /* Create a new context ID ... */
+                    uHostPID = ASMAtomicIncU32(&mNextHostPID);
+                    if (uHostPID == UINT32_MAX)
+                        ASMAtomicUoWriteU32(&mNextHostPID, 1000);
+                    /* Is the host PID already used? Try next PID ... */
+                    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
+                    if (it == mGuestProcessMap.end())
+                    {
+                        /* Host PID not used (anymore), we're done here ... */
+                        vrc = VINF_SUCCESS;
+                        break;
+                    }
+
+                    if (++uTries == UINT32_MAX)
+                        break; /* Don't try too hard. */
+                }
+
                 if (RT_SUCCESS(vrc))
-                {
-                    vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
-                                              (void**)&pExecStatus, NULL /* Don't need the size. */);
-                    if (RT_SUCCESS(vrc))
-                    {
-                        rc = executeProcessResult(Utf8Command.c_str(), Utf8UserName.c_str(), aTimeoutMS,
-                                                  pExecStatus, aPID);
-                        callbackFreeUserData(pExecStatus);
-                    }
-                    else
-                    {
-                        rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
-                                           tr("Unable to retrieve process execution status data"));
-                    }
-                }
-                else
-                    rc = handleErrorCompletion(vrc);
-
-                /*
-                 * Do *not* remove the callback yet - we might wait with the IProgress object on something
-                 * else (like end of process) ...
-                 */
+                    vrc = processSetStatus(uHostPID, 0 /* No guest PID yet */,
+                                           ExecuteProcessStatus_Undefined /* Process not started yet */,
+                                           0 /* uExitCode */, 0 /* uFlags */);
+
+                if (RT_SUCCESS(vrc))
+                    vrc = callbackAssignHostPID(uContextID, uHostPID);
             }
             else
-                rc = handleErrorHGCM(vrc);
+                rc = setErrorHGCM(vrc);
 
             for (unsigned i = 0; i < uNumArgs; i++)
                 RTMemFree(papszArgv[i]);
             RTMemFree(papszArgv);
+
+            if (RT_FAILURE(vrc))
+                rc = VBOX_E_IPRT_ERROR;
         }
 
         if (SUCCEEDED(rc))
         {
+            /* Return host PID. */
+            *aPID = uHostPID;
+
             /* Return the progress to the caller. */
             pProgress.queryInterfaceTo(aProgress);
@@ -1897,13 +2018,16 @@
             if (process.mStatus != ExecuteProcessStatus_Started)
                 rc = setError(VBOX_E_IPRT_ERROR,
-                              Guest::tr("Cannot inject input to not running process (PID %u)"), aPID);
+                              Guest::tr("Cannot inject input to a not running process (PID %u)"), aPID);
         }
         else
             rc = setError(VBOX_E_IPRT_ERROR,
-                          Guest::tr("Cannot inject input to non-existent process (PID %u)"), aPID);
+                          Guest::tr("Cannot inject input to a non-existent process (PID %u)"), aPID);
 
         if (RT_SUCCESS(vrc))
         {
             uint32_t uContextID = 0;
+
+            uint32_t uGuestPID = processGetGuestPID(aPID);
+            Assert(uGuestPID);
 
             /*
@@ -1935,5 +2059,5 @@
 
                 /* Save PID + output flags for later use. */
-                pData->u32PID = aPID;
+                pData->u32PID   = uGuestPID;
                 pData->u32Flags = aFlags;
             }
@@ -1950,5 +2074,5 @@
                 int i = 0;
                 paParms[i++].setUInt32(uContextID);
-                paParms[i++].setUInt32(aPID);
+                paParms[i++].setUInt32(uGuestPID);
                 paParms[i++].setUInt32(aFlags);
                 paParms[i++].setPointer(sfaData.raw(), cbSize);
@@ -1974,5 +2098,5 @@
                                                    i, paParms);
                         if (RT_FAILURE(vrc))
-                            rc = handleErrorHGCM(vrc);
+                            rc = setErrorHGCM(vrc);
                     }
                 }
@@ -2032,5 +2156,5 @@
                 }
                 else
-                    rc = handleErrorCompletion(vrc);
+                    rc = setErrorCompletion(vrc);
             }
 
@@ -2107,6 +2231,6 @@
         else if (proc.mStatus != ExecuteProcessStatus_Started)
         {
-            /* If the process is still in the process table but does not run anymore
-             * don't remove it but report back an appropriate error. */
+            /* If the process is already or still in the process table but does not run yet
+             * (or anymore) don't remove it but report back an appropriate error. */
             vrc = VERR_BROKEN_PIPE;
             /* Not getting any output is fine, so don't report an API error (rc)
@@ -2144,4 +2268,7 @@
                 uHandleID = OUTPUT_HANDLE_ID_STDERR;
 
+            uint32_t uGuestPID = processGetGuestPID(aPID);
+            Assert(uGuestPID);
+
             /** @todo Use a buffer for next iteration if returned data is too big
              *        for current read.
@@ -2154,5 +2281,5 @@
 
                 /* Save PID + output flags for later use. */
-                pData->u32PID = aPID;
+                pData->u32PID   = uGuestPID;
                 pData->u32Flags = aFlags;
             }
@@ -2166,5 +2293,5 @@
                 int i = 0;
                 paParms[i++].setUInt32(uContextID);
-                paParms[i++].setUInt32(aPID);
+                paParms[i++].setUInt32(uGuestPID);
                 paParms[i++].setUInt32(uHandleID);
                 paParms[i++].setUInt32(0 /* Flags, none set yet */);
@@ -2249,8 +2376,8 @@
                 }
                 else
-                    rc = handleErrorCompletion(vrc);
+                    rc = setErrorCompletion(vrc);
             }
             else
-                rc = handleErrorHGCM(vrc);
+                rc = setErrorHGCM(vrc);
 
             {
@@ -2427,17 +2554,17 @@
     HRESULT rc = S_OK;
 
-    ComObjPtr<Progress> progress;
+    ComObjPtr<Progress> pProgress;
     try
     {
         /* Create the progress object. */
-        progress.createObject();
-
-        rc = progress->init(static_cast<IGuest*>(this),
-                            Bstr(tr("Copying file from host to guest")).raw(),
-                            TRUE /* aCancelable */);
+        pProgress.createObject();
+
+        rc = pProgress->init(static_cast<IGuest*>(this),
+                             Bstr(tr("Copying file from host to guest")).raw(),
+                             TRUE /* aCancelable */);
         if (FAILED(rc)) throw rc;
 
         /* Initialize our worker task. */
-        GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, progress);
+        GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, pProgress);
         AssertPtr(pTask);
         std::auto_ptr<GuestTask> task(pTask);
@@ -2465,5 +2592,5 @@
     {
         /* Return progress to the caller. */
-        progress.queryInterfaceTo(aProgress);
+        pProgress.queryInterfaceTo(aProgress);
     }
     return rc;
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp	(revision 40684)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp	(revision 40685)
@@ -99,5 +99,5 @@
     }
 
-    HRESULT rc = S_OK;
+    HRESULT hr;
     try
     {
@@ -122,5 +122,7 @@
         args.push_back(Bstr(Utf8Directory).raw());  /* The directory we want to create. */
 
-        rc = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(), Bstr("Creating directory").raw(),
+        ULONG uPID;
+        ComPtr<IProgress> pProgress;
+        hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(), Bstr("Creating directory").raw(),
                                    ComSafeArrayAsInParam(args),
                                    ComSafeArrayAsInParam(env),
@@ -128,11 +130,16 @@
                                    ExecuteProcessFlag_None,
                                    NULL, NULL,
-                                   NULL /* Progress */, NULL /* PID */);
+                                   pProgress.asOutParam(), &uPID);
+        if (SUCCEEDED(hr))
+        {
+            hr = setErrorFromProgress(pProgress);
+            pProgress.setNull();
+        }
     }
     catch (std::bad_alloc &)
     {
-        rc = E_OUTOFMEMORY;
-    }
-    return rc;
+        hr = E_OUTOFMEMORY;
+    }
+    return hr;
 }
 
@@ -299,5 +306,5 @@
     {
 #ifdef DEBUG
-        it->second.mStream.Dump("/tmp/stream.txt");
+        it->second.mStream.Dump("c:\\temp\\stream.txt");
 #endif
         return executeStreamGetNextBlock(it->second.mPID,
@@ -482,4 +489,5 @@
          */
         ULONG uPID;
+        ComPtr<IProgress> pProgress;
         GuestCtrlStreamObjects stdOut;
         hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying directory information").raw(),
@@ -489,32 +497,38 @@
                                    ExecuteProcessFlag_WaitForStdOut,
                                    &stdOut, NULL /* stdErr */,
-                                   NULL /* Progress */, &uPID);
+                                   pProgress.asOutParam(), &uPID);
         if (SUCCEEDED(hr))
         {
-            int rc = VINF_SUCCESS;
-            if (stdOut.size())
+            hr = setErrorFromProgress(pProgress);
+            if (SUCCEEDED(hr))
             {
-                const char *pszFsType = stdOut[0].GetString("ftype");
-                if (!pszFsType) /* Attribute missing? */
-                     rc = VERR_PATH_NOT_FOUND;
-                if (   RT_SUCCESS(rc)
-                    && strcmp(pszFsType, "d")) /* Directory? */
+                int rc = VINF_SUCCESS;
+                if (stdOut.size())
                 {
-                     rc = VERR_PATH_NOT_FOUND;
-                     /* This is not critical for Main, so don't set hr --
-                      * we will take care of rc then. */
+                    const char *pszFsType = stdOut[0].GetString("ftype");
+                    if (!pszFsType) /* Attribute missing? */
+                         rc = VERR_PATH_NOT_FOUND;
+                    if (   RT_SUCCESS(rc)
+                        && strcmp(pszFsType, "d")) /* Directory? */
+                    {
+                         rc = VERR_PATH_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? */
+                    {
+                        rc = executeStreamQueryFsObjInfo(aDirectory, stdOut[0],
+                                                         aObjInfo, enmAddAttribs);
+                    }
                 }
-                if (   RT_SUCCESS(rc)
-                    && aObjInfo) /* Do we want object details? */
-                {
-                    rc = executeStreamQueryFsObjInfo(aDirectory, stdOut[0],
-                                                     aObjInfo, enmAddAttribs);
-                }
+                else
+                    rc = VERR_NO_DATA;
+
+                if (pRC)
+                    *pRC = rc;
             }
-            else
-                rc = VERR_NO_DATA;
-
-            if (pRC)
-                *pRC = rc;
+
+            pProgress.setNull();
         }
     }
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp	(revision 40684)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp	(revision 40685)
@@ -132,4 +132,5 @@
         ULONG uPID;
         GuestCtrlStreamObjects stdOut;
+        ComPtr<IProgress> pProgress;
         hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying file information").raw(),
                                    ComSafeArrayAsInParam(args),
@@ -138,36 +139,42 @@
                                    ExecuteProcessFlag_WaitForStdOut,
                                    &stdOut, NULL,
-                                   NULL /* Progress */, &uPID);
+                                   pProgress.asOutParam(), &uPID);
         if (SUCCEEDED(hr))
         {
-            int rc = VINF_SUCCESS;
-            if (stdOut.size())
+            hr = setErrorFromProgress(pProgress);
+            if (SUCCEEDED(hr))
             {
+                int rc = VINF_SUCCESS;
+                if (stdOut.size())
+                {
 #if 0
-                /* Dump the parsed stream contents to Log(). */
-                stdOut[0].Dump();
-#endif
-                const char *pszFsType = stdOut[0].GetString("ftype");
-                if (!pszFsType) /* Was an object found at all? */
-                    rc = VERR_FILE_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. */
+                    /* Dump the parsed stream contents to Log(). */
+                    stdOut[0].Dump();
+#endif
+                    const char *pszFsType = stdOut[0].GetString("ftype");
+                    if (!pszFsType) /* Was an object found at all? */
+                        rc = VERR_FILE_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? */
+                    {
+                        rc = executeStreamQueryFsObjInfo(aFile, stdOut[0],
+                                                         aObjInfo, enmAddAttribs);
+                    }
                 }
-                if (   RT_SUCCESS(rc)
-                    && aObjInfo) /* Do we want object details? */
-                {
-                    rc = executeStreamQueryFsObjInfo(aFile, stdOut[0],
-                                                     aObjInfo, enmAddAttribs);
-                }
+                else
+                    rc = VERR_NO_DATA;
+
+                if (pRC)
+                    *pRC = rc;
             }
-            else
-                rc = VERR_NO_DATA;
-
-            if (pRC)
-                *pRC = rc;
+
+            pProgress.setNull();
         }
     }
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp	(revision 40684)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp	(revision 40685)
@@ -279,5 +279,7 @@
                         BOOL fCompleted = FALSE;
                         BOOL fCanceled = FALSE;
+
                         uint64_t cbTransferedTotal = 0;
+                        uint64_t cbToRead = cbSize;
 
                         SafeArray<BYTE> aInputData(_64K);
@@ -285,5 +287,4 @@
                                && !fCompleted)
                         {
-                            size_t cbToRead = cbSize;
                             size_t cbRead = 0;
                             if (cbSize) /* If we have nothing to read, take a shortcut. */
@@ -334,8 +335,8 @@
                             }
 
-                            ULONG uBytesWritten = 0;
+                            ULONG cbBytesWritten = 0;
                             rc = pGuest->SetProcessInput(uPID, uFlags,
                                                          0 /* Infinite timeout */,
-                                                         ComSafeArrayAsInParam(aInputData), &uBytesWritten);
+                                                         ComSafeArrayAsInParam(aInputData), &cbBytesWritten);
                             if (FAILED(rc))
                             {
@@ -346,7 +347,8 @@
                             Assert(cbRead <= cbToRead);
                             Assert(cbToRead >= cbRead);
-                            cbToRead -= cbRead;
-
-                            cbTransferedTotal += uBytesWritten;
+                            /* Only subtract bytes reported written by the guest. */
+                            cbToRead -= cbBytesWritten;
+
+                            cbTransferedTotal += cbBytesWritten;
                             Assert(cbTransferedTotal <= cbSize);
                             aTask->pProgress->SetCurrentOperationProgress((ULONG)(cbTransferedTotal * 100 / cbSize));
@@ -377,9 +379,5 @@
                              * canceled or we simply got all stuff transferred.
                              */
-                            ExecuteProcessStatus_T retStatus;
-                            ULONG uRetExitCode;
-
-                            rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */,
-                                                    &retStatus, &uRetExitCode);
+                            rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */);
                             if (FAILED(rc))
                             {
@@ -388,10 +386,16 @@
                             else
                             {
-                                if (   uRetExitCode != 0
-                                    || retStatus    != ExecuteProcessStatus_TerminatedNormally)
+                                VBOXGUESTCTRL_PROCESS proc;
+                                vrc = processGetStatus(uPID, &proc, true /* Remove from PID list. */);
+                                if (RT_SUCCESS(vrc))
                                 {
-                                    rc = GuestTask::setProgressErrorMsg(VBOX_E_IPRT_ERROR, aTask->pProgress,
-                                                                        Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""),
-                                                                        uRetExitCode, retStatus, aTask->strSource.c_str(), aTask->strDest.c_str());
+
+                                    if (   proc.mExitCode != 0
+                                        || proc.mStatus   != ExecuteProcessStatus_TerminatedNormally)
+                                    {
+                                        rc = GuestTask::setProgressErrorMsg(VBOX_E_IPRT_ERROR, aTask->pProgress,
+                                                                            Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""),
+                                                                            proc.mExitCode, proc.mStatus, aTask->strSource.c_str(), aTask->strDest.c_str());
+                                    }
                                 }
                             }
Index: /trunk/src/VBox/Main/src-client/GuestImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 40684)
+++ /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 40685)
@@ -111,4 +111,6 @@
     /* Init the context ID counter at 1000. */
     mNextContextID = 1000;
+    /* Init the host PID counter. */
+    mNextHostPID = 0;
 #endif
 
@@ -211,6 +213,6 @@
      */
     uFreeTotal      = 0;
-    uAllocTotal     = 0; 
-    uBalloonedTotal = 0; 
+    uAllocTotal     = 0;
+    uBalloonedTotal = 0;
     uSharedTotal    = 0;
     uTotalMem       = 0;
@@ -253,5 +255,5 @@
     mParent->reportGuestStatistics(validStats,
                                    aGuestStats[GUESTSTATTYPE_CPUUSER],
-                                   aGuestStats[GUESTSTATTYPE_CPUKERNEL], 
+                                   aGuestStats[GUESTSTATTYPE_CPUKERNEL],
                                    aGuestStats[GUESTSTATTYPE_CPUIDLE],
                                    /* Convert the units for RAM usage stats: page (4K) -> 1KB units */
