Index: trunk/include/VBox/err.h
===================================================================
--- trunk/include/VBox/err.h	(revision 45433)
+++ trunk/include/VBox/err.h	(revision 45434)
@@ -2236,4 +2236,6 @@
 /** Guest side reported an error. */
 #define VERR_GSTCTL_GUEST_ERROR                     (-6200)
+/** A guest control object has changed its overall status. */
+#define VWRN_GSTCTL_OBJECTSTATE_CHANGED             6220
 /** @} */
 
Index: trunk/src/VBox/Main/include/GuestFileImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestFileImpl.h	(revision 45433)
+++ trunk/src/VBox/Main/include/GuestFileImpl.h	(revision 45434)
@@ -94,6 +94,7 @@
     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             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);
Index: trunk/src/VBox/Main/src-client/GuestFileImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestFileImpl.cpp	(revision 45433)
+++ trunk/src/VBox/Main/src-client/GuestFileImpl.cpp	(revision 45434)
@@ -74,5 +74,6 @@
  * @param   openInfo                File opening information.
  */
-int GuestFile::init(Console *pConsole, GuestSession *pSession, ULONG uFileID, const GuestFileOpenInfo &openInfo)
+int GuestFile::init(Console *pConsole, GuestSession *pSession,
+                    ULONG uFileID, const GuestFileOpenInfo &openInfo)
 {
     LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n",
@@ -86,4 +87,8 @@
     AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
 
+#ifndef VBOX_WITH_GUEST_CONTROL
+    autoInitSpan.setSucceeded();
+    return VINF_SUCCESS;
+#else
     int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */);
     if (RT_SUCCESS(vrc))
@@ -109,4 +114,5 @@
     LogFlowFuncLeaveRC(vrc);
     return vrc;
+#endif /* VBOX_WITH_GUEST_CONTROL */
 }
 
@@ -173,4 +179,7 @@
 STDMETHODIMP GuestFile::COMGETTER(EventSource)(IEventSource ** aEventSource)
 {
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
     CheckComArgOutPointerValid(aEventSource);
 
@@ -182,4 +191,5 @@
 
     return S_OK;
+#endif /* VBOX_WITH_GUEST_CONTROL */
 }
 
@@ -605,4 +615,7 @@
                         void* pvData, uint32_t cbData, uint32_t* pcbRead)
 {
+    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+    AssertReturn(cbData, VERR_INVALID_PARAMETER);
+
     LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
                      uSize, uTimeoutMS, pvData, cbData));
@@ -739,19 +752,15 @@
 }
 
-int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset)
-{
-    return VINF_SUCCESS;
-}
-
-int GuestFile::waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead)
-{
-    return VINF_SUCCESS;
-}
-
-int GuestFile::waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
-{
+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;
@@ -759,7 +768,7 @@
     if (SUCCEEDED(hr))
     {
-        com::SafeArray <VBoxEventType_T> eventTypes(1);
-        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
-        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
+        arrEventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(arrEventTypes),
+                                            TRUE /* Passive listener */);
     }
     else
@@ -768,6 +777,6 @@
     if (SUCCEEDED(hr))
     {
-        LogFlowThisFunc(("Waiting for guest file status change event (timeout=%RU32ms) ...\n",
-                         uTimeoutMS));
+        LogFlowThisFunc(("Waiting for guest file event(s) (timeout=%RU32ms, %zu events) ...\n",
+                         uTimeoutMS, arrEventTypes.size()));
 
         vrc = VINF_SUCCESS;
@@ -788,35 +797,56 @@
             }
 
-            ComPtr<IEvent> pEvent;
-            hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
+            ComPtr<IEvent> pThisEvent;
+            hr = mEventSource->GetEvent(pListener, cMsWait, pThisEvent.asOutParam());
             if (   SUCCEEDED(hr)
-                && !pEvent.isNull())
+                && !pThisEvent.isNull())
             {
-                VBoxEventType_T aType;
-                hr = pEvent->COMGETTER(Type)(&aType);
+                VBoxEventType_T type;
+                hr = pThisEvent->COMGETTER(Type)(&type);
                 ComAssertComRC(hr);
-                switch (aType)
+
+                for (size_t i = 0; i < arrEventTypes.size() && !fSignalled; i++)
                 {
-                    case VBoxEventType_OnGuestFileStateChanged:
+                    if (type == arrEventTypes[i])
                     {
-                        ComPtr<IGuestFileStateChangedEvent> pChangedEvent = pEvent;
-                        Assert(!pChangedEvent.isNull());
-
-                        ComPtr<IGuestFile> pFile;
-                        pChangedEvent->COMGETTER(File)(pFile.asOutParam());
-                        Assert(!pFile.isNull());
-
-                        if (pFile != this)
-                            continue;
+                        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;
+                        }
                     }
-
-                    default:
-                        AssertMsgFailed(("Unhandled event type %ld\n", aType));
-                        break;
                 }
-
-                fSignalled = true;
-                break;
             }
+            else
+                vrc = VERR_COM_UNEXPECTED;
 
         } while (!fSignalled);
@@ -828,5 +858,6 @@
         }
 
-        mEventSource->UnregisterListener(pListener);
+        hr = mEventSource->UnregisterListener(pListener);
+        ComAssertComRC(hr);
     }
     else
@@ -837,7 +868,108 @@
 }
 
+int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset)
+{
+    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)
+    {
+        Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
+        ComPtr<IGuestFileStateChangedEvent> pFileEvent = pEvent;
+        Assert(!pFileEvent.isNull());
+
+        HRESULT hr = pFileEvent->COMGETTER(Status)(pFileStatus);
+        ComAssertComRC(hr);
+    }
+
+    return vrc;
+}
+
 int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten)
 {
-    return VINF_SUCCESS;
+    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);
+    }
+
+    return vrc;
 }
 
@@ -904,19 +1036,15 @@
         paParms[i++].setPointer(pvData, cbData);
 
+        uint32_t cbWritten;
         vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
         if (RT_SUCCESS(vrc))
-        {
-            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;
-            }
+            vrc = waitForWrite(uTimeoutMS, &cbWritten);
+
+        if (RT_SUCCESS(vrc))
+        {
+            LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
+
+            if (cbWritten)
+                *pcbWritten = cbWritten;
         }
     }
@@ -1021,6 +1149,4 @@
     }
 
-    LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead));
-
     LogFlowFuncLeaveRC(vrc);
     return hr;
@@ -1066,6 +1192,4 @@
     }
 
-    LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead));
-
     LogFlowFuncLeaveRC(vrc);
     return hr;
@@ -1155,11 +1279,9 @@
             default:
                 hr = setError(VBOX_E_IPRT_ERROR,
-                              tr("Writing to file \"%s\" failed: %Rrc"),
-                              mData.mOpenInfo.mFileName.c_str(), vrc);
+                              tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
+                              data.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
                 break;
         }
     }
-
-    LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten));
 
     LogFlowFuncLeaveRC(vrc);
@@ -1191,12 +1313,10 @@
             default:
                 hr = setError(VBOX_E_IPRT_ERROR,
-                              tr("Writing to file \"%s\" (at offset %RU64) failed: %Rrc"),
-                              mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
+                              tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
+                              data.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
                 break;
         }
     }
 
-    LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten));
-
     LogFlowFuncLeaveRC(vrc);
     return hr;
Index: trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 45433)
+++ trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 45434)
@@ -867,13 +867,12 @@
 
             Assert(mData.mNumObjects);
-            LogFlowThisFunc(("Removing file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
+            LogFlowThisFunc(("Removing guest file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
                              Utf8Str(strName).c_str(), mData.mSession.mID, mData.mFiles.size() - 1, mData.mNumObjects - 1));
-#ifdef DEBUG
-            ULONG cRefs = pFile->AddRef();
-            LogFlowThisFunc(("pObject=%p, cRefs=%RU32\n", pFile, cRefs));
-            pFile->Release();
-#endif
+
             mData.mFiles.erase(itFiles);
             mData.mNumObjects--;
+
+            fireGuestFileRegisteredEvent(mEventSource, this, pFile,
+                                         false /* Unregistered */);
             return VINF_SUCCESS;
         }
@@ -974,6 +973,9 @@
         Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
 
-        LogFlowFunc(("Added new file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
+        LogFlowFunc(("Added new guest file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
                      openInfo.mFileName.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects));
+
+        fireGuestFileRegisteredEvent(mEventSource, this, pFile,
+                                     true /* Registered */);
     }
 
