Index: /trunk/src/VBox/HostServices/GuestControl/service.cpp
===================================================================
--- /trunk/src/VBox/HostServices/GuestControl/service.cpp	(revision 42353)
+++ /trunk/src/VBox/HostServices/GuestControl/service.cpp	(revision 42354)
@@ -752,5 +752,4 @@
 int Service::cancelHostCmd(uint32_t u32ContextID)
 {
-    AssertReturn(u32ContextID, VERR_INVALID_PARAMETER);
     Assert(mpfnHostCallback);
 
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42353)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42354)
@@ -8830,6 +8830,6 @@
   
   <enum
-    name="ProcessWaitReason"
-    uuid="3fcbabf5-27e0-407a-9881-421b36c23978"
+    name="ProcessWaitResult"
+    uuid="b03af138-c812-45eb-939d-5d564bd0b89a"
     >
     <desc>
@@ -8837,5 +8837,8 @@
     </desc>
 
-    <const name="Status"                 value="0">
+    <const name="None"                   value="0">
+      <desc>TODO</desc>
+    </const>
+    <const name="Status"                 value="1">
       <desc>TODO</desc>
     </const>    
@@ -9911,5 +9914,5 @@
         <desc>TODO</desc>
       </param>
-      <param name="reason" type="ProcessWaitReason" dir="return">
+      <param name="reason" type="ProcessWaitResult" dir="return">
         <desc>TODO</desc>
       </param>
Index: /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 42353)
+++ /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 42354)
@@ -19,4 +19,5 @@
 #define ____H_GUESTIMPLPRIVATE
 
+#include <iprt/asm.h>
 #include <iprt/semaphore.h>
 
@@ -67,10 +68,53 @@
 
 /**
- * Generic class for a all guest control callbacks.
- */
-class GuestCtrlCallback
-{
-public:
-
+ * Generic class for a all guest control callbacks/events.
+ */
+class GuestCtrlEvent
+{
+public:
+
+    GuestCtrlEvent(void);
+
+    virtual ~GuestCtrlEvent(void);
+
+    /** @todo Copy/comparison operator? */
+
+public:
+
+    int Cancel(void);
+
+    bool Canceled(void);
+
+    virtual void Destroy(void);
+
+    int Init(void);
+
+    virtual int Signal(int rc = VINF_SUCCESS);
+
+    int GetResultCode(void) { return mRC; }
+
+    int Wait(ULONG uTimeoutMS);
+
+protected:
+
+    /** Was the callback canceled? */
+    bool                        fCanceled;
+    /** Did the callback complete? */
+    bool                        fCompleted;
+    /** The event semaphore for triggering
+     *  the actual event. */
+    RTSEMEVENT                  hEventSem;
+    /** The waiting mutex. */
+    RTSEMMUTEX                  hEventMutex;
+    /** Overall result code. */
+    int                         mRC;
+};
+
+/*
+ * Class representing a guest control callback.
+ */
+class GuestCtrlCallback : public GuestCtrlEvent
+{
+public:
     GuestCtrlCallback(void);
 
@@ -79,49 +123,64 @@
     virtual ~GuestCtrlCallback(void);
 
-    /** @todo Copy/comparison operator? */
-
-public:
-
-    int Cancel(void);
-
-    bool Canceled(void);
+public:
+
+    void Destroy(void);
 
     int Init(eVBoxGuestCtrlCallbackType enmType);
 
-    void Destroy(void);
-
-    int Signal(int rc = VINF_SUCCESS, const Utf8Str &strMsg = "");
-
-    Utf8Str GetMessage(void) { return mMessage; }
-
-    int GetResultCode(void) { return mRC; }
-
-    eVBoxGuestCtrlCallbackType GetType(void) { return mType; }
-
-    int Wait(ULONG uTimeoutMS);
-
-protected:
-
+    eVBoxGuestCtrlCallbackType GetCallbackType(void) { return mType; }
+
+protected:
+
+    /** Pointer to user-supplied data. */
+    void                       *pvData;
+    /** Size of user-supplied data. */
+    size_t                      cbData;
     /** The callback type. */
     eVBoxGuestCtrlCallbackType  mType;
     /** Callback flags. */
     uint32_t                    uFlags;
-    /** Was the callback canceled? */
-    bool                        fCanceled;
-    /** Did the callback complete? */
-    bool                        fCompleted;
-    /** Pointer to user-supplied data. */
-    void                       *pvData;
-    /** Size of user-supplied data. */
-    size_t                      cbData;
-    /** The event semaphore triggering the*/
-    RTSEMEVENT                  hEventSem;
-    /** Overall result code. */
+};
+typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks;
+
+struct GuestProcessWaitResult
+{
+    /** The wait result when returning from the wait call. */
+    ProcessWaitResult_T         mResult;
     int                         mRC;
-    /** Error / information message to the
-     *  result code. */
-    Utf8Str                     mMessage;
-};
-typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks;
+};
+
+/*
+ * 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 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/GuestImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestImpl.h	(revision 42353)
+++ /trunk/src/VBox/Main/include/GuestImpl.h	(revision 42354)
@@ -209,5 +209,5 @@
     int         sessionClose(ComObjPtr<GuestSession> pSession);
     int         sessionCreate(const Utf8Str &strUser, const Utf8Str &aPassword, const Utf8Str &aDomain,
-                              const Utf8Str &aSessionName, IGuestSession **aGuestSession);
+                              const Utf8Str &aSessionName, ComObjPtr<GuestSession> &pGuestSession);
     inline bool sessionExists(uint32_t uSessionID);
     /** @}  */
Index: /trunk/src/VBox/Main/include/GuestProcessImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 42353)
+++ /trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 42354)
@@ -62,5 +62,5 @@
     STDMETHOD(Read)(ULONG aHandle, ULONG aSize, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData));
     STDMETHOD(Terminate)(void);
-    STDMETHOD(WaitFor)(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitReason_T *aReason);
+    STDMETHOD(WaitFor)(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason);
     STDMETHOD(Write)(ULONG aHandle, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten);
     /** @}  */
@@ -69,9 +69,23 @@
     /** @name Public internal methods.
      * @{ */
-    int callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID);
     int callbackDispatcher(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData);
     inline bool callbackExists(ULONG uContextID);
+    void close(void);
     bool isReady(void);
     ULONG getPID(void) { return mData.mPID; }
+    int readData(ULONG uHandle, ULONG uSize, ULONG uTimeoutMS, BYTE *pbData, size_t cbData);
+    int startProcess(void);
+    int startProcessAsync(void);
+    int terminateProcess(void);
+    int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult);
+    HRESULT waitResultToErrorEx(const GuestProcessWaitResult &waitResult, bool fLog);
+    int writeData(ULONG uHandle, BYTE const *pbData, size_t cbData, ULONG uTimeoutMS, ULONG *puWritten);
+    /** @}  */
+
+protected:
+    /** @name Protected internal methods.
+     * @{ */
+    inline int callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID);
+    inline int callbackRemove(ULONG uContextID);
     int onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData);
     int onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData);
@@ -79,12 +93,7 @@
     int onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData);
     int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars);
-    int readData(ULONG uHandle, ULONG uSize, ULONG uTimeoutMS, BYTE *pbData, size_t cbData);
     int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
-    int signalWaiters(int rc, const Utf8Str strMessage = "");
-    int startProcess(int *pRC = NULL, Utf8Str *pstrMessage = NULL);
+    int signalWaiters(ProcessWaitResult enmWaitResult, int rc = VINF_SUCCESS);
     static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser);
-    int terminateProcess(void);
-    int waitFor(uint32_t fFlags, ULONG uTimeoutMS, ProcessWaitReason_T *penmReason);
-    int writeData(ULONG uHandle, BYTE const *pbData, size_t cbData, ULONG uTimeoutMS, ULONG *puWritten);
     /** @}  */
 
@@ -110,16 +119,15 @@
         /** The current process status. */
         ProcessStatus_T          mStatus;
-        /** Flag indicating whether the process has been started. */
+        /** Flag indicating whether the process has been started
+         *  so that it can't be started a second time. */
         bool                     mStarted;
         /** The next upcoming context ID. */
         ULONG                    mNextContextID;
-        /** Flag indicating someone is waiting for an event. */
-        bool                     mWaiting;
-        /** The waiting mutex. */
-        RTSEMMUTEX               mWaitMutex;
-        /** The waiting flag(s). */
-        uint32_t                 mWaitFlags;
-        /** The waiting event. */
-        RTSEMEVENT               mWaitEvent;
+        /** How many waiters? At the moment there can only
+         *  be one. */
+        uint32_t                 mWaitCount;
+        /** The actual process event for doing the waits.
+         *  At the moment we only support one wait a time. */
+        GuestProcessEvent       *mWaitEvent;
     } mData;
 };
Index: /trunk/src/VBox/Main/include/GuestSessionImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 42353)
+++ /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 42354)
@@ -126,5 +126,5 @@
     const GuestEnvironment &getEnvironment(void);
     int                     processClose(ComObjPtr<GuestProcess> pProcess);
-    int                     processCreateExInteral(const GuestProcessInfo &aProcInfo, IGuestProcess **aProcess);
+    int                     processCreateExInteral(GuestProcessInfo &procInfo, ComObjPtr<GuestProcess> &pProgress);
     inline bool             processExists(ULONG uProcessID, ComObjPtr<GuestProcess> *pProcess);
     inline int              processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess);
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 42353)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 42354)
@@ -17,4 +17,5 @@
 
 #include "GuestImpl.h"
+#include "GuestSessionImpl.h"
 #include "GuestCtrlImplPrivate.h"
 
@@ -765,4 +766,6 @@
     }
 #endif /* VBOX_WITH_GUEST_CONTROL_LEGACY */
+
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -2724,8 +2727,6 @@
 
 int Guest::sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, const Utf8Str &strDomain,
-                         const Utf8Str &strSessionName, IGuestSession **aGuestSession)
-{
-    AssertPtrReturn(aGuestSession, VERR_INVALID_POINTER);
-
+                         const Utf8Str &strSessionName, ComObjPtr<GuestSession> &pGuestSession)
+{
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
@@ -2756,5 +2757,4 @@
 
         /* Create the session object. */
-        ComObjPtr<GuestSession> pGuestSession;
         HRESULT hr = pGuestSession.createObject();
         if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
@@ -2763,8 +2763,4 @@
                                  strUser, strPassword, strDomain, strSessionName);
         if (RT_FAILURE(rc)) throw rc;
-
-        /* Return guest session to the caller. */
-        hr = pGuestSession.queryInterfaceTo(aGuestSession);
-        if (FAILED(hr)) throw VERR_COM_OBJECT_NOT_FOUND;
 
         mData.mGuestSessions[uNewSessionID] = pGuestSession;
@@ -2804,10 +2800,34 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    int rc = sessionCreate(aUser, aPassword, aDomain, aSessionName, aGuestSession);
-
-    /** @todo Do setError() here. */
-    HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
-    LogFlowFuncLeaveRC(hr);
-
+    HRESULT hr = S_OK;
+
+    ComObjPtr<GuestSession> pSession;
+    int rc = sessionCreate(aUser, aPassword, aDomain, aSessionName, pSession);
+    if (RT_SUCCESS(rc))
+    {
+        /* Return guest session to the caller. */
+        HRESULT hr2 = pSession.queryInterfaceTo(aGuestSession);
+        if (FAILED(hr2))
+            rc = VERR_COM_OBJECT_NOT_FOUND;
+    }
+
+    if (RT_FAILURE(rc))
+    {
+        switch (rc)
+        {
+            case VERR_MAX_PROCS_REACHED:
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),
+                              VERR_MAX_PROCS_REACHED);
+                break;
+
+            /** @todo Add more errors here. */
+
+           default:
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session, rc=%Rrc"), rc);
+                break;
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
     return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
Index: /trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 42353)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 42354)
@@ -33,12 +33,95 @@
  ******************************************************************************/
 
+GuestCtrlEvent::GuestCtrlEvent(void)
+    : fCanceled(false),
+      fCompleted(false),
+      hEventSem(NIL_RTSEMEVENT),
+      mRC(VINF_SUCCESS)
+{
+}
+
+GuestCtrlEvent::~GuestCtrlEvent(void)
+{
+    Destroy();
+}
+
+int GuestCtrlEvent::Cancel(void)
+{
+    LogFlowThisFuncEnter();
+
+    int rc = VINF_SUCCESS;
+    if (!ASMAtomicReadBool(&fCompleted))
+    {
+        if (!ASMAtomicReadBool(&fCanceled))
+        {
+            ASMAtomicXchgBool(&fCanceled, true);
+
+            LogFlowThisFunc(("Cancelling ...\n"));
+            rc = hEventSem != NIL_RTSEMEVENT
+               ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
+        }
+    }
+
+    LogFlowThisFuncLeave(rc);
+    return rc;
+}
+
+bool GuestCtrlEvent::Canceled(void)
+{
+    return ASMAtomicReadBool(&fCanceled);
+}
+
+void GuestCtrlEvent::Destroy(void)
+{
+    LogFlowThisFuncEnter();
+
+    int rc = Cancel();
+    AssertRC(rc);
+
+    if (hEventSem != NIL_RTSEMEVENT)
+    {
+        RTSemEventDestroy(hEventSem);
+        hEventSem = NIL_RTSEMEVENT;
+    }
+
+    LogFlowThisFuncLeave();
+}
+
+int GuestCtrlEvent::Init(void)
+{
+    return RTSemEventCreate(&hEventSem);
+}
+
+int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/)
+{
+    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
+
+    mRC = rc;
+
+    return RTSemEventSignal(hEventSem);
+}
+
+int GuestCtrlEvent::Wait(ULONG uTimeoutMS)
+{
+    LogFlowFuncEnter();
+
+    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
+
+    RTMSINTERVAL msInterval = uTimeoutMS;
+    if (!uTimeoutMS)
+        msInterval = RT_INDEFINITE_WAIT;
+    int rc = RTSemEventWait(hEventSem, msInterval);
+    if (RT_SUCCESS(rc))
+        ASMAtomicWriteBool(&fCompleted, true);
+    return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 GuestCtrlCallback::GuestCtrlCallback(void)
     : mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
       uFlags(0),
-      fCanceled(false),
-      fCompleted(false),
       pvData(NULL),
-      cbData(0),
-      hEventSem(NIL_RTSEMEVENT)
+      cbData(0)
 {
 }
@@ -47,9 +130,6 @@
     : mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
       uFlags(0),
-      fCanceled(false),
-      fCompleted(false),
       pvData(NULL),
-      cbData(0),
-      hEventSem(NIL_RTSEMEVENT)
+      cbData(0)
 {
     int rc = Init(enmType);
@@ -62,25 +142,8 @@
 }
 
-int GuestCtrlCallback::Cancel(void)
-{
-    if (ASMAtomicReadBool(&fCompleted))
-        return VINF_SUCCESS;
-    if (!ASMAtomicReadBool(&fCanceled))
-    {
-        int rc = hEventSem != NIL_RTSEMEVENT
-               ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
-        if (RT_SUCCESS(rc))
-            ASMAtomicXchgBool(&fCanceled, true);
-    }
-    return VINF_SUCCESS;
-}
-
-bool GuestCtrlCallback::Canceled(void)
-{
-    return ASMAtomicReadBool(&fCanceled);
-}
-
 int GuestCtrlCallback::Init(eVBoxGuestCtrlCallbackType enmType)
 {
+    LogFlowFuncEnter();
+
     AssertReturn(enmType > VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER);
     Assert((pvData == NULL) && !cbData);
@@ -123,9 +186,10 @@
     if (RT_SUCCESS(rc))
     {
-        rc = RTSemEventCreate(&hEventSem);
+        rc = GuestCtrlEvent::Init();
         if (RT_SUCCESS(rc))
             mType  = enmType;
     }
 
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -133,6 +197,5 @@
 void GuestCtrlCallback::Destroy(void)
 {
-    int rc = Cancel();
-    AssertRC(rc);
+    GuestCtrlEvent::Destroy();
 
     mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN;
@@ -143,22 +206,38 @@
     }
     cbData = 0;
-    if (hEventSem != NIL_RTSEMEVENT)
-        RTSemEventDestroy(hEventSem);
-}
-
-int GuestCtrlCallback::Signal(int rc /*= VINF_SUCCESS*/, const Utf8Str &strMsg /*= "" */)
-{
-    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
-    return RTSemEventSignal(hEventSem);
-}
-
-int GuestCtrlCallback::Wait(ULONG uTimeoutMS)
-{
-    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
-
-    RTMSINTERVAL msInterval = uTimeoutMS;
-    if (!uTimeoutMS)
-        msInterval = RT_INDEFINITE_WAIT;
-    return RTSemEventWait(hEventSem, msInterval);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GuestProcessEvent::GuestProcessEvent(void)
+    : mWaitFlags(0)
+{
+}
+
+GuestProcessEvent::GuestProcessEvent(uint32_t uWaitFlags)
+    : mWaitFlags(uWaitFlags)
+{
+    int rc = GuestCtrlEvent::Init();
+    AssertRC(rc);
+}
+
+GuestProcessEvent::~GuestProcessEvent(void)
+{
+    Destroy();
+}
+
+void GuestProcessEvent::Destroy(void)
+{
+    GuestCtrlEvent::Destroy();
+
+    mWaitFlags = ProcessWaitForFlag_None;
+}
+
+int GuestProcessEvent::Signal(ProcessWaitResult enmResult, int rc /*= VINF_SUCCESS*/)
+{
+    mWaitResult.mRC = rc;
+    mWaitResult.mResult = enmResult;
+
+    return GuestCtrlEvent::Signal(rc);
 }
 
Index: /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 42353)
+++ /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 42354)
@@ -68,5 +68,5 @@
 HRESULT GuestProcess::FinalConstruct(void)
 {
-    LogFlowFuncEnter();
+    LogFlowThisFuncEnter();
 
     mData.mExitCode = 0;
@@ -76,7 +76,6 @@
     mData.mStatus = ProcessStatus_Undefined;
     mData.mStarted = false;
-    mData.mWaiting = false;
-    mData.mWaitFlags = 0;
-    mData.mWaitMutex = NIL_RTSEMMUTEX;
+
+    mData.mWaitCount = 0;
     mData.mWaitEvent = NIL_RTSEMEVENT;
 
@@ -104,6 +103,4 @@
     AutoInitSpan autoInitSpan(this);
     AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
     mData.mConsole = aConsole;
@@ -111,35 +108,10 @@
     mData.mProcessID = aProcessID;
     mData.mProcess = aProcInfo;
-
-    mData.mStatus = ProcessStatus_Starting;
     /* Everything else will be set by the actual starting routine. */
 
-    int rc = RTSemEventCreate(&mData.mWaitEvent);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    rc = RTSemMutexCreate(&mData.mWaitMutex);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    /* Asynchronously start the process on the guest by kicking off a
-     * worker thread. */
-    std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
-    AssertReturn(pTask->isOk(), pTask->rc());
-
-    rc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
-                        (void *)pTask.get(), 0,
-                        RTTHREADTYPE_MAIN_WORKER, 0,
-                        "gctlPrcStart");
-    if (RT_SUCCESS(rc))
-    {
-        /* task is now owned by startProcessThread(), so release it. */
-        pTask.release();
-
-        /* Confirm a successful initialization when it's the case. */
-        autoInitSpan.setSucceeded();
-    }
-
-    return rc;
+    /* Confirm a successful initialization when it's the case. */
+    autoInitSpan.setSucceeded();
+
+    return VINF_SUCCESS;
 }
 
@@ -157,10 +129,11 @@
         return;
 
-    int rc = RTSemEventDestroy(mData.mWaitEvent);
-    AssertRC(rc);
-    rc = RTSemMutexDestroy(mData.mWaitMutex);
-    AssertRC(rc);
-
-    LogFlowFuncLeaveRC(rc);
+#ifndef VBOX_WITH_GUEST_CONTROL
+    close();
+
+    mData.mParent->processClose(this);
+
+    LogFlowFuncLeave();
+#endif
 }
 
@@ -317,5 +290,5 @@
 */
 
-int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID)
+inline int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID)
 {
     const ComObjPtr<GuestSession> pSession(mData.mParent);
@@ -449,4 +422,49 @@
 }
 
+inline int GuestProcess::callbackRemove(ULONG uContextID)
+{
+    GuestCtrlCallbacks::iterator it = mData.mCallbacks.find(uContextID);
+    if (it == mData.mCallbacks.end())
+    {
+        delete it->second;
+        mData.mCallbacks.erase(it);
+
+        return VINF_SUCCESS;
+    }
+
+    return VERR_NOT_FOUND;
+}
+
+void GuestProcess::close(void)
+{
+    LogFlowThisFuncEnter();
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /*
+     * Cancel all callbacks + waiters.
+     * Note: Deleting them is the job of the caller!
+     */
+    for (GuestCtrlCallbacks::iterator itCallbacks = mData.mCallbacks.begin();
+         itCallbacks != mData.mCallbacks.end(); ++itCallbacks)
+    {
+        GuestCtrlCallback *pCallback = itCallbacks->second;
+        AssertPtr(pCallback);
+        int rc2 = pCallback->Cancel();
+        AssertRC(rc2);
+    }
+    mData.mCallbacks.clear();
+
+    if (mData.mWaitEvent)
+    {
+        int rc2 = mData.mWaitEvent->Cancel();
+        AssertRC(rc2);
+    }
+
+    mData.mStatus = ProcessStatus_Down; /** @todo Correct? */
+
+    LogFlowThisFuncLeave();
+}
+
 bool GuestProcess::isReady(void)
 {
@@ -464,5 +482,10 @@
 int GuestProcess::onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData)
 {
+    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
+    AssertPtrReturn(pData, VERR_INVALID_POINTER);
+
     LogFlowFunc(("uPID=%RU32, pCallback=%p, pData=%p\n", mData.mPID, pCallback, pData));
+
+    mData.mStatus = ProcessStatus_Down;
 
     /* First, signal callback in every case. */
@@ -470,5 +493,5 @@
 
     /* Signal in any case. */
-    int rc = signalWaiters(VERR_CANCELLED, tr("The guest got disconnected"));
+    int rc = signalWaiters(ProcessWaitResult_Status, VERR_CANCELLED);
     AssertRC(rc);
 
@@ -479,4 +502,7 @@
 int GuestProcess::onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData)
 {
+    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
+    AssertPtrReturn(pData, VERR_INVALID_POINTER);
+
     LogFlowFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, cbProcessed=%RU32, pCallback=%p, pData=%p\n",
                  mData.mPID, pData->u32Status, pData->u32Flags, pData->cbProcessed, pCallback, pData));
@@ -490,6 +516,10 @@
 
     /* Then do the WaitFor signalling stuff. */
-    if (mData.mWaitFlags & ProcessWaitForFlag_StdIn)
-        rc = signalWaiters(VINF_SUCCESS);
+    uint32_t uWaitFlags = mData.mWaitEvent
+                        ? mData.mWaitEvent->GetWaitFlags() : 0;
+    if (   (uWaitFlags & ProcessWaitForFlag_Status)
+        || (uWaitFlags & ProcessWaitForFlag_StdIn))
+        rc = signalWaiters(ProcessWaitResult_StdIn);
+    AssertRC(rc);
 
     LogFlowFuncLeaveRC(rc);
@@ -499,4 +529,7 @@
 int GuestProcess::onProcessStatusChange(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData)
 {
+    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
+    AssertPtrReturn(pData, VERR_INVALID_POINTER);
+
     LogFlowFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pData=%p\n",
                  pData->u32PID, pData->u32Status, pData->u32Flags, pCallback, pData));
@@ -508,30 +541,30 @@
         Assert(mData.mPID == pData->u32PID);
 
-    Utf8Str callbackMsg;
     int callbackRC = VINF_SUCCESS;
 
-    bool fSignal = false;
+    BOOL fSignal = FALSE;
+    ProcessWaitResult enmWaitResult;
+    uint32_t uWaitFlags = mData.mWaitEvent
+                        ? mData.mWaitEvent->GetWaitFlags() : 0;
     switch (pData->u32Status)
     {
-        case PROC_STS_STARTED:
-            fSignal = (   (mData.mWaitFlags & ProcessWaitForFlag_Start)
-                       || (mData.mWaitFlags & ProcessWaitForFlag_Status));
+       case PROC_STS_STARTED:
+        {
+            fSignal = (uWaitFlags & ProcessWaitForFlag_Start);
+            enmWaitResult = ProcessWaitResult_Status;
 
             mData.mStatus = ProcessStatus_Started;
             mData.mPID = pData->u32PID;
             mData.mStarted = true;
-
-            callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" was started (PID %RU32)"),
-                                     mData.mProcess.mCommand.c_str(), mData.mPID);
-            LogRel((callbackMsg.c_str()));
-            break;
+            break;
+        }
 
         case PROC_STS_TEN:
         {
+            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
+            enmWaitResult = ProcessWaitResult_Status;
+
             mData.mStatus = ProcessStatus_TerminatedNormally;
-
-            callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) terminated normally (exit code: %d)"),
-                                     mData.mProcess.mCommand.c_str(), mData.mPID, pData->u32Flags);
-            LogRel((callbackMsg.c_str()));
+            mData.mExitCode = pData->u32Flags; /* Contains the exit code. */
             break;
         }
@@ -539,10 +572,11 @@
         case PROC_STS_TES:
         {
+            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
+            enmWaitResult = ProcessWaitResult_Status;
+
             mData.mStatus = ProcessStatus_TerminatedSignal;
+            mData.mExitCode = pData->u32Flags; /* Contains the signal. */
 
             callbackRC = VERR_INTERRUPTED;
-            callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) terminated through signal (exit code: %d)"),
-                                     mData.mProcess.mCommand.c_str(), mData.mPID, pData->u32Flags);
-            LogRel((callbackMsg.c_str()));
             break;
         }
@@ -550,10 +584,10 @@
         case PROC_STS_TEA:
         {
+            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
+            enmWaitResult = ProcessWaitResult_Status;
+
             mData.mStatus = ProcessStatus_TerminatedAbnormally;
 
             callbackRC = VERR_BROKEN_PIPE;
-            callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) terminated abnormally (exit code: %d)"),
-                                     mData.mProcess.mCommand.c_str(), mData.mPID, pData->u32Flags);
-            LogRel((callbackMsg.c_str()));
             break;
         }
@@ -561,10 +595,10 @@
         case PROC_STS_TOK:
         {
+            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
+            enmWaitResult = ProcessWaitResult_Timeout;
+
             mData.mStatus = ProcessStatus_TimedOutKilled;
 
             callbackRC = VERR_TIMEOUT;
-            callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) timed out and was killed"),
-                                     mData.mProcess.mCommand.c_str(), mData.mPID);
-            LogRel((callbackMsg.c_str()));
             break;
         }
@@ -572,10 +606,10 @@
         case PROC_STS_TOA:
         {
+            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
+            enmWaitResult = ProcessWaitResult_Timeout;
+
             mData.mStatus = ProcessStatus_TimedOutAbnormally;
 
             callbackRC = VERR_TIMEOUT;
-            callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) timed out and could not be killed\n"),
-                                     mData.mProcess.mCommand.c_str(), mData.mPID);
-            LogRel((callbackMsg.c_str()));
             break;
         }
@@ -583,4 +617,7 @@
         case PROC_STS_DWN:
         {
+            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
+            enmWaitResult = ProcessWaitResult_Status;
+
             mData.mStatus = ProcessStatus_Down;
 
@@ -594,7 +631,4 @@
             callbackRC = mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses
                        ? VINF_SUCCESS : VERR_OBJECT_DESTROYED;
-            callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) was killed because system is shutting down\n"),
-                                     mData.mProcess.mCommand.c_str(), mData.mPID);
-            LogRel((callbackMsg.c_str()));
             break;
         }
@@ -602,58 +636,10 @@
         case PROC_STS_ERROR:
         {
+            fSignal = TRUE; /* Signal in any case. */
+            enmWaitResult = ProcessWaitResult_Error;
+
             mData.mStatus = ProcessStatus_Error;
 
-            callbackRC = pData->u32Flags;
-            callbackMsg = 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 (pData->u32PID)
-            {
-                callbackMsg += Utf8StrFmt(tr("Error rc=%Rrc occured"), pData->u32Flags);
-            }
-            else
-            {
-                switch (callbackRC) /* callbackRC contains the IPRT error code from guest side. */
-                {
-                    case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
-                        callbackMsg += Utf8StrFmt(tr("The specified file was not found on guest"));
-                        break;
-
-                    case VERR_PATH_NOT_FOUND:
-                        callbackMsg += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
-                        break;
-
-                    case VERR_BAD_EXE_FORMAT:
-                        callbackMsg += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
-                        break;
-
-                    case VERR_AUTHENTICATION_FAILURE:
-                        callbackMsg += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
-                        break;
-
-                    case VERR_TIMEOUT:
-                        callbackMsg += Utf8StrFmt(tr("The guest did not respond within time"));
-                        break;
-
-                    case VERR_CANCELLED:
-                        callbackMsg += Utf8StrFmt(tr("The execution operation was canceled"));
-                        break;
-
-                    case VERR_PERMISSION_DENIED:
-                        callbackMsg += Utf8StrFmt(tr("Invalid user/password credentials"));
-                        break;
-
-                    case VERR_MAX_PROCS_REACHED:
-                        callbackMsg += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
-                        break;
-
-                    default:
-                        callbackMsg += Utf8StrFmt(tr("Reported error %Rrc"), callbackRC);
-                        break;
-                }
-            }
-
-            LogRel((callbackMsg.c_str()));
+            callbackRC = pData->u32Flags; /** @todo int vs. uint32 -- IPRT errors are *negative* !!! */
             break;
         }
@@ -661,20 +647,29 @@
         case PROC_STS_UNDEFINED:
         default:
-
+        {
             /* Silently skip this request. */
-            fSignal = true; /* Signal in any case. */
-            break;
-    }
+            fSignal = TRUE; /* Signal in any case. */
+            enmWaitResult = ProcessWaitResult_Status;
+
+            mData.mStatus = ProcessStatus_Undefined;
+
+            callbackRC = VERR_NOT_IMPLEMENTED;
+            break;
+        }
+    }
+
+    LogFlowFunc(("Got rc=%Rrc, waitResult=%d\n",
+                 rc, enmWaitResult));
 
     /*
      * Now do the signalling stuff.
      */
-    rc = pCallback->Signal(callbackRC, callbackMsg);
+    rc = pCallback->Signal(callbackRC);
 
     if (!fSignal)
-        fSignal = mData.mWaitFlags & ProcessWaitForFlag_Status;
+        fSignal = (uWaitFlags & ProcessWaitForFlag_Status);
     if (fSignal)
     {
-        int rc2 = signalWaiters(callbackRC, callbackMsg);
+        int rc2 = signalWaiters(enmWaitResult, callbackRC);
         if (RT_SUCCESS(rc))
             rc = rc2;
@@ -687,4 +682,7 @@
 int GuestProcess::onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData)
 {
+    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
+    AssertPtrReturn(pData, VERR_INVALID_POINTER);
+
     LogFlowFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, pCallback=%p, pData=%p\n",
                  mData.mPID, pData->u32HandleId, pData->u32Flags, pData->pvData, pData->cbData, pCallback, pData));
@@ -698,27 +696,31 @@
 
     /* Then do the WaitFor signalling stuff. */
-    bool fSignal = false;
-    if (    (mData.mWaitFlags & ProcessWaitForFlag_StdOut)
-         || (mData.mWaitFlags & ProcessWaitForFlag_StdErr))
-    {
-        fSignal = true;
-    }
-    else if (   (mData.mWaitFlags & ProcessWaitForFlag_StdOut)
+    BOOL fSignal = FALSE;
+    uint32_t uWaitFlags = mData.mWaitEvent
+                        ? mData.mWaitEvent->GetWaitFlags() : 0;
+
+    if (    (uWaitFlags & ProcessWaitForFlag_StdOut)
+         || (uWaitFlags & ProcessWaitForFlag_StdErr))
+    {
+        fSignal = TRUE;
+    }
+    else if (   (uWaitFlags & ProcessWaitForFlag_StdOut)
              && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT))
     {
-        fSignal = true;
-    }
-    else if (   (mData.mWaitFlags & ProcessWaitForFlag_StdErr)
+        fSignal = TRUE;
+    }
+    else if (   (uWaitFlags & ProcessWaitForFlag_StdErr)
              && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDERR))
     {
-        fSignal = true;
-    }
+        fSignal = TRUE;
+    }
+
+    if (!fSignal)
+        fSignal = (uWaitFlags & ProcessWaitForFlag_Status);
 
     if (fSignal)
-    {
-        Assert(mData.mWaitEvent != NIL_RTSEMEVENT);
-        rc = RTSemEventSignal(mData.mWaitEvent);
-        AssertRC(rc);
-    }
+        rc = signalWaiters(  pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT
+                           ? ProcessWaitResult_StdOut : ProcessWaitResult_StdErr);
+    AssertRC(rc);
 
     LogFlowFuncLeaveRC(rc);
@@ -741,19 +743,12 @@
                               uint32_t uParms, PVBOXHGCMSVCPARM paParms)
 {
-    LogFlowFuncEnter();
-
-    const ComObjPtr<Console> pConsole(mData.mConsole);
-    Assert(!pConsole.isNull());
-
-    VMMDev *pVMMDev = NULL;
-    {
-        /* Make sure mParent is valid, so set the read lock while using.
-         * Do not keep this lock while doing the actual call, because in the meanwhile
-         * another thread could request a write lock which would be a bad idea ... */
-        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-        /* Forward the information to the VMM device. */
-        pVMMDev = pConsole->getVMMDev();
-    }
+    LogFlowThisFuncEnter();
+
+    Console *pConsole = mData.mConsole;
+    AssertPtr(pConsole);
+
+    /* Forward the information to the VMM device. */
+    VMMDev *pVMMDev = pConsole->getVMMDev();
+    AssertPtr(pVMMDev);
 
     LogFlowFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
@@ -767,35 +762,19 @@
 }
 
-int GuestProcess::signalWaiters(int rc, const Utf8Str strMessage)
-{
-    LogFlowFunc(("rc=%Rrc, strMessage=%s, mWaiting=%RTbool, mWaitEvent=%p\n",
-                 rc, strMessage.c_str(), mData.mWaiting, mData.mWaitEvent));
+int GuestProcess::signalWaiters(ProcessWaitResult enmWaitResult, int rc /*= VINF_SUCCESS*/)
+{
+    LogFlowFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
+                 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));
 
     /* Note: No locking here -- already done in the callback dispatcher. */
 
-    /* We have to set the error information here because the waiters are public
-     * Main clients which rely on it. */
-    if (RT_FAILURE(rc))
-    {
-        HRESULT hr = setError(VBOX_E_IPRT_ERROR, strMessage.c_str());
-        ComAssertComRC(hr);
-    }
-
-    int rc2 = VINF_SUCCESS;
-    if (   mData.mWaiting
-        && mData.mWaitEvent != NIL_RTSEMEVENT)
-    {
-        rc2 = RTSemEventSignal(mData.mWaitEvent);
-        AssertRC(rc2);
-    }
-
+    AssertPtr(mData.mWaitEvent);
+    int rc2 = mData.mWaitEvent->Signal(enmWaitResult, rc);
     LogFlowFuncLeaveRC(rc2);
     return rc2;
 }
 
-int GuestProcess::startProcess(int *pRC, Utf8Str *pstrMessage)
-{
-    /* Parameters are optional. */
-
+int GuestProcess::startProcess(void)
+{
     LogFlowFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
                  mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags));
@@ -804,5 +783,5 @@
 
     int rc;
-    ULONG uContextID;
+    ULONG uContextID = 0;
     GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback();
     if (!pCallbackStart)
@@ -813,4 +792,6 @@
          * has returned and continue operation. */
         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+        mData.mStatus = ProcessStatus_Starting;
 
         /* Create callback and add it to the map. */
@@ -822,6 +803,8 @@
     if (RT_SUCCESS(rc))
     {
-        ComObjPtr<GuestSession> pSession(mData.mParent);
-        Assert(!pSession.isNull());
+        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+        GuestSession *pSession = mData.mParent;
+        AssertPtr(pSession);
 
         const GuestCredentials &sessionCreds = pSession->getCredentials();
@@ -864,4 +847,5 @@
             paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
             paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
+            /** @todo New command needs the domain as well! */
 
             /*
@@ -883,4 +867,8 @@
             RTStrFree(pszArgs);
 
+        uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
+
+        alock.release(); /* Drop the read lock again. */
+
         if (RT_SUCCESS(rc))
         {
@@ -889,17 +877,22 @@
              * Note: Be sure not keeping a AutoRead/WriteLock here.
              */
-            rc = pCallbackStart->Wait(mData.mProcess.mTimeoutMS);
+            LogFlowFunc((tr("Waiting for callback (%RU32ms) ...\n"), uTimeoutMS));
+            rc = pCallbackStart->Wait(uTimeoutMS);
             if (RT_SUCCESS(rc)) /* Wait was successful, check for supplied information. */
             {
-                if (pRC)
-                    *pRC = pCallbackStart->GetResultCode();
-                if (pstrMessage)
-                    *pstrMessage = pCallbackStart->GetMessage();
+                rc = pCallbackStart->GetResultCode();
+                LogFlowFunc((tr("Callback returned rc=%Rrc\n"), rc));
             }
-        }
-    }
-
-    if (pCallbackStart)
-        delete pCallbackStart;
+            else
+                rc = VERR_TIMEOUT;
+        }
+
+        AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
+
+        AssertPtr(pCallbackStart);
+        int rc2 = callbackRemove(uContextID);
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
 
     LogFlowFuncLeaveRC(rc);
@@ -907,4 +900,27 @@
 }
 
+int GuestProcess::startProcessAsync(void)
+{
+    LogFlowThisFuncEnter();
+
+    /* Asynchronously start the process on the guest by kicking off a
+     * worker thread. */
+    std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
+    AssertReturn(pTask->isOk(), pTask->rc());
+
+    int rc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
+                            (void *)pTask.get(), 0,
+                            RTTHREADTYPE_MAIN_WORKER, 0,
+                            "gctlPrcStart");
+    if (RT_SUCCESS(rc))
+    {
+        /* pTask is now owned by startProcessThread(), so release it. */
+        pTask.release();
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
 DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser)
 {
@@ -917,6 +933,47 @@
     Assert(!pProcess.isNull());
 
-    int rc = pProcess->startProcess();
-    AssertRC(rc);
+    AutoCaller autoCaller(pProcess);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    int rcIgnored = pProcess->startProcess();
+    LogFlowFuncLeaveRC(rcIgnored);
+    return VINF_SUCCESS;
+}
+
+int GuestProcess::terminateProcess(void)
+{
+    LogFlowThisFuncEnter();
+
+    LogFlowFuncLeave();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult)
+{
+    LogFlowFunc(("fWaitFlags=%x, uTimeoutMS=%RU32, mWaitCount=%RU32, mWaitEvent=%p\n",
+                 fWaitFlags, uTimeoutMS, mData.mWaitCount, mData.mWaitEvent));
+
+    AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mData.mWaitCount > 0)
+        return VERR_ALREADY_EXISTS;
+    mData.mWaitCount++;
+
+    Assert(mData.mWaitEvent == NIL_RTSEMEVENT);
+    mData.mWaitEvent = new GuestProcessEvent(fWaitFlags);
+    AssertPtrReturn(mData.mWaitEvent, VERR_NO_MEMORY);
+
+    alock.release(); /* Release lock before waiting. */
+
+    int rc = mData.mWaitEvent->Wait(uTimeoutMS);
+    if (RT_SUCCESS(rc))
+        guestResult = mData.mWaitEvent->GetResult();
+
+    /* Note: The caller always is responsible of deleting the
+     *       stuff it created before. See close() for more information. */
+    delete mData.mWaitEvent;
+    mData.mWaitEvent = NULL;
 
     LogFlowFuncLeaveRC(rc);
@@ -924,38 +981,139 @@
 }
 
-int GuestProcess::terminateProcess(void)
-{
-    LogFlowFuncEnter();
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    LogFlowFuncLeave();
-    return 0;
-}
-
-int GuestProcess::waitFor(uint32_t fFlags, ULONG uTimeoutMS, ProcessWaitReason_T *penmReason)
-{
-    Assert(mData.mWaitEvent != NIL_RTSEMEVENT);
-
-    if (ASMAtomicReadBool(&mData.mWaiting))
-        return VERR_ALREADY_EXISTS;
-
-    /* At the moment we only support one waiter at a time. */
-    int rc = RTSemMutexRequest(mData.mWaitMutex, uTimeoutMS);
-    if (RT_SUCCESS(rc))
-    {
-        ASMAtomicWriteBool(&mData.mWaiting, true);
-        rc = RTSemEventWait(mData.mWaitEvent, uTimeoutMS);
-        if (RT_SUCCESS(rc))
-        {
-            /** @todo Error handling after waiting. */
-        }
-
-        int rc2 = RTSemMutexRelease(mData.mWaitMutex);
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-    }
-
-    return rc;
+HRESULT GuestProcess::waitResultToErrorEx(const GuestProcessWaitResult &waitResult, bool fLog)
+{
+    int rc = waitResult.mRC;
+
+    Utf8Str strMsg;
+    ProcessStatus_T procStatus = mData.mStatus;
+
+    switch (procStatus)
+    {
+        case ProcessStatus_Started:
+            strMsg = Utf8StrFmt(tr("Guest process \"%s\" was started (PID %RU32)"),
+                                mData.mProcess.mCommand.c_str(), mData.mPID);
+            break;
+
+        case ProcessStatus_TerminatedNormally:
+            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) terminated normally (exit code: %d)"),
+                                mData.mProcess.mCommand.c_str(), mData.mPID, mData.mExitCode);
+            break;
+
+        case ProcessStatus_TerminatedSignal:
+        {
+            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) terminated through signal (signal: %d)"),
+                                mData.mProcess.mCommand.c_str(), mData.mPID, mData.mExitCode);
+            break;
+        }
+
+        case ProcessStatus_TerminatedAbnormally:
+        {
+            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) terminated abnormally (exit code: %d)"),
+                                mData.mProcess.mCommand.c_str(), mData.mPID, mData.mExitCode);
+            break;
+        }
+
+        case ProcessStatus_TimedOutKilled:
+        {
+            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) timed out and was killed"),
+                                mData.mProcess.mCommand.c_str(), mData.mPID);
+            break;
+        }
+
+        case ProcessStatus_TimedOutAbnormally:
+        {
+            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) timed out and could not be killed\n"),
+                                mData.mProcess.mCommand.c_str(), mData.mPID);
+            break;
+        }
+
+        case ProcessStatus_Down:
+        {
+            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) was killed because guest OS is shutting down\n"),
+                                mData.mProcess.mCommand.c_str(), mData.mPID);
+            break;
+        }
+
+        case ProcessStatus_Error:
+        {
+            strMsg = 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)
+            {
+                strMsg += Utf8StrFmt(tr("Error rc=%Rrc occured (PID %RU32)"), rc, mData.mPID);
+            }
+            else
+            {
+                switch (rc) /* rc contains the IPRT error code from guest side. */
+                {
+                    case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
+                        strMsg += Utf8StrFmt(tr("The specified file was not found on guest"));
+                        break;
+
+                    case VERR_PATH_NOT_FOUND:
+                        strMsg += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
+                        break;
+
+                    case VERR_BAD_EXE_FORMAT:
+                        strMsg += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
+                        break;
+
+                    case VERR_AUTHENTICATION_FAILURE:
+                        strMsg += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
+                        break;
+
+                    case VERR_INVALID_NAME:
+                        strMsg += Utf8StrFmt(tr("The specified file is an invalid name"));
+                        break;
+
+                    case VERR_TIMEOUT:
+                        strMsg += Utf8StrFmt(tr("The guest did not respond within time"));
+                        break;
+
+                    case VERR_CANCELLED:
+                        strMsg += Utf8StrFmt(tr("The execution operation was canceled"));
+                        break;
+
+                    case VERR_PERMISSION_DENIED:
+                        strMsg += Utf8StrFmt(tr("Invalid user/password credentials"));
+                        break;
+
+                    case VERR_MAX_PROCS_REACHED:
+                        strMsg += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
+                        break;
+
+                    default:
+                        strMsg += Utf8StrFmt(tr("Reported error %Rrc"), rc);
+                        break;
+                }
+            }
+
+            break;
+        }
+
+        case ProcessStatus_Undefined:
+        default:
+
+            /* Silently skip this request. */
+            break;
+    }
+
+    HRESULT hr = S_OK;
+    if (RT_FAILURE(rc))
+    {
+        Assert(!strMsg.isEmpty());
+        hr = setError(VBOX_E_IPRT_ERROR, "%s", strMsg.c_str());
+    }
+
+    if (fLog)
+    {
+        Assert(!strMsg.isEmpty());
+
+        strMsg.append("\n");
+        LogRel(("%s", strMsg.c_str()));
+    }
+
+    return hr;
 }
 
@@ -1014,4 +1172,6 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
     int rc = terminateProcess();
     /** @todo Do setError() here. */
@@ -1023,5 +1183,5 @@
 }
 
-STDMETHODIMP GuestProcess::WaitFor(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitReason_T *aReason)
+STDMETHODIMP GuestProcess::WaitFor(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
 {
 #ifndef VBOX_WITH_GUEST_CONTROL
@@ -1043,9 +1203,19 @@
         fWaitFor |= flags[i];
 
-    int rc = waitFor(fWaitFor, aTimeoutMS, aReason);
-    /** @todo Do setError() here. */
-    HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
+    HRESULT hr;
+
+    GuestProcessWaitResult guestResult;
+    int rc = waitFor(fWaitFor, aTimeoutMS, guestResult);
+    if (RT_SUCCESS(rc))
+    {
+        hr = waitResultToErrorEx(guestResult, true /* fLog */);
+        if (SUCCEEDED(hr))
+            *aReason = guestResult.mResult;
+    }
+    else
+        hr = setError(VBOX_E_IPRT_ERROR,
+                      tr("Waiting for process \"%s\" (PID %RU32) failed with rc=%Rrc"),
+                      mData.mProcess.mCommand.c_str(), mData.mPID, rc);
     LogFlowFuncLeaveRC(hr);
-
     return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
Index: /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 42353)
+++ /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 42354)
@@ -115,4 +115,10 @@
          itProcs != mData.mProcesses.end(); ++itProcs)
     {
+        itProcs->second->close();
+    }
+
+    for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
+         itProcs != mData.mProcesses.end(); ++itProcs)
+    {
         itProcs->second->uninit();
         itProcs->second.setNull();
@@ -421,19 +427,17 @@
 }
 
-int GuestSession::processCreateExInteral(const GuestProcessInfo &aProcInfo, IGuestProcess **aProcess)
+int GuestSession::processCreateExInteral(GuestProcessInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
 {
     /* Validate flags. */
-    if (aProcInfo.mFlags)
-    {
-        if (   !(aProcInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
-            && !(aProcInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
-            && !(aProcInfo.mFlags & ProcessCreateFlag_Hidden)
-            && !(aProcInfo.mFlags & ProcessCreateFlag_NoProfile))
+    if (procInfo.mFlags)
+    {
+        if (   !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
+            && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
+            && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
+            && !(procInfo.mFlags & ProcessCreateFlag_NoProfile))
         {
             return VERR_INVALID_PARAMETER;
         }
     }
-
-    GuestProcessInfo procInfo = aProcInfo;
 
     /* Adjust timeout. If set to 0, we define
@@ -472,20 +476,16 @@
     if (RT_FAILURE(rc)) throw rc;
 
-    ComObjPtr<GuestProcess> pGuestProcess;
     try
     {
-        /* Create the session object. */
-        HRESULT hr = pGuestProcess.createObject();
+        /* Create the process object. */
+        HRESULT hr = pProcess.createObject();
         if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
 
-        rc = pGuestProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
-                                 uNewProcessID, procInfo);
+        rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
+                             uNewProcessID, procInfo);
         if (RT_FAILURE(rc)) throw rc;
 
-        mData.mProcesses[uNewProcessID] = pGuestProcess;
-
-        /* Return guest session to the caller. */
-        hr = pGuestProcess.queryInterfaceTo(aProcess);
-        if (FAILED(hr)) throw VERR_COM_OBJECT_NOT_FOUND;
+        /* Add the created process to our map. */
+        mData.mProcesses[uNewProcessID] = pProcess;
     }
     catch (int rc2)
@@ -972,7 +972,6 @@
     {
         com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
-        procInfo.mArguments.reserve(arguments.size());
         for (size_t i = 0; i < arguments.size(); i++)
-            procInfo.mArguments[i] = Utf8Str(Bstr(arguments[i]));
+            procInfo.mArguments.push_back(Utf8Str(arguments[i]));
     }
 
@@ -986,5 +985,6 @@
      */
     procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
-    if (aEnvironment) /* Apply/overwrite environment, if set. */
+
+    if (aEnvironment)
     {
         com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
@@ -992,4 +992,6 @@
             rc = mData.mEnvironment.Set(Utf8Str(environment[i]));
     }
+
+    HRESULT hr = S_OK;
 
     if (RT_SUCCESS(rc))
@@ -1007,5 +1009,4 @@
         {
             com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
-            procInfo.mAffinity.reserve(affinity.size());
             for (size_t i = 0; i < affinity.size(); i++)
                 procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */
@@ -1014,9 +1015,36 @@
         procInfo.mPriority = aPriority;
 
-        rc = processCreateExInteral(procInfo, aProcess);
-    }
-
-    HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
-    LogFlowFuncLeaveRC(hr);
+        ComObjPtr<GuestProcess> pProcess;
+        rc = processCreateExInteral(procInfo, pProcess);
+        if (RT_SUCCESS(rc))
+        {
+            /* Return guest session to the caller. */
+            HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
+            if (FAILED(hr2))
+                rc = VERR_COM_OBJECT_NOT_FOUND;
+
+            if (RT_SUCCESS(rc))
+                rc = pProcess->startProcessAsync();
+        }
+    }
+
+    if (RT_FAILURE(rc))
+    {
+        switch (rc)
+        {
+            case VERR_MAX_PROCS_REACHED:
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest processes (%ld) reached"),
+                              VERR_MAX_PROCS_REACHED);
+                break;
+
+            /** @todo Add more errors here. */
+
+           default:
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
+                break;
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
     return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
@@ -1051,5 +1079,5 @@
         hr = hr2;
 
-    LogFlowThisFunc(("aProcess=%p, hr=%Rrc\n", *aProcess, hr));
+    LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
     return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
