Index: trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 45776)
+++ trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 45780)
@@ -375,4 +375,32 @@
 };
 
+class GuestWaitEvent
+{
+public:
+
+    GuestWaitEvent(uint32_t mCID, const std::list<VBoxEventType_T> &lstEvents);
+    virtual ~GuestWaitEvent(void);
+
+public:
+
+    uint32_t                         ContextID(void) { return mCID; };
+    const ComPtr<IEvent>             Event(void) { return mEvent; };
+    const std::list<VBoxEventType_T> Types(void) { return mEventTypes; };
+    int                              Signal(IEvent *pEvent);
+    int                              Wait(RTMSINTERVAL uTimeoutMS);
+
+protected:
+
+    uint32_t                   mCID;
+    std::list<VBoxEventType_T> mEventTypes;
+    /** The event semaphore for triggering
+     *  the actual event. */
+    RTSEMEVENT                 mEventSem;
+    /** Pointer to the actual event. */
+    ComPtr<IEvent>             mEvent;
+};
+typedef std::list < GuestWaitEvent* > GuestWaitEvents;
+typedef std::map < VBoxEventType_T, GuestWaitEvents > GuestWaitEventTypes;
+
 class GuestBase
 {
@@ -385,5 +413,14 @@
 public:
 
+    /** For external event listeners. */
+    int signalWaitEvents(VBoxEventType_T aType, IEvent *aEvent);
+
+public:
+
     int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID);
+    int registerEvent(uint32_t uSessionID, uint32_t uObjectID, const std::list<VBoxEventType_T> &lstEvents, GuestWaitEvent **ppEvent);
+    void unregisterEvent(GuestWaitEvent *pEvent);
+    void unregisterEventListener(void);
+    int waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, VBoxEventType_T *pType, IEvent **ppEvent);
 
 protected:
@@ -394,4 +431,10 @@
     /** The next upcoming context ID for this object. */
     uint32_t                 mNextContextID;
+    /** Local listener for handling the waiting events. */
+    ComPtr<IEventListener>   mListener;
+    /** Critical section for wait events access. */
+    RTCRITSECT               mWaitEventCritSect;
+    /** Map of internal events to wait for. */
+    GuestWaitEventTypes      mWaitEvents;
 };
 
@@ -420,4 +463,5 @@
 
     int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID);
+    int registerEvent(const std::list<VBoxEventType_T> &lstEvents, GuestWaitEvent **ppEvent);
     int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
 
Index: trunk/src/VBox/Main/include/GuestFileImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestFileImpl.h	(revision 45776)
+++ trunk/src/VBox/Main/include/GuestFileImpl.h	(revision 45780)
@@ -94,9 +94,8 @@
     static HRESULT  setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
     int             setFileStatus(FileStatus_T fileStatus, int fileRc);
-    int             waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents), VBoxEventType_T *pType, IEvent **ppEvent);
-    int             waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset);
-    int             waitForRead(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead);
-    int             waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus);
-    int             waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten);
+    int             waitForOffsetChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint64_t *puOffset);
+    int             waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead);
+    int             waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, FileStatus_T *pFileStatus);
+    int             waitForWrite(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint32_t *pcbWritten);
     int             writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten);
     int             writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten);
Index: trunk/src/VBox/Main/include/GuestProcessImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 45776)
+++ trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 45780)
@@ -84,8 +84,7 @@
     int terminateProcess(int *pGuestRc);
     int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc);
-    int waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents), VBoxEventType_T *pType, IEvent **ppEvent);
-    int waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed);
-    int waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead);
-    int waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc);
+    int waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed);
+    int waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead);
+    int waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc);
     int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc);
     /** @}  */
Index: trunk/src/VBox/Main/include/GuestSessionImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 45776)
+++ trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 45780)
@@ -371,5 +371,5 @@
     int                     queryInfo(void);
     int                     waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc);
-    int                     waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc);
+    int                     waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc);
     /** @}  */
 
Index: trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 45776)
+++ trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 45780)
@@ -804,4 +804,150 @@
 }
 
+int GuestBase::registerEvent(uint32_t uSessionID, uint32_t uObjectID,
+                             const std::list<VBoxEventType_T> &lstEvents,
+                             GuestWaitEvent **ppEvent)
+{
+    AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
+
+    uint32_t uContextID;
+    int rc = generateContextID(uSessionID, uObjectID, &uContextID);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = RTCritSectEnter(&mWaitEventCritSect);
+    if (RT_SUCCESS(rc))
+    {
+        try
+        {
+            GuestWaitEvent *pEvent = new GuestWaitEvent(uContextID, lstEvents);
+            AssertPtr(pEvent);
+
+            for (std::list<VBoxEventType_T>::const_iterator itEvents = lstEvents.begin();
+                 itEvents != lstEvents.end(); itEvents++)
+            {
+                mWaitEvents[(*itEvents)].push_back(pEvent);
+            }
+
+            *ppEvent = pEvent;
+        }
+        catch(std::bad_alloc &)
+        {
+            rc = VERR_NO_MEMORY;
+        }
+
+        int rc2 = RTCritSectLeave(&mWaitEventCritSect);
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
+
+    return rc;
+}
+
+int GuestBase::signalWaitEvents(VBoxEventType_T aType, IEvent *aEvent)
+{
+    int rc = RTCritSectEnter(&mWaitEventCritSect);
+    if (RT_SUCCESS(rc))
+    {
+        GuestWaitEventTypes::iterator itTypes = mWaitEvents.find(aType);
+        if (itTypes != mWaitEvents.end())
+        {
+            for (GuestWaitEvents::iterator itEvents = itTypes->second.begin();
+                 itEvents != itTypes->second.end(); itEvents++)
+            {
+                ComPtr<IEvent> pThisEvent = aEvent;
+                Assert(!pThisEvent.isNull());
+                int rc2 = (*itEvents)->Signal(aEvent);
+                if (RT_SUCCESS(rc))
+                    rc = rc2;
+            }
+        }
+
+        int rc2 = RTCritSectLeave(&mWaitEventCritSect);
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
+
+    return rc;
+}
+
+void GuestBase::unregisterEvent(GuestWaitEvent *pEvent)
+{
+    AssertPtrReturnVoid(pEvent);
+
+    int rc = RTCritSectEnter(&mWaitEventCritSect);
+    if (RT_SUCCESS(rc))
+    {
+        const std::list<VBoxEventType_T> lstTypes = pEvent->Types();
+        for (std::list<VBoxEventType_T>::const_iterator itEvents = lstTypes.begin();
+             itEvents != lstTypes.end(); itEvents++)
+        {
+            /** @todo Slow O(n) lookup. Optimize this. */
+            GuestWaitEvents::iterator itCurEvent = mWaitEvents[(*itEvents)].begin();
+            while (itCurEvent != mWaitEvents[(*itEvents)].end())
+            {
+             if ((*itCurEvent) == pEvent)
+             {
+                 itCurEvent = mWaitEvents[(*itEvents)].erase(itCurEvent);
+                 break;
+             }
+             else
+                 itCurEvent++;
+            }
+        }
+
+        delete pEvent;
+
+        int rc2 = RTCritSectLeave(&mWaitEventCritSect);
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
+}
+
+void GuestBase::unregisterEventListener(void)
+{
+    if (mListener)
+    {
+        ComPtr<IEventSource> es;
+        HRESULT hr = mConsole->COMGETTER(EventSource)(es.asOutParam());
+        if (SUCCEEDED(hr))
+        {
+            Assert(!es.isNull());
+            es->UnregisterListener(mListener);
+        }
+
+        mListener.setNull();
+    }
+
+    int rc2 = RTCritSectDelete(&mWaitEventCritSect);
+    AssertRC(rc2);
+}
+
+int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
+                            VBoxEventType_T *pType, IEvent **ppEvent)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("pEvent=%p, uTimeoutMS=%RU32\n",
+                 pEvent, uTimeoutMS));
+
+    int vrc = pEvent->Wait(uTimeoutMS);
+    if (RT_SUCCESS(vrc))
+    {
+        const ComPtr<IEvent> pThisEvent = pEvent->Event();
+        Assert(!pThisEvent.isNull());
+
+        if (pType)
+        {
+            HRESULT hr = pThisEvent->COMGETTER(Type)(pType);
+            ComAssertComRC(hr);
+        }
+        if (ppEvent)
+            pThisEvent.queryInterfaceTo(ppEvent);
+    }
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
 GuestObject::GuestObject(void)
     : mSession(NULL),
@@ -824,4 +970,11 @@
 
     return VINF_SUCCESS;
+}
+
+int GuestObject::registerEvent(const std::list<VBoxEventType_T> &lstEvents,
+                               GuestWaitEvent **ppEvent)
+{
+    AssertPtr(mSession);
+    return GuestBase::registerEvent(mSession->getId(), mObjectID, lstEvents, ppEvent);
 }
 
@@ -853,2 +1006,44 @@
 }
 
+GuestWaitEvent::GuestWaitEvent(uint32_t uCID,
+                               const std::list<VBoxEventType_T> &lstEvents)
+    : mCID(uCID),
+      mEventTypes(lstEvents),
+      mEventSem(NIL_RTSEMEVENT),
+      mEvent(false)
+{
+    int rc = RTSemEventCreate(&mEventSem);
+    AssertRC(rc);
+    /** @todo Throw an exception on failure! */
+}
+
+GuestWaitEvent::~GuestWaitEvent(void)
+{
+
+}
+
+int GuestWaitEvent::Signal(IEvent *pEvent)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+    AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
+
+    mEvent = pEvent;
+
+    return RTSemEventSignal(mEventSem);
+}
+
+int GuestWaitEvent::Wait(RTMSINTERVAL uTimeoutMS)
+{
+    LogFlowThisFuncEnter();
+
+    AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
+
+    RTMSINTERVAL msInterval = uTimeoutMS;
+    if (!uTimeoutMS)
+        msInterval = RT_INDEFINITE_WAIT;
+    int rc = RTSemEventWait(mEventSem, msInterval);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
Index: trunk/src/VBox/Main/src-client/GuestFileImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestFileImpl.cpp	(revision 45776)
+++ trunk/src/VBox/Main/src-client/GuestFileImpl.cpp	(revision 45780)
@@ -33,5 +33,7 @@
 #include <iprt/cpp/utils.h> /* For unconst(). */
 #include <iprt/file.h>
+
 #include <VBox/com/array.h>
+#include <VBox/com/listeners.h>
 
 #ifdef LOG_GROUP
@@ -41,4 +43,61 @@
 #include <VBox/log.h>
 
+
+/**
+ * Internal listener class to serve events in an
+ * active manner, e.g. without polling delays.
+ */
+class GuestFileListener
+{
+public:
+
+    GuestFileListener(void)
+    {
+    }
+
+    HRESULT init(GuestFile *pFile)
+    {
+        mFile = pFile;
+        return S_OK;
+    }
+
+    void uninit(void)
+    {
+        mFile.setNull();
+    }
+
+    STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
+    {
+        switch (aType)
+        {
+            case VBoxEventType_OnGuestFileStateChanged:
+            case VBoxEventType_OnGuestFileOffsetChanged:
+            case VBoxEventType_OnGuestFileRead:
+            case VBoxEventType_OnGuestFileWrite:
+            {
+                Assert(!mFile.isNull());
+                int rc2 = mFile->signalWaitEvents(aType, aEvent);
+#ifdef DEBUG_andy
+                LogFlowFunc(("Signalling events of type=%ld, file=%p resulted in rc=%Rrc\n",
+                             aType, mFile, rc2));
+#endif
+                break;
+            }
+
+            default:
+                AssertMsgFailed(("Unhandled event %ld\n", aType));
+                break;
+        }
+
+        return S_OK;
+    }
+
+private:
+
+    ComObjPtr<GuestFile> mFile;
+};
+typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
+
+VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
 
 // constructor / destructor
@@ -106,4 +165,43 @@
     if (RT_SUCCESS(vrc))
     {
+        try
+        {
+            GuestFileListener *pListener = new GuestFileListener();
+            ComObjPtr<GuestFileListenerImpl> thisListener;
+            HRESULT hr = thisListener.createObject();
+            if (SUCCEEDED(hr))
+                hr = thisListener->init(pListener, this);
+
+            if (SUCCEEDED(hr))
+            {
+                mListener = thisListener;
+
+                com::SafeArray <VBoxEventType_T> eventTypes;
+                eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+                eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
+                eventTypes.push_back(VBoxEventType_OnGuestFileRead);
+                eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
+                hr = mEventSource->RegisterListener(mListener,
+                                                    ComSafeArrayAsInParam(eventTypes),
+                                                    TRUE /* Active listener */);
+                if (SUCCEEDED(hr))
+                {
+                    vrc = RTCritSectInit(&mWaitEventCritSect);
+                    AssertRC(vrc);
+                }
+                else
+                    vrc = VERR_COM_UNEXPECTED;
+            }
+            else
+                vrc = VERR_COM_UNEXPECTED;
+        }
+        catch(std::bad_alloc &)
+        {
+            vrc = VERR_NO_MEMORY;
+        }
+    }
+
+    if (RT_SUCCESS(vrc))
+    {
         /* Confirm a successful initialization when it's the case. */
         autoInitSpan.setSucceeded();
@@ -132,4 +230,5 @@
 #ifdef VBOX_WITH_GUEST_CONTROL
     unconst(mEventSource).setNull();
+    unregisterEventListener();
 #endif
 
@@ -325,19 +424,33 @@
     LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str()));
 
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
-    if (RT_SUCCESS(vrc))
-    {
-        /* Prepare HGCM call. */
-        VBOXHGCMSVCPARM paParms[4];
-        int i = 0;
-        paParms[i++].setUInt32(mData.mID /* Guest file ID */);
-
-        vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
-        if (RT_SUCCESS(vrc))
-            vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */,
-                                      NULL /* FileStatus */);
-    }
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    /* Prepare HGCM call. */
+    VBOXHGCMSVCPARM paParms[4];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mID /* Guest file ID */);
+
+    vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
+    if (RT_SUCCESS(vrc))
+        vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
+                                  NULL /* FileStatus */);
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -590,8 +703,26 @@
                      mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mOpenMode.c_str(),
                      mData.mOpenInfo.mDisposition.c_str(), mData.mOpenInfo.mCreationMode));
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
 
     /* Prepare HGCM call. */
     VBOXHGCMSVCPARM paParms[8];
     int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
     paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
                             (ULONG)mData.mOpenInfo.mFileName.length() + 1);
@@ -603,8 +734,10 @@
     paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
 
-    int vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
-    if (RT_SUCCESS(vrc))
-        vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */,
+    vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
+    if (RT_SUCCESS(vrc))
+        vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
                                   NULL /* FileStatus */);
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -620,87 +753,137 @@
     LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
                      uSize, uTimeoutMS, pvData, cbData));
-
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
-    if (RT_SUCCESS(vrc))
-    {
-        /* Prepare HGCM call. */
-        VBOXHGCMSVCPARM paParms[4];
-        int i = 0;
-        paParms[i++].setUInt32(mData.mID /* File handle */);
-        paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
-
-        uint32_t cbRead;
-        vrc = sendCommand(HOST_FILE_READ, i, paParms);
-        if (RT_SUCCESS(vrc))
-            vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead);
-
-        if (RT_SUCCESS(vrc))
-        {
-            LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
-
-            if (pcbRead)
-                *pcbRead = cbRead;
-        }
-    }
-
-    LogFlowFuncLeaveRC(vrc);
-    return vrc;
-}
-
-int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
-                          void* pvData, size_t cbData, size_t* pcbRead)
-{
-    LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
-                     uOffset, uSize, uTimeoutMS, pvData, cbData));
-
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
-    if (RT_SUCCESS(vrc))
-    {
-
-        /* Prepare HGCM call. */
-        VBOXHGCMSVCPARM paParms[4];
-        int i = 0;
-        paParms[i++].setUInt32(mData.mID /* File handle */);
-        paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
-        paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
-
-        uint32_t cbRead;
-        vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
-        if (RT_SUCCESS(vrc))
-            vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead);
-
-        if (RT_SUCCESS(vrc))
-        {
-            LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
-
-            if (pcbRead)
-                *pcbRead = cbRead;
-        }
-    }
-
-    LogFlowFuncLeaveRC(vrc);
-    return vrc;
-}
-
-int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType,
-                      uint32_t uTimeoutMS, uint64_t *puOffset)
-{
-    LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n",
-                     uOffset, uTimeoutMS));
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+        eventTypes.push_back(VBoxEventType_OnGuestFileRead);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
 
     /* Prepare HGCM call. */
     VBOXHGCMSVCPARM paParms[4];
     int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mID /* File handle */);
+    paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
+
+    uint32_t cbRead;
+    vrc = sendCommand(HOST_FILE_READ, i, paParms);
+    if (RT_SUCCESS(vrc))
+        vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
+
+    if (RT_SUCCESS(vrc))
+    {
+        LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
+
+        if (pcbRead)
+            *pcbRead = cbRead;
+    }
+
+    unregisterEvent(pEvent);
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
+                          void* pvData, size_t cbData, size_t* pcbRead)
+{
+    LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
+                     uOffset, uSize, uTimeoutMS, pvData, cbData));
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+        eventTypes.push_back(VBoxEventType_OnGuestFileRead);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    /* Prepare HGCM call. */
+    VBOXHGCMSVCPARM paParms[4];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mID /* File handle */);
+    paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
+    paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
+
+    uint32_t cbRead;
+    vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
+    if (RT_SUCCESS(vrc))
+        vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
+
+    if (RT_SUCCESS(vrc))
+    {
+        LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
+
+        if (pcbRead)
+            *pcbRead = cbRead;
+    }
+
+    unregisterEvent(pEvent);
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType,
+                      uint32_t uTimeoutMS, uint64_t *puOffset)
+{
+    LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n",
+                     uOffset, uTimeoutMS));
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+        eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    /* Prepare HGCM call. */
+    VBOXHGCMSVCPARM paParms[4];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
     paParms[i++].setUInt32(mData.mID /* File handle */);
     paParms[i++].setUInt32(eSeekType /* Seek method */);
     paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
 
-    int vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
-    if (RT_SUCCESS(vrc))
-        vrc = waitForOffsetChange(uTimeoutMS, puOffset);
+    vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
+    if (RT_SUCCESS(vrc))
+        vrc = waitForOffsetChange(pEvent, uTimeoutMS, puOffset);
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -752,193 +935,90 @@
 }
 
-int GuestFile::waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents),
-                             VBoxEventType_T *pType, IEvent **ppEvent)
-{
-    AssertPtrReturn(pType, VERR_INVALID_POINTER);
-    AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
-
-    int vrc;
-
-    /** @todo Parameter validation. */
-
-    com::SafeArray <VBoxEventType_T> arrEventTypes(ComSafeArrayInArg(pEvents));
-
-    ComPtr<IEventListener> pListener;
-    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
-    if (SUCCEEDED(hr))
-    {
-        arrEventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
-        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(arrEventTypes),
-                                            FALSE /* Passive listener */);
-    }
-    else
-        vrc = VERR_COM_UNEXPECTED;
-
-    if (SUCCEEDED(hr))
-    {
-        LogFlowThisFunc(("Waiting for guest file event(s) (timeout=%RU32ms, %zu events) ...\n",
-                         uTimeoutMS, arrEventTypes.size()));
-
-        vrc = VINF_SUCCESS;
-
-        uint64_t u64Started = RTTimeMilliTS();
-        bool fSignalled = false;
-        do
-        {
-            unsigned cMsWait;
-            if (uTimeoutMS == RT_INDEFINITE_WAIT)
-                cMsWait = 1000;
-            else
+int GuestFile::waitForOffsetChange(GuestWaitEvent *pEvent,
+                                   uint32_t uTimeoutMS, uint64_t *puOffset)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+    VBoxEventType_T evtType;
+    ComPtr<IEvent> pIEvent;
+    int vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+    if (RT_SUCCESS(vrc))
+    {
+        if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
+        {
+            if (puOffset)
             {
-                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
-                if (cMsElapsed >= uTimeoutMS)
-                    break; /* timed out */
-                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
+                ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
+                Assert(!pFileEvent.isNull());
+
+                HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
+                ComAssertComRC(hr);
             }
-
-            ComPtr<IEvent> pThisEvent;
-            hr = mEventSource->GetEvent(pListener, cMsWait, pThisEvent.asOutParam());
-            if (   SUCCEEDED(hr)
-                && !pThisEvent.isNull())
+        }
+        else
+            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
+    }
+
+    return vrc;
+}
+
+int GuestFile::waitForRead(GuestWaitEvent *pEvent,
+                           uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+    VBoxEventType_T evtType;
+    ComPtr<IEvent> pIEvent;
+    int vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+    if (RT_SUCCESS(vrc))
+    {
+        if (evtType == VBoxEventType_OnGuestFileRead)
+        {
+            ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
+            Assert(!pFileEvent.isNull());
+
+            HRESULT hr;
+            if (pvData)
             {
-                VBoxEventType_T type;
-                hr = pThisEvent->COMGETTER(Type)(&type);
+                com::SafeArray <BYTE> data;
+                hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
                 ComAssertComRC(hr);
-
-                for (size_t i = 0; i < arrEventTypes.size() && !fSignalled; i++)
+                size_t cbRead = data.size();
+                if (   cbRead
+                    && cbRead <= cbData)
                 {
-                    if (type == arrEventTypes[i])
-                    {
-                        switch (type)
-                        {
-                            case VBoxEventType_OnGuestFileStateChanged:
-                            case VBoxEventType_OnGuestFileOffsetChanged:
-                            case VBoxEventType_OnGuestFileRead:
-                            case VBoxEventType_OnGuestFileWrite:
-                            {
-                                ComPtr<IGuestFileEvent> pFileEvent = pThisEvent;
-                                Assert(!pFileEvent.isNull());
-
-                                ComPtr<IGuestFile> pFile;
-                                pFileEvent->COMGETTER(File)(pFile.asOutParam());
-                                Assert(!pFile.isNull());
-
-                                fSignalled = (pFile == this);
-                                break;
-                            }
-
-                            default:
-                                AssertMsgFailed(("Unhandled event %ld\n", type));
-                                break;
-                        }
-
-                        if (fSignalled)
-                        {
-                            if (pType)
-                                *pType = type;
-                            if (ppEvent)
-                                pThisEvent.queryInterfaceTo(ppEvent);
-                            if (   type == VBoxEventType_OnGuestFileStateChanged
-                                && RT_SUCCESS(vrc))
-                                vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
-                            break;
-                        }
-                    }
+                    memcpy(pvData, data.raw(), data.size());
                 }
+                else
+                    vrc = VERR_BUFFER_OVERFLOW;
             }
-
-        } while (!fSignalled);
-
-        if (   RT_SUCCESS(vrc)
-            && !fSignalled)
-        {
-            vrc = VERR_TIMEOUT;
-        }
-
-        hr = mEventSource->UnregisterListener(pListener);
-        ComAssertComRC(hr);
-    }
-    else
-        vrc = VERR_COM_UNEXPECTED;
-
-    LogFlowFuncLeaveRC(vrc);
+            if (pcbRead)
+            {
+                hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
+                ComAssertComRC(hr);
+            }
+        }
+        else
+            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
+    }
+
     return vrc;
 }
 
-int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset)
-{
+int GuestFile::waitForStatusChange(GuestWaitEvent *pEvent,
+                                   uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
     VBoxEventType_T evtType;
-    ComPtr<IEvent> pEvent;
-    com::SafeArray<VBoxEventType_T> eventTypes;
-    eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
-    int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
-                           &evtType, pEvent.asOutParam());
-    if (   vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
-        && puOffset)
-    {
-        Assert(evtType == VBoxEventType_OnGuestFileOffsetChanged);
-        ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pEvent;
-        Assert(!pFileEvent.isNull());
-
-        HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
-        ComAssertComRC(hr);
-    }
-
-    return vrc;
-}
-
-int GuestFile::waitForRead(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead)
-{
-    VBoxEventType_T evtType;
-    ComPtr<IEvent> pEvent;
-    com::SafeArray<VBoxEventType_T> eventTypes;
-    eventTypes.push_back(VBoxEventType_OnGuestFileRead);
-    int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
-                           &evtType, pEvent.asOutParam());
-    if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
-    {
-        Assert(evtType == VBoxEventType_OnGuestFileRead);
-        ComPtr<IGuestFileReadEvent> pFileEvent = pEvent;
-        Assert(!pFileEvent.isNull());
-
-        HRESULT hr;
-        if (pvData)
-        {
-            com::SafeArray <BYTE> data;
-            hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
-            ComAssertComRC(hr);
-            size_t cbRead = data.size();
-            if (   cbRead
-                && cbRead <= cbData)
-            {
-                memcpy(pvData, data.raw(), data.size());
-            }
-            else
-                vrc = VERR_BUFFER_OVERFLOW;
-        }
-        if (pcbRead)
-        {
-            hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
-            ComAssertComRC(hr);
-        }
-    }
-
-    return vrc;
-}
-
-int GuestFile::waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
-{
-    VBoxEventType_T evtType;
-    ComPtr<IEvent> pEvent;
-    com::SafeArray<VBoxEventType_T> eventTypes;
-    /* No own event types needed. VBoxEventType_OnGuestFileStateChanged already will
-     * part of the array when processed in waitForEvents. */
-    int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
-                           &evtType, pEvent.asOutParam());
-    if (   vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
-        && pFileStatus)
+    ComPtr<IEvent> pIEvent;
+    int vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+    if (RT_SUCCESS(vrc))
     {
         Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
-        ComPtr<IGuestFileStateChangedEvent> pFileEvent = pEvent;
+        ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
         Assert(!pFileEvent.isNull());
 
@@ -950,21 +1030,28 @@
 }
 
-int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten)
-{
+int GuestFile::waitForWrite(GuestWaitEvent *pEvent,
+                            uint32_t uTimeoutMS, uint32_t *pcbWritten)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
     VBoxEventType_T evtType;
-    ComPtr<IEvent> pEvent;
-    com::SafeArray<VBoxEventType_T> eventTypes;
-    eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
-    int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
-                           &evtType, pEvent.asOutParam());
-    if (   vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
-        && pcbWritten)
-    {
-        Assert(evtType == VBoxEventType_OnGuestFileWrite);
-        ComPtr<IGuestFileWriteEvent> pFileEvent = pEvent;
-        Assert(!pFileEvent.isNull());
-
-        HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
-        ComAssertComRC(hr);
+    ComPtr<IEvent> pIEvent;
+    int vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+    if (RT_SUCCESS(vrc))
+    {
+        if (evtType == VBoxEventType_OnGuestFileWrite)
+        {
+            if (pcbWritten)
+            {
+                ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
+                Assert(!pFileEvent.isNull());
+
+                HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
+                ComAssertComRC(hr);
+            }
+        }
+        else
+            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
     }
 
@@ -980,31 +1067,45 @@
     LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
                      uTimeoutMS, pvData, cbData));
-
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
-    if (RT_SUCCESS(vrc))
-    {
-        /* Prepare HGCM call. */
-        VBOXHGCMSVCPARM paParms[8];
-        int i = 0;
-        paParms[i++].setUInt32(uContextID);
-        paParms[i++].setUInt32(mData.mID /* File handle */);
-        paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
-        paParms[i++].setPointer(pvData, cbData);
-
-        uint32_t cbWritten;
-        vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
-        if (RT_SUCCESS(vrc))
-            vrc = waitForWrite(uTimeoutMS, &cbWritten);
-
-        if (RT_SUCCESS(vrc))
-        {
-            LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
-
-            if (cbWritten)
-                *pcbWritten = cbWritten;
-        }
-    }
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+        eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    /* Prepare HGCM call. */
+    VBOXHGCMSVCPARM paParms[8];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mID /* File handle */);
+    paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
+    paParms[i++].setPointer(pvData, cbData);
+
+    uint32_t cbWritten;
+    vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
+    if (RT_SUCCESS(vrc))
+        vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
+
+    if (RT_SUCCESS(vrc))
+    {
+        LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
+
+        if (cbWritten)
+            *pcbWritten = cbWritten;
+    }
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -1020,31 +1121,46 @@
     LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
                      uOffset, uTimeoutMS, pvData, cbData));
-
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
-    if (RT_SUCCESS(vrc))
-    {
-        /* Prepare HGCM call. */
-        VBOXHGCMSVCPARM paParms[8];
-        int i = 0;
-        paParms[i++].setUInt32(mData.mID /* File handle */);
-        paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
-        paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
-        paParms[i++].setPointer(pvData, cbData);
-
-        uint32_t cbWritten;
-        vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
-        if (RT_SUCCESS(vrc))
-            vrc = waitForWrite(uTimeoutMS, &cbWritten);
-
-        if (RT_SUCCESS(vrc))
-        {
-            LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
-
-            if (cbWritten)
-                *pcbWritten = cbWritten;
-        }
-    }
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+        eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    /* Prepare HGCM call. */
+    VBOXHGCMSVCPARM paParms[8];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mID /* File handle */);
+    paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
+    paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
+    paParms[i++].setPointer(pvData, cbData);
+
+    uint32_t cbWritten;
+    vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
+    if (RT_SUCCESS(vrc))
+        vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
+
+    if (RT_SUCCESS(vrc))
+    {
+        LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
+
+        if (cbWritten)
+            *pcbWritten = cbWritten;
+    }
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
Index: trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 45776)
+++ trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 45780)
@@ -45,4 +45,6 @@
 #include <iprt/getopt.h>
 
+#include <VBox/com/listeners.h>
+
 #include <VBox/com/array.h>
 
@@ -82,4 +84,60 @@
 };
 
+/**
+ * Internal listener class to serve events in an
+ * active manner, e.g. without polling delays.
+ */
+class GuestProcessListener
+{
+public:
+
+    GuestProcessListener(void)
+    {
+    }
+
+    HRESULT init(GuestProcess *pProcess)
+    {
+        mProcess = pProcess;
+        return S_OK;
+    }
+
+    void uninit(void)
+    {
+        mProcess.setNull();
+    }
+
+    STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
+    {
+        switch (aType)
+        {
+            case VBoxEventType_OnGuestProcessStateChanged:
+            case VBoxEventType_OnGuestProcessInputNotify:
+            case VBoxEventType_OnGuestProcessOutput:
+            {
+                Assert(!mProcess.isNull());
+                int rc2 = mProcess->signalWaitEvents(aType, aEvent);
+#ifdef DEBUG_andy
+                LogFlowFunc(("Signalling events of type=%ld, process=%p resulted in rc=%Rrc\n",
+                             aType, mProcess, rc2));
+#endif
+                break;
+            }
+
+            default:
+                AssertMsgFailed(("Unhandled event %ld\n", aType));
+                break;
+        }
+
+        return S_OK;
+    }
+
+private:
+
+    ComObjPtr<GuestProcess> mProcess;
+};
+typedef ListenerImpl<GuestProcessListener, GuestProcess*> GuestProcessListenerImpl;
+
+VBOX_LISTENER_DECLARE(GuestProcessListenerImpl)
+
 // constructor / destructor
 /////////////////////////////////////////////////////////////////////////////
@@ -121,4 +179,6 @@
     return VINF_SUCCESS;
 #else
+    HRESULT hr;
+
     int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */);
     if (RT_SUCCESS(vrc))
@@ -126,7 +186,45 @@
         unconst(mEventSource).createObject();
         Assert(!mEventSource.isNull());
-        HRESULT hr = mEventSource->init(static_cast<IGuestProcess*>(this));
+        hr = mEventSource->init(static_cast<IGuestProcess*>(this));
         if (FAILED(hr))
             vrc = VERR_COM_UNEXPECTED;
+    }
+
+    if (RT_SUCCESS(vrc))
+    {
+        try
+        {
+            GuestProcessListener *pListener = new GuestProcessListener();
+            ComObjPtr<GuestProcessListenerImpl> thisListener;
+            hr = thisListener.createObject();
+            if (SUCCEEDED(hr))
+                hr = thisListener->init(pListener, this);
+
+            if (SUCCEEDED(hr))
+            {
+                mListener = thisListener;
+
+                com::SafeArray <VBoxEventType_T> eventTypes;
+                eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
+                eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
+                eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
+                hr = mEventSource->RegisterListener(mListener,
+                                                    ComSafeArrayAsInParam(eventTypes),
+                                                    TRUE /* Active listener */);
+                if (SUCCEEDED(hr))
+                {
+                    vrc = RTCritSectInit(&mWaitEventCritSect);
+                    AssertRC(vrc);
+                }
+                else
+                    vrc = VERR_COM_UNEXPECTED;
+            }
+            else
+                vrc = VERR_COM_UNEXPECTED;
+        }
+        catch(std::bad_alloc &)
+        {
+            vrc = VERR_NO_MEMORY;
+        }
     }
 
@@ -169,4 +267,5 @@
 #ifdef VBOX_WITH_GUEST_CONTROL
     unconst(mEventSource).setNull();
+    unregisterEventListener();
 #endif
 
@@ -775,12 +874,28 @@
     }
 
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
+        eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
     if (RT_SUCCESS(vrc))
     {
         VBOXHGCMSVCPARM paParms[8];
         int i = 0;
-        paParms[i++].setUInt32(uContextID);
+        paParms[i++].setUInt32(pEvent->ContextID());
         paParms[i++].setUInt32(mData.mPID);
         paParms[i++].setUInt32(uHandle);
@@ -793,6 +908,8 @@
 
     if (RT_SUCCESS(vrc))
-        vrc = waitForOutput(uHandle, uTimeoutMS,
+        vrc = waitForOutput(pEvent, uHandle, uTimeoutMS,
                             pvData, cbData, pcbRead);
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -857,125 +974,135 @@
     mData.mStatus = ProcessStatus_Starting;
 
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    GuestSession *pSession = mSession;
+    AssertPtr(pSession);
+
+    const GuestCredentials &sessionCreds = pSession->getCredentials();
+
+    /* Prepare arguments. */
+    char *pszArgs = NULL;
+    size_t cArgs = mData.mProcess.mArguments.size();
+    if (cArgs >= UINT32_MAX)
+        vrc = VERR_BUFFER_OVERFLOW;
+
+    if (   RT_SUCCESS(vrc)
+        && cArgs)
+    {
+        char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
+        AssertReturn(papszArgv, VERR_NO_MEMORY);
+
+        for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
+        {
+            const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
+            AssertPtr(pszCurArg);
+            vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
+        }
+        papszArgv[cArgs] = NULL;
+
+        if (RT_SUCCESS(vrc))
+            vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
+
+        if (papszArgv)
+        {
+            size_t i = 0;
+            while (papszArgv[i])
+                RTStrFree(papszArgv[i++]);
+            RTMemFree(papszArgv);
+        }
+    }
+
+    /* Calculate arguments size (in bytes). */
+    size_t cbArgs = 0;
     if (RT_SUCCESS(vrc))
-    {
-        GuestSession *pSession = mSession;
-        AssertPtr(pSession);
-
-        const GuestCredentials &sessionCreds = pSession->getCredentials();
-
-        /* Prepare arguments. */
-        char *pszArgs = NULL;
-        size_t cArgs = mData.mProcess.mArguments.size();
-        if (cArgs >= UINT32_MAX)
-            vrc = VERR_BUFFER_OVERFLOW;
-
-        if (   RT_SUCCESS(vrc)
-            && cArgs)
-        {
-            char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
-            AssertReturn(papszArgv, VERR_NO_MEMORY);
-
-            for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
-            {
-                const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
-                AssertPtr(pszCurArg);
-                vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
-            }
-            papszArgv[cArgs] = NULL;
-
-            if (RT_SUCCESS(vrc))
-                vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
-
-            if (papszArgv)
-            {
-                size_t i = 0;
-                while (papszArgv[i])
-                    RTStrFree(papszArgv[i++]);
-                RTMemFree(papszArgv);
-            }
-        }
-
-        /* Calculate arguments size (in bytes). */
-        size_t cbArgs = 0;
-        if (RT_SUCCESS(vrc))
-            cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
-
-        /* Prepare environment. */
-        void *pvEnv = NULL;
-        size_t cbEnv = 0;
-        if (RT_SUCCESS(vrc))
-            vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
-
-        uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
-
-        if (RT_SUCCESS(vrc))
-        {
-            AssertPtr(mSession);
-            uint32_t uProtocol = mSession->getProtocolVersion();
-
-            /* Prepare HGCM call. */
-            VBOXHGCMSVCPARM paParms[16];
-            int i = 0;
-            paParms[i++].setUInt32(uContextID);
-            paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
-                                    (ULONG)mData.mProcess.mCommand.length() + 1);
-            paParms[i++].setUInt32(mData.mProcess.mFlags);
-            paParms[i++].setUInt32(mData.mProcess.mArguments.size());
-            paParms[i++].setPointer((void*)pszArgs, cbArgs);
-            paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
-            paParms[i++].setUInt32(cbEnv);
-            paParms[i++].setPointer((void*)pvEnv, cbEnv);
-            if (uProtocol < 2)
-            {
-                /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
-                 * call. In newer protocols these credentials are part of the opened guest
-                 * session, so not needed anymore here. */
-                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);
-            }
-            /*
-             * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
-             * until the process was started - the process itself then gets an infinite timeout for execution.
-             * This is handy when we want to start a process inside a worker thread within a certain timeout
-             * but let the started process perform lengthly operations then.
-             */
-            if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
-                paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
-            else
-                paParms[i++].setUInt32(uTimeoutMS);
-            if (uProtocol >= 2)
-            {
-                paParms[i++].setUInt32(mData.mProcess.mPriority);
-                /* CPU affinity: We only support one CPU affinity block at the moment,
-                 * so that makes up to 64 CPUs total. This can be more in the future. */
-                paParms[i++].setUInt32(1);
-                /* The actual CPU affinity blocks. */
-                paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
-            }
-
-            alock.release(); /* Drop the write lock before sending. */
-
-            /* Note: Don't hold the write lock in here. */
-            vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
-            if (RT_FAILURE(vrc))
-            {
-                int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
-                AssertRC(rc2);
-            }
-        }
-
-        GuestEnvironment::FreeEnvironmentBlock(pvEnv);
-        if (pszArgs)
-            RTStrFree(pszArgs);
-
-        if (RT_SUCCESS(vrc))
-        {
-            vrc = waitForStatusChange(ProcessWaitForFlag_Start, uTimeoutMS,
-                                      NULL /* Process status */, pGuestRc);
-        }
-    }
+        cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
+
+    /* Prepare environment. */
+    void *pvEnv = NULL;
+    size_t cbEnv = 0;
+    if (RT_SUCCESS(vrc))
+        vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
+
+    uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
+
+    if (RT_SUCCESS(vrc))
+    {
+        AssertPtr(mSession);
+        uint32_t uProtocol = mSession->getProtocolVersion();
+
+        /* Prepare HGCM call. */
+        VBOXHGCMSVCPARM paParms[16];
+        int i = 0;
+        paParms[i++].setUInt32(pEvent->ContextID());
+        paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
+                                (ULONG)mData.mProcess.mCommand.length() + 1);
+        paParms[i++].setUInt32(mData.mProcess.mFlags);
+        paParms[i++].setUInt32(mData.mProcess.mArguments.size());
+        paParms[i++].setPointer((void*)pszArgs, cbArgs);
+        paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
+        paParms[i++].setUInt32(cbEnv);
+        paParms[i++].setPointer((void*)pvEnv, cbEnv);
+        if (uProtocol < 2)
+        {
+            /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
+             * call. In newer protocols these credentials are part of the opened guest
+             * session, so not needed anymore here. */
+            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);
+        }
+        /*
+         * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
+         * until the process was started - the process itself then gets an infinite timeout for execution.
+         * This is handy when we want to start a process inside a worker thread within a certain timeout
+         * but let the started process perform lengthly operations then.
+         */
+        if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
+            paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
+        else
+            paParms[i++].setUInt32(uTimeoutMS);
+        if (uProtocol >= 2)
+        {
+            paParms[i++].setUInt32(mData.mProcess.mPriority);
+            /* CPU affinity: We only support one CPU affinity block at the moment,
+             * so that makes up to 64 CPUs total. This can be more in the future. */
+            paParms[i++].setUInt32(1);
+            /* The actual CPU affinity blocks. */
+            paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
+        }
+
+        alock.release(); /* Drop the write lock before sending. */
+
+        vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
+        if (RT_FAILURE(vrc))
+        {
+            int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
+            AssertRC(rc2);
+        }
+    }
+
+    GuestEnvironment::FreeEnvironmentBlock(pvEnv);
+    if (pszArgs)
+        RTStrFree(pszArgs);
+
+    if (RT_SUCCESS(vrc))
+        vrc = waitForStatusChange(pEvent, ProcessWaitForFlag_Start, uTimeoutMS,
+                                  NULL /* Process status */, pGuestRc);
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -1049,23 +1176,36 @@
         return VINF_SUCCESS; /* Nothing to do (anymore). */
 
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    VBOXHGCMSVCPARM paParms[4];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mPID);
+
+    alock.release(); /* Drop the write lock before sending. */
+
+    vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
     if (RT_SUCCESS(vrc))
-    {
-        VBOXHGCMSVCPARM paParms[4];
-        int i = 0;
-        paParms[i++].setUInt32(uContextID);
-        paParms[i++].setUInt32(mData.mPID);
-
-        alock.release(); /* Drop the write lock before sending. */
-
-        vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
-    }
-
-    if (RT_SUCCESS(vrc))
-        vrc = waitForStatusChange(ProcessWaitForFlag_Terminate,
+        vrc = waitForStatusChange(pEvent, ProcessWaitForFlag_Terminate,
                                   30 * 1000 /* 30s timeout */,
                                   NULL /* ProcessStatus */, pGuestRc);
+    unregisterEvent(pEvent);
+
     LogFlowFuncLeaveRC(vrc);
     return vrc;
@@ -1207,6 +1347,25 @@
     alock.release(); /* Release lock before waiting. */
 
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
     ProcessStatus_T processStatus;
-    int vrc = waitForStatusChange(fWaitFlags, uTimeoutMS, &processStatus, pGuestRc);
+    vrc = waitForStatusChange(pEvent, fWaitFlags,
+                              uTimeoutMS, &processStatus, pGuestRc);
     if (RT_SUCCESS(vrc))
     {
@@ -1242,113 +1401,102 @@
     }
 
+    unregisterEvent(pEvent);
+
     LogFlowFuncLeaveRC(vrc);
     return vrc;
 }
 
-int GuestProcess::waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents),
-                                VBoxEventType_T *pType, IEvent **ppEvent)
-{
-    AssertPtrReturn(pType, VERR_INVALID_POINTER);
-    AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
+int GuestProcess::waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
+                                     ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+    VBoxEventType_T evtType;
+    ComPtr<IEvent> pIEvent;
+    int vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+    if (RT_SUCCESS(vrc))
+    {
+        if (evtType == VBoxEventType_OnGuestProcessInputNotify)
+        {
+            ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pIEvent;
+            Assert(!pProcessEvent.isNull());
+
+            if (pInputStatus)
+            {
+                HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
+                ComAssertComRC(hr2);
+            }
+            if (pcbProcessed)
+            {
+                HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
+                ComAssertComRC(hr2);
+            }
+        }
+        else
+            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
+    }
+
+    LogFlowFuncLeaveRC(vrc);
+    return vrc;
+}
+
+int GuestProcess::waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
+                                void *pvData, size_t cbData, uint32_t *pcbRead)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
 
     int vrc;
 
-    /** @todo Parameter validation. */
-
-    com::SafeArray <VBoxEventType_T> arrEventTypes(ComSafeArrayInArg(pEvents));
-
-    ComPtr<IEventListener> pListener;
-    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
-    if (SUCCEEDED(hr))
-        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(arrEventTypes),
-                                            FALSE /* Passive listener */);
-    else
-        vrc = VERR_COM_UNEXPECTED;
-
-    if (SUCCEEDED(hr))
-    {
-        LogFlowThisFunc(("Waiting for guest process event(s) (timeout=%RU32ms, %zu events) ...\n",
-                         uTimeoutMS, arrEventTypes.size()));
-
-        vrc = VINF_SUCCESS;
-
-        uint64_t u64Started = RTTimeMilliTS();
-        bool fSignalled = false;
-        do
-        {
-            unsigned cMsWait;
-            if (uTimeoutMS == RT_INDEFINITE_WAIT)
-                cMsWait = 1000;
-            else
+    VBoxEventType_T evtType;
+    ComPtr<IEvent> pIEvent;
+    do
+    {
+        vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+        if (RT_SUCCESS(vrc))
+        {
+            if (evtType == VBoxEventType_OnGuestProcessOutput)
             {
-                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
-                if (cMsElapsed >= uTimeoutMS)
-                    break; /* timed out */
-                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
-            }
-
-            ComPtr<IEvent> pThisEvent;
-            hr = mEventSource->GetEvent(pListener, cMsWait, pThisEvent.asOutParam());
-            if (   SUCCEEDED(hr)
-                && !pThisEvent.isNull())
-            {
-                VBoxEventType_T type;
-                hr = pThisEvent->COMGETTER(Type)(&type);
-                ComAssertComRC(hr);
-
-                for (size_t i = 0; i < arrEventTypes.size() && !fSignalled; i++)
+                ComPtr<IGuestProcessOutputEvent> pProcessEvent = pIEvent;
+                Assert(!pProcessEvent.isNull());
+
+                ULONG uHandleEvent;
+                HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
+                if (uHandleEvent == uHandle)
                 {
-                    if (type == arrEventTypes[i])
+                    if (pvData)
                     {
-                        switch (type)
+                        com::SafeArray <BYTE> data;
+                        hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
+                        ComAssertComRC(hr);
+                        size_t cbRead = data.size();
+                        if (cbRead)
                         {
-                            case VBoxEventType_OnGuestProcessStateChanged:
-                            case VBoxEventType_OnGuestProcessInputNotify:
-                            case VBoxEventType_OnGuestProcessOutput:
+                            if (cbRead <= cbData)
                             {
-                                ComPtr<IGuestProcessEvent> pFileEvent = pThisEvent;
-                                Assert(!pFileEvent.isNull());
-
-                                ComPtr<IGuestProcess> pProcess;
-                                pFileEvent->COMGETTER(Process)(pProcess.asOutParam());
-                                Assert(!pProcess.isNull());
-
-                                fSignalled = (pProcess == this);
-                                break;
+                                /* Copy data from event into our buffer. */
+                                memcpy(pvData, data.raw(), data.size());
                             }
-
-                            default:
-                                AssertMsgFailed(("Unhandled event %ld\n", type));
-                                break;
-                        }
-
-                        if (fSignalled)
-                        {
-                            if (pType)
-                                *pType = type;
-                            if (ppEvent)
-                                pThisEvent.queryInterfaceTo(ppEvent);
-                            if (   type == VBoxEventType_OnGuestProcessStateChanged
-                                && RT_SUCCESS(vrc))
-                                vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
-                            break;
+                            else
+                                vrc = VERR_BUFFER_OVERFLOW;
                         }
                     }
+                    if (pcbRead)
+                    {
+                        ULONG cbRead;
+                        hr = pProcessEvent->COMGETTER(Processed)(&cbRead);
+                        ComAssertComRC(hr);
+                        *pcbRead = (uint32_t)cbRead;
+                    }
+
+                    break;
                 }
             }
-
-        } while (!fSignalled);
-
-        if (   RT_SUCCESS(vrc)
-            && !fSignalled)
-        {
-            vrc = VERR_TIMEOUT;
-        }
-
-        hr = mEventSource->UnregisterListener(pListener);
-        ComAssertComRC(hr);
-    }
-    else
-        vrc = VERR_COM_UNEXPECTED;
+            else
+                vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
+        }
+
+    } while (RT_SUCCESS(vrc));
 
     LogFlowFuncLeaveRC(vrc);
@@ -1356,120 +1504,17 @@
 }
 
-int GuestProcess::waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS,
-                                     ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
-{
+int GuestProcess::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
+                                      ProcessStatus_T *pProcessStatus, int *pGuestRc)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
     VBoxEventType_T evtType;
-    ComPtr<IEvent> pEvent;
-    com::SafeArray<VBoxEventType_T> eventTypes;
-    eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
-    int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
-                           &evtType, pEvent.asOutParam());
-    if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
-    {
-        Assert(evtType == VBoxEventType_OnGuestProcessInputNotify);
-        ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pEvent;
-        Assert(!pProcessEvent.isNull());
-
-        if (pInputStatus)
-        {
-            HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
-            ComAssertComRC(hr2);
-        }
-        if (pcbProcessed)
-        {
-            HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
-            ComAssertComRC(hr2);
-        }
-    }
-
-    LogFlowFuncLeaveRC(vrc);
-    return vrc;
-}
-
-int GuestProcess::waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS,
-                                void *pvData, size_t cbData, uint32_t *pcbRead)
-{
-    VBoxEventType_T evtType;
-    ComPtr<IEvent> pEvent;
-    com::SafeArray<VBoxEventType_T> eventTypes;
-
-    int vrc = VINF_SUCCESS;
-
-    try
-    {
-        eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
-    }
-    catch (std::bad_alloc)
-    {
-        vrc = VERR_NO_MEMORY;
-    }
-
-    if (RT_FAILURE(vrc))
-        return vrc;
-
-    do
-    {
-        vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
-                           &evtType, pEvent.asOutParam());
-        if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
-        {
-            Assert(evtType == VBoxEventType_OnGuestProcessOutput);
-            ComPtr<IGuestProcessOutputEvent> pProcessEvent = pEvent;
-            Assert(!pProcessEvent.isNull());
-
-            ULONG uHandleEvent;
-            HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
-            if (uHandleEvent == uHandle)
-            {
-                if (pvData)
-                {
-                    com::SafeArray <BYTE> data;
-                    hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
-                    ComAssertComRC(hr);
-                    size_t cbRead = data.size();
-                    if (cbRead)
-                    {
-                        if (cbRead <= cbData)
-                        {
-                            /* Copy data from event into our buffer. */
-                            memcpy(pvData, data.raw(), data.size());
-                        }
-                        else
-                            vrc = VERR_BUFFER_OVERFLOW;
-                    }
-                }
-                if (pcbRead)
-                {
-                    ULONG cbRead;
-                    hr = pProcessEvent->COMGETTER(Processed)(&cbRead);
-                    ComAssertComRC(hr);
-                    *pcbRead = (uint32_t)cbRead;
-                }
-
-                break;
-            }
-        }
-
-    } while (RT_SUCCESS(vrc));
-
-    LogFlowFuncLeaveRC(vrc);
-    return vrc;
-}
-
-int GuestProcess::waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
-                                      ProcessStatus_T *pProcessStatus, int *pGuestRc)
-{
-    /* All pointers are optional. */
-
-    VBoxEventType_T evtType;
-    ComPtr<IEvent> pEvent;
-    com::SafeArray<VBoxEventType_T> eventTypes(1);
-    eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
-    int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
-                            &evtType, pEvent.asOutParam());
-    if (RT_SUCCESS(vrc)) /* Includes VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
+    ComPtr<IEvent> pIEvent;
+    int vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+    if (RT_SUCCESS(vrc))
     {
         Assert(evtType == VBoxEventType_OnGuestProcessStateChanged);
-        ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pEvent;
+        ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pIEvent;
         Assert(!pProcessEvent.isNull());
 
@@ -1517,28 +1562,39 @@
     }
 
-    uint32_t uContextID;
-    int vrc = generateContextID(mSession->getId(), mObjectID,
-                                &uContextID);
-    if (RT_SUCCESS(vrc))
-    {
-        VBOXHGCMSVCPARM paParms[5];
-
-        int i = 0;
-        paParms[i++].setUInt32(uContextID);
-        paParms[i++].setUInt32(mData.mPID);
-        paParms[i++].setUInt32(uFlags);
-        paParms[i++].setPointer(pvData, cbData);
-        paParms[i++].setUInt32(cbData);
-
-        alock.release(); /* Drop the write lock before sending. */
-
-        vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
-    }
-
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
+        eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
+
+        vrc = registerEvent(eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    VBOXHGCMSVCPARM paParms[5];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mPID);
+    paParms[i++].setUInt32(uFlags);
+    paParms[i++].setPointer(pvData, cbData);
+    paParms[i++].setUInt32(cbData);
+
+    alock.release(); /* Drop the write lock before sending. */
+
+    vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
     if (RT_SUCCESS(vrc))
     {
         ProcessInputStatus_T inputStatus;
         uint32_t cbProcessed;
-        vrc = waitForInputNotify(uHandle, uTimeoutMS, &inputStatus, &cbProcessed);
+        vrc = waitForInputNotify(pEvent, uHandle, uTimeoutMS, &inputStatus, &cbProcessed);
         if (RT_SUCCESS(vrc))
         {
@@ -1550,4 +1606,6 @@
         /** @todo Error handling. */
     }
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
Index: trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 45776)
+++ trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 45780)
@@ -84,4 +84,58 @@
 };
 
+/**
+ * Internal listener class to serve events in an
+ * active manner, e.g. without polling delays.
+ */
+class GuestSessionListener
+{
+public:
+
+    GuestSessionListener(void)
+    {
+    }
+
+    HRESULT init(GuestSession *pSession)
+    {
+        mSession = pSession;
+        return S_OK;
+    }
+
+    void uninit(void)
+    {
+        mSession.setNull();
+    }
+
+    STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
+    {
+        switch (aType)
+        {
+            case VBoxEventType_OnGuestSessionStateChanged:
+            {
+                Assert(!mSession.isNull());
+                int rc2 = mSession->signalWaitEvents(aType, aEvent);
+#ifdef DEBUG_andy
+                LogFlowFunc(("Signalling events of type=%ld, session=%p resulted in rc=%Rrc\n",
+                             aType, mSession, rc2));
+#endif
+                break;
+            }
+
+            default:
+                AssertMsgFailed(("Unhandled event %ld\n", aType));
+                break;
+        }
+
+        return S_OK;
+    }
+
+private:
+
+    ComObjPtr<GuestSession> mSession;
+};
+typedef ListenerImpl<GuestSessionListener, GuestSession*> GuestSessionListenerImpl;
+
+VBOX_LISTENER_DECLARE(GuestProcessListenerImpl)
+
 // constructor / destructor
 /////////////////////////////////////////////////////////////////////////////
@@ -148,4 +202,6 @@
     mData.mNumObjects = 0;
 
+    HRESULT hr;
+
     int rc = queryInfo();
     if (RT_SUCCESS(rc))
@@ -160,4 +216,40 @@
     if (RT_SUCCESS(rc))
     {
+        try
+        {
+            GuestSessionListener *pListener = new GuestSessionListener();
+            ComObjPtr<GuestSessionListenerImpl> thisListener;
+            hr = thisListener.createObject();
+            if (SUCCEEDED(hr))
+                hr = thisListener->init(pListener, this);
+
+            if (SUCCEEDED(hr))
+            {
+                mListener = thisListener;
+
+                com::SafeArray <VBoxEventType_T> eventTypes;
+                eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
+                hr = mEventSource->RegisterListener(mListener,
+                                                    ComSafeArrayAsInParam(eventTypes),
+                                                    TRUE /* Active listener */);
+                if (SUCCEEDED(hr))
+                {
+                    rc = RTCritSectInit(&mWaitEventCritSect);
+                    AssertRC(rc);
+                }
+                else
+                    rc = VERR_COM_UNEXPECTED;
+            }
+            else
+                rc = VERR_COM_UNEXPECTED;
+        }
+        catch(std::bad_alloc &)
+        {
+            rc = VERR_NO_MEMORY;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
         /* Confirm a successful initialization when it's the case. */
         autoInitSpan.setSucceeded();
@@ -217,4 +309,5 @@
 
     unconst(mEventSource).setNull();
+    unregisterEventListener();
 
 #endif /* VBOX_WITH_GUEST_CONTROL */
@@ -537,30 +630,41 @@
         return VINF_SUCCESS;
 
-    uint32_t uContextID;
-    int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */,
-                                &uContextID);
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
+
+        vrc = registerEvent(mData.mSession.mID, 0 /* Object ID */,
+                            eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
+                     mData.mSession.mID, uFlags));
+
+    VBOXHGCMSVCPARM paParms[4];
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(uFlags);
+
+    vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
     if (RT_SUCCESS(vrc))
     {
-        if (RT_SUCCESS(vrc))
-        {
-            LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
-                             mData.mSession.mID, uFlags));
-
-            VBOXHGCMSVCPARM paParms[4];
-            int i = 0;
-            paParms[i++].setUInt32(uContextID);
-            paParms[i++].setUInt32(uFlags);
-
-            vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
-        }
-
-        if (RT_SUCCESS(vrc))
-        {
-            alock.release(); /* Drop the write lock before waiting. */
-
-            vrc = waitForStateChange(GuestSessionWaitForFlag_Terminate, uTimeoutMS,
-                                     NULL /* Session status */, pGuestRc);
-        }
-    }
+        alock.release(); /* Drop the write lock before waiting. */
+
+        vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS,
+                                  NULL /* Session status */, pGuestRc);
+    }
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -1241,32 +1345,47 @@
     mData.mStatus = GuestSessionStatus_Starting;
 
-    uint32_t uContextID;
-    int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */,
-                                &uContextID);
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
+
+        vrc = registerEvent(mData.mSession.mID, 0 /* Object ID */,
+                            eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    VBOXHGCMSVCPARM paParms[8];
+
+    int i = 0;
+    paParms[i++].setUInt32(pEvent->ContextID());
+    paParms[i++].setUInt32(mData.mProtocolVersion);
+    paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
+                            (ULONG)mData.mCredentials.mUser.length() + 1);
+    paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
+                            (ULONG)mData.mCredentials.mPassword.length() + 1);
+    paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
+                            (ULONG)mData.mCredentials.mDomain.length() + 1);
+    paParms[i++].setUInt32(mData.mSession.mOpenFlags);
+
+    vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
     if (RT_SUCCESS(vrc))
     {
-        VBOXHGCMSVCPARM paParms[8];
-
-        int i = 0;
-        paParms[i++].setUInt32(uContextID);
-        paParms[i++].setUInt32(mData.mProtocolVersion);
-        paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
-                                (ULONG)mData.mCredentials.mUser.length() + 1);
-        paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
-                                (ULONG)mData.mCredentials.mPassword.length() + 1);
-        paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
-                                (ULONG)mData.mCredentials.mDomain.length() + 1);
-        paParms[i++].setUInt32(mData.mSession.mOpenFlags);
-
-        vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
-    }
-
-    if (RT_SUCCESS(vrc))
-    {
         alock.release(); /* Drop write lock before waiting. */
 
-        vrc = waitForStateChange(GuestSessionWaitForFlag_Start,  30 * 1000 /* 30s timeout */,
-                                 NULL /* Session status */, pGuestRc);
-    }
+        vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Start,
+                                  30 * 1000 /* 30s timeout */,
+                                  NULL /* Session status */, pGuestRc);
+    }
+
+    unregisterEvent(pEvent);
 
     LogFlowFuncLeaveRC(vrc);
@@ -1782,6 +1901,26 @@
     alock.release(); /* Release lock before waiting. */
 
+    int vrc;
+
+    GuestWaitEvent *pEvent = NULL;
+    std::list < VBoxEventType_T > eventTypes;
+    try
+    {
+        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
+
+        vrc = registerEvent(mData.mSession.mID, 0 /* Object ID */,
+                            eventTypes, &pEvent);
+    }
+    catch (std::bad_alloc)
+    {
+        vrc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
     GuestSessionStatus_T sessionStatus;
-    int vrc = waitForStateChange(fWaitFlags, uTimeoutMS, &sessionStatus, pGuestRc);
+    vrc = waitForStatusChange(pEvent, fWaitFlags,
+                              uTimeoutMS, &sessionStatus, pGuestRc);
     if (RT_SUCCESS(vrc))
     {
@@ -1815,135 +1954,47 @@
     }
 
+    unregisterEvent(pEvent);
+
     LogFlowFuncLeaveRC(vrc);
     return vrc;
 }
 
-int GuestSession::waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
-                                     GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
-{
-    /** @todo Param validation. */
-
-    int vrc;
-
-    ComPtr<IEventListener> pListener;
-    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
-    if (SUCCEEDED(hr))
-    {
-        com::SafeArray <VBoxEventType_T> eventTypes(1);
-        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
-        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
-    }
-    else
-        vrc = VERR_COM_UNEXPECTED;
-
-    if (SUCCEEDED(hr))
-    {
-        LogFlowThisFunc(("Waiting for guest session state changed event (timeout=%RU32ms, flags=%x) ...\n",
-                         uTimeoutMS, fWaitFlags));
-
-        vrc = VINF_SUCCESS;
-
-        uint64_t u64Started = RTTimeMilliTS();
-        bool fSignalled = false;
-        do
-        {
-            unsigned cMsWait;
-            if (uTimeoutMS == RT_INDEFINITE_WAIT)
-                cMsWait = 1000;
-            else
-            {
-                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
-                if (cMsElapsed >= uTimeoutMS)
-                    break; /* timed out */
-                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
-            }
-
-            ComPtr<IEvent> pEvent;
-            hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
-            if (   SUCCEEDED(hr)
-                && !pEvent.isNull())
-            {
-                VBoxEventType_T aType;
-                hr = pEvent->COMGETTER(Type)(&aType);
-                ComAssertComRC(hr);
-                switch (aType)
-                {
-                    case VBoxEventType_OnGuestSessionStateChanged:
-                    {
-                        ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pEvent;
-                        Assert(!pChangedEvent.isNull());
-
-                        ULONG uSessionID;
-                        pChangedEvent->COMGETTER(Id)(&uSessionID);
-                        if (uSessionID != mData.mSession.mID)
-                            continue; /* Only our own session is of interest. */
-
-                        GuestSessionStatus_T sessionStatus;
-                        pChangedEvent->COMGETTER(Status)(&sessionStatus);
-                        if (pSessionStatus)
-                            *pSessionStatus = sessionStatus;
-
-                        LogFlowThisFunc(("Got status changed event for session ID=%RU32: %ld\n",
-                                         mData.mSession.mID, sessionStatus));
-
-                        bool fSignal = false;
-                        if (fWaitFlags)
-                        {
-                            switch (sessionStatus)
-                            {
-                                case GuestSessionStatus_Started:
-                                    fSignal = (   fWaitFlags & GuestSessionWaitForFlag_Start
-                                               || fWaitFlags & GuestSessionWaitForFlag_Status);
-                                    break;
-
-                                default:
-                                    fSignal = true;
-                                    break;
-                            }
-                        }
-                        else
-                            fSignal = true;
-
-                        if (!fSignal)
-                            continue;
-
-                        ComPtr<IGuestErrorInfo> errorInfo;
-                        hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
-                        ComAssertComRC(hr);
-
-                        LONG lGuestRc;
-                        hr = errorInfo->COMGETTER(Result)(&lGuestRc);
-                        ComAssertComRC(hr);
-                        if (RT_FAILURE((int)lGuestRc))
-                            vrc = VERR_GSTCTL_GUEST_ERROR;
-                        if (pGuestRc)
-                            *pGuestRc = (int)lGuestRc;
-
-                        LogFlowThisFunc(("Status changed event for session ID=%RU32: %ld (%Rrc)\n",
-                                         mData.mSession.mID, sessionStatus,
-                                         RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
-
-                        fSignalled = true;
-                        break;
-                    }
-
-                    default:
-                         AssertMsgFailed(("Unhandled event type %ld\n", aType));
-                         break;
-                }
-            }
-
-        } while (!fSignalled);
-
-        if (   RT_SUCCESS(vrc)
-            && !fSignalled)
-        {
-            vrc = VERR_TIMEOUT;
-        }
-
-        mEventSource->UnregisterListener(pListener);
-    }
-    else
-        vrc = VERR_COM_UNEXPECTED;
+int GuestSession::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
+                                      GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+    VBoxEventType_T evtType;
+    ComPtr<IEvent> pIEvent;
+    int vrc = waitForEvent(pEvent, uTimeoutMS,
+                           &evtType, pIEvent.asOutParam());
+    if (RT_SUCCESS(vrc))
+    {
+        Assert(evtType == VBoxEventType_OnGuestSessionStateChanged);
+
+        ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pIEvent;
+        Assert(!pChangedEvent.isNull());
+
+        GuestSessionStatus_T sessionStatus;
+        pChangedEvent->COMGETTER(Status)(&sessionStatus);
+        if (pSessionStatus)
+            *pSessionStatus = sessionStatus;
+
+        ComPtr<IGuestErrorInfo> errorInfo;
+        HRESULT hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
+        ComAssertComRC(hr);
+
+        LONG lGuestRc;
+        hr = errorInfo->COMGETTER(Result)(&lGuestRc);
+        ComAssertComRC(hr);
+        if (RT_FAILURE((int)lGuestRc))
+            vrc = VERR_GSTCTL_GUEST_ERROR;
+        if (pGuestRc)
+            *pGuestRc = (int)lGuestRc;
+
+        LogFlowThisFunc(("Status changed event for session ID=%RU32: %ld (%Rrc)\n",
+                         mData.mSession.mID, sessionStatus,
+                         RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
+    }
 
     LogFlowFuncLeaveRC(vrc);
