Index: trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 43161)
+++ trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 43162)
@@ -9031,6 +9031,6 @@
       <desc>
         The waiting operation timed out. This also will happen
-        when no event has been occured matching the specified the
-        current waiting flags in the <link to="IProcess::waitFor"/> call.
+        when no event has been occured matching the
+        current waiting flags in a <link to="IProcess::waitFor"/> call.
       </desc>
     </const>
Index: trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 43161)
+++ trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 43162)
@@ -71,5 +71,5 @@
 
 /**
- * Generic class for a all guest control callbacks/events.
+ * Base class for a all guest control callbacks/events.
  */
 class GuestCtrlEvent
@@ -121,4 +121,5 @@
 {
 public:
+
     GuestCtrlCallback(void);
 
@@ -165,48 +166,40 @@
 typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks;
 
-struct GuestProcessWaitResult
-{
-    GuestProcessWaitResult(void)
-        : mResult(ProcessWaitResult_None),
-          mRC(VINF_SUCCESS) { }
-
-    /** The wait result when returning from the wait call. */
+
+/*
+ * Class representing a guest control process waiting
+ * event.
+ */
+class GuestProcessWaitEvent : public GuestCtrlEvent
+{
+public:
+
+    GuestProcessWaitEvent(void);
+
+    GuestProcessWaitEvent(uint32_t uWaitFlags);
+
+    virtual ~GuestProcessWaitEvent(void);
+
+public:
+
+    void Destroy(void);
+
+    int Init(uint32_t uWaitFlags);
+
+    uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mFlags); }
+
+    ProcessWaitResult_T GetWaitResult(void) { return mResult; }
+
+    int GetWaitRc(void) { return mRC; }
+
+    int Signal(ProcessWaitResult_T enmResult, int rc = VINF_SUCCESS);
+
+protected:
+
+    /** The waiting flag(s). The specifies what to
+     *  wait for. See ProcessWaitFlag_T. */
+    uint32_t                    mFlags;
+    /** Structure containing the overall result. */
     ProcessWaitResult_T         mResult;
-    /** Optional rc to this result. */
-    int                         mRC;
-};
-
-
-/*
- * Class representing a guest control process event.
- */
-class GuestProcessEvent : public GuestCtrlEvent
-{
-public:
-    GuestProcessEvent(void);
-
-    GuestProcessEvent(uint32_t uWaitFlags);
-
-    virtual ~GuestProcessEvent(void);
-
-public:
-
-    void Destroy(void);
-
-    int Init(uint32_t uWaitFlags);
-
-    uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mWaitFlags); }
-
-    GuestProcessWaitResult GetResult(void) { return mWaitResult; }
-
-    int Signal(ProcessWaitResult_T enmResult, int rc = VINF_SUCCESS);
-
-protected:
-
-    /** The waiting flag(s). The specifies what to
-     *  wait for. */
-    uint32_t                    mWaitFlags;
-    /** Structure containing the overall result. */
-    GuestProcessWaitResult      mWaitResult;
 };
 
Index: trunk/src/VBox/Main/include/GuestDirectoryImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestDirectoryImpl.h	(revision 43161)
+++ trunk/src/VBox/Main/include/GuestDirectoryImpl.h	(revision 43162)
@@ -21,7 +21,6 @@
 
 #include "VirtualBoxBase.h"
-#include "GuestCtrlImplPrivate.h"
+#include "GuestProcessImpl.h"
 
-class GuestProcess;
 class GuestSession;
 
@@ -45,5 +44,5 @@
     DECLARE_EMPTY_CTOR_DTOR(GuestDirectory)
 
-    int     init(GuestSession *aSession, const Utf8Str &strPath, const Utf8Str &strFilter = "", uint32_t uFlags = 0);
+    int     init(GuestSession *aSession, const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags);
     void    uninit(void);
     HRESULT FinalConstruct(void);
@@ -68,5 +67,4 @@
     /** @name Private internal methods.
      * @{ */
-    int parseData(GuestProcessStreamBlock &streamBlock);
     /** @}  */
 
@@ -77,11 +75,5 @@
         Utf8Str                    mFilter;
         uint32_t                   mFlags;
-        /** The stdout stream object which contains all
-         *  read out data for parsing. Must be persisent
-         *  between several read() calls. */
-        GuestProcessStream         mStream;
-        /** The guest process which is responsible for
-         *  getting the stdout stream. */
-        GuestProcess              *mProcess;
+        GuestProcessTool           mProcessTool;
     } mData;
 };
Index: trunk/src/VBox/Main/include/GuestFileImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestFileImpl.h	(revision 43161)
+++ trunk/src/VBox/Main/include/GuestFileImpl.h	(revision 43162)
@@ -46,5 +46,5 @@
     DECLARE_EMPTY_CTOR_DTOR(GuestFile)
 
-    int     init(GuestSession *pSession, const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, int64_t iOffset);
+    int     init(GuestSession *pSession, const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, int64_t iOffset, int *pGuestRc);
     void    uninit(void);
     HRESULT FinalConstruct(void);
Index: trunk/src/VBox/Main/include/GuestProcessImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 43161)
+++ trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 43162)
@@ -75,15 +75,14 @@
     inline bool callbackExists(uint32_t uContextID);
     inline int checkPID(uint32_t uPID);
-    Utf8Str errorMsg(void) { return mData.mErrorMsg; }
+    static Utf8Str guestErrorToString(int guestRc);
     bool isReady(void);
     ULONG getProcessID(void) { return mData.mProcessID; }
-    int rc(void) { return mData.mRC; }
-    int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead);
-    int startProcess(void);
+    int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc);
+    static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
+    int startProcess(int *pGuestRc);
     int startProcessAsync(void);
     int terminateProcess(void);
-    int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult);
-    int waitForStart(uint32_t uTimeoutMS);
-    int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten);
+    int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc);
+    int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc);
     /** @}  */
 
@@ -101,7 +100,6 @@
     int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars);
     int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
-    int setErrorInternal(int rc, const Utf8Str &strMessage);
-    HRESULT setErrorExternal(void);
-    int signalWaiters(ProcessWaitResult_T enmWaitResult);
+    int setProcessStatus(ProcessStatus_T procStatus, int procRc);
+    int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS);
     static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser);
     /** @}  */
@@ -130,9 +128,5 @@
         /** The current process status. */
         ProcessStatus_T          mStatus;
-        /** The overall rc of the process execution. */
         int                      mRC;
-        /** The overall error message of the
-         *  process execution. */
-        Utf8Str                  mErrorMsg;
         /** The next upcoming context ID. */
         ULONG                    mNextContextID;
@@ -144,6 +138,56 @@
         /** The actual process event for doing the waits.
          *  At the moment we only support one wait a time. */
-        GuestProcessEvent       *mWaitEvent;
+        GuestProcessWaitEvent   *mWaitEvent;
     } mData;
+};
+
+/**
+ * Guest process tool flags.
+ */
+/** No flags specified. */
+#define GUESTPROCESSTOOL_FLAG_NONE            0
+/** Run until next stream block from stdout has been
+ *  read in completely, then return.
+ */
+#define GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK    RT_BIT(0)
+
+/**
+ * Internal class for handling a VBoxService tool ("vbox_ls", vbox_stat", ...).
+ */
+class GuestProcessTool
+{
+public:
+
+    GuestProcessTool(void);
+
+    virtual ~GuestProcessTool(void);
+
+public:
+
+    int Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo, bool fAsync, int *pGuestRc);
+
+    GuestProcessStream &GetStdOut(void) { return mStdOut; }
+
+    GuestProcessStream &GetStdErr(void) { return mStdErr; }
+
+    int Wait(uint32_t fFlags, int *pGuestRc);
+
+    int WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc);
+
+    int GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock);
+
+    bool IsRunning(void);
+
+    int TerminatedOk(LONG *pExitCode);
+
+    void Terminate(void);
+
+protected:
+
+    GuestSession               *pSession;
+    ComObjPtr<GuestProcess>     pProcess;
+    GuestProcessStartupInfo     mStartupInfo;
+    GuestProcessStream          mStdOut;
+    GuestProcessStream          mStdErr;
 };
 
Index: trunk/src/VBox/Main/include/GuestSessionImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 43161)
+++ trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 43162)
@@ -297,20 +297,16 @@
      * @{ */
     int                     directoryRemoveFromList(GuestDirectory *pDirectory);
-    int                     directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags);
-    int                     objectCreateTempInternal(Utf8Str strTemplate,
-                                                     Utf8Str strPath,
-                                                     bool fDirectory,
-                                                     Utf8Str &strName,
-                                                     int *prc);
+    int                     directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc);
+    int                     objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, bool fDirectory, const Utf8Str &strName, int *pGuestRc);
     int                     directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory);
-    int                     directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData);
+    int                     directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc);
     int                     dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData);
     int                     fileRemoveFromList(GuestFile *pFile);
-    int                     fileRemoveInternal(Utf8Str strPath, int *prc);
+    int                     fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc);
     int                     fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,
-                                             uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile);
-    int                     fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData);
-    int                     fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize);
-    int                     fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData);
+                                             uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile, int *pGuestRc);
+    int                     fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc);
+    int                     fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc);
+    int                     fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc);
     const GuestCredentials &getCredentials(void);
     const GuestEnvironment &getEnvironment(void);
Index: trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 43161)
+++ trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 43162)
@@ -102,5 +102,5 @@
 int GuestCtrlEvent::Wait(ULONG uTimeoutMS)
 {
-    LogFlowFuncEnter();
+    LogFlowThisFuncEnter();
 
     AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
@@ -304,11 +304,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
-GuestProcessEvent::GuestProcessEvent(void)
-    : mWaitFlags(0)
-{
-}
-
-GuestProcessEvent::GuestProcessEvent(uint32_t uWaitFlags)
-    : mWaitFlags(uWaitFlags)
+GuestProcessWaitEvent::GuestProcessWaitEvent(void)
+    : mFlags(0),
+      mResult(ProcessWaitResult_None)
+{
+}
+
+GuestProcessWaitEvent::GuestProcessWaitEvent(uint32_t uWaitFlags)
+    : mFlags(uWaitFlags)
 {
     int rc = GuestCtrlEvent::Init();
@@ -316,20 +317,19 @@
 }
 
-GuestProcessEvent::~GuestProcessEvent(void)
+GuestProcessWaitEvent::~GuestProcessWaitEvent(void)
 {
     Destroy();
 }
 
-void GuestProcessEvent::Destroy(void)
+void GuestProcessWaitEvent::Destroy(void)
 {
     GuestCtrlEvent::Destroy();
 
-    mWaitFlags = ProcessWaitForFlag_None;
-}
-
-int GuestProcessEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
-{
-    mWaitResult.mRC = rc;
-    mWaitResult.mResult = enmResult;
+    mFlags = ProcessWaitForFlag_None;
+}
+
+int GuestProcessWaitEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/)
+{
+    mResult = enmResult;
 
     return GuestCtrlEvent::Signal(rc);
Index: trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp	(revision 43161)
+++ trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp	(revision 43162)
@@ -60,5 +60,5 @@
 
 int GuestDirectory::init(GuestSession *aSession,
-                         const Utf8Str &strPath, const Utf8Str &strFilter /*= ""*/, uint32_t uFlags /*= 0*/)
+                         const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags)
 {
     LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n",
@@ -78,6 +78,6 @@
     procInfo.mName      = Utf8StrFmt(tr("Reading directory \"%s\"", strPath.c_str()));
     procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_LS);
-    procInfo.mTimeoutMS = 0; /* No timeout. */
-    procInfo.mFlags     = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
+    procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
+    procInfo.mFlags     = ProcessCreateFlag_WaitForStdOut;
 
     procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
@@ -94,16 +94,10 @@
      * Start the process asynchronously and keep it around so that we can use
      * it later in subsequent read() calls.
+     * Note: No guest rc available because operation is asynchronous.
      */
-    ComObjPtr<GuestProcess> pProcess;
-    int rc = mData.mSession->processCreateExInteral(procInfo, pProcess);
+    int rc = mData.mProcessTool.Init(mData.mSession, procInfo,
+                                     true /* Async */, NULL /* Guest rc */);
     if (RT_SUCCESS(rc))
-        rc = pProcess->startProcessAsync();
-
-    LogFlowThisFunc(("rc=%Rrc\n", rc));
-
-    if (RT_SUCCESS(rc))
-    {
-        mData.mProcess = pProcess;
-
+    {
         /* Confirm a successful initialization when it's the case. */
         autoInitSpan.setSucceeded();
@@ -169,24 +163,4 @@
 /////////////////////////////////////////////////////////////////////////////
 
-int GuestDirectory::parseData(GuestProcessStreamBlock &streamBlock)
-{
-    LogFlowThisFunc(("cbStream=%RU32\n", mData.mStream.GetSize()));
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    int rc;
-    do
-    {
-        /* Try parsing the data to see if the current block is complete. */
-        rc = mData.mStream.ParseBlock(streamBlock);
-        if (streamBlock.GetCount())
-            break;
-
-    } while (RT_SUCCESS(rc));
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
 // implementation of public methods
 /////////////////////////////////////////////////////////////////////////////
@@ -204,10 +178,6 @@
     AssertPtr(mData.mSession);
     int rc = mData.mSession->directoryRemoveFromList(this);
-    if (mData.mProcess)
-    {
-        int rc2 = mData.mSession->processRemoveFromList(mData.mProcess);
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-    }
+
+    mData.mProcessTool.Terminate();
 
     /*
@@ -233,107 +203,28 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    ComObjPtr<GuestProcess> pProcess = mData.mProcess;
-    Assert(!pProcess.isNull());
-
-    GuestProcessStreamBlock streamBlock;
-    GuestFsObjData objData;
-
-    int rc = parseData(streamBlock);
-    if (   RT_FAILURE(rc)
-        || streamBlock.IsEmpty()) /* More data needed. */
-    {
-        rc = pProcess->waitForStart(30 * 1000 /* 30s timeout */);
+    GuestProcessStreamBlock curBlock;
+    int guestRc;
+
+    int rc = mData.mProcessTool.WaitEx(GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK,
+                                       &curBlock, &guestRc);
+
+    /*
+     * Note: The guest process can still be around to serve the next
+     *       upcoming stream block next time.
+     */
+    if (   RT_SUCCESS(rc)
+        && !mData.mProcessTool.IsRunning())
+    {
+        rc = mData.mProcessTool.TerminatedOk(NULL /* Exit code */);
+        if (rc == VERR_NOT_EQUAL)
+            rc = VERR_ACCESS_DENIED;
     }
 
     if (RT_SUCCESS(rc))
     {
-        BYTE byBuf[_64K];
-        size_t cbRead = 0;
-
-        /** @todo Merge with GuestSession::queryFileInfoInternal. */
-        for (;RT_SUCCESS(rc);)
+        if (curBlock.GetCount()) /* Did we get content? */
         {
-            GuestProcessWaitResult waitRes;
-            rc = pProcess->waitFor(  ProcessWaitForFlag_Terminate
-                                   | ProcessWaitForFlag_StdOut,
-                                   30 * 1000 /* Timeout */, waitRes);
-            if (   RT_FAILURE(rc)
-                || waitRes.mResult == ProcessWaitResult_Terminate
-                || waitRes.mResult == ProcessWaitResult_Error
-                || waitRes.mResult == ProcessWaitResult_Timeout)
-            {
-                if (RT_FAILURE(waitRes.mRC))
-                    rc = waitRes.mRC;
-                break;
-            }
-
-            rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
-                                    30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
-                                    &cbRead);
-            if (RT_FAILURE(rc))
-                break;
-
-            if (cbRead)
-            {
-                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-                rc = mData.mStream.AddData(byBuf, cbRead);
-                if (RT_FAILURE(rc))
-                    break;
-
-                LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
-                                 rc, cbRead, mData.mStream.GetSize()));
-
-                rc = parseData(streamBlock);
-                if (RT_SUCCESS(rc))
-                {
-                    /* Parsing the current stream block succeeded so
-                     * we don't need more at the moment. */
-                    break;
-                }
-            }
-        }
-
-        LogFlowThisFunc(("Reading done with rc=%Rrc, cbRead=%RU64, cbStream=%RU32\n",
-                         rc, cbRead, mData.mStream.GetSize()));
-
-        if (RT_SUCCESS(rc))
-        {
-            rc = parseData(streamBlock);
-            if (rc == VERR_NO_DATA) /* Since this is the last parsing call, this is ok. */
-                rc = VINF_SUCCESS;
-        }
-
-        /*
-         * Note: The guest process can still be around to serve the next
-         *       upcoming stream block next time.
-         */
-        if (RT_SUCCESS(rc))
-        {
-            /** @todo Move into common function. */
-            ProcessStatus_T procStatus = ProcessStatus_Undefined;
-            LONG exitCode = 0;
-
-            HRESULT hr2 = pProcess->COMGETTER(Status(&procStatus));
-            ComAssertComRC(hr2);
-            hr2 = pProcess->COMGETTER(ExitCode(&exitCode));
-            ComAssertComRC(hr2);
-
-            if (   (   procStatus != ProcessStatus_Started
-                    && procStatus != ProcessStatus_Paused
-                    && procStatus != ProcessStatus_Terminating
-                   )
-                && exitCode != 0)
-            {
-                rc = VERR_ACCESS_DENIED;
-            }
-        }
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        if (streamBlock.GetCount()) /* Did we get content? */
-        {
-            rc = objData.FromLs(streamBlock);
+            GuestFsObjData objData;
+            rc = objData.FromLs(curBlock);
             if (RT_FAILURE(rc))
                 rc = VERR_PATH_NOT_FOUND;
@@ -372,4 +263,8 @@
         switch (rc)
         {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
+
             case VERR_ACCESS_DENIED:
                 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
@@ -383,4 +278,5 @@
 
             case VERR_NO_MORE_FILES:
+                /* See SDK reference. */
                 hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
                               mData.mName.c_str());
Index: trunk/src/VBox/Main/src-client/GuestFileImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestFileImpl.cpp	(revision 43161)
+++ trunk/src/VBox/Main/src-client/GuestFileImpl.cpp	(revision 43162)
@@ -61,5 +61,5 @@
 int GuestFile::init(GuestSession *pSession, const Utf8Str &strPath,
                     const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode,
-                    int64_t iOffset)
+                    int64_t iOffset, int *pGuestRc)
 {
     /* Enclose the state transition NotReady->InInit->Ready. */
@@ -76,4 +76,5 @@
 
     /** @todo Validate parameters! */
+    /** @todo Implement guest side file handling! */
 
     /* Confirm a successful initialization when it's the case. */
Index: trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 43161)
+++ trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 43162)
@@ -426,5 +426,6 @@
         AssertPtr(pCallback);
 #ifdef DEBUG
-        LogFlowThisFunc(("pCallback=%p\n", pCallback));
+        LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
+                         pCallback, uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)));
 #endif
     }
@@ -497,4 +498,10 @@
 inline int GuestProcess::callbackRemove(uint32_t uContextID)
 {
+    LogFlowThisFunc(("Removing callback (Session: %RU32, Process: %RU32, Count=%RU32) CID=%RU32\n",
+                     VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),
+                     VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),
+                     VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID),
+                     uContextID));
+
     GuestCtrlCallbacks::iterator it =
         mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
@@ -545,4 +552,72 @@
 }
 
+/* static */
+Utf8Str GuestProcess::guestErrorToString(int guestRc)
+{
+    Utf8Str strError;
+
+    /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
+    switch (guestRc)
+    {
+        case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
+            strError += Utf8StrFmt(tr("The specified file was not found on guest"));
+            break;
+
+        case VERR_INVALID_VM_HANDLE:
+            strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
+            break;
+
+        case VERR_HGCM_SERVICE_NOT_FOUND:
+            strError += Utf8StrFmt(tr("The guest execution service is not available"));
+            break;
+
+        case VERR_PATH_NOT_FOUND:
+            strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
+            break;
+
+        case VERR_BAD_EXE_FORMAT:
+            strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
+            break;
+
+        case VERR_AUTHENTICATION_FAILURE:
+            strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
+            break;
+
+        case VERR_INVALID_NAME:
+            strError += Utf8StrFmt(tr("The specified file is an invalid name"));
+            break;
+
+        case VERR_TIMEOUT:
+            strError += Utf8StrFmt(tr("The guest did not respond within time"));
+            break;
+
+        case VERR_CANCELLED:
+            strError += Utf8StrFmt(tr("The execution operation was canceled"));
+            break;
+
+        case VERR_PERMISSION_DENIED:
+            strError += Utf8StrFmt(tr("Invalid user/password credentials"));
+            break;
+
+        case VERR_MAX_PROCS_REACHED:
+            strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
+            break;
+
+        case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
+            strError += Utf8StrFmt(tr("Unable to retrieving requested information"));
+            break;
+
+        case VERR_NOT_FOUND:
+            strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
+            break;
+
+        default:
+            strError += Utf8StrFmt(tr("%Rrc"), guestRc);
+            break;
+    }
+
+    return strError;
+}
+
 inline bool GuestProcess::isAlive(void)
 {
@@ -649,21 +724,25 @@
         return vrc;
 
-    BOOL fSignal = FALSE;
+    ProcessStatus_T procStatus = ProcessStatus_Undefined;
+    int procRc = VINF_SUCCESS;
+
+    bool fSignalWaiters = false;
     ProcessWaitResult_T waitRes;
+
     uint32_t uWaitFlags = mData.mWaitEvent
                         ? mData.mWaitEvent->GetWaitFlags() : 0;
     switch (pData->u32Status)
     {
-       case PROC_STS_STARTED:
-        {
-            fSignal = (uWaitFlags & ProcessWaitForFlag_Start);
+        case PROC_STS_STARTED:
+        {
+            fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start);
             /* If the caller only wants to wait until the process has been started,
              * notify in any case. */
             if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
-                fSignal = true;
+                fSignalWaiters = true;
             waitRes = ProcessWaitResult_Start;
 
-            mData.mStatus = ProcessStatus_Started;
-            mData.mPID = pData->u32PID;
+            procStatus = ProcessStatus_Started;
+            mData.mPID = pData->u32PID; /* Set the process PID. */
             break;
         }
@@ -671,8 +750,8 @@
         case PROC_STS_TEN:
         {
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             waitRes = ProcessWaitResult_Terminate;
 
-            mData.mStatus = ProcessStatus_TerminatedNormally;
+            procStatus = ProcessStatus_TerminatedNormally;
             mData.mExitCode = pData->u32Flags; /* Contains the exit code. */
             break;
@@ -681,8 +760,8 @@
         case PROC_STS_TES:
         {
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             waitRes = ProcessWaitResult_Terminate;
 
-            mData.mStatus = ProcessStatus_TerminatedSignal;
+            procStatus = ProcessStatus_TerminatedSignal;
             mData.mExitCode = pData->u32Flags; /* Contains the signal. */
             break;
@@ -691,8 +770,8 @@
         case PROC_STS_TEA:
         {
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             waitRes = ProcessWaitResult_Terminate;
 
-            mData.mStatus = ProcessStatus_TerminatedAbnormally;
+            procStatus = ProcessStatus_TerminatedAbnormally;
             break;
         }
@@ -700,8 +779,8 @@
         case PROC_STS_TOK:
         {
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             waitRes = ProcessWaitResult_Timeout;
 
-            mData.mStatus = ProcessStatus_TimedOutKilled;
+            procStatus = ProcessStatus_TimedOutKilled;
             break;
         }
@@ -709,8 +788,8 @@
         case PROC_STS_TOA:
         {
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             waitRes = ProcessWaitResult_Timeout;
 
-            mData.mStatus = ProcessStatus_TimedOutAbnormally;
+            procStatus = ProcessStatus_TimedOutAbnormally;
             break;
         }
@@ -718,5 +797,5 @@
         case PROC_STS_DWN:
         {
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             /* Do we need to report termination? */
             if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
@@ -725,5 +804,5 @@
                 waitRes = ProcessWaitResult_Terminate;
 
-            mData.mStatus = ProcessStatus_Down;
+            procStatus = ProcessStatus_Down;
             break;
         }
@@ -731,65 +810,9 @@
         case PROC_STS_ERROR:
         {
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             waitRes = ProcessWaitResult_Error;
 
-            mData.mStatus = ProcessStatus_Error;
-
-            Utf8Str strError = Utf8StrFmt(tr("Guest process \"%s\" could not be started: "), mData.mProcess.mCommand.c_str());
-
-            /* Note: It's not required that the process has been started before. */
-            if (mData.mPID)
-            {
-                strError += Utf8StrFmt(tr("Error vrc=%Rrc occured (PID %RU32)"), vrc, mData.mPID);
-            }
-            else
-            {
-                /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
-                switch (pData->u32Flags) /* pData->u32Flags contains the IPRT error code from guest side. */
-                {
-                    case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
-                        strError += Utf8StrFmt(tr("The specified file was not found on guest"));
-                        break;
-
-                    case VERR_PATH_NOT_FOUND:
-                        strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
-                        break;
-
-                    case VERR_BAD_EXE_FORMAT:
-                        strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
-                        break;
-
-                    case VERR_AUTHENTICATION_FAILURE:
-                        strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
-                        break;
-
-                    case VERR_INVALID_NAME:
-                        strError += Utf8StrFmt(tr("The specified file is an invalid name"));
-                        break;
-
-                    case VERR_TIMEOUT:
-                        strError += Utf8StrFmt(tr("The guest did not respond within time"));
-                        break;
-
-                    case VERR_CANCELLED:
-                        strError += Utf8StrFmt(tr("The execution operation was canceled"));
-                        break;
-
-                    case VERR_PERMISSION_DENIED:
-                        strError += Utf8StrFmt(tr("Invalid user/password credentials"));
-                        break;
-
-                    case VERR_MAX_PROCS_REACHED:
-                        strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
-                        break;
-
-                    default:
-                        strError += Utf8StrFmt(tr("Reported error %Rrc"), pData->u32Flags);
-                        break;
-                }
-            }
-
-            vrc = setErrorInternal(pData->u32Flags, strError);
-            AssertRC(vrc);
+            procRc = pData->u32Flags; /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
+            procStatus = ProcessStatus_Error;
             break;
         }
@@ -799,13 +822,19 @@
         {
             /* Silently skip this request. */
-            fSignal = TRUE; /* Signal in any case. */
+            fSignalWaiters = true; /* Signal in any case. */
             waitRes = ProcessWaitResult_Status;
 
-            mData.mStatus = ProcessStatus_Undefined;
-            break;
-        }
-    }
-
-    LogFlowThisFunc(("Got vrc=%Rrc, waitResult=%d\n", vrc, waitRes));
+            procStatus = ProcessStatus_Undefined;
+            break;
+        }
+    }
+
+    LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n",
+                     vrc, waitRes, procStatus, procRc, fSignalWaiters));
+
+    /* Set the process status. */
+    int rc2 = setProcessStatus(procStatus, procRc);
+    if (RT_SUCCESS(vrc))
+        vrc = rc2;
 
     /*
@@ -813,9 +842,9 @@
      */
     if (pCallback)
-        vrc = pCallback->Signal();
-
-    if (fSignal)
-    {
-        int rc2 = signalWaiters(waitRes);
+        vrc = pCallback->Signal(procRc);
+
+    if (fSignalWaiters)
+    {
+        rc2 = signalWaiters(waitRes, procRc);
         if (RT_SUCCESS(vrc))
             vrc = rc2;
@@ -885,8 +914,8 @@
 
 int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
-                           void *pvData, size_t cbData, size_t *pcbRead)
-{
-    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32\n",
-                     mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData));
+                           void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc)
+{
+    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n",
+                     mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc));
     AssertReturn(uSize, VERR_INVALID_PARAMETER);
     AssertPtrReturn(pvData, VERR_INVALID_POINTER);
@@ -900,16 +929,30 @@
         if (pcbRead)
             *pcbRead = 0;
+        if (pGuestRc)
+            *pGuestRc = VINF_SUCCESS;
         return VINF_SUCCESS; /* Nothing to read anymore. */
     }
 
+    int vrc = VINF_SUCCESS;
+
+    GuestCtrlCallback *pCallbackRead;
+    try
+    {
+        pCallbackRead = new GuestCtrlCallback();
+        AssertPtr(pCallbackRead);
+    }
+    catch(std::bad_alloc &)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    /* Create callback and add it to the map. */
     uint32_t uContextID = 0;
-    GuestCtrlCallback *pCallbackRead = new GuestCtrlCallback();
-    if (!pCallbackRead)
-        return VERR_NO_MEMORY;
-
-    /* Create callback and add it to the map. */
-    int vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT);
     if (RT_SUCCESS(vrc))
-        vrc = callbackAdd(pCallbackRead, &uContextID);
+    {
+        vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT);
+        if (RT_SUCCESS(vrc))
+            vrc = callbackAdd(pCallbackRead, &uContextID);
+    }
 
     alock.release(); /* Drop the write lock again. */
@@ -938,8 +981,8 @@
         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
         {
-            vrc = pCallbackRead->GetResultCode();
-            LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackRead->GetDataSize()));
-
-            if (RT_SUCCESS(vrc))
+            int guestRc = pCallbackRead->GetResultCode();
+            LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize()));
+
+            if (RT_SUCCESS(guestRc))
             {
                 Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATAEXECOUT));
@@ -959,7 +1002,10 @@
                     *pcbRead = cbRead;
             }
-        }
-        else
-            vrc = VERR_TIMEOUT;
+            else
+                vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+
+            if (pGuestRc)
+                *pGuestRc = guestRc;
+        }
     }
 
@@ -991,13 +1037,5 @@
     if (RT_FAILURE(vrc))
     {
-        int rc2;
-        if (vrc == VERR_INVALID_VM_HANDLE)
-            rc2 = setErrorInternal(vrc, tr("VMM device is not available (is the VM running?)"));
-        else if (vrc == VERR_NOT_FOUND)
-            rc2 = setErrorInternal(vrc, tr("The guest execution service is not ready (yet)"));
-        else if (vrc == VERR_HGCM_SERVICE_NOT_FOUND)
-            rc2 = setErrorInternal(vrc, tr("The guest execution service is not available"));
-        else
-            rc2 = setErrorInternal(vrc, Utf8StrFmt(tr("The HGCM call failed with error %Rrc"), vrc));
+        int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
         AssertRC(rc2);
     }
@@ -1008,37 +1046,40 @@
 
 /* Does not do locking; caller is responsible for that! */
-int GuestProcess::setErrorInternal(int vrc, const Utf8Str &strMessage)
-{
-    LogFlowThisFunc(("vrc=%Rrc, strMsg=%s\n", vrc, strMessage.c_str()));
-
-    Assert(RT_FAILURE(vrc));
-    Assert(!strMessage.isEmpty());
+int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc)
+{
+    LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, procRc=%Rrc\n",
+                     mData.mStatus, procStatus, procRc));
 
 #ifdef DEBUG
-    /* Do not allow overwriting an already set error. If this happens
-     * this means we forgot some error checking/locking somewhere. */
-    Assert(RT_SUCCESS(mData.mRC));
-    Assert(mData.mErrorMsg.isEmpty());
+    if (procStatus == ProcessStatus_Error)
+    {
+        AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc));
+        /* Do not allow overwriting an already set error. If this happens
+         * this means we forgot some error checking/locking somewhere. */
+        AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
+    }
+    else
+        AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
 #endif
 
-    mData.mStatus = ProcessStatus_Error;
-    mData.mRC = vrc;
-    mData.mErrorMsg = strMessage;
-
-    int rc2 = signalWaiters(ProcessWaitResult_Error);
-    LogFlowFuncLeaveRC(rc2);
-    return rc2;
-}
-
-HRESULT GuestProcess::setErrorExternal(void)
-{
-    return RT_SUCCESS(mData.mRC)
-           ? S_OK : setError(VBOX_E_IPRT_ERROR, "%s", mData.mErrorMsg.c_str());
-}
-
-int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult)
-{
-    LogFlowThisFunc(("enmWaitResult=%d, mWaitCount=%RU32, mWaitEvent=%p\n",
-                 enmWaitResult, mData.mWaitCount, mData.mWaitEvent));
+    mData.mStatus = procStatus;
+    mData.mRC     = procRc;
+
+    return VINF_SUCCESS;
+}
+
+/* static */
+HRESULT GuestProcess::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
+{
+    AssertPtr(pInterface);
+    AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
+
+    return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str());
+}
+
+int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
+{
+    LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
+                     enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));
 
     /* Note: No write locking here -- already done in the caller. */
@@ -1046,10 +1087,10 @@
     int vrc = VINF_SUCCESS;
     if (mData.mWaitEvent)
-        vrc = mData.mWaitEvent->Signal(enmWaitResult);
+        vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);
     LogFlowFuncLeaveRC(vrc);
     return vrc;
 }
 
-int GuestProcess::startProcess(void)
+int GuestProcess::startProcess(int *pGuestRc)
 {
     LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
@@ -1060,16 +1101,27 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    int vrc;
+    int vrc = VINF_SUCCESS;
     uint32_t uContextID = 0;
-    GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback();
-    if (!pCallbackStart)
-        return VERR_NO_MEMORY;
-
-    mData.mStatus = ProcessStatus_Starting;
-
-    /* Create callback and add it to the map. */
-    vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START);
+
+    GuestCtrlCallback *pCallbackStart;
+    try
+    {
+        pCallbackStart = new GuestCtrlCallback();
+        AssertPtr(pCallbackStart);
+    }
+    catch(std::bad_alloc &)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
     if (RT_SUCCESS(vrc))
-        vrc = callbackAdd(pCallbackStart, &uContextID);
+    {
+        mData.mStatus = ProcessStatus_Starting;
+
+        /* Create callback and add it to the map. */
+        vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START);
+        if (RT_SUCCESS(vrc))
+            vrc = callbackAdd(pCallbackStart, &uContextID);
+    }
 
     if (RT_SUCCESS(vrc))
@@ -1175,6 +1227,8 @@
             if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
             {
-                vrc = pCallbackStart->GetResultCode();
-                LogFlowThisFunc(("Callback returned vrc=%Rrc\n", vrc));
+                int guestRc = pCallbackStart->GetResultCode();
+                if (pGuestRc)
+                    *pGuestRc = guestRc;
+                LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
             }
             else
@@ -1240,9 +1294,6 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    int vrc = pProcess->startProcess();
-    if (RT_FAILURE(vrc))
-    {
-        /** @todo What now? */
-    }
+    int vrc = pProcess->startProcess(NULL /* Guest rc, ignored */);
+    /* Nothing to do here anymore. */
 
     LogFlowFuncLeaveRC(vrc);
@@ -1263,5 +1314,5 @@
 }
 
-int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &waitRes)
+int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc)
 {
     LogFlowThisFuncEnter();
@@ -1269,21 +1320,20 @@
     AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
 
-    LogFlowThisFunc(("fWaitFlags=%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p\n",
-                     fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent));
+    LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
+                     fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    ProcessStatus_T curStatus = mData.mStatus;
-
     /* Did some error occur before? Then skip waiting and return. */
-    if (curStatus == ProcessStatus_Error)
-    {
-        waitRes.mResult = ProcessWaitResult_Error;
-        return VINF_SUCCESS;
-    }
-
-    waitRes.mResult = ProcessWaitResult_None;
-    waitRes.mRC = VINF_SUCCESS;
-
+    if (mData.mStatus == ProcessStatus_Error)
+    {
+        waitResult = ProcessWaitResult_Error;
+        AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mRC));
+        if (pGuestRc)
+            *pGuestRc = mData.mRC; /* Return last set error. */
+        return VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+    }
+
+    waitResult = ProcessWaitResult_None;
     if (   (fWaitFlags & ProcessWaitForFlag_Terminate)
         || (fWaitFlags & ProcessWaitForFlag_StdIn)
@@ -1297,36 +1347,18 @@
             case ProcessStatus_TerminatedAbnormally:
             case ProcessStatus_Down:
-                waitRes.mResult = ProcessWaitResult_Terminate;
-                waitRes.mRC = mData.mRC;
+                waitResult = ProcessWaitResult_Terminate;
                 break;
 
             case ProcessStatus_TimedOutKilled:
             case ProcessStatus_TimedOutAbnormally:
-                waitRes.mResult = ProcessWaitResult_Timeout;
-                waitRes.mRC = mData.mRC;
+                waitResult = ProcessWaitResult_Timeout;
                 break;
 
             case ProcessStatus_Error:
-                waitRes.mResult = ProcessWaitResult_Error;
-                waitRes.mRC = mData.mRC;
+                /* Handled above. */
                 break;
 
             case ProcessStatus_Started:
             {
-                /* Filter out waits which are *not* supported using
-                 * older guest control Guest Additions. */
-                if (mData.mParent->getProtocolVersion() < 2)
-                {
-                    /* We don't support waiting for stdin, out + err,
-                     * just skip waiting then. */
-                    if (   (fWaitFlags & ProcessWaitForFlag_StdIn)
-                        || (fWaitFlags & ProcessWaitForFlag_StdOut)
-                        || (fWaitFlags & ProcessWaitForFlag_StdErr))
-                    {
-                        /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
-                        waitRes.mResult = ProcessWaitResult_WaitFlagNotSupported;
-                    }
-                }
-
                 /*
                  * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
@@ -1335,5 +1367,5 @@
                  */
                 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
-                    waitRes.mResult = ProcessWaitResult_Start;
+                    waitResult = ProcessWaitResult_Start;
                 break;
             }
@@ -1360,16 +1392,14 @@
             case ProcessStatus_TerminatedAbnormally:
             case ProcessStatus_Down:
-                waitRes.mResult = ProcessWaitResult_Start;
+                waitResult = ProcessWaitResult_Start;
                 break;
 
             case ProcessStatus_Error:
-                waitRes.mResult = ProcessWaitResult_Error;
-                waitRes.mRC = mData.mRC;
+                waitResult = ProcessWaitResult_Error;
                 break;
 
             case ProcessStatus_TimedOutKilled:
             case ProcessStatus_TimedOutAbnormally:
-                waitRes.mResult = ProcessWaitResult_Timeout;
-                waitRes.mRC = mData.mRC;
+                waitResult = ProcessWaitResult_Timeout;
                 break;
 
@@ -1385,9 +1415,32 @@
     }
 
-    LogFlowThisFunc(("waitResult=%ld, waitRC=%Rrc\n", waitRes.mResult, waitRes.mRC));
-
-    /* No waiting needed? Return immediately. */
-    if (waitRes.mResult != ProcessWaitResult_None)
-        return VINF_SUCCESS;
+    /* Filter out waits which are *not* supported using
+     * older guest control Guest Additions. */
+    if (mData.mParent->getProtocolVersion() < 2)
+    {
+        if (   waitResult == ProcessWaitResult_None
+            /* We don't support waiting for stdin, out + err,
+             * just skip waiting then. */
+            && (   (fWaitFlags & ProcessWaitForFlag_StdIn)
+                || (fWaitFlags & ProcessWaitForFlag_StdOut)
+                || (fWaitFlags & ProcessWaitForFlag_StdErr)
+               )
+           )
+        {
+            /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
+            waitResult = ProcessWaitResult_WaitFlagNotSupported;
+        }
+    }
+
+    LogFlowThisFunc(("procStatus=%ld, procRc=%Rrc, waitResult=%ld\n",
+                     mData.mStatus, mData.mRC, waitResult));
+
+    /* No waiting needed? Return immediately using the last set error. */
+    if (waitResult != ProcessWaitResult_None)
+    {
+        if (pGuestRc)
+            *pGuestRc = mData.mRC; /* Return last set error (if any). */
+        return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+    }
 
     if (mData.mWaitCount > 0)
@@ -1395,30 +1448,45 @@
     mData.mWaitCount++;
 
-    Assert(mData.mWaitEvent == NULL);
-    mData.mWaitEvent = new GuestProcessEvent(fWaitFlags);
-    AssertPtrReturn(mData.mWaitEvent, VERR_NO_MEMORY);
-
-    alock.release(); /* Release lock before waiting. */
-
-    int vrc = mData.mWaitEvent->Wait(uTimeoutMS);
+    int vrc = VINF_SUCCESS;
+    try
+    {
+        Assert(mData.mWaitEvent == NULL);
+        mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags);
+    }
+    catch(std::bad_alloc &)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
     if (RT_SUCCESS(vrc))
     {
-        waitRes = mData.mWaitEvent->GetResult();
-    }
-    else if (vrc == VERR_TIMEOUT)
-    {
-        waitRes.mRC = VINF_SUCCESS;
-        waitRes.mResult = ProcessWaitResult_Timeout;
-
-        vrc = VINF_SUCCESS;
-    }
-
-    alock.acquire(); /* Get the lock again. */
-
-    /* Note: The caller always is responsible of deleting the
-     *       stuff it created before. See close() for more information. */
-    delete mData.mWaitEvent;
-    mData.mWaitEvent = NULL;
-
+        GuestProcessWaitEvent *pEvent = mData.mWaitEvent;
+        AssertPtr(pEvent);
+
+        alock.release(); /* Release lock before waiting. */
+
+        vrc = pEvent->Wait(uTimeoutMS);
+        if (RT_SUCCESS(vrc))
+        {
+            waitResult = pEvent->GetWaitResult();
+            int waitRc = pEvent->GetWaitRc();
+
+            LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", waitRc));
+
+            if (pGuestRc)
+                *pGuestRc = waitRc;
+
+            vrc = RT_SUCCESS(waitRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+        }
+
+        alock.acquire(); /* Get the lock again. */
+
+        /* Note: The caller always is responsible of deleting the
+         *       stuff it created before. See close() for more information. */
+        delete mData.mWaitEvent;
+        mData.mWaitEvent = NULL;
+    }
+
+    Assert(mData.mWaitCount);
     mData.mWaitCount--;
 
@@ -1427,51 +1495,43 @@
 }
 
-int GuestProcess::waitForStart(uint32_t uTimeoutMS)
-{
-    LogFlowThisFunc(("uTimeoutMS=%RU32\n", uTimeoutMS));
+int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
+                            void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc)
+{
+    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n",
+                     mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc));
+    /* All is optional. There can be 0 byte writes. */
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mData.mStatus != ProcessStatus_Started)
+    {
+        if (puWritten)
+            *puWritten = 0;
+        if (pGuestRc)
+            *pGuestRc = VINF_SUCCESS;
+        return VINF_SUCCESS; /* Not available for writing (anymore). */
+    }
 
     int vrc = VINF_SUCCESS;
 
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-    if (mData.mStatus != ProcessStatus_Started)
-    {
-        alock.release();
-
-        GuestProcessWaitResult waitRes;
-        vrc = waitFor(ProcessWaitForFlag_Start, uTimeoutMS, waitRes);
-        if (   RT_FAILURE(vrc)
-            || waitRes.mResult == ProcessWaitResult_Start)
-        {
-            if (RT_SUCCESS(vrc))
-                vrc = waitRes.mRC;
-        }
-        /** @todo More error handling needed. */
-    }
-
-    LogFlowFuncLeaveRC(vrc);
-    return vrc;
-}
-
-int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
-                            void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten)
-{
-    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p\n",
-                     mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten));
-    /* All is optional. There can be 0 byte writes. */
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (mData.mStatus != ProcessStatus_Started)
-        return VINF_SUCCESS; /* Not available for writing (anymore). */
-
+    GuestCtrlCallback *pCallbackWrite;
+    try
+    {
+        pCallbackWrite = new GuestCtrlCallback();
+        AssertPtr(pCallbackWrite);
+    }
+    catch(std::bad_alloc &)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    /* Create callback and add it to the map. */
     uint32_t uContextID = 0;
-    GuestCtrlCallback *pCallbackWrite = new GuestCtrlCallback();
-    if (!pCallbackWrite)
-        return VERR_NO_MEMORY;
-
-    /* Create callback and add it to the map. */
-    int vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS);
     if (RT_SUCCESS(vrc))
-        vrc = callbackAdd(pCallbackWrite, &uContextID);
+    {
+        vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS);
+        if (RT_SUCCESS(vrc))
+            vrc = callbackAdd(pCallbackWrite, &uContextID);
+    }
 
     alock.release(); /* Drop the write lock again. */
@@ -1501,8 +1561,8 @@
         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
         {
-            vrc = pCallbackWrite->GetResultCode();
-            LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackWrite->GetDataSize()));
-
-            if (RT_SUCCESS(vrc))
+            int guestRc = pCallbackWrite->GetResultCode();
+            LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackWrite->GetDataSize()));
+
+            if (RT_SUCCESS(guestRc))
             {
                 Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATAEXECINSTATUS));
@@ -1536,10 +1596,14 @@
                 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
 
+                if (pGuestRc)
+                    *pGuestRc = guestRc;
+
                 if (puWritten)
                     *puWritten = cbWritten;
+
+                if (RT_FAILURE(guestRc))
+                    vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
             }
         }
-        else
-            vrc = VERR_TIMEOUT;
     }
 
@@ -1573,6 +1637,8 @@
     Assert(data.size() >= aToRead);
 
-    size_t cbRead;
-    int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead);
+    HRESULT hr = S_OK;
+
+    size_t cbRead; int guestRc;
+    int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead, &guestRc);
     if (RT_SUCCESS(vrc))
     {
@@ -1581,11 +1647,23 @@
         data.detachTo(ComSafeArrayOutArg(aData));
     }
-
-    LogFlowThisFunc(("readData returned %Rrc, cbRead=%RU64\n", vrc, cbRead));
-
-    /** @todo Do setError() here. */
-    HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR;
+    else
+    {
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
+
+            default:
+                hr = setError(VBOX_E_IPRT_ERROR,
+                              tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
+                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
+                break;
+        }
+    }
+
+    LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead));
+
     LogFlowFuncLeaveRC(vrc);
-
     return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
@@ -1657,19 +1735,28 @@
      * Note: Do not hold any locks here while waiting!
      */
-    HRESULT hr;
-
-    GuestProcessWaitResult waitRes;
-    int vrc = waitFor(aWaitFlags, aTimeoutMS, waitRes);
+    HRESULT hr = S_OK;
+
+    int guestRc; ProcessWaitResult_T waitResult;
+    int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc);
     if (RT_SUCCESS(vrc))
     {
-        *aReason = waitRes.mResult;
-        hr = setErrorExternal();
+        *aReason = waitResult;
     }
     else
     {
-        hr = setError(VBOX_E_IPRT_ERROR,
-                      tr("Waiting for process \"%s\" (PID %RU32) failed with vrc=%Rrc"),
-                      mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
-    }
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
+
+            default:
+                hr = setError(VBOX_E_IPRT_ERROR,
+                              tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
+                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
+                break;
+        }
+    }
+
     LogFlowFuncLeaveRC(vrc);
     return hr;
@@ -1716,13 +1803,27 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
-    int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten);
-
-    LogFlowThisFunc(("writeData returned %Rrc, aWritten=%RU32\n", vrc, aWritten));
-
-    /** @todo Do setError() here. */
-    HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR;
+    HRESULT hr = S_OK;
+
+    com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc;
+    int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten, &guestRc);
+    if (RT_FAILURE(vrc))
+    {
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
+
+            default:
+                hr = setError(VBOX_E_IPRT_ERROR,
+                              tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
+                              mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
+                break;
+        }
+    }
+
+    LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten));
+
     LogFlowFuncLeaveRC(vrc);
-
     return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
@@ -1754,2 +1855,264 @@
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
+GuestProcessTool::GuestProcessTool(void)
+    : pSession(NULL)
+{
+}
+
+GuestProcessTool::~GuestProcessTool(void)
+{
+    Terminate();
+}
+
+int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
+                           bool fAsync, int *pGuestRc)
+{
+    LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",
+                     pGuestSession, startupInfo.mCommand.c_str(), fAsync));
+
+    AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
+
+    pSession     = pGuestSession;
+    mStartupInfo = startupInfo;
+
+    /* Make sure the process is hidden. */
+    mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
+
+    int vrc = pSession->processCreateExInteral(mStartupInfo, pProcess);
+    if (RT_SUCCESS(vrc))
+        vrc = fAsync ? pProcess->startProcessAsync() : pProcess->startProcess(pGuestRc);
+
+    if (   !fAsync
+        && (   pGuestRc
+            && RT_FAILURE(*pGuestRc)
+           )
+       )
+    {
+        vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+    }
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+int GuestProcessTool::GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
+{
+    const GuestProcessStream *pStream = NULL;
+    if (uHandle == OUTPUT_HANDLE_ID_STDOUT)
+        pStream = &mStdOut;
+    else if (uHandle == OUTPUT_HANDLE_ID_STDERR)
+        pStream = &mStdErr;
+
+    if (!pStream)
+        return VERR_INVALID_PARAMETER;
+
+    int vrc;
+    do
+    {
+        /* Try parsing the data to see if the current block is complete. */
+        vrc = mStdOut.ParseBlock(strmBlock);
+        if (strmBlock.GetCount())
+            break;
+    } while (RT_SUCCESS(vrc));
+
+    LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n",
+                      vrc, strmBlock.GetCount()));
+    return vrc;
+}
+
+bool GuestProcessTool::IsRunning(void)
+{
+    AssertReturn(!pProcess.isNull(), true);
+
+    ProcessStatus_T procStatus = ProcessStatus_Undefined;
+    HRESULT hr = pProcess->COMGETTER(Status(&procStatus));
+    Assert(SUCCEEDED(hr));
+
+    if (   procStatus != ProcessStatus_Started
+        && procStatus != ProcessStatus_Paused
+        && procStatus != ProcessStatus_Terminating)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+int GuestProcessTool::TerminatedOk(LONG *pExitCode)
+{
+    Assert(!pProcess.isNull());
+    /* pExitCode is optional. */
+
+    if (!IsRunning())
+    {
+        LONG exitCode;
+        HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode));
+        Assert(SUCCEEDED(hr));
+
+        if (pExitCode)
+            *pExitCode = exitCode;
+
+        if (exitCode != 0)
+            return VERR_NOT_EQUAL; /** @todo Special guest control rc needed! */
+        return VINF_SUCCESS;
+    }
+
+    return VERR_INVALID_STATE; /** @todo Special guest control rc needed! */
+}
+
+int GuestProcessTool::Wait(uint32_t fFlags, int *pGuestRc)
+{
+    return WaitEx(fFlags, NULL /* pStreamBlock */, pGuestRc);
+}
+
+int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc)
+{
+    LogFlowThisFunc(("pSession=%p, pProcess=%p, fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n",
+                     pSession, pProcess, fFlags, pStreamBlock, pGuestRc));
+
+    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+    Assert(!pProcess.isNull());
+    /* Other parameters are optional. */
+
+    /* Can we parse the next block without waiting? */
+    int vrc;
+    if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)
+    {
+        AssertPtr(pStreamBlock);
+        vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
+        if (RT_SUCCESS(vrc))
+            return vrc;
+    }
+
+    /* Do the waiting. */
+    uint32_t fWaitFlags = ProcessWaitForFlag_Terminate;
+    if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
+        fWaitFlags |= ProcessWaitForFlag_StdOut;
+    if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
+        fWaitFlags |= ProcessWaitForFlag_StdErr;
+
+    LogFlowFunc(("waitFlags=0x%x\n", fWaitFlags));
+
+    /** @todo Decrease timeout. */
+    uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS;
+
+    int guestRc;
+    bool fDone = false;
+
+    BYTE byBuf[_64K];
+    size_t cbRead;
+
+    bool fHandleStdOut = false;
+    bool fHandleStdErr = false;
+
+    ProcessWaitResult_T waitRes;
+    do
+    {
+        vrc = pProcess->waitFor(fWaitFlags,
+                                uTimeoutMS, waitRes, &guestRc);
+        if (RT_FAILURE(vrc))
+            break;
+
+        switch (waitRes)
+        {
+            case ProcessWaitResult_StdOut:
+                fHandleStdOut = true;
+                break;
+
+            case ProcessWaitResult_StdErr:
+                fHandleStdErr = true;
+                break;
+
+            case ProcessWaitResult_WaitFlagNotSupported:
+                if (fWaitFlags & ProcessWaitForFlag_StdOut)
+                    fHandleStdOut = true;
+                if (fWaitFlags & ProcessWaitForFlag_StdErr)
+                    fHandleStdErr = true;
+                /* Since waiting for stdout / stderr is not supported by the guest,
+                 * wait a bit to not hog the CPU too much when polling for data. */
+                RTThreadSleep(1); /* Optional, don't check rc. */
+                break;
+
+            case ProcessWaitResult_Error:
+            case ProcessWaitResult_Terminate:
+                fDone = true;
+                break;
+
+            default:
+                AssertMsgFailed(("Unhandled process wait result %ld\n", waitRes));
+                fDone = true;
+                break;
+        }
+
+        if (fHandleStdOut)
+        {
+            vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
+                                     uTimeoutMS, byBuf, sizeof(byBuf),
+                                     &cbRead, &guestRc);
+            if (RT_FAILURE(vrc))
+                break;
+
+            if (cbRead)
+            {
+                LogFlowThisFunc(("Received %RU64 bytes from stdout\n", cbRead));
+                vrc = mStdOut.AddData(byBuf, cbRead);
+
+                if (   RT_SUCCESS(vrc)
+                    && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK))
+                {
+                    AssertPtr(pStreamBlock);
+                    vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
+                    if (RT_SUCCESS(vrc))
+                        fDone = true;
+                }
+            }
+
+            fHandleStdOut = false;
+        }
+
+        if (fHandleStdErr)
+        {
+            vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf),
+                                     uTimeoutMS, byBuf, sizeof(byBuf),
+                                     &cbRead, &guestRc);
+            if (RT_FAILURE(vrc))
+                break;
+
+            if (cbRead)
+            {
+                LogFlowThisFunc(("Received %RU64 bytes from stderr\n", cbRead));
+                vrc = mStdErr.AddData(byBuf, cbRead);
+            }
+
+            fHandleStdErr = false;
+        }
+
+    } while (!fDone && RT_SUCCESS(vrc));
+
+    LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%ld\n",
+                     vrc, guestRc, waitRes));
+    if (pGuestRc)
+        *pGuestRc = guestRc;
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+void GuestProcessTool::Terminate(void)
+{
+    LogFlowThisFuncEnter();
+
+    if (!pProcess.isNull())
+    {
+        Assert(pSession);
+        int rc2 = pSession->processRemoveFromList(pProcess);
+        AssertRC(rc2);
+
+        pProcess.setNull();
+    }
+
+    LogFlowThisFuncLeave();
+}
+
Index: trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 43161)
+++ trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 43162)
@@ -426,5 +426,5 @@
             Assert(mData.mDirectories.size());
             LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n",
-                         Utf8Str(strName).c_str(), mData.mNumObjects - 1));
+                         Utf8Str(strName).c_str(), mData.mId, mData.mDirectories.size() - 1));
 
             mData.mDirectories.erase(itDirs);
@@ -436,5 +436,5 @@
 }
 
-int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags)
+int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc)
 {
     LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",
@@ -442,9 +442,8 @@
 
     GuestProcessStartupInfo procInfo;
-    procInfo.mName      = Utf8StrFmt(tr("Creating directory \"%s\"", strPath.c_str()));
-    procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
-    procInfo.mFlags     = ProcessCreateFlag_Hidden;
-
-    int rc = VINF_SUCCESS;
+    procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
+    procInfo.mFlags   = ProcessCreateFlag_Hidden;
+
+    int vrc = VINF_SUCCESS;
 
     /* Construct arguments. */
@@ -461,76 +460,60 @@
         }
         else
-            rc = VERR_INVALID_PARAMETER;
+            vrc = VERR_BUFFER_OVERFLOW;
     }
     procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
 
-    ComObjPtr<GuestProcess> pProcess;
-    rc = processCreateExInteral(procInfo, pProcess);
-    if (RT_SUCCESS(rc))
-        rc = pProcess->startProcess();
-    if (RT_SUCCESS(rc))
-    {
-        GuestProcessWaitResult waitRes;
-        rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 30 * 1000 /* Timeout */, waitRes);
-        if (RT_SUCCESS(rc))
-        {
-            ProcessStatus_T procStatus;
-            HRESULT hr = pProcess->COMGETTER(Status)(&procStatus);
-            ComAssertComRC(hr);
-            if (procStatus == ProcessStatus_TerminatedNormally)
-            {
-                LONG lExitCode;
-                pProcess->COMGETTER(ExitCode)(&lExitCode);
-                if (lExitCode != 0)
-                    return VERR_CANT_CREATE;
-            }
-            else
-                rc = VERR_BROKEN_PIPE; /** @todo Find a better rc. */
-        }
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
+    int guestRc;
+    if (RT_SUCCESS(vrc))
+    {
+        GuestProcessTool procTool;
+        vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
+        if (RT_SUCCESS(vrc))
+        {
+            if (RT_SUCCESS(guestRc))
+                vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
+        }
+
+        if (RT_SUCCESS(vrc))
+        {
+            if (RT_SUCCESS(guestRc))
+                guestRc = procTool.TerminatedOk(NULL /* Exit code */);
+        }
+
+        if (pGuestRc)
+            *pGuestRc = guestRc;
+    }
+
+    LogFlowFuncLeaveRC(vrc);
+    if (RT_FAILURE(vrc))
+        return vrc;
+    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
+}
+
+int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
 {
     LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
 
-    int rc = fsQueryInfoInternal(strPath, objData);
-    if (RT_SUCCESS(rc))
-    {
-        rc = objData.mType == FsObjType_Directory
-           ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-int GuestSession::objectCreateTempInternal(Utf8Str strTemplate,
-                                           Utf8Str strPath,
-                                           bool fDirectory,
-                                           Utf8Str &strName, int *prc)
+    int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
+    if (RT_SUCCESS(vrc))
+    {
+        vrc = objData.mType == FsObjType_Directory
+            ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
+    }
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath,
+                                           bool fDirectory, const Utf8Str &strName, int *pGuestRc)
 {
     GuestProcessStartupInfo procInfo;
-    GuestProcessStream      streamOut;
-    ComObjPtr<GuestProcess> pProcess;
-    int rc = VINF_SUCCESS;
-
-    if (fDirectory)
-        procInfo.mName    = Utf8StrFmt(tr("Creating temporary directory from template \"%s\"",
-                                   strTemplate.c_str()));
-    else
-        procInfo.mName    = Utf8StrFmt(tr("Creating temporary file from template \"%s\"",
-                                   strTemplate.c_str()));
     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
-    procInfo.mFlags   =   ProcessCreateFlag_Hidden
-                        | ProcessCreateFlag_WaitForStdOut;
-    /* Construct arguments. */
+    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
     procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
     if (fDirectory)
         procInfo.mArguments.push_back(Utf8Str("-d"));
-    if (strPath.length())  /* Otherwise use /tmp or equivalent. */
+    if (strPath.length()) /* Otherwise use /tmp or equivalent. */
     {
         procInfo.mArguments.push_back(Utf8Str("-t"));
@@ -539,80 +522,24 @@
     procInfo.mArguments.push_back(strTemplate);
 
-    rc = processCreateExInteral(procInfo, pProcess);
-    if (RT_SUCCESS(rc))
-        rc = pProcess->startProcess();
-    if (RT_SUCCESS(rc))
-    {
-        GuestProcessWaitResult waitRes;
-        BYTE byBuf[_64K];
-        size_t cbRead;
-
-        for (;;)
-        {
-            rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
-                                   30 * 1000 /* Timeout */, waitRes);
-            if (   RT_FAILURE(rc)
-                || waitRes.mResult == ProcessWaitResult_Terminate
-                || waitRes.mResult == ProcessWaitResult_Error
-                || waitRes.mResult == ProcessWaitResult_Timeout)
-            {
-                break;
-            }
-
-            rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
-                                    30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
-                                    &cbRead);
-            if (RT_FAILURE(rc))
-                break;
-
-            if (cbRead)
-            {
-                rc = streamOut.AddData(byBuf, cbRead);
-                if (RT_FAILURE(rc))
-                    break;
-            }
-        }
-
-        LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
-                         rc, cbRead, streamOut.GetSize()));
-    }
-    else
-        LogThisFunc(("Error while starting temporary object creation tool on guest: %Rrc\n", rc));
-    if (RT_FAILURE(rc))
-        LogThisFunc(("Error while running temporary object creation tool: %Rrc\n", rc));
-    else if (!streamOut.GetSize())
-    {
-        LogThisFunc(("No return code after creating temporary object\n"));
-        rc = VERR_NO_DATA;
-    }
-    if (RT_SUCCESS(rc))
-    {
-        const char *pcszName;
-        int64_t i64rc;
-        GuestProcessStreamBlock streamBlock;
-        rc = streamOut.ParseBlock(streamBlock);
-        if (RT_SUCCESS(rc))
-        {
-            pcszName = streamBlock.GetString("name");
-            if (pcszName)
-                strName = pcszName;
-            else
-            {
-                LogThisFunc(("No name returned after creating temporary object\n"));
-                rc = VERR_NO_DATA;
-            }
-            if (RT_FAILURE(rc = streamBlock.GetInt64Ex("rc", &i64rc)))
-                LogThisFunc(("No return code after creating temporary object\n"));
-        }
-        if (   RT_SUCCESS(rc)
-            && (   i64rc == VERR_INVALID_PARAMETER
-                || i64rc == VERR_NOT_SUPPORTED))
-            rc = (int)i64rc;
-        if (RT_SUCCESS(rc))
-            *prc = (int)i64rc;
-    }
-    else
-        LogThisFunc(("Error while getting return code from creating temporary object: %Rrc\n", rc));
-    return rc;
+    GuestProcessTool procTool; int guestRc;
+    int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
+    if (RT_SUCCESS(vrc))
+    {
+        if (RT_SUCCESS(guestRc))
+            vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
+    }
+
+    if (RT_SUCCESS(vrc))
+    {
+        if (RT_SUCCESS(guestRc))
+            guestRc = procTool.TerminatedOk(NULL /* Exit code */);
+    }
+
+    if (pGuestRc)
+        *pGuestRc = guestRc;
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
 }
 
@@ -630,8 +557,8 @@
         return VERR_COM_UNEXPECTED;
 
-    int rc = pDirectory->init(this /* Parent */,
-                              strPath, strFilter, uFlags);
-    if (RT_FAILURE(rc))
-        return rc;
+    int vrc = pDirectory->init(this /* Parent */,
+                               strPath, strFilter, uFlags);
+    if (RT_FAILURE(vrc))
+        return vrc;
 
     /* Add the created directory to our vector. */
@@ -641,6 +568,6 @@
                  strPath.c_str(), mData.mId));
 
-    LogFlowFuncLeaveRC(rc);
-    return rc;
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
 }
 
@@ -704,91 +631,35 @@
 }
 
-/**
- * Implementation of FileRemove().  Can throw an exception due to the use of
- * Utf8Str, Utf8StrFmt and std::vector near the beginning (and others?).  The
- * caller should catch this.  On success, *prc will be set to the return code
- * of the delete operation to distinguish between API and command failure.
- */
-int GuestSession::fileRemoveInternal(Utf8Str strPath, int *prc)
+int GuestSession::fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc)
 {
     GuestProcessStartupInfo procInfo;
     GuestProcessStream      streamOut;
-    int rc = VINF_SUCCESS;
-
-    AssertPtrReturn(prc, VERR_INVALID_POINTER);
-    procInfo.mName    = Utf8StrFmt(tr("Removing file \"%s\"",
-                                   strPath.c_str()));
+
     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
-    procInfo.mFlags   =   ProcessCreateFlag_Hidden
-                        | ProcessCreateFlag_WaitForStdOut;
-    /* Construct arguments. */
+    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
     procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
-    procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
-
-    ComObjPtr<GuestProcess> pProcess;
-    rc = processCreateExInteral(procInfo, pProcess);
-    if (RT_SUCCESS(rc))
-        rc = pProcess->startProcess();
-    if (RT_SUCCESS(rc))
-    {
-        GuestProcessWaitResult waitRes;
-        BYTE byBuf[_64K];
-        size_t cbRead;
-
-        for (;;)
-        {
-            rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
-                                   30 * 1000 /* Timeout */, waitRes);
-            if (   RT_FAILURE(rc)
-                || waitRes.mResult == ProcessWaitResult_Terminate
-                || waitRes.mResult == ProcessWaitResult_Error
-                || waitRes.mResult == ProcessWaitResult_Timeout)
-            {
-                break;
-            }
-
-            rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
-                                    30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
-                                    &cbRead);
-            if (RT_FAILURE(rc))
-                break;
-
-            if (cbRead)
-            {
-                rc = streamOut.AddData(byBuf, cbRead);
-                if (RT_FAILURE(rc))
-                    break;
-            }
-        }
-
-        LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
-                         rc, cbRead, streamOut.GetSize()));
-    }
-    else
-        LogThisFunc(("Error starting delete tool on guest: %Rrc\n", rc));
-    if (RT_FAILURE(rc))
-        LogThisFunc(("Error running delete tool on guest: %Rrc\n", rc));
-    else if (!streamOut.GetSize())
-    {
-        LogThisFunc(("No return code after deleting file"));
-        rc = VERR_NO_DATA;
-    }
-    if (RT_SUCCESS(rc))
-    {
-        GuestProcessStreamBlock streamBlock;
-        int64_t i64rc;
-        rc = streamOut.ParseBlock(streamBlock);
-        streamBlock.GetString("fname");
-        rc = streamBlock.GetInt64Ex("rc", &i64rc);
-        if (RT_SUCCESS(rc))
-            *prc = (int)i64rc;
-    }
-    else
-        Log(("Error getting return code from deleting file: %Rrc\n", rc));
-    return rc;
+    procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
+
+    GuestProcessTool procTool; int guestRc;
+    int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
+    if (RT_SUCCESS(vrc))
+        vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
+
+    if (RT_SUCCESS(vrc))
+    {
+        if (RT_SUCCESS(guestRc))
+            guestRc = procTool.TerminatedOk(NULL /* Exit code */);
+    }
+
+    if (pGuestRc)
+        *pGuestRc = guestRc;
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
 }
 
 int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,
-                                   uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile)
+                                   uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile, int *pGuestRc)
 {
     LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
@@ -800,8 +671,9 @@
         return VERR_COM_UNEXPECTED;
 
-    int rc = pFile->init(this /* Parent */,
-                         strPath, strOpenMode, strDisposition, uCreationMode, iOffset);
-    if (RT_FAILURE(rc))
-        return rc;
+    int vrc = pFile->init(this /* Parent */,
+                          strPath, strOpenMode, strDisposition, uCreationMode, iOffset, pGuestRc);
+    if (RT_FAILURE(vrc))
+        return vrc;
+    /** @todo Handle guestRc. */
 
     /* Add the created directory to our vector. */
@@ -813,41 +685,36 @@
                  strPath.c_str(), mData.mId, mData.mProcesses.size(), mData.mNumObjects));
 
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
 {
     LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
 
-    int rc = fsQueryInfoInternal(strPath, objData);
-    if (RT_SUCCESS(rc))
-    {
-        rc = objData.mType == FsObjType_File
-           ? VINF_SUCCESS : VERR_NOT_A_FILE;
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize)
+    int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
+    if (RT_SUCCESS(vrc))
+    {
+        vrc = objData.mType == FsObjType_File
+            ? VINF_SUCCESS : VERR_NOT_A_FILE;
+    }
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc)
 {
     AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
 
     GuestFsObjData objData;
-    int rc = fileQueryInfoInternal(strPath, objData);
-    if (RT_SUCCESS(rc))
-    {
-        if (objData.mType == FsObjType_File)
-            *pllSize = objData.mObjectSize;
-        else
-            rc = VERR_NOT_A_FILE;
-    }
-
-    return rc;
-}
-
-int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
+    int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc);
+    if (RT_SUCCESS(vrc))
+        *pllSize = objData.mObjectSize;
+
+    return vrc;
+}
+
+int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
 {
     LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
@@ -855,7 +722,6 @@
     /** @todo Merge this with IGuestFile::queryInfo(). */
     GuestProcessStartupInfo procInfo;
-    procInfo.mName    = Utf8StrFmt(tr("Querying info for \"%s\""), strPath.c_str());
     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
-    procInfo.mFlags   = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
+    procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
 
     /* Construct arguments. */
@@ -863,61 +729,28 @@
     procInfo.mArguments.push_back(strPath);
 
-    GuestProcessStream streamOut;
-
-    ComObjPtr<GuestProcess> pProcess;
-    int rc = processCreateExInteral(procInfo, pProcess);
-    if (RT_SUCCESS(rc))
-        rc = pProcess->startProcess();
-    if (RT_SUCCESS(rc))
-    {
-        GuestProcessWaitResult waitRes;
-        BYTE byBuf[_64K];
-        size_t cbRead = 0;
-
-        /** @todo Merge with GuestDirectory::read. */
-        for (;;)
-        {
-            rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
-                                   30 * 1000 /* Timeout */, waitRes);
-            if (   RT_FAILURE(rc)
-                || waitRes.mResult == ProcessWaitResult_Terminate
-                || waitRes.mResult == ProcessWaitResult_Error
-                || waitRes.mResult == ProcessWaitResult_Timeout)
-            {
-                break;
-            }
-
-            rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
-                                    30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
-                                    &cbRead);
-            if (RT_FAILURE(rc))
-                break;
-
-            if (cbRead)
-            {
-                rc = streamOut.AddData(byBuf, cbRead);
-                if (RT_FAILURE(rc))
-                    break;
-            }
-        }
-
-        LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
-                         rc, cbRead, streamOut.GetSize()));
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        GuestProcessStreamBlock streamBlock;
-        rc = streamOut.ParseBlock(streamBlock);
-        if (RT_SUCCESS(rc))
-        {
-            rc = objData.FromStat(streamBlock);
-        }
-        else
-            AssertMsgFailed(("Parsing stream block failed: %Rrc\n", rc));
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
+    GuestProcessTool procTool; int guestRc;
+    int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
+    if (RT_SUCCESS(vrc))
+        vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
+    if (RT_SUCCESS(vrc))
+    {
+        guestRc = procTool.TerminatedOk(NULL /* Exit code */);
+        if (RT_SUCCESS(guestRc))
+        {
+            GuestProcessStreamBlock curBlock;
+            vrc = procTool.GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT,  curBlock);
+            /** @todo Check for more / validate blocks! */
+            if (RT_SUCCESS(vrc))
+                vrc = objData.FromStat(curBlock);
+        }
+    }
+
+    if (pGuestRc)
+        *pGuestRc = guestRc;
+
+    LogFlowFuncLeaveRC(vrc);
+    if (RT_FAILURE(vrc))
+        return vrc;
+    return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
 }
 
@@ -1341,10 +1174,14 @@
     HRESULT hr = S_OK;
 
-    ComObjPtr <GuestDirectory> pDirectory;
-    int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags);
+    ComObjPtr <GuestDirectory> pDirectory; int guestRc;
+    int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags, &guestRc);
     if (RT_FAILURE(rc))
     {
         switch (rc)
         {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
+
             case VERR_INVALID_PARAMETER:
                hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
@@ -1377,32 +1214,38 @@
 
     if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
-        return setError(E_INVALIDARG, tr("No file to remove specified"));
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    int rc = VINF_SUCCESS;
-
-    try  /* Can this be done without exceptions? */
-    {
-        Utf8Str strName;
-        if (RT_FAILURE(objectCreateTempInternal(Utf8Str(aTemplate),
-                                                Utf8Str(aPath),
-                                                true, strName, &rc)))
-            return E_FAIL;
-        HRESULT hrc =   rc == VERR_INVALID_PARAMETER ? E_INVALIDARG
-                      : rc == VERR_NOT_SUPPORTED ? VBOX_E_NOT_SUPPORTED
-                      : RT_FAILURE(rc) ? VBOX_E_IPRT_ERROR
-                      : S_OK;
-        if (FAILED(hrc))
-            return setError(hrc, tr("Temporary directory creation failed: %Rrc"),
-                            rc);
+        return setError(E_INVALIDARG, tr("No template specified"));
+    if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
+        return setError(E_INVALIDARG, tr("No directory name specified"));
+    CheckComArgOutPointerValid(aDirectory);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    HRESULT hr = S_OK;
+
+    Utf8Str strName; int guestRc;
+    int rc = objectCreateTempInternal(Utf8Str(aTemplate),
+                                      Utf8Str(aPath),
+                                      true /* Directory */, strName, &guestRc);
+    if (RT_SUCCESS(rc))
+    {
         strName.cloneTo(aDirectory);
-        return S_OK;
-    }
-    catch (...)
-    {
-        return E_OUTOFMEMORY;
-    }
+    }
+    else
+    {
+        switch (rc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
+
+            default:
+               hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
+                             Utf8Str(aPath).c_str(), Utf8Str(aTemplate).c_str(), rc);
+               break;
+        }
+    }
+
+    return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
 }
@@ -1424,6 +1267,6 @@
     HRESULT hr = S_OK;
 
-    GuestFsObjData objData;
-    int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);
+    GuestFsObjData objData; int guestRc;
+    int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
     if (RT_SUCCESS(rc))
     {
@@ -1434,8 +1277,11 @@
         switch (rc)
         {
-            /** @todo Add more errors here! */
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
 
             default:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc);
+               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
+                             Utf8Str(aPath).c_str(), rc);
                break;
         }
@@ -1456,6 +1302,5 @@
         return setError(E_INVALIDARG, tr("No directory to open specified"));
     if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
-        return setError(E_INVALIDARG, tr("Directory filters not implemented yet"));
-
+        return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
     CheckComArgOutPointerValid(aDirectory);
 
@@ -1480,15 +1325,6 @@
     if (RT_SUCCESS(rc))
     {
-        if (aDirectory)
-        {
-            /* Return directory object to the caller. */
-            hr = pDirectory.queryInterfaceTo(aDirectory);
-        }
-        else
-        {
-            rc = directoryRemoveFromList(pDirectory);
-            if (RT_FAILURE(rc))
-                hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);
-        }
+        /* Return directory object to the caller. */
+        hr = pDirectory.queryInterfaceTo(aDirectory);
     }
     else
@@ -1497,13 +1333,11 @@
         {
             case VERR_INVALID_PARAMETER:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given"));
+               hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given",
+                                                   Utf8Str(aPath).c_str()));
                break;
 
-            case VERR_BROKEN_PIPE:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));
-               break;
-
             default:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc);
+               hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
+                             Utf8Str(aPath).c_str(),rc);
                break;
         }
@@ -1530,7 +1364,7 @@
     HRESULT hr = S_OK;
 
-    GuestFsObjData objData;
-    int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);
-    if (RT_SUCCESS(rc))
+    GuestFsObjData objData; int guestRc;
+    int vrc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
+    if (RT_SUCCESS(vrc))
     {
         if (objData.mType == FsObjType_Directory)
@@ -1538,25 +1372,31 @@
             ComObjPtr<GuestFsObjInfo> pFsObjInfo;
             hr = pFsObjInfo.createObject();
-            if (FAILED(hr))
-                return VERR_COM_UNEXPECTED;
-
-            rc = pFsObjInfo->init(objData);
-            if (RT_SUCCESS(rc))
+            if (FAILED(hr)) return hr;
+
+            vrc = pFsObjInfo->init(objData);
+            if (RT_SUCCESS(vrc))
+            {
                 hr = pFsObjInfo.queryInterfaceTo(aInfo);
-        }
-    }
-
-    if (RT_FAILURE(rc))
-    {
-        switch (rc)
-        {
-            /** @todo Add more errors here! */
+                if (FAILED(hr)) return hr;
+            }
+        }
+    }
+
+    if (RT_FAILURE(vrc))
+    {
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
 
             case VERR_NOT_A_DIRECTORY:
-                hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a directory"));
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory",
+                                                    Utf8Str(aPath).c_str()));
                 break;
 
             default:
-                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information failed: %Rrc"), rc);
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
+                              Utf8Str(aPath).c_str(), vrc);
                 break;
         }
@@ -1737,22 +1577,28 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
+    GuestFsObjData objData; int guestRc;
+    int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
+    if (RT_SUCCESS(vrc))
+    {
+        *aExists = TRUE;
+        return S_OK;
+    }
+
     HRESULT hr = S_OK;
 
-    GuestFsObjData objData;
-    int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
-    if (RT_SUCCESS(rc))
-    {
-        *aExists = objData.mType == FsObjType_File;
-    }
-    else
-    {
-        switch (rc)
-        {
-            /** @todo Add more errors here! */
-
-            default:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc);
-               break;
-        }
+    switch (vrc)
+    {
+        case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+            hr = GuestProcess::setErrorExternal(this, guestRc);
+            break;
+
+        case VERR_NOT_A_FILE:
+            *aExists = FALSE;
+            break;
+
+        default:
+            hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
+                          Utf8Str(aPath).c_str(), vrc);
+            break;
     }
 
@@ -1774,20 +1620,24 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    try  /* Can this be done without exceptions? */
-    {
-        int rc2;
-        int rc = fileRemoveInternal(Utf8Str(aPath), &rc2);
-        if (RT_FAILURE((rc)))
-            return setError(E_FAIL,
-                            tr("Internal error deleting file: %Rrc"), rc);
-        else if (RT_FAILURE((rc2)))
-            return setError(VBOX_E_IPRT_ERROR,
-                            tr("File deletion on guest returned: %Rrc"), rc2);
-    }
-    catch (...)
-    {
-        return E_OUTOFMEMORY;
-    }
-    return S_OK;
+    HRESULT hr = S_OK;
+
+    int guestRc;
+    int vrc = fileRemoveInternal(Utf8Str(aPath), &guestRc);
+    if (RT_FAILURE(vrc))
+    {
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
+
+            default:
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
+                              Utf8Str(aPath).c_str(), vrc);
+                break;
+        }
+    }
+
+    return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
 }
@@ -1820,8 +1670,8 @@
     HRESULT hr = S_OK;
 
-    ComObjPtr <GuestFile> pFile;
-    int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
-                              aCreationMode, aOffset, pFile);
-    if (RT_SUCCESS(rc))
+    ComObjPtr <GuestFile> pFile; int guestRc;
+    int vrc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
+                               aCreationMode, aOffset, pFile, &guestRc);
+    if (RT_SUCCESS(vrc))
     {
         /* Return directory object to the caller. */
@@ -1830,11 +1680,14 @@
     else
     {
-        switch (rc)
-        {
-            /** @todo Add more error info! */
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
 
             default:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
-               break;
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Creating directory \"%s\" failed: %Rrc"),
+                              Utf8Str(aPath).c_str(), vrc);
+                break;
         }
     }
@@ -1860,23 +1713,27 @@
     HRESULT hr = S_OK;
 
-    GuestFsObjData objData;
-    int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
-    if (RT_SUCCESS(rc))
+    GuestFsObjData objData; int guestRc;
+    int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
+    if (RT_SUCCESS(vrc))
     {
         ComObjPtr<GuestFsObjInfo> pFsObjInfo;
         hr = pFsObjInfo.createObject();
-        if (FAILED(hr))
-            return VERR_COM_UNEXPECTED;
-
-        rc = pFsObjInfo->init(objData);
-        if (RT_SUCCESS(rc))
+        if (FAILED(hr)) return hr;
+
+        vrc = pFsObjInfo->init(objData);
+        if (RT_SUCCESS(vrc))
+        {
             hr = pFsObjInfo.queryInterfaceTo(aInfo);
-    }
-
-    if (RT_FAILURE(rc))
-    {
-        switch (rc)
-        {
-            /** @todo Add more errors here! */
+            if (FAILED(hr)) return hr;
+        }
+    }
+
+    if (RT_FAILURE(vrc))
+    {
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
 
             case VERR_NOT_A_FILE:
@@ -1885,5 +1742,5 @@
 
             default:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), rc);
+               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
                break;
         }
@@ -1910,7 +1767,7 @@
     HRESULT hr = S_OK;
 
-    int64_t llSize;
-    int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);
-    if (RT_SUCCESS(rc))
+    int64_t llSize; int guestRc;
+    int vrc = fileQuerySizeInternal(Utf8Str(aPath), &llSize, &guestRc);
+    if (RT_SUCCESS(vrc))
     {
         *aSize = llSize;
@@ -1918,10 +1775,12 @@
     else
     {
-        switch (rc)
-        {
-            /** @todo Add more errors here! */
+        switch (vrc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                hr = GuestProcess::setErrorExternal(this, guestRc);
+                break;
 
             default:
-               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);
+               hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
                break;
         }
@@ -1970,7 +1829,6 @@
     com::SafeArray<LONG> affinity;
 
-    HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
-                                 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
-    return hr;
+    return ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
+                           ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
 #endif /* VBOX_WITH_GUEST_CONTROL */
 }
Index: trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 43161)
+++ trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp	(revision 43162)
@@ -50,8 +50,8 @@
  * Update file flags.
  */
-#define UPDATEFILE_FLAG_NONE                RT_BIT(0)
+#define UPDATEFILE_FLAG_NONE                0
 /** Copy over the file from host to the
  *  guest. */
-#define UPDATEFILE_FLAG_COPY_FROM_ISO       RT_BIT(1)
+#define UPDATEFILE_FLAG_COPY_FROM_ISO       RT_BIT(0)
 /** Execute file on the guest after it has
  *  been successfully transfered. */
@@ -251,6 +251,4 @@
 
     GuestProcessStartupInfo procInfo;
-    procInfo.mName    = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"),
-                                   mSource.c_str(), mDest.c_str(), mSourceSize);
     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT);
     procInfo.mFlags   = ProcessCreateFlag_Hidden;
@@ -260,16 +258,28 @@
 
     /* Startup process. */
-    ComObjPtr<GuestProcess> pProcess;
+    ComObjPtr<GuestProcess> pProcess; int guestRc;
     rc = pSession->processCreateExInteral(procInfo, pProcess);
     if (RT_SUCCESS(rc))
-        rc = pProcess->startProcess();
+        rc = pProcess->startProcess(&guestRc);
     if (RT_FAILURE(rc))
     {
-        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                            Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc));
-    }
-    else
-    {
-        GuestProcessWaitResult waitRes;
+        switch (rc)
+        {
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                    GuestProcess::guestErrorToString(guestRc));
+                break;
+
+            default:
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                    Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
+                                               mSource.c_str(), rc));
+                break;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        ProcessWaitResult_T waitRes;
         BYTE byBuf[_64K];
 
@@ -280,9 +290,10 @@
         for (;;)
         {
+            int guestRc;
             rc = pProcess->waitFor(ProcessWaitForFlag_StdIn,
-                                   30 * 1000 /* Timeout */, waitRes);
+                                   30 * 1000 /* Timeout */, waitRes, &guestRc);
             if (   RT_FAILURE(rc)
-                || (   waitRes.mResult != ProcessWaitResult_StdIn
-                    && waitRes.mResult != ProcessWaitResult_WaitFlagNotSupported))
+                || (   waitRes != ProcessWaitResult_StdIn
+                    && waitRes != ProcessWaitResult_WaitFlagNotSupported))
             {
                 break;
@@ -291,6 +302,6 @@
             /* If the guest does not support waiting for stdin, we now yield in
              * order to reduce the CPU load due to busy waiting. */
-            if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
-                RTThreadYield(); /* Optional, don't check rc. */
+            if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
+                RTThreadSleep(1); /* Optional, don't check rc. */
 
             size_t cbRead = 0;
@@ -320,5 +331,5 @@
                 {
                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                        Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"),
+                                        Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" to offset %RU64 failed: %Rrc"),
                                                    mSource.c_str(), cbWrittenTotal, rc));
                     break;
@@ -333,8 +344,10 @@
                 || (cbToRead - cbRead == 0)
                 /* ... or does the user want to cancel? */
-                || (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
+                || (   !mProgress.isNull()
+                    && SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
                     && fCanceled)
                )
             {
+                LogFlowThisFunc(("Writing last chunk cbRead=%RU64\n", cbRead));
                 fFlags |= ProcessInputFlag_EndOfFile;
             }
@@ -344,15 +357,23 @@
             rc = pProcess->writeData(0 /* StdIn */, fFlags,
                                      byBuf, cbRead,
-                                     30 * 1000 /* Timeout */, &cbWritten);
+                                     30 * 1000 /* Timeout */, &cbWritten, &guestRc);
             if (RT_FAILURE(rc))
             {
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),
-                                               mDest.c_str(), cbWrittenTotal, rc));
+                switch (rc)
+                {
+                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            GuestProcess::guestErrorToString(guestRc));
+                        break;
+
+                    default:
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),
+                                            mDest.c_str(), cbWrittenTotal, rc));
+                        break;
+                }
+
                 break;
             }
-
-            LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
-                             cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize));
 
             /* Only subtract bytes reported written by the guest. */
@@ -363,4 +384,7 @@
             cbWrittenTotal += cbWritten;
             Assert(cbWrittenTotal <= mSourceSize);
+
+            LogFlowThisFunc(("rc=%Rrc, cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
+                             rc, cbWritten, cbToRead, cbWrittenTotal, mSourceSize));
 
             /* Did the user cancel the operation above? */
@@ -381,4 +405,6 @@
         } /* for */
 
+        LogFlowThisFunc(("Copy loop ended with rc=%Rrc\n" ,rc));
+
         if (   !fCanceled
             || RT_SUCCESS(rc))
@@ -393,30 +419,35 @@
                 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
                  * to the destination -> access denied. */
-                rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                         Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
-                                                    mSource.c_str(), mDest.c_str()));
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                    Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
+                                               mSource.c_str(), mDest.c_str()));
+                rc = VERR_GENERAL_FAILURE; /* Fudge. */
             }
             else if (cbWrittenTotal < mSourceSize)
             {
                 /* If we did not copy all let the user know. */
-                rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                         Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"),
-                                                    mSource.c_str(), cbWrittenTotal, mSourceSize));
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                    Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"),
+                                               mSource.c_str(), cbWrittenTotal, mSourceSize));
+                rc = VERR_GENERAL_FAILURE; /* Fudge. */
             }
             else
             {
                 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,
-                                       30 * 1000 /* Timeout */, waitRes);
+                                       30 * 1000 /* Timeout */, waitRes, &guestRc);
                 if (   RT_FAILURE(rc)
-                    || waitRes.mResult != ProcessWaitResult_Terminate)
+                    || waitRes != ProcessWaitResult_Terminate)
                 {
                     if (RT_FAILURE(rc))
-                        rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                                 Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"),
-                                                            mSource.c_str(), rc));
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"),
+                                                       mSource.c_str(), rc));
                     else
-                        rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                                 Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),
-                                                            mSource.c_str(), waitRes.mResult));
+                    {
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),
+                                                       mSource.c_str(), waitRes));
+                        rc = VERR_GENERAL_FAILURE; /* Fudge. */
+                    }
                 }
 
@@ -431,7 +462,8 @@
                        )
                     {
-                        rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                                 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"),
-                                                            mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"),
+                                                       mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */
+                        rc = VERR_GENERAL_FAILURE; /* Fudge. */
                     }
                 }
@@ -508,6 +540,6 @@
      ** @todo Implement guest file locking!
      */
-    GuestFsObjData objData;
-    int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData);
+    GuestFsObjData objData; int guestRc;
+    int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData, &guestRc);
     if (RT_FAILURE(rc))
     {
@@ -545,16 +577,27 @@
 
             /* Startup process. */
-            ComObjPtr<GuestProcess> pProcess;
+            ComObjPtr<GuestProcess> pProcess; int guestRc;
             rc = pSession->processCreateExInteral(procInfo, pProcess);
             if (RT_SUCCESS(rc))
-                rc = pProcess->startProcess();
+                rc = pProcess->startProcess(&guestRc);
             if (RT_FAILURE(rc))
             {
-                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Unable to start guest process for copying data from guest to host: %Rrc"), rc));
+                switch (rc)
+                {
+                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            GuestProcess::guestErrorToString(guestRc));
+                        break;
+
+                    default:
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
+                                                       mSource.c_str(), rc));
+                        break;
+                }
             }
             else
             {
-                GuestProcessWaitResult waitRes;
+                ProcessWaitResult_T waitRes;
                 BYTE byBuf[_64K];
 
@@ -563,25 +606,57 @@
                 uint64_t cbToRead = objData.mObjectSize;
 
+                int guestRc;
+
                 for (;;)
                 {
                     rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
-                                           30 * 1000 /* Timeout */, waitRes);
-                    if (   waitRes.mResult == ProcessWaitResult_StdOut
-                        || waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
+                                           30 * 1000 /* Timeout */, waitRes, &guestRc);
+                    if (RT_FAILURE(rc))
+                    {
+                        switch (rc)
+                        {
+                            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                                    GuestProcess::guestErrorToString(guestRc));
+                                break;
+
+                            default:
+                                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                                    Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
+                                                               mSource.c_str(), rc));
+                                break;
+                        }
+
+                        break;
+                    }
+
+                    if (   waitRes == ProcessWaitResult_StdOut
+                        || waitRes == ProcessWaitResult_WaitFlagNotSupported)
                     {
                         /* If the guest does not support waiting for stdin, we now yield in
                          * order to reduce the CPU load due to busy waiting. */
-                        if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
-                            RTThreadYield(); /* Optional, don't check rc. */
-
-                        size_t cbRead;
+                        if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
+                            RTThreadSleep(1); /* Optional, don't check rc. */
+
+                        size_t cbRead; int guestRc;
                         rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
                                                 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
-                                                &cbRead);
+                                                &cbRead, &guestRc);
                         if (RT_FAILURE(rc))
                         {
-                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                                Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"),
-                                                mSource.c_str(), cbWrittenTotal, rc));
+                            switch (rc)
+                            {
+                                case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                                        GuestProcess::guestErrorToString(guestRc));
+                                    break;
+
+                                default:
+                                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                                        Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"),
+                                                                   mSource.c_str(), cbWrittenTotal, rc));
+                                    break;
+                            }
+
                             break;
                         }
@@ -616,17 +691,13 @@
                         }
                     }
-                    else if (   RT_FAILURE(rc)
-                             || waitRes.mResult == ProcessWaitResult_Terminate
-                             || waitRes.mResult == ProcessWaitResult_Error
-                             || waitRes.mResult == ProcessWaitResult_Timeout)
+                    else
                     {
-                        if (RT_FAILURE(waitRes.mRC))
-                            rc = waitRes.mRC;
                         break;
                     }
+
                 } /* for */
 
-                LogFlowThisFunc(("rc=%Rrc, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
-                                 rc, cbWrittenTotal, objData.mObjectSize, cbToRead));
+                LogFlowThisFunc(("rc=%Rrc, guestrc=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
+                                 rc, guestRc, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead));
 
                 if (   !fCanceled
@@ -794,6 +865,6 @@
 
         GuestFsObjData objData;
-        int64_t cbSizeOnGuest;
-        rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest);
+        int64_t cbSizeOnGuest; int guestRc;
+        rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest, &guestRc);
         if (   RT_SUCCESS(rc)
             && cbSize == (uint64_t)cbSizeOnGuest)
@@ -811,6 +882,19 @@
             }
             else
-                LogFlowThisFunc(("Error copying Guest Additions installer file \"%s\": %Rrc\n",
-                                 strFileDest.c_str(), rc));
+            {
+                switch (rc)
+                {
+                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            GuestProcess::guestErrorToString(guestRc));
+                        break;
+
+                    default:
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            Utf8StrFmt(GuestSession::tr("Error while querying size for file \"%s\": %Rrc"),
+                                                       strFileDest.c_str(), rc));
+                        break;
+                }
+            }
         }
 
@@ -829,70 +913,41 @@
     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
 
-    ComObjPtr<GuestProcess> pProcess;
-    int rc = pSession->processCreateExInteral(procInfo, pProcess);
-    if (RT_SUCCESS(rc))
-        rc = pProcess->startProcess();
-
-    if (RT_SUCCESS(rc))
-    {
-        LogRel(("Running %s ...\n", procInfo.mName.c_str()));
-
-        GuestProcessWaitResult waitRes;
-        rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,
-                               10 * 60 * 1000 /* 10 mins Timeout */, waitRes);
-        LogFlowThisFunc(("waitFor rc=%Rrc, waitRes=%ld\n", rc, waitRes));
-        if (waitRes.mResult == ProcessWaitResult_Terminate)
-        {
-            ProcessStatus_T procStatus;
-            LONG exitCode;
-            if (   (   SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))
-                    && procStatus != ProcessStatus_TerminatedNormally)
-                || (   SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))
-                    && exitCode != 0)
-               )
-            {
+    LogRel(("Running %s ...\n", procInfo.mName.c_str()));
+
+    LONG exitCode;
+    GuestProcessTool procTool; int guestRc;
+    int vrc = procTool.Init(pSession, procInfo, false /* Async */, &guestRc);
+    if (RT_SUCCESS(vrc))
+    {
+        if (RT_SUCCESS(guestRc))
+            vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
+        if (RT_SUCCESS(vrc))
+            vrc = procTool.TerminatedOk(&exitCode);
+    }
+
+    if (RT_FAILURE(vrc))
+    {
+        switch (vrc)
+        {
+            case VERR_NOT_EQUAL: /** @todo Special guest control rc needed! */
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Running %s failed with status %ld, exit code %ld"),
-                                               procInfo.mName.c_str(), procStatus, exitCode));
-                rc = VERR_GENERAL_FAILURE; /* Fudge. */
-            }
-            else /* Yay, success! */
-            {
-                LogFlowThisFunc(("%s successfully completed\n", procInfo.mName.c_str()));
-            }
-        }
-        else if (   procInfo.mFlags == ProcessCreateFlag_WaitForProcessStartOnly
-                 && waitRes.mResult == ProcessWaitResult_Start)
-        {
-            LogFlowThisFunc(("%s successfully started\n", procInfo.mName.c_str()));
-        }
-        else
-        {
-            /** @todo Unify error handling. */
-            if (RT_FAILURE(rc))
-            {
+                                    Utf8StrFmt(GuestSession::tr("Running update file \"%s\" on guest terminated with exit code %ld"),
+                                               procInfo.mCommand.c_str(), exitCode));
+                break;
+
+            case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                    Utf8StrFmt(GuestSession::tr("Error while waiting running %s: %Rrc"),
-                                               procInfo.mName.c_str(), rc));
-            }
-            else
-            {
-                if (pProcess->errorMsg().isEmpty())
-                {
-                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                        Utf8StrFmt(GuestSession::tr("Running %s returned unexpectedly with status %ld"),
-                                                   procInfo.mName.c_str(), waitRes.mResult));
-                }
-                else
-                    setProgressErrorMsg(VBOX_E_IPRT_ERROR, pProcess->errorMsg());
-                rc = VERR_GENERAL_FAILURE; /* Fudge. */
-            }
-        }
-    }
-
-    if (!pProcess.isNull())
-        pProcess->uninit();
-
-    return rc;
+                                    GuestProcess::guestErrorToString(vrc));
+                break;
+
+            default:
+                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                    Utf8StrFmt(GuestSession::tr("Error while running update file \"%s\" on guest: %Rrc"),
+                                               procInfo.mCommand.c_str(), vrc));
+                break;
+        }
+    }
+
+    return vrc;
 }
 
@@ -1080,5 +1135,5 @@
                 rc = getGuestProperty(pGuest, "/VirtualBox/GuestAdd/Version", strAddsVer);
                 if (   RT_SUCCESS(rc)
-                    && RTStrVersionCompare(strAddsVer.c_str(), "4.2") >= 0)
+                    && RTStrVersionCompare(strAddsVer.c_str(), "4.2r80329") > 0)
                 {
                     fUseInstallDir = true;
@@ -1107,10 +1162,23 @@
 
             /* Create the installation directory. */
+            int guestRc;
             rc = pSession->directoryCreateInternal(strUpdateDir,
-                                                   755 /* Mode */, DirectoryCreateFlag_Parents);
+                                                   755 /* Mode */, DirectoryCreateFlag_Parents, &guestRc);
             if (RT_FAILURE(rc))
-                hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,
-                                         Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"),
-                                                    strUpdateDir.c_str(), rc));
+            {
+                switch (rc)
+                {
+                    case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            GuestProcess::guestErrorToString(guestRc));
+                        break;
+
+                    default:
+                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
+                                            Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"),
+                                                       strUpdateDir.c_str(), rc));
+                        break;
+                }
+            }
             if (RT_SUCCESS(rc))
                 rc = setProgress(10);
