Index: trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
===================================================================
--- trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 29784)
+++ trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 29785)
@@ -367,5 +367,6 @@
 
                 /* Wait for process to exit ... */
-                BOOL fCompleted = false;
+                BOOL fCompleted = FALSE;
+                BOOL fCanceled = FALSE;
                 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
                 {
@@ -424,7 +425,14 @@
                         hrc = progress->Cancel();
                         if (SUCCEEDED(hrc))
-                            fCanceledAlready = true;
+                            fCanceledAlready = TRUE;
                         else
                             g_fExecCanceled = false;
+                    }
+
+                    /* progress canceled by Main API? */
+                    if (   SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled)))
+                        && fCanceled)
+                    {
+                        break;
                     }
 
@@ -441,7 +449,6 @@
                 }
 
-                BOOL fCanceled;
-                if (SUCCEEDED(progress->COMGETTER(Canceled)(&fCanceled)) && fCanceled)
-                    if (fVerbose) RTPrintf("Process execution canceled!\n");
+                if (fCanceled && fVerbose)
+                    RTPrintf("Process execution canceled!\n");
 
                 if (fCompleted)
Index: trunk/src/VBox/HostServices/GuestControl/service.cpp
===================================================================
--- trunk/src/VBox/HostServices/GuestControl/service.cpp	(revision 29784)
+++ trunk/src/VBox/HostServices/GuestControl/service.cpp	(revision 29785)
@@ -48,10 +48,37 @@
 
 /**
- * Structure for holding a buffered host command
+ * Structure for holding all clients with their
+ * generated host contexts. This is necessary for 
+ * mainting the relationship between a client and its context IDs.
+ */
+struct ClientContexts
+{
+    /** This client ID. */
+    uint32_t mClientID;
+    /** The list of contexts a client is assigned to. */
+    std::list< uint32_t > mContextList;
+
+    /** The normal contructor. */
+    ClientContexts(uint32_t aClientID)
+                   : mClientID(aClientID) {}
+};
+/** The client list + iterator type */
+typedef std::list< ClientContexts > ClientContextsList;
+typedef std::list< ClientContexts >::iterator ClientContextsListIter;
+typedef std::list< ClientContexts >::const_iterator ClientContextsListIterConst;
+
+/**
+ * Structure for holding a buffered host command.
  */
 struct HostCmd
 {
+    /** The context ID this command belongs to. Will be extracted
+      * from the HGCM parameters. */
+    uint32_t mContextID;
     /** Dynamic structure for holding the HGCM parms */
-    VBOXGUESTCTRPARAMBUFFER parmBuf;
+    VBOXGUESTCTRPARAMBUFFER mParmBuf;
+
+    /** The standard contructor. */
+    HostCmd() : mContextID(0) {}
 };
 /** The host cmd list + iterator type */
@@ -61,5 +88,5 @@
 
 /**
- * Structure for holding an uncompleted guest call
+ * Structure for holding an uncompleted guest call.
  */
 struct GuestCall
@@ -74,7 +101,7 @@
     uint32_t mNumParms;
 
-    /** The standard constructor */
+    /** The standard contructor. */
     GuestCall() : mClientID(0), mHandle(0), mParms(NULL), mNumParms(0) {}
-    /** The normal contructor */
+    /** The normal contructor. */
     GuestCall(uint32_t aClientID, VBOXHGCMCALLHANDLE aHandle, 
               VBOXHGCMSVCPARM aParms[], uint32_t cParms)
@@ -92,17 +119,21 @@
 {
 private:
-    /** Type definition for use in callback functions */
+    /** Type definition for use in callback functions. */
     typedef Service SELF;
     /** HGCM helper functions. */
     PVBOXHGCMSVCHELPERS mpHelpers;
-    /** Callback function supplied by the host for notification of updates
-     * to properties */
+    /*
+     * Callback function supplied by the host for notification of updates
+     * to properties.
+     */
     PFNHGCMSVCEXT mpfnHostCallback;
-    /** User data pointer to be supplied to the host callback function */
+    /** User data pointer to be supplied to the host callback function. */
     void *mpvHostData;
-    /** The deferred calls list */
+    /** The deferred calls list. */
     CallList mClientList;
-    /** The host command list */
+    /** The host command list. */
     HostCmdList mHostCmds;
+    /** Client contexts list. */
+    ClientContextsList mClientContextsList;
 
 public:
@@ -368,16 +399,43 @@
 {
     LogFlowFunc(("Client (%ld) disconnected\n", u32ClientID));
+
     /*
      * Throw out all stale clients.
      */
-    CallListIter it = mClientList.begin();
-    while (it != mClientList.end())
+    int rc = VINF_SUCCESS;
+
+    ClientContextsListIter it = mClientContextsList.begin();
+    while (   it != mClientContextsList.end()
+           && RT_SUCCESS(rc))
     {
         if (it->mClientID == u32ClientID)
-            it = mClientList.erase(it);
+        {
+            std::list< uint32_t >::iterator itContext = it->mContextList.begin();
+            while (   itContext != it->mContextList.end()
+                   && RT_SUCCESS(rc))
+            {
+                LogFlowFunc(("Notifying host context %u of disconnect ...\n", (*itContext)));
+
+                /*
+                 * Notify the host that clients with u32ClientID are no longer
+                 * around and need to be cleaned up (canceling waits etc).
+                 */
+                if (mpfnHostCallback)
+                {
+                    CALLBACKDATACLIENTDISCONNECTED data;
+                    data.hdr.u32Magic = CALLBACKDATAMAGICCLIENTDISCONNECTED;
+                    data.hdr.u32ContextID = (*itContext);
+                    rc = mpfnHostCallback(mpvHostData, GUEST_DISCONNECTED, (void *)(&data), sizeof(data));
+                    if (RT_FAILURE(rc))
+                        LogFlowFunc(("Notification of host context %u failed with %Rrc\n", rc));
+                }
+                itContext++;
+            }
+            it = mClientContextsList.erase(it);
+        }
         else
             it++;
     }
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -388,8 +446,8 @@
   
     /* Sufficient parameter space? */
-    if (pCmd->parmBuf.uParmCount > cParms)
-    {
-        paParms[0].setUInt32(pCmd->parmBuf.uMsg);       /* Message ID */
-        paParms[1].setUInt32(pCmd->parmBuf.uParmCount); /* Required parameters for message */
+    if (pCmd->mParmBuf.uParmCount > cParms)
+    {
+        paParms[0].setUInt32(pCmd->mParmBuf.uMsg);       /* Message ID */
+        paParms[1].setUInt32(pCmd->mParmBuf.uParmCount); /* Required parameters for message */
         
         /*
@@ -402,5 +460,5 @@
     else
     {
-        rc = paramBufferAssign(&pCmd->parmBuf, cParms, paParms);
+        rc = paramBufferAssign(&pCmd->mParmBuf, cParms, paParms);
     }
     return rc;
@@ -415,4 +473,24 @@
 {
     int rc = VINF_SUCCESS;
+
+    /* 
+     * Lookup client in our list so that we can assign the context ID of
+     * a command to that client.
+     */
+    std::list< ClientContexts >::reverse_iterator it = mClientContextsList.rbegin();
+    while (it != mClientContextsList.rend())
+    {
+        if (it->mClientID == u32ClientID)
+            break;
+        it++;
+    }
+
+    /* Not found? Add client to list. */
+    if (it == mClientContextsList.rend())
+    {
+        mClientContextsList.push_back(ClientContexts(u32ClientID));
+        it = mClientContextsList.rbegin();
+    }
+    Assert(it != mClientContextsList.rend());
 
     /*
@@ -435,7 +513,11 @@
          if (RT_SUCCESS(rc))
          {
-             /* Only if the guest really got and understood the message 
-              * remove it from the list. */
-             paramBufferFree(&curCmd.parmBuf);
+             /* Remember which client processes which context (for
+              * later reference & cleanup). */
+             Assert(curCmd.mContextID > 0);
+             it->mContextList.push_back(curCmd.mContextID);
+
+             /* Only if the guest really got and understood the message remove it from the list. */
+             paramBufferFree(&curCmd.mParmBuf);
              mHostCmds.pop_front();
          }
@@ -444,4 +526,8 @@
 }
 
+/*
+ * Client asks itself (in another thread) to cancel all pending waits which are blocking the client
+ * from shutting down / doing something else.
+ */
 int Service::cancelPendingWaits(uint32_t u32ClientID)
 {
@@ -454,6 +540,6 @@
             if (it->mNumParms >= 2)
             {
-                it->mParms[0].setUInt32(GETHOSTMSG_EXEC_HOST_CANCEL_WAIT); /* Message ID */
-                it->mParms[1].setUInt32(0);                                /* Required parameters for message */
+                it->mParms[0].setUInt32(GETHOSTMSG_EXEC_HOST_CANCEL_WAIT); /* Message ID. */
+                it->mParms[1].setUInt32(0);                                /* Required parameters for message. */
             }              
             if (mpHelpers)
@@ -475,6 +561,6 @@
         && cParms    == 5)
     {
-        HOSTEXECCALLBACKDATA data;
-        data.hdr.u32Magic = HOSTEXECCALLBACKDATAMAGIC;
+        CALLBACKDATAEXECSTATUS data;
+        data.hdr.u32Magic = CALLBACKDATAMAGICEXECSTATUS;
         paParms[0].getUInt32(&data.hdr.u32ContextID);
 
@@ -491,6 +577,6 @@
              && cParms    == 5)
     {
-        HOSTEXECOUTCALLBACKDATA data;
-        data.hdr.u32Magic = HOSTEXECOUTCALLBACKDATAMAGIC;
+        CALLBACKDATAEXECOUT data;
+        data.hdr.u32Magic = CALLBACKDATAMAGICEXECOUT;
         paParms[0].getUInt32(&data.hdr.u32ContextID);
 
@@ -515,6 +601,17 @@
 
     HostCmd newCmd;
+    rc = paramBufferAllocate(&newCmd.mParmBuf, eFunction, cParms, paParms);
+    if (   RT_SUCCESS(rc)
+        && newCmd.mParmBuf.uParmCount > 0)
+    {
+        /* 
+         * Assume that the context ID *always* is the first parameter,
+         * assign the context ID to the command.
+         */
+        newCmd.mParmBuf.pParms[0].getUInt32(&newCmd.mContextID);
+        Assert(newCmd.mContextID > 0);
+    }
+
     bool fProcessed = false;
-    rc = paramBufferAllocate(&newCmd.parmBuf, eFunction, cParms, paParms);
     if (RT_SUCCESS(rc))
     {
@@ -539,5 +636,5 @@
             else /* If command was understood by the client, free and remove from host commands list. */
             {
-                paramBufferFree(&newCmd.parmBuf);
+                paramBufferFree(&newCmd.mParmBuf);
                 fProcessed = true;
             }
@@ -668,5 +765,5 @@
     HostCmdListIter it;
     for (it = mHostCmds.begin(); it != mHostCmds.end(); it++)
-        paramBufferFree(&it->parmBuf);
+        paramBufferFree(&it->mParmBuf);
     mHostCmds.clear();
 
Index: trunk/src/VBox/Main/GuestImpl.cpp
===================================================================
--- trunk/src/VBox/Main/GuestImpl.cpp	(revision 29784)
+++ trunk/src/VBox/Main/GuestImpl.cpp	(revision 29785)
@@ -484,14 +484,25 @@
 
     int rc = VINF_SUCCESS;
-    if (u32Function == GUEST_EXEC_SEND_STATUS)
+    if (u32Function == GUEST_DISCONNECTED)
+    {
+        LogFlowFunc(("GUEST_DISCONNECTED\n"));
+
+        PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
+        AssertPtr(pCBData);
+        AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbParms, VERR_INVALID_PARAMETER);
+        AssertReturn(CALLBACKDATAMAGICCLIENTDISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+        rc = pGuest->notifyCtrlClientDisconnected(u32Function, pCBData);
+    }
+    else if (u32Function == GUEST_EXEC_SEND_STATUS)
     {
         LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n"));
 
-        PHOSTEXECCALLBACKDATA pCBData = reinterpret_cast<PHOSTEXECCALLBACKDATA>(pvParms);
+        PCALLBACKDATAEXECSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvParms);
         AssertPtr(pCBData);
-        AssertReturn(sizeof(HOSTEXECCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER);
-        AssertReturn(HOSTEXECCALLBACKDATAMAGIC == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
-
-        rc = pGuest->notifyCtrlExec(u32Function, pCBData);
+        AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER);
+        AssertReturn(CALLBACKDATAMAGICEXECSTATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+        rc = pGuest->notifyCtrlExecStatus(u32Function, pCBData);
     }
     else if (u32Function == GUEST_EXEC_SEND_OUTPUT)
@@ -499,8 +510,8 @@
         LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
 
-        PHOSTEXECOUTCALLBACKDATA pCBData = reinterpret_cast<PHOSTEXECOUTCALLBACKDATA>(pvParms);
+        PCALLBACKDATAEXECOUT pCBData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvParms);
         AssertPtr(pCBData);
-        AssertReturn(sizeof(HOSTEXECOUTCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER);
-        AssertReturn(HOSTEXECOUTCALLBACKDATAMAGIC == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+        AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbParms, VERR_INVALID_PARAMETER);
+        AssertReturn(CALLBACKDATAMAGICEXECOUT == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
         rc = pGuest->notifyCtrlExecOut(u32Function, pCBData);
@@ -512,6 +523,6 @@
 
 /* Function for handling the execution start/termination notification. */
-int Guest::notifyCtrlExec(uint32_t              u32Function,
-                          PHOSTEXECCALLBACKDATA pData)
+int Guest::notifyCtrlExecStatus(uint32_t                u32Function,
+                                PCALLBACKDATAEXECSTATUS pData)
 {
     LogFlowFuncEnter();
@@ -526,5 +537,5 @@
     if (it != mCallbackList.end())
     {
-        PHOSTEXECCALLBACKDATA pCBData = (HOSTEXECCALLBACKDATA*)it->pvData;
+        PCALLBACKDATAEXECSTATUS pCBData = (PCALLBACKDATAEXECSTATUS)it->pvData;
         AssertPtr(pCBData);
 
@@ -617,5 +628,5 @@
                              pData->hdr.u32ContextID, pData->u32Status));
         }
-        ASMAtomicWriteBool(&it->bCalled, true);
+        ASMAtomicWriteBool(&it->fCalled, true);
     }
     else
@@ -626,6 +637,6 @@
 
 /* Function for handling the execution output notification. */
-int Guest::notifyCtrlExecOut(uint32_t                 u32Function,
-                             PHOSTEXECOUTCALLBACKDATA pData)
+int Guest::notifyCtrlExecOut(uint32_t             u32Function,
+                             PCALLBACKDATAEXECOUT pData)
 {
     LogFlowFuncEnter();
@@ -638,6 +649,6 @@
     if (it != mCallbackList.end())
     {
-        Assert(!it->bCalled);
-        PHOSTEXECOUTCALLBACKDATA pCBData = (HOSTEXECOUTCALLBACKDATA*)it->pvData;
+        Assert(!it->fCalled);
+        PCALLBACKDATAEXECOUT pCBData = (CALLBACKDATAEXECOUT*)it->pvData;
         AssertPtr(pCBData);
 
@@ -662,8 +673,28 @@
             pCBData->cbData = 0;
         }
-        ASMAtomicWriteBool(&it->bCalled, true);
+        ASMAtomicWriteBool(&it->fCalled, true);
     }
     else
         LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
+    LogFlowFuncLeave();
+    return rc;
+}
+
+int Guest::notifyCtrlClientDisconnected(uint32_t                        u32Function,
+                                        PCALLBACKDATACLIENTDISCONNECTED pData)
+{
+    LogFlowFuncEnter();
+    int rc = VINF_SUCCESS;
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /** @todo Maybe use a map instead of list for fast context lookup. */
+    CallbackListIter it;
+    for (it = mCallbackList.begin(); it != mCallbackList.end(); it++)
+    {
+        if (it->mContextID == pData->hdr.u32ContextID)
+            destroyCtrlCallbackContext(it);
+    }
+
     LogFlowFuncLeave();
     return rc;
@@ -738,5 +769,5 @@
     context.mContextID = uNewContext;
     context.mType = enmType;
-    context.bCalled = false;
+    context.fCalled = false;
     context.pvData = pvData;
     context.cbData = cbData;
@@ -868,8 +899,8 @@
                 if (RT_SUCCESS(vrc))
                 {
-                    PHOSTEXECCALLBACKDATA pData = (HOSTEXECCALLBACKDATA*)RTMemAlloc(sizeof(HOSTEXECCALLBACKDATA));
+                    PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
                     AssertReturn(pData, VBOX_E_IPRT_ERROR);
                     uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, 
-                                                        pData, sizeof(HOSTEXECCALLBACKDATA), progress);
+                                                        pData, sizeof(CALLBACKDATAEXECSTATUS), progress);
                     Assert(uContextID > 0);
 
@@ -926,5 +957,5 @@
                 {
                     uint64_t u64Started = RTTimeMilliTS();
-                    while (!it->bCalled)
+                    while (!it->fCalled)
                     {
                         /* Check for timeout. */
@@ -957,9 +988,9 @@
                     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 
 
-                    PHOSTEXECCALLBACKDATA pData = (HOSTEXECCALLBACKDATA*)it->pvData;
-                    Assert(it->cbData == sizeof(HOSTEXECCALLBACKDATA));
+                    PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)it->pvData;
+                    Assert(it->cbData == sizeof(CALLBACKDATAEXECSTATUS));
                     AssertPtr(pData);
 
-                    if (it->bCalled)
+                    if (it->fCalled)
                     {
                         /* Did we get some status? */
@@ -1008,4 +1039,9 @@
                             rc = setError(VBOX_E_IPRT_ERROR,
                                           tr("The file '%s' was not found on guest"), Utf8Command.raw());
+                        }
+                        else if (vrc == VERR_PATH_NOT_FOUND)
+                        {
+                            rc = setError(VBOX_E_IPRT_ERROR,
+                                          tr("The path to file '%s' was not found on guest"), Utf8Command.raw());
                         }
                         else if (vrc == VERR_BAD_EXE_FORMAT)
@@ -1123,8 +1159,8 @@
 
         /* Search for existing PID. */
-        PHOSTEXECOUTCALLBACKDATA pData = (HOSTEXECOUTCALLBACKDATA*)RTMemAlloc(sizeof(HOSTEXECOUTCALLBACKDATA));
+        PCALLBACKDATAEXECOUT pData = (CALLBACKDATAEXECOUT*)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT));
         AssertReturn(pData, VBOX_E_IPRT_ERROR);
         uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT,
-                                                     pData, sizeof(HOSTEXECOUTCALLBACKDATA), progress);
+                                                     pData, sizeof(CALLBACKDATAEXECOUT), progress);
         Assert(uContextID > 0);
     
@@ -1175,5 +1211,5 @@
             {
                 uint64_t u64Started = RTTimeMilliTS();
-                while (!it->bCalled)
+                while (!it->fCalled)
                 {
                     /* Check for timeout. */
@@ -1203,11 +1239,11 @@
                 if (!fCanceled)
                 {
-                    if (it->bCalled)
+                    if (it->fCalled)
                     {
                         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
             
                         /* Did we get some output? */
-                        pData = (HOSTEXECOUTCALLBACKDATA*)it->pvData;
-                        Assert(it->cbData == sizeof(HOSTEXECOUTCALLBACKDATA));
+                        pData = (PCALLBACKDATAEXECOUT)it->pvData;
+                        Assert(it->cbData == sizeof(CALLBACKDATAEXECOUT));
                         AssertPtr(pData);
             
Index: trunk/src/VBox/Main/include/GuestImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestImpl.h	(revision 29784)
+++ trunk/src/VBox/Main/include/GuestImpl.h	(revision 29785)
@@ -127,5 +127,5 @@
         uint32_t                    cbData;
         /** Atomic flag whether callback was called. */
-        volatile bool               bCalled;
+        volatile bool               fCalled;
         /** Pointer to user-supplied IProgress. */
         ComObjPtr<Progress>         pProgress;
@@ -137,8 +137,8 @@
     struct GuestProcess
     {
-        uint32_t                 mPID;
-        uint32_t                 mStatus;
-        uint32_t                 mFlags;
-        uint32_t                 mExitCode;
+        uint32_t                    mPID;
+        uint32_t                    mStatus;
+        uint32_t                    mFlags;
+        uint32_t                    mExitCode;
     };
     typedef std::list< GuestProcess > GuestProcessList;
@@ -148,6 +148,7 @@
     int prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv);
     /** Handler for guest execution control notifications. */
-    int notifyCtrlExec(uint32_t u32Function, PHOSTEXECCALLBACKDATA pData);
-    int notifyCtrlExecOut(uint32_t u32Function, PHOSTEXECOUTCALLBACKDATA pData);
+    int notifyCtrlClientDisconnected(uint32_t u32Function, PCALLBACKDATACLIENTDISCONNECTED pData);
+    int notifyCtrlExecStatus(uint32_t u32Function, PCALLBACKDATAEXECSTATUS pData);
+    int notifyCtrlExecOut(uint32_t u32Function, PCALLBACKDATAEXECOUT pData);
     CallbackListIter getCtrlCallbackContextByID(uint32_t u32ContextID);
     GuestProcessIter getProcessByPID(uint32_t u32PID);
