Index: /trunk/include/VBox/GuestHost/SharedClipboard.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard.h	(revision 82526)
+++ /trunk/include/VBox/GuestHost/SharedClipboard.h	(revision 82527)
@@ -157,7 +157,7 @@
     RTLISTNODE          Node;
     /** The event's ID, for self-reference. */
-    SHCLEVENTID         uID;
+    SHCLEVENTID         idEvent;
     /** Event semaphore for signalling the event. */
-    RTSEMEVENT          hEventSem;
+    RTSEMEVENTMULTI     hEvtMulSem;
     /** Payload to this event, optional (NULL). */
     PSHCLEVENTPAYLOAD   pPayload;
@@ -177,5 +177,5 @@
     SHCLEVENTSOURCEID uID;
     /** Next upcoming event ID. */
-    SHCLEVENTID       uEventIDNext;
+    SHCLEVENTID       idNextEvent;
     /** List of events (PSHCLEVENT). */
     RTLISTANCHOR      lstEvents;
@@ -202,4 +202,5 @@
  *  @{
  */
+SHCLEVENTID ShClEventIdGenerateAndRegister(PSHCLEVENTSOURCE pSource);
 SHCLEVENTID ShClEventIDGenerate(PSHCLEVENTSOURCE pSource);
 SHCLEVENTID ShClEventGetLast(PSHCLEVENTSOURCE pSource);
Index: /trunk/include/VBox/HostServices/VBoxClipboardSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/VBoxClipboardSvc.h	(revision 82526)
+++ /trunk/include/VBox/HostServices/VBoxClipboardSvc.h	(revision 82527)
@@ -114,21 +114,54 @@
 /** Returned only when the HGCM client session is closed (by different thread).
  *
- * This can require no futher host interaction has session has been closed.
+ * This can require no futher host interaction since the session has been
+ * closed.
+ *
+ * @since 1.3.2
  */
 #define VBOX_SHCL_HOST_MSG_QUIT                             1
 /** Request data for a specific format from the guest.
  *
- * This takes one parameter (in addition to the message number), a 32-bit
+ * Two parameters, first the 32-bit message ID followed by a  a 32-bit
  * format bit (VBOX_SHCL_FMT_XXX).  The guest will respond by issuing a
- * VBOX_SHCL_GUEST_F_DATA_WRITE.
+ * VBOX_SHCL_GUEST_FN_DATA_WRITE.
+ *
+ * @note  The host may sometimes incorrectly set more than one format bit, in
+ *        which case it's up to the guest to pick which to write back.
+ * @since 1.3.2
  */
 #define VBOX_SHCL_HOST_MSG_READ_DATA                        2
-/** Reports available clipboard format from host to the guest.
- *  Formerly known as VBOX_SHCL_HOST_MSG_REPORT_FORMATS. */
+/** Reports available clipboard format on the host to the guest.
+ *
+ * Two parameters, first the 32-bit message ID followed by a 32-bit format mask
+ * containing zero or more VBOX_SHCL_FMT_XXX flags.  The guest is not require to
+ * respond to the host when receiving this message.
+ *
+ * @since 1.3.2
+ */
 #define VBOX_SHCL_HOST_MSG_FORMATS_REPORT                   3
 /** Message PEEK or GET operation was canceled, try again.
+ *
+ * This is returned by VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT and
+ * VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT in response to the guest calling
+ * VBOX_SHCL_GUEST_FN_MSG_CANCEL.  The 2nd parameter is set to zero (be it
+ * thought of as a parameter count or a format mask).
+ *
  * @since   6.1.0
  */
 #define VBOX_SHCL_HOST_MSG_CANCELED                         4
+
+/** Request data for a specific format from the guest with context ID.
+ *
+ * This is send instead of the VBOX_SHCL_HOST_MSG_READ_DATA message to guest
+ * that advertises VBOX_SHCL_GF_0_CONTEXT_ID.  The first parameter is a 64-bit
+ * context ID which is to be used when issuing VBOX_SHCL_GUEST_F_DATA_WRITE, and
+ * the second parameter is a 32-bit format bit (VBOX_SHCL_FMT_XXX).  The guest
+ * will respond by issuing a VBOX_SHCL_GUEST_F_DATA_WRITE.
+ *
+ * @note  The host may sometimes incorrectly set more than one format bit, in
+ *        which case it's up to the guest to pick which to write back.
+ * @since 6.3.2
+ */
+#define VBOX_SHCL_HOST_MSG_READ_DATA_CID                    5
 
 /** Sends a transfer status to the guest side.
@@ -710,49 +743,4 @@
 #define VBOX_SHCL_CPARMS_REPORT_FORMATS_61B 3   /**< The 6.1 dev cycle variant, see VBOX_SHCL_GUEST_FN_REPORT_FORMATS. */
 /** @} */
-/**
- * Reports available formats.
- */
-typedef struct _VBoxShClFormatsMsg
-{
-    VBGLIOCHGCMCALL hdr;
-
-    union
-    {
-        struct
-        {
-            /** uint32_t, out:  VBOX_SHCL_FMT_*. */
-            HGCMFunctionParameter uFormats;
-        } v0;
-
-        struct
-        {
-            /** uint64_t, out: Context ID. */
-            HGCMFunctionParameter uContext;
-            /** uint32_t, out: VBOX_SHCL_FMT_*. */
-            HGCMFunctionParameter uFormats;
-            /** uint32_t, out: Format flags. */
-            HGCMFunctionParameter fFlags;
-        } v1;
-    } u;
-} VBoxShClFormatsMsg;
-
-/**
- * Requests to read clipboard data.
- */
-typedef struct _VBoxShClReadDataReqMsg
-{
-    VBGLIOCHGCMCALL hdr;
-
-    /** uint64_t, out: Context ID. */
-    HGCMFunctionParameter uContext;
-    /** uint32_t, out: Request flags; currently unused and must be set to 0. */
-    HGCMFunctionParameter fFlags;
-    /** uint32_t, out: Requested format to read data in. */
-    HGCMFunctionParameter uFormat;
-    /** uint32_t, out: Maximum size (in bytes) to read. */
-    HGCMFunctionParameter cbSize;
-} VBoxShClReadDataReqMsg;
-
-#define VBOX_SHCL_CPARMS_READ_DATA_REQ 4
 
 /** @name VBOX_SHCL_GUEST_FN_DATA_READ
Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 82526)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 82527)
@@ -624,4 +624,5 @@
 /**
  * Enumeration specifying a Shared Clipboard event type.
+ * @todo r=bird: Surely, this isn't necessary?!
  */
 typedef enum _VBGLR3CLIPBOARDEVENTTYPE
@@ -657,5 +658,5 @@
         SHCLFORMATDATA       ReportedFormats;
         /** Reports that data needs to be read from the guest. */
-        SHCLDATAREQ          ReadData;
+        SHCLFORMAT           fReadData;
 #  ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
         /** Reports a transfer status to the guest. */
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 82526)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 82527)
@@ -93,4 +93,5 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+
 /**
  * Cleanup helper function for transfer callbacks.
@@ -218,4 +219,5 @@
     vboxClipboardTransferCallbackCleanup(pData);
 }
+
 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
 
@@ -559,5 +561,5 @@
             Assert(pEvent->enmType == VBGLR3CLIPBOARDEVENTTYPE_READ_DATA);
 
-            const SHCLFORMAT fFormat = (uint32_t)pEvent->u.ReadData.uFmt;
+            const SHCLFORMAT fFormat = (uint32_t)pEvent->u.fReadData;
 
             HANDLE hClip = NULL;
@@ -991,80 +993,23 @@
     int rc;
 
-    uint32_t uMsg;
-    uint32_t uFormats;
-
     /* The thread waits for incoming messages from the host. */
     for (;;)
     {
-        PVBGLR3CLIPBOARDEVENT pEvent = NULL;
-
         LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n",
                      pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
 
-        if (pCtx->CmdCtx.fUseLegacyProtocol)
-        {
-            rc = VbglR3ClipboardGetHostMsgOld(pCtx->CmdCtx.idClient, &uMsg, &uFormats);
-            if (RT_FAILURE(rc))
-            {
-                if (rc == VERR_INTERRUPTED)
-                    break;
-
-                LogFunc(("Error getting host message, rc=%Rrc\n", rc));
-            }
-            else
-            {
-                pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
-                AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
-
-                switch (uMsg)
-                {
-                    case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
-                    {
-                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
-                        pEvent->u.ReportedFormats.Formats = uFormats;
-                        break;
-                    }
-
-                    case VBOX_SHCL_HOST_MSG_READ_DATA:
-                    {
-                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
-                        pEvent->u.ReadData.uFmt = uFormats;
-                        break;
-                    }
-
-                    case VBOX_SHCL_HOST_MSG_QUIT:
-                    {
-                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
-                        break;
-                    }
-
-                    default:
-                        rc = VERR_NOT_SUPPORTED;
-                        break;
-                }
-
-                if (RT_SUCCESS(rc))
-                {
-                    /* Copy over our command context to the event. */
-                    pEvent->cmdCtx = pCtx->CmdCtx;
-                }
-            }
-        }
-        else /* Host service has peeking for messages support. */
-        {
-            pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
-            AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
-
-            uint32_t uMsg   = 0;
-            uint32_t cParms = 0;
-            rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &uMsg, &cParms, NULL /* pidRestoreCheck */);
-            if (RT_SUCCESS(rc))
-            {
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-                rc = VbglR3ClipboardEventGetNextEx(uMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
+        PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
+        AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
+
+        uint32_t idMsg  = 0;
+        uint32_t cParms = 0;
+        rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
+        if (RT_SUCCESS(rc))
+        {
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+            rc = VbglR3ClipboardEventGetNextEx(idMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
 #else
-                rc = VbglR3ClipboardEventGetNext(uMsg, cParms, &pCtx->CmdCtx, pEvent);
-#endif
-            }
+            rc = VbglR3ClipboardEventGetNext(idMsg, cParms, &pCtx->CmdCtx, pEvent);
+#endif
         }
 
Index: /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 82526)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 82527)
@@ -249,26 +249,30 @@
  * @param   pFormats            Where to store the received formats from the host.
  */
-VBGLR3DECL(int) VbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATDATA pFormats)
+static int vbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATDATA pFormats)
 {
     AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     AssertPtrReturn(pFormats, VERR_INVALID_POINTER);
 
-    VBoxShClFormatsMsg Msg;
-    RT_ZERO(Msg);
-
-    VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 3);
-
-    Msg.u.v1.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
-    Msg.u.v1.uFormats.SetUInt32(0);
-    Msg.u.v1.fFlags.SetUInt32(0);
-
-    int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
-    if (RT_SUCCESS(rc))
-    {
-        rc = Msg.u.v1.uContext.GetUInt64(&pCtx->idContext);
-        if (RT_SUCCESS(rc))
-            rc = Msg.u.v1.uFormats.GetUInt32(&pFormats->Formats);
-        if (RT_SUCCESS(rc))
-            rc = Msg.u.v1.fFlags.GetUInt32(&pFormats->fFlags);
+    pFormats->fFlags = 0;
+    pFormats->Formats = 0;
+
+    struct
+    {
+        VBGLIOCHGCMCALL         Hdr;
+        HGCMFunctionParameter   id64Context;
+        HGCMFunctionParameter   f32Formats;
+    } Msg;
+
+    VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 3);
+    Msg.id64Context.SetUInt64(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
+    Msg.f32Formats.SetUInt32(0);
+
+    int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.id64Context.GetUInt64(&pCtx->idContext);
+        AssertRC(rc);
+        int rc2 = Msg.f32Formats.GetUInt32(&pFormats->Formats);
+        AssertRCStmt(rc2, rc = rc2);
     }
 
@@ -283,29 +287,29 @@
  * @returns VBox status code.
  * @param   pCtx                Shared Clipboard command context to use for the connection.
- * @param   pDataReq            Where to store the read data request from the host.
- */
-VBGLR3DECL(int) VbglR3ClipboardReadDataRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLDATAREQ pDataReq)
+ * @param   pfFormat            Where to return the requested format.
+ */
+static int vbglR3ClipboardReadDataRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
 {
     AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
-    AssertPtrReturn(pDataReq, VERR_INVALID_POINTER);
-
-    VBoxShClReadDataReqMsg Msg;
-
-    VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
-                       VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_READ_DATA_REQ);
-
-    Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_READ_DATA);
-    Msg.fFlags.SetUInt32(0);
-    Msg.uFormat.SetUInt32(0);
-    Msg.cbSize.SetUInt32(0);
-
-    int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
-    if (RT_SUCCESS(rc))
-    {
-        rc = Msg.uContext.GetUInt64(&pCtx->idContext);
-        if (RT_SUCCESS(rc))
-            rc = Msg.uFormat.GetUInt32(&pDataReq->uFmt);
-        if (RT_SUCCESS(rc))
-            rc = Msg.cbSize.GetUInt32(&pDataReq->cbSize);
+    AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
+
+    struct
+    {
+        VBGLIOCHGCMCALL         Hdr;
+        HGCMFunctionParameter   id64Context;
+        HGCMFunctionParameter   f32Format;
+    } Msg;
+
+    VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
+    Msg.id64Context.SetUInt64(VBOX_SHCL_HOST_MSG_READ_DATA_CID);
+    Msg.f32Format.SetUInt32(0);
+
+    int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.id64Context.GetUInt64(&pCtx->idContext);
+        AssertRC(rc);
+        int rc2 = Msg.f32Format.GetUInt32(pfFormat);
+        AssertRCStmt(rc2, rc = rc2);
     }
 
@@ -332,7 +336,5 @@
     VBoxShClGetHostMsgOld Msg;
 
-    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
-                       VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
-
+    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
     VbglHGCMParmUInt32Set(&Msg.msg, 0);
     VbglHGCMParmUInt32Set(&Msg.formats, 0);
@@ -466,4 +468,9 @@
  * Peeks at the next host message, waiting for one to turn up.
  *
+ * This glosses over the difference between new (6.1) and old (1.3.2) host
+ * service versions, however it does so by abusing @a pcParameters, so don't use
+ * it directly when in legacy mode, always pass it on to
+ * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
+ *
  * @returns VBox status code.
  * @retval  VERR_INTERRUPTED if interrupted.  Does the necessary cleanup, so
@@ -485,6 +492,4 @@
     AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
 
-    int rc;
-
     struct
     {
@@ -493,19 +498,40 @@
         HGCMFunctionParameter cParameters;
     } Msg;
-    VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, 2);
-    VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
-    VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
-    rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
-    LogFlowFunc(("VbglR3HGCMCall -> %Rrc\n", rc));
-    if (RT_SUCCESS(rc))
-    {
-        AssertMsgReturn(   Msg.idMsg.type       == VMMDevHGCMParmType_64bit
-                        && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
-                        ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
-                        VERR_INTERNAL_ERROR_3);
-
-        *pidMsg       = (uint32_t)Msg.idMsg.u.value64;
-        *pcParameters = Msg.cParameters.u.value32;
-        return rc;
+    int rc;
+    if (!pCtx->fUseLegacyProtocol)
+    {
+        VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, 2);
+        VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
+        VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
+        rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+        LogFlowFunc(("VbglR3HGCMCall -> %Rrc\n", rc));
+        if (RT_SUCCESS(rc))
+        {
+            AssertMsgReturn(   Msg.idMsg.type       == VMMDevHGCMParmType_64bit
+                            && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
+                            ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
+                            VERR_INTERNAL_ERROR_3);
+
+            *pidMsg       = (uint32_t)Msg.idMsg.u.value64;
+            *pcParameters = Msg.cParameters.u.value32;
+            return rc;
+        }
+
+        /*
+         * If restored, update pidRestoreCheck.
+         */
+        if (rc == VERR_VM_RESTORED && pidRestoreCheck)
+            *pidRestoreCheck = Msg.idMsg.u.value64;
+    }
+    else
+    {
+        /*
+         * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
+         * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
+         * VbglR3ClipboardEventGetNextEx, so that's fine...
+         */
+        rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
+        if (RT_SUCCESS(rc))
+            return rc;
     }
 
@@ -519,10 +545,4 @@
         AssertRC(rc2);
     }
-
-    /*
-     * If restored, update pidRestoreCheck.
-     */
-    if (rc == VERR_VM_RESTORED && pidRestoreCheck)
-        *pidRestoreCheck = Msg.idMsg.u.value64;
 
     *pidMsg       = UINT32_MAX - 1;
@@ -1922,133 +1942,113 @@
 
     int rc;
-
-    bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
-
-    switch (idMsg)
-    {
-        case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
+    if (!pCmdCtx->fUseLegacyProtocol)
+    {
+        bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
+
+        switch (idMsg)
         {
-            SHCLTRANSFERDIR    enmDir;
-            SHCLTRANSFERREPORT transferReport;
-            rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
-            if (RT_SUCCESS(rc))
+            case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
             {
-                const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID);
-
-                LogFlowFunc(("[Transfer %RU16] enmDir=%RU32, status=%s\n",
-                             uTransferID, enmDir, ShClTransferStatusToStr(transferReport.uStatus)));
-
-                switch (transferReport.uStatus)
-                {
-                    case SHCLTRANSFERSTATUS_INITIALIZED:
-                        RT_FALL_THROUGH();
-                    case SHCLTRANSFERSTATUS_STARTED:
-                    {
-                        SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
-
-                        /* The host announces the transfer direction from its point of view, so inverse the direction here. */
-                        if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
-                        {
-                            enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
-                            enmSource = SHCLSOURCE_REMOTE;
-                        }
-                        else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
-                        {
-                            enmDir = SHCLTRANSFERDIR_TO_REMOTE;
-                            enmSource = SHCLSOURCE_LOCAL;
-                        }
-                        else
-                            AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
-
-                        rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
-                                                          enmDir, enmSource, NULL /* ppTransfer */);
-                        break;
-                    }
-
-                    case SHCLTRANSFERSTATUS_STOPPED:
-                        RT_FALL_THROUGH();
-                    case SHCLTRANSFERSTATUS_CANCELED:
-                        RT_FALL_THROUGH();
-                    case SHCLTRANSFERSTATUS_KILLED:
-                        RT_FALL_THROUGH();
-                    case SHCLTRANSFERSTATUS_ERROR:
-                    {
-                        rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx,
-                                                         VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
-                        break;
-                    }
-
-                    default:
-                        rc = VERR_NOT_SUPPORTED;
-                        break;
-                }
-
+                SHCLTRANSFERDIR    enmDir;
+                SHCLTRANSFERREPORT transferReport;
+                rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
                 if (RT_SUCCESS(rc))
                 {
-                    pEvent->u.TransferStatus.enmDir = enmDir;
-                    pEvent->u.TransferStatus.Report = transferReport;
-                    pEvent->u.TransferStatus.uID    = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID);
-
-                    pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
-
-                    LogRel2(("Shared Clipboard: Received status %s (rc=%Rrc) for transfer ID=%RU16\n",
-                             ShClTransferStatusToStr(pEvent->u.TransferStatus.Report.uStatus), pEvent->u.TransferStatus.Report.rc,
-                             pEvent->u.TransferStatus.uID));
+                    const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID);
+
+                    LogFlowFunc(("[Transfer %RU16] enmDir=%RU32, status=%s\n",
+                                 uTransferID, enmDir, ShClTransferStatusToStr(transferReport.uStatus)));
+
+                    switch (transferReport.uStatus)
+                    {
+                        case SHCLTRANSFERSTATUS_INITIALIZED:
+                            RT_FALL_THROUGH();
+                        case SHCLTRANSFERSTATUS_STARTED:
+                        {
+                            SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
+
+                            /* The host announces the transfer direction from its point of view, so inverse the direction here. */
+                            if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
+                            {
+                                enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
+                                enmSource = SHCLSOURCE_REMOTE;
+                            }
+                            else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
+                            {
+                                enmDir = SHCLTRANSFERDIR_TO_REMOTE;
+                                enmSource = SHCLSOURCE_LOCAL;
+                            }
+                            else
+                                AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
+
+                            rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
+                                                              enmDir, enmSource, NULL /* ppTransfer */);
+                            break;
+                        }
+
+                        case SHCLTRANSFERSTATUS_STOPPED:
+                            RT_FALL_THROUGH();
+                        case SHCLTRANSFERSTATUS_CANCELED:
+                            RT_FALL_THROUGH();
+                        case SHCLTRANSFERSTATUS_KILLED:
+                            RT_FALL_THROUGH();
+                        case SHCLTRANSFERSTATUS_ERROR:
+                        {
+                            rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx,
+                                                             VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
+                            break;
+                        }
+
+                        default:
+                            rc = VERR_NOT_SUPPORTED;
+                            break;
+                    }
+
+                    if (RT_SUCCESS(rc))
+                    {
+                        pEvent->u.TransferStatus.enmDir = enmDir;
+                        pEvent->u.TransferStatus.Report = transferReport;
+                        pEvent->u.TransferStatus.uID    = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID);
+
+                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
+
+                        LogRel2(("Shared Clipboard: Received status %s (rc=%Rrc) for transfer ID=%RU16\n",
+                                 ShClTransferStatusToStr(pEvent->u.TransferStatus.Report.uStatus), pEvent->u.TransferStatus.Report.rc,
+                                 pEvent->u.TransferStatus.uID));
+                    }
                 }
+                break;
             }
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
-        {
-            uint32_t fRoots;
-            rc = VbglR3ClipboardRootListHdrReadReq(pCmdCtx, &fRoots);
-
-            /** @todo Validate / handle fRoots. */
-
-            if (RT_SUCCESS(rc))
+
+            case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
             {
-                PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
-                                                                    VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
-                AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
-
-                SHCLROOTLISTHDR rootListHdr;
-                RT_ZERO(rootListHdr);
-
-                rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
-
-                LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
-
-                rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
+                uint32_t fRoots;
+                rc = VbglR3ClipboardRootListHdrReadReq(pCmdCtx, &fRoots);
+
+                /** @todo Validate / handle fRoots. */
+
+                if (RT_SUCCESS(rc))
+                {
+                    PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
+                                                                        VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
+                    AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+                    SHCLROOTLISTHDR rootListHdr;
+                    RT_ZERO(rootListHdr);
+
+                    rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
+
+                    LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
+
+                    rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
+                }
+                break;
             }
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
-        {
-            uint32_t uIndex;
-            uint32_t fInfo;
-            rc = VbglR3ClipboardRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
-            if (RT_SUCCESS(rc))
+
+            case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
             {
-                PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
-                                                                     VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
-                AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
-
-                SHCLROOTLISTENTRY rootListEntry;
-                rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
-                if (RT_SUCCESS(rc))
-                    rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
-            }
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
-        {
-            SHCLLISTOPENPARMS openParmsList;
-            rc = ShClTransferListOpenParmsInit(&openParmsList);
-            if (RT_SUCCESS(rc))
-            {
-                rc = VbglR3ClipboardListOpenRecv(pCmdCtx, &openParmsList);
+                uint32_t uIndex;
+                uint32_t fInfo;
+                rc = VbglR3ClipboardRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
                 if (RT_SUCCESS(rc))
                 {
@@ -2057,77 +2057,45 @@
                     AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
 
-                    LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
-
-                    SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
-                    rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
-
-                    /* Reply in any case. */
-                    int rc2 = VbglR3ClipboardListOpenReply(pCmdCtx, rc, hList);
-                    AssertRC(rc2);
+                    SHCLROOTLISTENTRY rootListEntry;
+                    rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
+                    if (RT_SUCCESS(rc))
+                        rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
                 }
-
-                ShClTransferListOpenParmsDestroy(&openParmsList);
+                break;
             }
 
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
-        {
-            SHCLLISTHANDLE hList;
-            rc = VbglR3ClipboardListCloseRecv(pCmdCtx, &hList);
-            if (RT_SUCCESS(rc))
+            case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
             {
-                PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
-                                                                     VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
-                AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
-
-                rc = ShClTransferListClose(pTransfer, hList);
-
-                /* Reply in any case. */
-                int rc2 = VbglR3ClipboardListCloseReply(pCmdCtx, rc, hList);
-                AssertRC(rc2);
-            }
-
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
-        {
-            /** @todo Handle filter + list features. */
-
-            SHCLLISTHANDLE hList  = SHCLLISTHANDLE_INVALID;
-            uint32_t       fFlags = 0;
-            rc = VbglR3ClipboardListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
-            if (RT_SUCCESS(rc))
-            {
-                PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
-                                                                     VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
-                AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
-
-                SHCLLISTHDR hdrList;
-                rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
+                SHCLLISTOPENPARMS openParmsList;
+                rc = ShClTransferListOpenParmsInit(&openParmsList);
                 if (RT_SUCCESS(rc))
                 {
-                    rc = VbglR3ClipboardListHdrWrite(pCmdCtx, hList, &hdrList);
-
-                    ShClTransferListHdrDestroy(&hdrList);
+                    rc = VbglR3ClipboardListOpenRecv(pCmdCtx, &openParmsList);
+                    if (RT_SUCCESS(rc))
+                    {
+                        PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
+                                                                             VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
+                        AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+                        LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
+
+                        SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
+                        rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
+
+                        /* Reply in any case. */
+                        int rc2 = VbglR3ClipboardListOpenReply(pCmdCtx, rc, hList);
+                        AssertRC(rc2);
+                    }
+
+                    ShClTransferListOpenParmsDestroy(&openParmsList);
                 }
+
+                break;
             }
 
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
-        {
-            LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
-
-            SHCLLISTENTRY entryList;
-            rc = ShClTransferListEntryInit(&entryList);
-            if (RT_SUCCESS(rc))
+            case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
             {
                 SHCLLISTHANDLE hList;
-                uint32_t       fInfo;
-                rc = VbglR3ClipboardListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
+                rc = VbglR3ClipboardListCloseRecv(pCmdCtx, &hList);
                 if (RT_SUCCESS(rc))
                 {
@@ -2136,31 +2104,21 @@
                     AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
 
-                    rc = ShClTransferListRead(pTransfer, hList, &entryList);
-                    if (RT_SUCCESS(rc))
-                    {
-                        PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
-                        Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
-
-                        RT_NOREF(pObjInfo);
-
-                        LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
-
-                        rc = VbglR3ClipboardListEntryWrite(pCmdCtx, hList, &entryList);
-                    }
+                    rc = ShClTransferListClose(pTransfer, hList);
+
+                    /* Reply in any case. */
+                    int rc2 = VbglR3ClipboardListCloseReply(pCmdCtx, rc, hList);
+                    AssertRC(rc2);
                 }
 
-                ShClTransferListEntryDestroy(&entryList);
+                break;
             }
 
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
-        {
-            SHCLOBJOPENCREATEPARMS openParms;
-            rc = ShClTransferObjOpenParmsInit(&openParms);
-            if (RT_SUCCESS(rc))
+            case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
             {
-                rc = VbglR3ClipboardObjOpenRecv(pCmdCtx, &openParms);
+                /** @todo Handle filter + list features. */
+
+                SHCLLISTHANDLE hList  = SHCLLISTHANDLE_INVALID;
+                uint32_t       fFlags = 0;
+                rc = VbglR3ClipboardListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
                 if (RT_SUCCESS(rc))
                 {
@@ -2169,89 +2127,182 @@
                     AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
 
-                    SHCLOBJHANDLE hObj;
-                    rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
+                    SHCLLISTHDR hdrList;
+                    rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
+                    if (RT_SUCCESS(rc))
+                    {
+                        rc = VbglR3ClipboardListHdrWrite(pCmdCtx, hList, &hdrList);
+
+                        ShClTransferListHdrDestroy(&hdrList);
+                    }
+                }
+
+                break;
+            }
+
+            case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
+            {
+                LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
+
+                SHCLLISTENTRY entryList;
+                rc = ShClTransferListEntryInit(&entryList);
+                if (RT_SUCCESS(rc))
+                {
+                    SHCLLISTHANDLE hList;
+                    uint32_t       fInfo;
+                    rc = VbglR3ClipboardListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
+                    if (RT_SUCCESS(rc))
+                    {
+                        PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
+                                                                             VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
+                        AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+                        rc = ShClTransferListRead(pTransfer, hList, &entryList);
+                        if (RT_SUCCESS(rc))
+                        {
+                            PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
+                            Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
+
+                            RT_NOREF(pObjInfo);
+
+                            LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
+
+                            rc = VbglR3ClipboardListEntryWrite(pCmdCtx, hList, &entryList);
+                        }
+                    }
+
+                    ShClTransferListEntryDestroy(&entryList);
+                }
+
+                break;
+            }
+
+            case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
+            {
+                SHCLOBJOPENCREATEPARMS openParms;
+                rc = ShClTransferObjOpenParmsInit(&openParms);
+                if (RT_SUCCESS(rc))
+                {
+                    rc = VbglR3ClipboardObjOpenRecv(pCmdCtx, &openParms);
+                    if (RT_SUCCESS(rc))
+                    {
+                        PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
+                                                                             VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
+                        AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+                        SHCLOBJHANDLE hObj;
+                        rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
+
+                        /* Reply in any case. */
+                        int rc2 = VbglR3ClipboardObjOpenReply(pCmdCtx, rc, hObj);
+                        AssertRC(rc2);
+                    }
+
+                    ShClTransferObjOpenParmsDestroy(&openParms);
+                }
+
+                break;
+            }
+
+            case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
+            {
+                SHCLOBJHANDLE hObj;
+                rc = VbglR3ClipboardObjCloseRecv(pCmdCtx, &hObj);
+                if (RT_SUCCESS(rc))
+                {
+                    PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
+                                                                         VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
+                    AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+                    rc = ShClTransferObjClose(pTransfer, hObj);
 
                     /* Reply in any case. */
-                    int rc2 = VbglR3ClipboardObjOpenReply(pCmdCtx, rc, hObj);
+                    int rc2 = VbglR3ClipboardObjCloseReply(pCmdCtx, rc, hObj);
                     AssertRC(rc2);
                 }
 
-                ShClTransferObjOpenParmsDestroy(&openParms);
+                break;
             }
 
-            break;
+            case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
+            {
+                SHCLOBJHANDLE hObj;
+                uint32_t      cbBuf;
+                uint32_t      fFlags;
+                rc = VbglR3ClipboardObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
+                if (RT_SUCCESS(rc))
+                {
+                    PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
+                                                                         VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
+                    AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+                    AssertBreakStmt(pCmdCtx->cbChunkSize, rc = VERR_INVALID_PARAMETER);
+
+                    const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->cbChunkSize);
+
+                    LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
+                                 hObj, cbBuf, fFlags, pCmdCtx->cbChunkSize, cbToRead));
+
+                    void *pvBuf = RTMemAlloc(cbToRead);
+                    if (pvBuf)
+                    {
+                        uint32_t cbRead;
+                        rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, &cbRead, fFlags);
+                        if (RT_SUCCESS(rc))
+                            rc = VbglR3ClipboardObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
+
+                        RTMemFree(pvBuf);
+                    }
+                    else
+                        rc = VERR_NO_MEMORY;
+                }
+
+                break;
+            }
+
+            default:
+            {
+                rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
+                if (RT_FAILURE(rc))
+                    fErrorSent = true;
+                break;
+            }
         }
 
-        case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
+        if (   !fErrorSent
+            && RT_FAILURE(rc))
         {
-            SHCLOBJHANDLE hObj;
-            rc = VbglR3ClipboardObjCloseRecv(pCmdCtx, &hObj);
-            if (RT_SUCCESS(rc))
-            {
-                PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
-                                                                     VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
-                AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
-
-                rc = ShClTransferObjClose(pTransfer, hObj);
-
-                /* Reply in any case. */
-                int rc2 = VbglR3ClipboardObjCloseReply(pCmdCtx, rc, hObj);
-                AssertRC(rc2);
-            }
-
-            break;
+            /* Report error back to the host. */
+            int rc2 = VbglR3ClipboardWriteError(pCmdCtx->uClientID, rc);
+            AssertRC(rc2);
         }
-
-        case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
+    }
+    else
+    {
+        /*
+         * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
+         * !HACK ALERT! cParms is the format flag or flags.
+         */
+        rc = VINF_SUCCESS;
+        switch (idMsg)
         {
-            SHCLOBJHANDLE hObj;
-            uint32_t      cbBuf;
-            uint32_t      fFlags;
-            rc = VbglR3ClipboardObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
-            if (RT_SUCCESS(rc))
-            {
-                PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransfer(pTransferCtx,
-                                                                     VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
-                AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
-
-                AssertBreakStmt(pCmdCtx->cbChunkSize, rc = VERR_INVALID_PARAMETER);
-
-                const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->cbChunkSize);
-
-                LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
-                             hObj, cbBuf, fFlags, pCmdCtx->cbChunkSize, cbToRead));
-
-                void *pvBuf = RTMemAlloc(cbToRead);
-                if (pvBuf)
-                {
-                    uint32_t cbRead;
-                    rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, &cbRead, fFlags);
-                    if (RT_SUCCESS(rc))
-                        rc = VbglR3ClipboardObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
-
-                    RTMemFree(pvBuf);
-                }
-                else
-                    rc = VERR_NO_MEMORY;
-            }
-
-            break;
+            case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
+                pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
+                pEvent->u.ReportedFormats.Formats = cParms;
+                break;
+
+            case VBOX_SHCL_HOST_MSG_READ_DATA:
+                pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
+                pEvent->u.fReadData = cParms;
+                break;
+
+            case VBOX_SHCL_HOST_MSG_QUIT:
+                pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
+                break;
+
+            default:
+                AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
+                rc = VERR_NOT_SUPPORTED;
+                break;
         }
-
-        default:
-        {
-            rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
-            if (RT_FAILURE(rc))
-                fErrorSent = true;
-            break;
-        }
-    }
-
-    if (   !fErrorSent
-        && RT_FAILURE(rc))
-    {
-        /* Report error back to the host. */
-        int rc2 = VbglR3ClipboardWriteError(pCmdCtx->uClientID, rc);
-        AssertRC(rc2);
     }
 
@@ -2262,6 +2313,5 @@
 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
 
-VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms,
-                                            PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
+VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
 {
     AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
@@ -2271,50 +2321,79 @@
 
     int rc;
-
-#ifdef LOG_ENABLED
-    LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
-#endif
-    switch (idMsg)
-    {
-        case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
+    if (!pCtx->fUseLegacyProtocol)
+    {
+        LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
+        switch (idMsg)
         {
-            rc = VbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.ReportedFormats);
-            if (RT_SUCCESS(rc))
+            case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
+            {
+                rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.ReportedFormats);
+                if (RT_SUCCESS(rc))
+                    pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
+                break;
+            }
+
+            case VBOX_SHCL_HOST_MSG_READ_DATA:
+            {
+                rc = vbglR3ClipboardReadDataRecv(pCtx, &pEvent->u.fReadData);
+                if (RT_SUCCESS(rc))
+                    pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
+                break;
+            }
+
+            case VBOX_SHCL_HOST_MSG_QUIT:
+            {
+                pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
+                rc = VINF_SUCCESS;
+                break;
+            }
+
+            default:
+            {
+                rc = VERR_NOT_SUPPORTED;
+                break;
+            }
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            /* Copy over our command context to the event. */
+            pEvent->cmdCtx = *pCtx;
+        }
+        else
+        {
+            /* Report error back to the host. */
+            int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
+            AssertRC(rc2);
+        }
+    }
+    else
+    {
+        /*
+         * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
+         * !HACK ALERT! cParms is the format flag or flags.
+         */
+        rc = VINF_SUCCESS;
+        switch (idMsg)
+        {
+            case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
                 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
-            break;
+                pEvent->u.ReportedFormats.Formats = cParms;
+                break;
+
+            case VBOX_SHCL_HOST_MSG_READ_DATA:
+                pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
+                pEvent->u.fReadData = cParms;
+                break;
+
+            case VBOX_SHCL_HOST_MSG_QUIT:
+                pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
+                break;
+
+            default:
+                AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
+                rc = VERR_NOT_SUPPORTED;
+                break;
         }
-
-        case VBOX_SHCL_HOST_MSG_READ_DATA:
-        {
-            rc = VbglR3ClipboardReadDataRecv(pCtx, &pEvent->u.ReadData);
-            if (RT_SUCCESS(rc))
-                pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_QUIT:
-        {
-            pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
-            rc = VINF_SUCCESS;
-            break;
-        }
-
-        default:
-        {
-            rc = VERR_NOT_SUPPORTED;
-            break;
-        }
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        /* Copy over our command context to the event. */
-        pEvent->cmdCtx = *pCtx;
-    }
-    else
-    {
-        /* Report error back to the host. */
-        int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
-        AssertRC(rc2);
     }
 
Index: /trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp	(revision 82526)
+++ /trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp	(revision 82527)
@@ -276,77 +276,20 @@
     for (;;)
     {
-        PVBGLR3CLIPBOARDEVENT pEvent = NULL;
+        PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
+        AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
 
         LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n",
                      pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
 
-        if (pCtx->CmdCtx.fUseLegacyProtocol)
-        {
-            uint32_t uMsg;
-            uint32_t uFormats;
-
-            rc = VbglR3ClipboardGetHostMsgOld(pCtx->CmdCtx.idClient, &uMsg, &uFormats);
-            if (RT_FAILURE(rc))
-            {
-                if (rc == VERR_INTERRUPTED) /** @todo r=bird: What on earth is the meaning of this?!?!?!?!?!?!? */
-                    break;
-
-                LogFunc(("Error getting host message, rc=%Rrc\n", rc));
-            }
-            else
-            {
-                pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
-                AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
-
-                switch (uMsg)
-                {
-                    case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
-                    {
-                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
-                        pEvent->u.ReportedFormats.Formats = uFormats;
-                        break;
-                    }
-
-                    case VBOX_SHCL_HOST_MSG_READ_DATA:
-                    {
-                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
-                        pEvent->u.ReadData.uFmt = uFormats;
-                        break;
-                    }
-
-                    case VBOX_SHCL_HOST_MSG_QUIT:
-                    {
-                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
-                        break;
-                    }
-
-                    default:
-                        rc = VERR_NOT_SUPPORTED;
-                        break;
-                }
-
-                if (RT_SUCCESS(rc))
-                {
-                    /* Copy over our command context to the event. */
-                    pEvent->cmdCtx = pCtx->CmdCtx;
-                }
-            }
-        }
-        else /* Host service has peeking for messages support. */
-        {
-            pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
-            AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
-
-            uint32_t uMsg   = 0;
-            uint32_t cParms = 0;
-            rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &uMsg, &cParms, NULL /* pidRestoreCheck */);
-            if (RT_SUCCESS(rc))
-            {
+        uint32_t idMsg  = 0;
+        uint32_t cParms = 0;
+        rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
+        if (RT_SUCCESS(rc))
+        {
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-                rc = VbglR3ClipboardEventGetNextEx(uMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
+            rc = VbglR3ClipboardEventGetNextEx(idMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
 #else
-                rc = VbglR3ClipboardEventGetNext(uMsg, cParms, &pCtx->CmdCtx, pEvent);
-#endif
-            }
+            rc = VbglR3ClipboardEventGetNext(idMsg, cParms, &pCtx->CmdCtx, pEvent);
+#endif
         }
 
@@ -385,5 +328,5 @@
                     if (pReq)
                     {
-                        pReq->Format = pEvent->u.ReadData.uFmt;
+                        pReq->Format = pEvent->u.fReadData;
                         ShClX11ReadDataFromX11(&g_Ctx.X11, pReq->Format, pReq);
                     }
Index: /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp	(revision 82526)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp	(revision 82527)
@@ -89,4 +89,5 @@
 }
 
+#if 0 /* currently not used */
 /**
  * Creates (initializes) an event.
@@ -94,16 +95,16 @@
  * @returns VBox status code.
  * @param   pEvent              Event to initialize.
- * @param   uID                 Event ID to use.
- */
-int ShClEventCreate(PSHCLEVENT pEvent, SHCLEVENTID uID)
+ * @param   idEvent             Event ID to use.
+ */
+static int shClEventInit(PSHCLEVENT pEvent, SHCLEVENTID idEvent)
 {
     AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
 
-    LogFlowFunc(("Event %RU32\n", uID));
-
-    int rc = RTSemEventCreate(&pEvent->hEventSem);
+    LogFlowFunc(("Event %RU32\n", idEvent));
+
+    int rc = RTSemEventMultiCreate(&pEvent->hEvtMulSem);
     if (RT_SUCCESS(rc))
     {
-        pEvent->uID      = uID;
+        pEvent->idEvent  = idEvent;
         pEvent->pPayload = NULL;
     }
@@ -111,26 +112,27 @@
     return rc;
 }
-
-/**
- * Destroys an event.
+#endif
+
+/**
+ * Destroys an event, but doesn't free the memory.
  *
  * @param   pEvent              Event to destroy.
  */
-void ShClEventDestroy(PSHCLEVENT pEvent)
+static void shClEventTerm(PSHCLEVENT pEvent)
 {
     if (!pEvent)
         return;
 
-    LogFlowFunc(("Event %RU32\n", pEvent->uID));
-
-    if (pEvent->hEventSem != NIL_RTSEMEVENT)
-    {
-        RTSemEventDestroy(pEvent->hEventSem);
-        pEvent->hEventSem = NIL_RTSEMEVENT;
+    LogFlowFunc(("Event %RU32\n", pEvent->idEvent));
+
+    if (pEvent->hEvtMulSem != NIL_RTSEMEVENT)
+    {
+        RTSemEventMultiDestroy(pEvent->hEvtMulSem);
+        pEvent->hEvtMulSem = NIL_RTSEMEVENT;
     }
 
     ShClPayloadFree(pEvent->pPayload);
 
-    pEvent->uID = 0;
+    pEvent->idEvent = 0;
 }
 
@@ -151,5 +153,5 @@
     pSource->uID          = uID;
     /* Choose a random event ID starting point. */
-    pSource->uEventIDNext = RTRandU32() % VBOX_SHCL_MAX_EVENTS;
+    pSource->idNextEvent  = RTRandU32Ex(1, VBOX_SHCL_MAX_EVENTS - 1);
 
     LogFlowFuncLeaveRC(VINF_SUCCESS);
@@ -172,5 +174,5 @@
 
     pSource->uID          = UINT16_MAX;
-    pSource->uEventIDNext = UINT32_MAX;
+    pSource->idNextEvent  = UINT32_MAX;
 }
 
@@ -190,28 +192,9 @@
         RTListNodeRemove(&pEvIt->Node);
 
-        ShClEventDestroy(pEvIt);
+        shClEventTerm(pEvIt);
 
         RTMemFree(pEvIt);
         pEvIt = NULL;
     }
-}
-
-/**
- * Generates a new event ID for a specific event source.
- *
- * @returns New event ID generated, or 0 on error.
- * @param   pSource             Event source to generate event for.
- */
-SHCLEVENTID ShClEventIDGenerate(PSHCLEVENTSOURCE pSource)
-{
-    AssertPtrReturn(pSource, 0);
-
-    LogFlowFunc(("uSource=%RU16: New event: %RU32\n", pSource->uID, pSource->uEventIDNext));
-
-    pSource->uEventIDNext++;
-    if (pSource->uEventIDNext == VBOX_SHCL_MAX_EVENTS)
-        pSource->uEventIDNext = 0;
-
-    return pSource->uEventIDNext;
 }
 
@@ -223,14 +206,79 @@
  * @param   uID                 Event ID to get.
  */
-inline PSHCLEVENT shclEventGet(PSHCLEVENTSOURCE pSource, SHCLEVENTID uID)
-{
-    PSHCLEVENT pEvIt;
-    RTListForEach(&pSource->lstEvents, pEvIt, SHCLEVENT, Node)
-    {
-        if (pEvIt->uID == uID)
-            return pEvIt;
+DECLINLINE(PSHCLEVENT) shclEventGet(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent)
+{
+    PSHCLEVENT pEvent;
+    RTListForEach(&pSource->lstEvents, pEvent, SHCLEVENT, Node)
+    {
+        if (pEvent->idEvent == idEvent)
+            return pEvent;
     }
 
     return NULL;
+}
+
+/**
+ * Generates a new event ID for a specific event source.
+ *
+ * @returns New event ID generated, or 0 on error.
+ * @param   pSource             Event source to generate event for.
+ * @deprecated as this does not deal with duplicates.
+ */
+SHCLEVENTID ShClEventIDGenerate(PSHCLEVENTSOURCE pSource)
+{
+    AssertPtrReturn(pSource, 0);
+
+    SHCLEVENTID idEvent = ++pSource->idNextEvent;
+    if (idEvent >= VBOX_SHCL_MAX_EVENTS)
+        pSource->idNextEvent = idEvent = 1;  /* zero == error, remember! */
+
+    LogFlowFunc(("uSource=%RU16: New event: %RU32\n", pSource->uID, idEvent));
+    return idEvent;
+}
+
+/**
+ * Generates a new event ID for a specific event source and registers it.
+ *
+ * @returns New event ID generated, or 0 on error.
+ * @param   pSource             Event source to generate event for.
+ */
+SHCLEVENTID ShClEventIdGenerateAndRegister(PSHCLEVENTSOURCE pSource)
+{
+    AssertPtrReturn(pSource, 0);
+
+    /*
+     * Allocate an event.
+     */
+    PSHCLEVENT pEvent = (PSHCLEVENT)RTMemAllocZ(sizeof(SHCLEVENT));
+    AssertReturn(pEvent, 0);
+    int rc = RTSemEventMultiCreate(&pEvent->hEvtMulSem);
+    AssertRCReturnStmt(rc, RTMemFree(pEvent), 0);
+
+    /*
+     * Allocate an unique event ID.
+     */
+    for (uint32_t cTries = 0;; cTries++)
+    {
+        SHCLEVENTID idEvent = ++pSource->idNextEvent;
+        if (idEvent < VBOX_SHCL_MAX_EVENTS)
+        { /* likely */ }
+        else
+            pSource->idNextEvent = idEvent = 1; /* zero == error, remember! */
+
+        if (shclEventGet(pSource, idEvent) == NULL)
+        {
+
+            pEvent->idEvent = idEvent;
+            RTListAppend(&pSource->lstEvents, &pEvent->Node);
+
+            LogFlowFunc(("uSource=%RU16: New event: %#x\n", pSource->uID, idEvent));
+            return idEvent;
+        }
+
+        AssertBreak(cTries < 4096);
+    }
+
+    RTMemFree(pEvent);
+    return 0;
 }
 
@@ -246,5 +294,5 @@
     PSHCLEVENT pEvent = RTListGetLast(&pSource->lstEvents, SHCLEVENT, Node);
     if (pEvent)
-        return pEvent->uID;
+        return pEvent->idEvent;
 
     return 0;
@@ -266,4 +314,5 @@
 }
 
+#if 0 /** @todo fix later */
 /**
  * Registers an event.
@@ -283,9 +332,8 @@
     if (shclEventGet(pSource, uID) == NULL)
     {
-        PSHCLEVENT pEvent
-            = (PSHCLEVENT)RTMemAllocZ(sizeof(SHCLEVENT));
+        PSHCLEVENT pEvent = (PSHCLEVENT)RTMemAllocZ(sizeof(SHCLEVENT));
         if (pEvent)
         {
-            rc = ShClEventCreate(pEvent, uID);
+            rc = shClEventInit(pEvent, uID);
             if (RT_SUCCESS(rc))
             {
@@ -308,4 +356,5 @@
     return rc;
 }
+#endif /* later */
 
 /**
@@ -327,9 +376,9 @@
     if (pEvent)
     {
-        LogFlowFunc(("Event %RU32\n", pEvent->uID));
+        LogFlowFunc(("Event %RU32\n", pEvent->idEvent));
 
         RTListNodeRemove(&pEvent->Node);
 
-        ShClEventDestroy(pEvent);
+        shClEventTerm(pEvent);
 
         RTMemFree(pEvent);
@@ -368,5 +417,5 @@
     if (pEvent)
     {
-        rc = RTSemEventWait(pEvent->hEventSem, uTimeoutMs);
+        rc = RTSemEventMultiWait(pEvent->hEvtMulSem, uTimeoutMs);
         if (RT_SUCCESS(rc))
         {
@@ -411,5 +460,5 @@
         pEvent->pPayload = pPayload;
 
-        rc = RTSemEventSignal(pEvent->hEventSem);
+        rc = RTSemEventMultiSignal(pEvent->hEvtMulSem);
     }
     else
Index: /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp	(revision 82526)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp	(revision 82527)
@@ -1190,5 +1190,5 @@
     RTListInit(&pTransfer->Events.lstEvents);
     pTransfer->Events.uID          = 0;
-    pTransfer->Events.uEventIDNext = 1;
+    pTransfer->Events.idNextEvent  = 1;
 
     if (RT_SUCCESS(rc))
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp	(revision 82526)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp	(revision 82527)
@@ -70,12 +70,5 @@
     if (   RT_SUCCESS(rc)
         && fChanged)
-    {
-        SHCLFORMATDATA formatData;
-        RT_ZERO(formatData);
-
-        formatData.Formats = fFormats;
-
-        rc = ShClSvcFormatsReport(pCtx->pClient, &formatData);
-    }
+        rc = ShClSvcHostReportFormats(pCtx->pClient, fFormats);
 
     LogFlowFuncLeaveRC(rc);
@@ -215,11 +208,5 @@
 #endif
 
-    SHCLDATAREQ dataReq;
-    RT_ZERO(dataReq);
-
-    dataReq.uFmt   = pFormats->Formats;
-    dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
-
-    return ShClSvcDataReadRequest(pClient, &dataReq, NULL /* puEvent */);
+    return ShClSvcDataReadRequest(pClient, pFormats->Formats, NULL /* puEvent */);
 }
 
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h	(revision 82526)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h	(revision 82527)
@@ -53,17 +53,22 @@
 
 /**
- * Structure for keeping a single HGCM message.
+ * A queued message for the guest.
  */
 typedef struct _SHCLCLIENTMSG
 {
-    /** Stored message type. */
-    uint32_t         uMsg;
-    /** Number of stored HGCM parameters. */
-    uint32_t         cParms;
-    /** Stored HGCM parameters. */
-    PVBOXHGCMSVCPARM paParms;
-    /** Message context. */
-    SHCLMSGCTX       Ctx;
-} SHCLCLIENTMSG, *PSHCLCLIENTMSG;
+    /** The queue list entry. */
+    RTLISTNODE          ListEntry;
+    /** Stored message ID (VBOX_SHCL_HOST_MSG_XXX). */
+    uint32_t            idMsg;
+    /** Number of stored parameters. */
+    uint32_t            cParms;
+    /** The context ID for this message.
+     * @todo r=bird: Why do we need this? */
+    uint64_t            idContext;
+    /** HGCM parameters. */
+    VBOXHGCMSVCPARM     aParms[RT_FLEXIBLE_ARRAY];
+} SHCLCLIENTMSG;
+/** Pointer to a queue message for the guest.   */
+typedef SHCLCLIENTMSG *PSHCLCLIENTMSG;
 
 typedef struct SHCLCLIENTTRANSFERSTATE
@@ -141,11 +146,14 @@
 {
     /** General client state data. */
-    SHCLCLIENTSTATE          State;
-    RTCRITSECT               CritSect;
-    /** The client's message queue (FIFO). */
-    RTCList<SHCLCLIENTMSG *> queueMsg;
+    SHCLCLIENTSTATE             State;
+    /** The critical section protecting the queue, event source and whatnot.   */
+    RTCRITSECT                  CritSect;
+    /** The client's message queue (SHCLCLIENTMSG). */
+    RTLISTANCHOR                MsgQueue;
+    /** Number of allocated messages (updated atomically, not under critsect). */
+    uint32_t volatile           cAllocatedMessages;
     /** The client's own event source.
      *  Needed for events which are not bound to a specific transfer. */
-    SHCLEVENTSOURCE          EventSrc;
+    SHCLEVENTSOURCE             EventSrc;
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     /** Transfer contextdata. */
@@ -210,5 +218,5 @@
     /** The actual clipboard formats announced while the host service
      *  is reading clipboard data from the extension. */
-    uint32_t       uDelayedFormats;
+    uint32_t       fDelayedFormats;
 } SHCLEXTSTATE, *PSHCLEXTSTATE;
 
@@ -216,8 +224,8 @@
 
 void shClSvcMsgQueueReset(PSHCLCLIENT pClient);
-PSHCLCLIENTMSG shClSvcMsgAlloc(uint32_t uMsg, uint32_t cParms);
-void shClSvcMsgFree(PSHCLCLIENTMSG pMsg);
-void shClSvcMsgSetPeekReturn(PSHCLCLIENTMSG pMsg, PVBOXHGCMSVCPARM paDstParms, uint32_t cDstParms);
-int shClSvcMsgAdd(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg, bool fAppend);
+PSHCLCLIENTMSG shClSvcMsgAlloc(PSHCLCLIENT pClient, uint32_t uMsg, uint32_t cParms);
+void shClSvcMsgFree(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg);
+void shClSvcMsgAdd(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg, bool fAppend);
+int shClSvcMsgAddAndWakeupClient(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg);
 
 int shClSvcClientInit(PSHCLCLIENT pClient, uint32_t uClientID);
@@ -243,7 +251,7 @@
  * @{
  */
-int ShClSvcDataReadRequest(PSHCLCLIENT pClient, PSHCLDATAREQ pDataReq, PSHCLEVENTID puEvent);
+int ShClSvcDataReadRequest(PSHCLCLIENT pClient, SHCLFORMAT fFormat, PSHCLEVENTID puEvent);
 int ShClSvcDataReadSignal(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, PSHCLDATABLOCK pData);
-int ShClSvcFormatsReport(PSHCLCLIENT pClient, PSHCLFORMATDATA pFormats);
+int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats);
 uint32_t ShClSvcGetMode(void);
 bool ShClSvcGetHeadless(void);
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp	(revision 82526)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp	(revision 82527)
@@ -121,5 +121,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsgHdr = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
+    PSHCLCLIENTMSG pMsgHdr = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
                                              VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
     if (pMsgHdr)
@@ -162,5 +162,5 @@
                                 for (uint32_t i = 0; i < pSrcRootListHdr->cRoots; i++)
                                 {
-                                    PSHCLCLIENTMSG pMsgEntry = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
+                                    PSHCLCLIENTMSG pMsgEntry = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
                                                                                VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
 
@@ -240,5 +240,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN,
                                           VBOX_SHCL_CPARMS_LIST_OPEN);
     if (pMsg)
@@ -300,5 +300,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE,
                                           VBOX_SHCL_CPARMS_LIST_CLOSE);
     if (pMsg)
@@ -348,5 +348,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ,
                                           VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
     if (pMsg)
@@ -409,5 +409,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ,
                                           VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
     if (pMsg)
@@ -469,5 +469,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN,
                                           VBOX_SHCL_CPARMS_OBJ_OPEN);
     if (pMsg)
@@ -531,5 +531,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE,
                                           VBOX_SHCL_CPARMS_OBJ_CLOSE);
     if (pMsg)
@@ -587,5 +587,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ,
                                           VBOX_SHCL_CPARMS_OBJ_READ_REQ);
     if (pMsg)
@@ -646,5 +646,5 @@
     int rc;
 
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE,
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE,
                                           VBOX_SHCL_CPARMS_OBJ_WRITE);
     if (pMsg)
@@ -1986,5 +1986,5 @@
     /* puEvent is optional. */
 
-    PSHCLCLIENTMSG pMsgReadData = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
+    PSHCLCLIENTMSG pMsgReadData = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
                                                   VBOX_SHCL_CPARMS_TRANSFER_STATUS);
     if (!pMsgReadData)
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 82526)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 82527)
@@ -167,23 +167,17 @@
 }
 
-static int vboxClipboardSvcWinDataRead(PSHCLCONTEXT pCtx, UINT cfFormat,
-                                       void **ppvData, uint32_t *pcbData)
-{
-    SHCLDATAREQ dataReq;
-    RT_ZERO(dataReq);
-
-    dataReq.uFmt   = SharedClipboardWinClipboardFormatToVBox(cfFormat);
-    dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
-
-    LogFlowFunc(("cfFormat=%u -> uFmt=0x%x\n", cfFormat, dataReq.uFmt));
-
-    if (dataReq.uFmt == VBOX_SHCL_FMT_NONE)
-    {
-        LogRel2(("Shared Clipbaord: Windows format %u not supported, ingoring\n", cfFormat));
+static int vboxClipboardSvcWinDataRead(PSHCLCONTEXT pCtx, UINT uFormat, void **ppvData, uint32_t *pcbData)
+{
+    SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(uFormat);
+    LogFlowFunc(("uFormat=%u -> uFmt=0x%x\n", uFormat, fFormat));
+
+    if (fFormat == VBOX_SHCL_FMT_NONE)
+    {
+        LogRel2(("Shared Clipbaord: Windows format %u not supported, ingoring\n", uFormat));
         return VERR_NOT_SUPPORTED;
     }
 
     SHCLEVENTID uEvent = 0;
-    int rc = ShClSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent);
+    int rc = ShClSvcDataReadRequest(pCtx->pClient, fFormat, &uEvent);
     if (RT_SUCCESS(rc))
     {
@@ -310,9 +304,7 @@
 
             /* Insert the requested clipboard format data into the clipboard. */
-            const UINT cfFormat = (UINT)wParam;
-
-            const SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(cfFormat);
-
-            LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat));
+            const UINT       uFormat = (UINT)wParam;
+            const SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(uFormat);
+            LogFunc(("WM_RENDERFORMAT: uFormat=%u -> fFormat=0x%x\n", uFormat, fFormat));
 
             if (   fFormat       == VBOX_SHCL_FMT_NONE
@@ -327,10 +319,10 @@
                 void    *pvData = NULL;
                 uint32_t cbData = 0;
-                int rc = vboxClipboardSvcWinDataRead(pCtx, cfFormat, &pvData, &cbData);
+                int rc = vboxClipboardSvcWinDataRead(pCtx, uFormat, &pvData, &cbData);
                 if (   RT_SUCCESS(rc)
                     && pvData
                     && cbData)
                 {
-                    rc = vboxClipboardSvcWinDataSet(pCtx, cfFormat, pvData, cbData);
+                    rc = vboxClipboardSvcWinDataSet(pCtx, uFormat, pvData, cbData);
 
                     RTMemFree(pvData);
@@ -597,8 +589,6 @@
         rc = SharedClipboardWinGetFormats(&pCtx->Win, &Formats);
         if (   RT_SUCCESS(rc)
-            && Formats.Formats != VBOX_SHCL_FMT_NONE)
-        {
-            rc = ShClSvcFormatsReport(pCtx->pClient, &Formats);
-        }
+            && Formats.Formats != VBOX_SHCL_FMT_NONE) /** @todo r=bird: BUGBUG: revisit this. */
+            rc = ShClSvcHostReportFormats(pCtx->pClient, Formats.Formats);
     }
     else /* If we don't have any client data (yet), bail out. */
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp	(revision 82526)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp	(revision 82527)
@@ -113,10 +113,5 @@
      * there is data in the host clipboard it will automatically be sent to
      * the guest when the clipboard starts up. */
-    SHCLFORMATDATA formatData;
-    RT_ZERO(formatData);
-
-    formatData.Formats = VBOX_SHCL_FMT_NONE;
-
-    return ShClSvcFormatsReport(pClient, &formatData);
+    return ShClSvcHostReportFormats(pClient, VBOX_SHCL_FMT_NONE);
 }
 
@@ -250,19 +245,15 @@
  *
  * @param  pCtx                 Opaque context pointer for the glue code.
- * @param  Formats              The formats available.
- */
-DECLCALLBACK(void) ShClX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t Formats)
-{
-    LogFlowFunc(("pCtx=%p, Formats=%02X\n", pCtx, Formats));
-
-    if (Formats == VBOX_SHCL_FMT_NONE) /* No formats to report? Bail out early. */
+ * @param  fFormats             The formats available.
+ */
+DECLCALLBACK(void) ShClX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats)
+{
+    LogFlowFunc(("pCtx=%p, fFormats=%#x\n", pCtx, fFormats));
+
+    /** @todo r=bird: BUGBUG: Revisit this   */
+    if (fFormats == VBOX_SHCL_FMT_NONE) /* No formats to report? Bail out early. */
         return;
 
-    SHCLFORMATDATA formatData;
-    RT_ZERO(formatData);
-
-    formatData.Formats = Formats;
-
-    int rc = ShClSvcFormatsReport(pCtx->pClient, &formatData);
+    int rc = ShClSvcHostReportFormats(pCtx->pClient, fFormats);
     RT_NOREF(rc);
 
@@ -317,5 +308,6 @@
  *
  * @param  pCtx      Pointer to the host clipboard structure.
- * @param  Format    The format in which the data should be transferred.
+ * @param  fFormat   The format in which the data should be transferred
+ *                   (VBOX_SHCL_FMT_XXX).
  * @param  ppv       On success and if pcb > 0, this will point to a buffer
  *                   to be freed with RTMemFree containing the data read.
@@ -323,7 +315,7 @@
  *                   returned.
  */
-DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb)
-{
-    LogFlowFunc(("pCtx=%p, Format=0x%x\n", pCtx, Format));
+DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, SHCLFORMAT fFormat, void **ppv, uint32_t *pcb)
+{
+    LogFlowFunc(("pCtx=%p, Format=0x%x\n", pCtx, fFormat));
 
     if (pCtx->fShuttingDown)
@@ -337,20 +329,12 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-    if (Format == VBOX_SHCL_FMT_URI_LIST)
-    {
-        rc = 0;
-    }
+    if (fFormat == VBOX_SHCL_FMT_URI_LIST)
+        rc = VINF_SUCCESS;
     else
 #endif
     {
         /* Request data from the guest. */
-        SHCLDATAREQ dataReq;
-        RT_ZERO(dataReq);
-
-        dataReq.uFmt   = Format;
-        dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
-
         SHCLEVENTID uEvent;
-        rc = ShClSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent);
+        rc = ShClSvcDataReadRequest(pCtx->pClient, fFormat, &uEvent);
         if (RT_SUCCESS(rc))
         {
@@ -375,4 +359,5 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+
 int ShClSvcImplTransferCreate(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
 {
@@ -429,3 +414,4 @@
     return rc;
 }
-#endif
+
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 82526)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 82527)
@@ -368,13 +368,15 @@
  *
  * @param   pClient             Pointer to the client data structure to reset message queue for.
+ * @note    Caller enters pClient->CritSect.
  */
 void shClSvcMsgQueueReset(PSHCLCLIENT pClient)
 {
+    Assert(RTCritSectIsOwner(&pClient->CritSect));
     LogFlowFuncEnter();
 
-    while (!pClient->queueMsg.isEmpty())
-    {
-        RTMemFree(pClient->queueMsg.last());
-        pClient->queueMsg.removeLast();
+    while (!RTListIsEmpty(&pClient->MsgQueue))
+    {
+        PSHCLCLIENTMSG pMsg = RTListRemoveFirst(&pClient->MsgQueue, SHCLCLIENTMSG, ListEntry);
+        shClSvcMsgFree(pClient, pMsg);
     }
 }
@@ -384,23 +386,26 @@
  *
  * @returns Allocated clipboard message, or NULL on failure.
- * @param   uMsg                Message type of message to allocate.
- * @param   cParms              Number of HGCM parameters to allocate.
- */
-PSHCLCLIENTMSG shClSvcMsgAlloc(uint32_t uMsg, uint32_t cParms)
-{
-    PSHCLCLIENTMSG pMsg = (PSHCLCLIENTMSG)RTMemAlloc(sizeof(SHCLCLIENTMSG));
+ * @param   pClient     The client which is target of this message.
+ * @param   idMsg       The message ID (VBOX_SHCL_HOST_MSG_XXX) to use
+ * @param   cParms      The number of parameters the message takes.
+ */
+PSHCLCLIENTMSG shClSvcMsgAlloc(PSHCLCLIENT pClient, uint32_t idMsg, uint32_t cParms)
+{
+    RT_NOREF(pClient);
+    PSHCLCLIENTMSG pMsg = (PSHCLCLIENTMSG)RTMemAllocZ(RT_UOFFSETOF_DYN(SHCLCLIENTMSG, aParms[cParms]));
     if (pMsg)
     {
-        pMsg->paParms = (PVBOXHGCMSVCPARM)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * cParms);
-        if (pMsg->paParms)
-        {
+        uint32_t cAllocated = ASMAtomicIncU32(&pClient->cAllocatedMessages);
+        if (cAllocated <= 4096)
+        {
+            RTListInit(&pMsg->ListEntry);
             pMsg->cParms = cParms;
-            pMsg->uMsg   = uMsg;
-
+            pMsg->idMsg  = idMsg;
             return pMsg;
         }
-    }
-
-    RTMemFree(pMsg);
+        AssertMsgFailed(("Too many messages allocated for client %u! (%u)\n", pClient->State.uClientID, cAllocated));
+        ASMAtomicDecU32(&pClient->cAllocatedMessages);
+        RTMemFree(pMsg);
+    }
     return NULL;
 }
@@ -409,17 +414,19 @@
  * Frees a formerly allocated clipboard message.
  *
- * @param   pMsg                Clipboard message to free.
- *                              The pointer will be invalid after calling this function.
- */
-void shClSvcMsgFree(PSHCLCLIENTMSG pMsg)
-{
-    if (!pMsg)
-        return;
-
-    if (pMsg->paParms)
-        RTMemFree(pMsg->paParms);
-
-    RTMemFree(pMsg);
-    pMsg = NULL;
+ * @param   pClient     The client which was the target of this message.
+ * @param   pMsg        Clipboard message to free.
+ */
+void shClSvcMsgFree(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg)
+{
+    RT_NOREF(pClient);
+    /** @todo r=bird: Do accounting. */
+    if (pMsg)
+    {
+        pMsg->idMsg = UINT32_C(0xdeadface);
+        RTMemFree(pMsg);
+
+        uint32_t cAllocated = ASMAtomicDecU32(&pClient->cAllocatedMessages);
+        Assert(cAllocated < UINT32_MAX / 2);
+    }
 }
 
@@ -433,20 +440,20 @@
  * @remarks ASSUMES the parameters has been cleared by clientMsgPeek.
  */
-void shClSvcMsgSetPeekReturn(PSHCLCLIENTMSG pMsg, PVBOXHGCMSVCPARM paDstParms, uint32_t cDstParms)
+static void shClSvcMsgSetPeekReturn(PSHCLCLIENTMSG pMsg, PVBOXHGCMSVCPARM paDstParms, uint32_t cDstParms)
 {
     Assert(cDstParms >= 2);
     if (paDstParms[0].type == VBOX_HGCM_SVC_PARM_32BIT)
-        paDstParms[0].u.uint32 = pMsg->uMsg;
+        paDstParms[0].u.uint32 = pMsg->idMsg;
     else
-        paDstParms[0].u.uint64 = pMsg->uMsg;
+        paDstParms[0].u.uint64 = pMsg->idMsg;
     paDstParms[1].u.uint32 = pMsg->cParms;
 
     uint32_t i = RT_MIN(cDstParms, pMsg->cParms + 2);
     while (i-- > 2)
-        switch (pMsg->paParms[i - 2].type)
+        switch (pMsg->aParms[i - 2].type)
         {
             case VBOX_HGCM_SVC_PARM_32BIT: paDstParms[i].u.uint32 = ~(uint32_t)sizeof(uint32_t); break;
             case VBOX_HGCM_SVC_PARM_64BIT: paDstParms[i].u.uint32 = ~(uint32_t)sizeof(uint64_t); break;
-            case VBOX_HGCM_SVC_PARM_PTR:   paDstParms[i].u.uint32 = pMsg->paParms[i - 2].u.pointer.size; break;
+            case VBOX_HGCM_SVC_PARM_PTR:   paDstParms[i].u.uint32 = pMsg->aParms[i - 2].u.pointer.size; break;
         }
 }
@@ -455,94 +462,37 @@
  * Sets the VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT return parameters.
  *
- * This function does the necessary translation between the legacy protocol (<= VBox 6.0) and the new protocols (>= VBox 6.1),
- * as messages are always stored as >= v1 messages in the message queue.
- *
  * @returns VBox status code.
- * @param   pMsg        Message to set return parameters to.
+ * @param   pMsg        The message which parameters to return to the guest.
  * @param   paDstParms  The peek parameter vector.
- * @param   cDstParms   The number of peek parameters (at least two).
- * @param   pfRemove    Returns whether the message can be removed from the queue or not.
- *                      This is needed for certain messages which need to stay around for more than one (guest) call.
- */
-int shClSvcMsgSetGetHostMsgOldReturn(PSHCLCLIENTMSG pMsg, PVBOXHGCMSVCPARM paDstParms, uint32_t cDstParms,
-                                     bool *pfRemove)
-{
-    AssertPtrReturn(pMsg,           VERR_INVALID_POINTER);
-    AssertPtrReturn(paDstParms,     VERR_INVALID_POINTER);
-    AssertReturn   (cDstParms >= 2, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pfRemove,       VERR_INVALID_POINTER);
-
-    int rc = VINF_SUCCESS;
-
-    bool fRemove = true;
-
-    LogFlowFunc(("uMsg=%RU32 (%s), cParms=%RU32\n",
-                 pMsg->uMsg, ShClHostMsgToStr(pMsg->uMsg), pMsg->cParms));
-
-    switch (pMsg->uMsg)
-    {
-        case VBOX_SHCL_HOST_MSG_QUIT:
-        {
-            HGCMSvcSetU32(&paDstParms[0], VBOX_SHCL_HOST_MSG_QUIT);
-            HGCMSvcSetU32(&paDstParms[1], 0 /* Not used */);
+ * @param   cDstParms   The number of peek parameters should be exactly two
+ */
+static int shClSvcMsgSetOldWaitReturn(PSHCLCLIENTMSG pMsg, PVBOXHGCMSVCPARM paDstParms, uint32_t cDstParms)
+{
+    /*
+     * Assert sanity.
+     */
+    AssertPtr(pMsg);
+    AssertPtrReturn(paDstParms, VERR_INVALID_POINTER);
+    AssertReturn(cDstParms >= 2, VERR_INVALID_PARAMETER);
+
+    Assert(pMsg->cParms == 2);
+    Assert(pMsg->aParms[0].u.uint32 == pMsg->idMsg);
+    switch (pMsg->idMsg)
+    {
+        case VBOX_SHCL_HOST_MSG_READ_DATA:
+        case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
             break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_READ_DATA:
-        {
-            HGCMSvcSetU32(&paDstParms[0], VBOX_SHCL_HOST_MSG_READ_DATA);
-            AssertBreakStmt(pMsg->cParms >= 2, rc = VERR_INVALID_PARAMETER); /* Paranoia. */
-            uint32_t uSrcFmt = VBOX_SHCL_FMT_NONE;
-            uint32_t uDstFmt = VBOX_SHCL_FMT_NONE;
-            rc = HGCMSvcGetU32(&pMsg->paParms[2] /* uFormat */, &uSrcFmt);
-            if (RT_SUCCESS(rc))
-            {
-                if (uSrcFmt & VBOX_SHCL_FMT_UNICODETEXT)
-                    uDstFmt = VBOX_SHCL_FMT_UNICODETEXT;
-                else if (uSrcFmt & VBOX_SHCL_FMT_BITMAP)
-                    uDstFmt = VBOX_SHCL_FMT_BITMAP;
-                else if (uSrcFmt & VBOX_SHCL_FMT_HTML)
-                    uDstFmt = VBOX_SHCL_FMT_HTML;
-                else
-                    AssertStmt(uSrcFmt == VBOX_SHCL_FMT_NONE, uSrcFmt = VBOX_SHCL_FMT_NONE);
-
-                LogFlowFunc(("uSrcFmt=0x%x, uDstFmt=0x%x\n", uSrcFmt, uDstFmt));
-
-                /* Remove format we're going to return from the queued message. */
-                uSrcFmt &= ~uDstFmt;
-                HGCMSvcSetU32(&pMsg->paParms[2], uSrcFmt);
-
-                /* Only report back one format at a time. */
-                HGCMSvcSetU32(&paDstParms[1], uDstFmt);
-
-                /* If no more formats are left, the message can be removed finally. */
-                fRemove = uSrcFmt == VBOX_SHCL_FMT_NONE;
-
-                LogFlowFunc(("uSrcFmt=0x%x, fRemove=%RTbool\n", uSrcFmt, fRemove));
-            }
-            break;
-        }
-
-        case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
-        {
-            HGCMSvcSetU32(&paDstParms[0], VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
-            AssertBreakStmt(pMsg->cParms >= 2, rc = VERR_INVALID_PARAMETER); /* Paranoia. */
-            uint32_t uFmts;
-            rc = HGCMSvcGetU32(&pMsg->paParms[1] /* uFormats */, &uFmts);
-            if (RT_SUCCESS(rc))
-                HGCMSvcSetU32(&paDstParms[1], uFmts);
-            break;
-        }
-
         default:
-            AssertFailed(); /* Not supported by legacy protocol. */
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-
-    *pfRemove = fRemove;
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
+            AssertFailed();
+    }
+
+    /*
+     * Set the parameters.
+     */
+    if (pMsg->cParms > 0)
+        paDstParms[0] = pMsg->aParms[0];
+    if (pMsg->cParms > 1)
+        paDstParms[1] = pMsg->aParms[1];
+    return VINF_SUCCESS;
 }
 
@@ -554,20 +504,42 @@
  * @param   pMsg                Pointer to message to add. The queue then owns the pointer.
  * @param   fAppend             Whether to append or prepend the message to the queue.
- */
-int shClSvcMsgAdd(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg, bool fAppend)
-{
-    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
-
-    LogFlowFunc(("uMsg=%RU32 (%s), cParms=%RU32, fAppend=%RTbool\n",
-                 pMsg->uMsg, ShClHostMsgToStr(pMsg->uMsg), pMsg->cParms, fAppend));
+ *
+ * @note    Caller must enter critical section.
+ */
+void shClSvcMsgAdd(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg, bool fAppend)
+{
+    Assert(RTCritSectIsOwned(&pClient->CritSect));
+    AssertPtr(pMsg);
+
+    LogFlowFunc(("idMsg=%s (%RU32) cParms=%RU32 fAppend=%RTbool\n",
+                 ShClHostMsgToStr(pMsg->idMsg), pMsg->idMsg, pMsg->cParms, fAppend));
 
     if (fAppend)
-        pClient->queueMsg.append(pMsg);
+        RTListAppend(&pClient->MsgQueue, &pMsg->ListEntry);
     else
-        pClient->queueMsg.prepend(pMsg);
-
-    /** @todo Catch / handle OOM? */
-
-    return VINF_SUCCESS;
+        RTListPrepend(&pClient->MsgQueue, &pMsg->ListEntry);
+}
+
+
+/**
+ * Appends a message to the client's queue and wake it up.
+ *
+ * @returns VBox status code, though the message is consumed regardless of what
+ *          is returned.
+ * @param   pClient             The client to queue the message on.
+ * @param   pMsg                The message to queue.  Ownership is always
+ *                              transfered to the queue.
+ *
+ * @note    Caller must enter critical section.
+ */
+int shClSvcMsgAddAndWakeupClient(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg)
+{
+    Assert(RTCritSectIsOwned(&pClient->CritSect));
+    AssertPtr(pMsg);
+    AssertPtr(pClient);
+    LogFlowFunc(("idMsg=%s (%u) cParms=%u\n", ShClHostMsgToStr(pMsg->idMsg), pMsg->idMsg, pMsg->cParms));
+
+    RTListAppend(&pClient->MsgQueue, &pMsg->ListEntry);
+    return shClSvcClientWakeup(pClient);
 }
 
@@ -584,4 +556,6 @@
     /* Assign the client ID. */
     pClient->State.uClientID = uClientID;
+    RTListInit(&pClient->MsgQueue);
+    pClient->cAllocatedMessages = 0;
 
     LogFlowFunc(("[Client %RU32]\n", pClient->State.uClientID));
@@ -669,4 +643,5 @@
 
     LogFlowFunc(("[Client %RU32]\n", pClient->State.uClientID));
+    RTCritSectEnter(&pClient->CritSect);
 
     /* Reset message queue. */
@@ -684,4 +659,6 @@
 
     shclSvcClientStateReset(&pClient->State);
+
+    RTCritSectLeave(&pClient->CritSect);
 }
 
@@ -824,15 +801,11 @@
      * Return information about the first message if one is pending in the list.
      */
-    if (!pClient->queueMsg.isEmpty())
-    {
-        PSHCLCLIENTMSG pFirstMsg = pClient->queueMsg.first();
-        if (pFirstMsg)
-        {
-            shClSvcMsgSetPeekReturn(pFirstMsg, paParms, cParms);
-            LogFlowFunc(("[Client %RU32] VBOX_SHCL_GUEST_FN_MSG_PEEK_XXX -> VINF_SUCCESS (idMsg=%u (%s), cParms=%u)\n",
-                         pClient->State.uClientID, pFirstMsg->uMsg, ShClHostMsgToStr(pFirstMsg->uMsg),
-                         pFirstMsg->cParms));
-            return VINF_SUCCESS;
-        }
+    PSHCLCLIENTMSG pFirstMsg = RTListGetFirst(&pClient->MsgQueue, SHCLCLIENTMSG, ListEntry);
+    if (pFirstMsg)
+    {
+        shClSvcMsgSetPeekReturn(pFirstMsg, paParms, cParms);
+        LogFlowFunc(("[Client %RU32] VBOX_SHCL_GUEST_FN_MSG_PEEK_XXX -> VINF_SUCCESS (idMsg=%s (%u), cParms=%u)\n",
+                     pClient->State.uClientID, ShClHostMsgToStr(pFirstMsg->idMsg), pFirstMsg->idMsg, pFirstMsg->cParms));
+        return VINF_SUCCESS;
     }
 
@@ -875,56 +848,51 @@
 static int shClSvcClientMsgOldGet(PSHCLCLIENT pClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
 {
+    /*
+     * Validate input.
+     */
+    ASSERT_GUEST_RETURN(cParms == VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD, VERR_WRONG_PARAMETER_COUNT);
+    ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* id32Msg */
+    ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* f32Formats */
+
+    paParms[0].u.uint32 = 0;
+    paParms[1].u.uint32 = 0;
+
+    /*
+     * If there is a message pending we can return immediately.
+     */
     int rc;
-
-    if (cParms != VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD)
-    {
-        rc = VERR_INVALID_PARAMETER;
-    }
-    else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT  /* msg */
-             || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT) /* formats */
-    {
-        rc = VERR_INVALID_PARAMETER;
-    }
+    PSHCLCLIENTMSG pFirstMsg = RTListGetFirst(&pClient->MsgQueue, SHCLCLIENTMSG, ListEntry);
+    if (pFirstMsg)
+    {
+        LogFlowFunc(("[Client %RU32] uMsg=%s (%RU32), cParms=%RU32\n", pClient->State.uClientID,
+                     ShClHostMsgToStr(pFirstMsg->idMsg), pFirstMsg->idMsg, pFirstMsg->cParms));
+
+        rc = shClSvcMsgSetOldWaitReturn(pFirstMsg, paParms, cParms);
+        AssertPtr(g_pHelpers);
+        rc = g_pHelpers->pfnCallComplete(hCall, rc);
+        if (rc != VERR_CANCELLED)
+        {
+            RTListNodeRemove(&pFirstMsg->ListEntry);
+            shClSvcMsgFree(pClient, pFirstMsg);
+
+            rc = VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
+        }
+    }
+    /*
+     * Otherwise we must wait.
+     */
     else
     {
-        if (!pClient->queueMsg.isEmpty())
-        {
-            PSHCLCLIENTMSG pFirstMsg = pClient->queueMsg.first();
-            AssertPtr(pFirstMsg);
-
-            LogFlowFunc(("[Client %RU32] uMsg=%RU32 (%s), cParms=%RU32\n",
-                         pClient->State.uClientID, pFirstMsg->uMsg, ShClHostMsgToStr(pFirstMsg->uMsg),
-                         pFirstMsg->cParms));
-
-            bool fRemove;
-            rc = shClSvcMsgSetGetHostMsgOldReturn(pFirstMsg, paParms, cParms, &fRemove);
-            if (RT_SUCCESS(rc))
-            {
-                AssertPtr(g_pHelpers);
-                rc = g_pHelpers->pfnCallComplete(hCall, rc);
-                if (   rc != VERR_CANCELLED
-                    && fRemove)
-                {
-                    pClient->queueMsg.removeFirst();
-                    shClSvcMsgFree(pFirstMsg);
-
-                    rc = VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
-                }
-            }
-        }
-        else
-        {
-            ASSERT_GUEST_MSG_RETURN(pClient->Pending.uType == 0, ("Already pending! (idClient=%RU32)\n",
-                                                                   pClient->State.uClientID), VERR_RESOURCE_BUSY);
-
-            pClient->Pending.hHandle = hCall;
-            pClient->Pending.cParms  = cParms;
-            pClient->Pending.paParms = paParms;
-            pClient->Pending.uType   = VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT;
-
-            rc = VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
-
-            LogFlowFunc(("[Client %RU32] Is now in pending mode...\n", pClient->State.uClientID));
-        }
+        ASSERT_GUEST_MSG_RETURN(pClient->Pending.uType == 0, ("Already pending! (idClient=%RU32)\n", pClient->State.uClientID),
+                                VERR_RESOURCE_BUSY);
+
+        pClient->Pending.hHandle = hCall;
+        pClient->Pending.cParms  = cParms;
+        pClient->Pending.paParms = paParms;
+        pClient->Pending.uType   = VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT;
+
+        rc = VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
+
+        LogFlowFunc(("[Client %RU32] Is now in pending mode...\n", pClient->State.uClientID));
     }
 
@@ -965,91 +933,87 @@
      * Return information about the first message if one is pending in the list.
      */
-    if (!pClient->queueMsg.isEmpty())
-    {
-        PSHCLCLIENTMSG pFirstMsg = pClient->queueMsg.first();
-        if (pFirstMsg)
-        {
-            LogFlowFunc(("First message is: %RU32 (%s), cParms=%RU32\n",
-                         pFirstMsg->uMsg, ShClHostMsgToStr(pFirstMsg->uMsg), pFirstMsg->cParms));
-
-            ASSERT_GUEST_MSG_RETURN(pFirstMsg->uMsg == idMsgExpected || idMsgExpected == UINT32_MAX,
-                                    ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
-                                     pFirstMsg->uMsg, ShClHostMsgToStr(pFirstMsg->uMsg), pFirstMsg->cParms,
-                                     idMsgExpected, ShClHostMsgToStr(idMsgExpected), cParms),
-                                    VERR_MISMATCH);
-            ASSERT_GUEST_MSG_RETURN(pFirstMsg->cParms == cParms,
-                                    ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
-                                     pFirstMsg->uMsg, ShClHostMsgToStr(pFirstMsg->uMsg), pFirstMsg->cParms,
-                                     idMsgExpected, ShClHostMsgToStr(idMsgExpected), cParms),
-                                    VERR_WRONG_PARAMETER_COUNT);
-
-            /* Check the parameter types. */
-            for (uint32_t i = 0; i < cParms; i++)
-                ASSERT_GUEST_MSG_RETURN(pFirstMsg->paParms[i].type == paParms[i].type,
-                                        ("param #%u: type %u, caller expected %u (idMsg=%u %s)\n", i, pFirstMsg->paParms[i].type,
-                                         paParms[i].type, pFirstMsg->uMsg, ShClHostMsgToStr(pFirstMsg->uMsg)),
-                                        VERR_WRONG_PARAMETER_TYPE);
+    PSHCLCLIENTMSG pFirstMsg = RTListGetFirst(&pClient->MsgQueue, SHCLCLIENTMSG, ListEntry);
+    if (pFirstMsg)
+    {
+        LogFlowFunc(("First message is: %s (%u), cParms=%RU32\n", ShClHostMsgToStr(pFirstMsg->idMsg), pFirstMsg->idMsg, pFirstMsg->cParms));
+
+        ASSERT_GUEST_MSG_RETURN(pFirstMsg->idMsg == idMsgExpected || idMsgExpected == UINT32_MAX,
+                                ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
+                                 pFirstMsg->idMsg, ShClHostMsgToStr(pFirstMsg->idMsg), pFirstMsg->cParms,
+                                 idMsgExpected, ShClHostMsgToStr(idMsgExpected), cParms),
+                                VERR_MISMATCH);
+        ASSERT_GUEST_MSG_RETURN(pFirstMsg->cParms == cParms,
+                                ("idMsg=%u (%s) cParms=%u, caller expected %u (%s) and %u\n",
+                                 pFirstMsg->idMsg, ShClHostMsgToStr(pFirstMsg->idMsg), pFirstMsg->cParms,
+                                 idMsgExpected, ShClHostMsgToStr(idMsgExpected), cParms),
+                                VERR_WRONG_PARAMETER_COUNT);
+
+        /* Check the parameter types. */
+        for (uint32_t i = 0; i < cParms; i++)
+            ASSERT_GUEST_MSG_RETURN(pFirstMsg->aParms[i].type == paParms[i].type,
+                                    ("param #%u: type %u, caller expected %u (idMsg=%u %s)\n", i, pFirstMsg->aParms[i].type,
+                                     paParms[i].type, pFirstMsg->idMsg, ShClHostMsgToStr(pFirstMsg->idMsg)),
+                                    VERR_WRONG_PARAMETER_TYPE);
+        /*
+         * Copy out the parameters.
+         *
+         * No assertions on buffer overflows, and keep going till the end so we can
+         * communicate all the required buffer sizes.
+         */
+        int rc = VINF_SUCCESS;
+        for (uint32_t i = 0; i < cParms; i++)
+            switch (pFirstMsg->aParms[i].type)
+            {
+                case VBOX_HGCM_SVC_PARM_32BIT:
+                    paParms[i].u.uint32 = pFirstMsg->aParms[i].u.uint32;
+                    break;
+
+                case VBOX_HGCM_SVC_PARM_64BIT:
+                    paParms[i].u.uint64 = pFirstMsg->aParms[i].u.uint64;
+                    break;
+
+                case VBOX_HGCM_SVC_PARM_PTR:
+                {
+                    uint32_t const cbSrc = pFirstMsg->aParms[i].u.pointer.size;
+                    uint32_t const cbDst = paParms[i].u.pointer.size;
+                    paParms[i].u.pointer.size = cbSrc; /** @todo Check if this is safe in other layers...
+                                                        * Update: Safe, yes, but VMMDevHGCM doesn't pass it along. */
+                    if (cbSrc <= cbDst)
+                        memcpy(paParms[i].u.pointer.addr, pFirstMsg->aParms[i].u.pointer.addr, cbSrc);
+                    else
+                    {
+                        AssertMsgFailed(("#%u: cbSrc=%RU32 is bigger than cbDst=%RU32\n", i, cbSrc, cbDst));
+                        rc = VERR_BUFFER_OVERFLOW;
+                    }
+                    break;
+                }
+
+                default:
+                    AssertMsgFailed(("#%u: %u\n", i, pFirstMsg->aParms[i].type));
+                    rc = VERR_INTERNAL_ERROR;
+                    break;
+            }
+        if (RT_SUCCESS(rc))
+        {
             /*
-             * Copy out the parameters.
-             *
-             * No assertions on buffer overflows, and keep going till the end so we can
-             * communicate all the required buffer sizes.
+             * Complete the message and remove the pending message unless the
+             * guest raced us and cancelled this call in the meantime.
              */
-            int rc = VINF_SUCCESS;
-            for (uint32_t i = 0; i < cParms; i++)
-                switch (pFirstMsg->paParms[i].type)
-                {
-                    case VBOX_HGCM_SVC_PARM_32BIT:
-                        paParms[i].u.uint32 = pFirstMsg->paParms[i].u.uint32;
-                        break;
-
-                    case VBOX_HGCM_SVC_PARM_64BIT:
-                        paParms[i].u.uint64 = pFirstMsg->paParms[i].u.uint64;
-                        break;
-
-                    case VBOX_HGCM_SVC_PARM_PTR:
-                    {
-                        uint32_t const cbSrc = pFirstMsg->paParms[i].u.pointer.size;
-                        uint32_t const cbDst = paParms[i].u.pointer.size;
-                        paParms[i].u.pointer.size = cbSrc; /** @todo Check if this is safe in other layers...
-                                                            * Update: Safe, yes, but VMMDevHGCM doesn't pass it along. */
-                        if (cbSrc <= cbDst)
-                            memcpy(paParms[i].u.pointer.addr, pFirstMsg->paParms[i].u.pointer.addr, cbSrc);
-                        else
-                        {
-                            AssertMsgFailed(("#%u: cbSrc=%RU32 is bigger than cbDst=%RU32\n", i, cbSrc, cbDst));
-                            rc = VERR_BUFFER_OVERFLOW;
-                        }
-                        break;
-                    }
-
-                    default:
-                        AssertMsgFailed(("#%u: %u\n", i, pFirstMsg->paParms[i].type));
-                        rc = VERR_INTERNAL_ERROR;
-                        break;
-                }
-            if (RT_SUCCESS(rc))
+            AssertPtr(g_pHelpers);
+            rc = g_pHelpers->pfnCallComplete(hCall, rc);
+
+            LogFlowFunc(("[Client %RU32] pfnCallComplete -> %Rrc\n", pClient->State.uClientID, rc));
+
+            if (rc != VERR_CANCELLED)
             {
-                /*
-                 * Complete the message and remove the pending message unless the
-                 * guest raced us and cancelled this call in the meantime.
-                 */
-                AssertPtr(g_pHelpers);
-                rc = g_pHelpers->pfnCallComplete(hCall, rc);
-
-                LogFlowFunc(("[Client %RU32] pfnCallComplete -> %Rrc\n", pClient->State.uClientID, rc));
-
-                if (rc != VERR_CANCELLED)
-                {
-                    pClient->queueMsg.removeFirst();
-                    shClSvcMsgFree(pFirstMsg);
-                }
-
-                return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
+                RTListNodeRemove(&pFirstMsg->ListEntry);
+                shClSvcMsgFree(pClient, pFirstMsg);
             }
 
-            LogFlowFunc(("[Client %RU32] Returning %Rrc\n", pClient->State.uClientID, rc));
-            return rc;
-        }
+            return VINF_HGCM_ASYNC_EXECUTE; /* The caller must not complete it. */
+        }
+
+        LogFlowFunc(("[Client %RU32] Returning %Rrc\n", pClient->State.uClientID, rc));
+        return rc;
     }
 
@@ -1096,5 +1060,8 @@
         {
             Assert(pClient->Pending.cParms >= 2);
-            HGCMSvcSetU32(&pClient->Pending.paParms[0], VBOX_SHCL_HOST_MSG_CANCELED);
+            if (pClient->Pending.paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT)
+                HGCMSvcSetU64(&pClient->Pending.paParms[0], VBOX_SHCL_HOST_MSG_CANCELED);
+            else
+                HGCMSvcSetU32(&pClient->Pending.paParms[0], VBOX_SHCL_HOST_MSG_CANCELED);
             rcComplete = VINF_TRY_AGAIN;
         }
@@ -1133,72 +1100,46 @@
  *
  * @param   pClient             Client to wake up.
+ * @note    Caller must enter pClient->CritSect.
  */
 int shClSvcClientWakeup(PSHCLCLIENT pClient)
 {
+    Assert(RTCritSectIsOwner(&pClient->CritSect));
     int rc = VINF_NO_CHANGE;
 
-    if (pClient->Pending.uType)
+    if (pClient->Pending.uType != 0)
     {
         LogFunc(("[Client %RU32] Waking up ...\n", pClient->State.uClientID));
 
-        rc = VINF_SUCCESS;
-
-        if (!pClient->queueMsg.isEmpty())
-        {
-            PSHCLCLIENTMSG pFirstMsg = pClient->queueMsg.first();
-            if (pFirstMsg)
-            {
-                LogFunc(("[Client %RU32] Current host message is %RU32 (%s), cParms=%RU32\n",
-                         pClient->State.uClientID, pFirstMsg->uMsg, ShClHostMsgToStr(pFirstMsg->uMsg),
-                         pFirstMsg->cParms));
-
-                bool fDonePending = false;
-
-                if (pClient->Pending.uType == VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT)
-                {
-                    shClSvcMsgSetPeekReturn(pFirstMsg, pClient->Pending.paParms, pClient->Pending.cParms);
-                    fDonePending = true;
-                }
-                else if (pClient->Pending.uType == VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT) /* Legacy, Guest Additions < 6.1. */
-                {
-                    bool fRemove;
-                    rc = shClSvcMsgSetGetHostMsgOldReturn(pFirstMsg, pClient->Pending.paParms, pClient->Pending.cParms,
-                                                          &fRemove);
-                    if (RT_SUCCESS(rc))
-                    {
-                        if (fRemove)
-                        {
-                            /* The old (legacy) protocol gets the message right when returning from peeking, so
-                             * remove the actual message from our queue right now. */
-                            pClient->queueMsg.removeFirst();
-                            shClSvcMsgFree(pFirstMsg);
-                        }
-
-                        fDonePending = true;
-                    }
-                }
-
-                if (fDonePending)
-                {
-                    rc = g_pHelpers->pfnCallComplete(pClient->Pending.hHandle, VINF_SUCCESS);
-
-                    pClient->Pending.hHandle = NULL;
-                    pClient->Pending.paParms = NULL;
-                    pClient->Pending.cParms  = 0;
-                    pClient->Pending.uType   = 0;
-                }
-            }
-            else
-                AssertFailed();
-        }
+        PSHCLCLIENTMSG pFirstMsg = RTListGetFirst(&pClient->MsgQueue, SHCLCLIENTMSG, ListEntry);
+        AssertReturn(pFirstMsg, VERR_INTERNAL_ERROR);
+
+        LogFunc(("[Client %RU32] Current host message is %s (%RU32), cParms=%RU32\n",
+                 pClient->State.uClientID, ShClHostMsgToStr(pFirstMsg->idMsg), pFirstMsg->idMsg, pFirstMsg->cParms));
+
+        if (pClient->Pending.uType == VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT)
+            shClSvcMsgSetPeekReturn(pFirstMsg, pClient->Pending.paParms, pClient->Pending.cParms);
+        else if (pClient->Pending.uType == VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT) /* Legacy, Guest Additions < 6.1. */
+            shClSvcMsgSetOldWaitReturn(pFirstMsg, pClient->Pending.paParms, pClient->Pending.cParms);
         else
-            AssertMsgFailed(("Waking up client ID=%RU32 with no host message in queue is a bad idea\n", pClient->State.uClientID));
-
-        return rc;
+            AssertMsgFailedReturn(("pClient->Pending.uType=%u\n", pClient->Pending.uType), VERR_INTERNAL_ERROR_3);
+
+        rc = g_pHelpers->pfnCallComplete(pClient->Pending.hHandle, VINF_SUCCESS);
+
+        if (   rc != VERR_CANCELLED
+            && pClient->Pending.uType == VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT)
+        {
+            RTListNodeRemove(&pFirstMsg->ListEntry);
+            shClSvcMsgFree(pClient, pFirstMsg);
+        }
+
+        pClient->Pending.hHandle = NULL;
+        pClient->Pending.paParms = NULL;
+        pClient->Pending.cParms  = 0;
+        pClient->Pending.uType   = 0;
     }
     else
         LogFunc(("[Client %RU32] Not in pending state, skipping wakeup\n", pClient->State.uClientID));
 
-    return VINF_NO_CHANGE;
+    return rc;
 }
 
@@ -1208,47 +1149,55 @@
  * @returns VBox status code.
  * @param   pClient             Client to request to read data form.
- * @param   pDataReq            Data request to send to the guest.
+ * @param   fFormat             The format being requested (VBOX_SHCL_FMT_XXX).
  * @param   puEvent             Event ID for waiting for new data. Optional.
  */
-int ShClSvcDataReadRequest(PSHCLCLIENT pClient, PSHCLDATAREQ pDataReq, PSHCLEVENTID puEvent)
-{
+int ShClSvcDataReadRequest(PSHCLCLIENT pClient, SHCLFORMAT fFormat, PSHCLEVENTID pidEvent)
+{
+    LogFlowFuncEnter();
+    if (pidEvent)
+        *pidEvent = 0;
     AssertPtrReturn(pClient,  VERR_INVALID_POINTER);
-    AssertPtrReturn(pDataReq, VERR_INVALID_POINTER);
-    /* puEvent is optional. */
-
-    LogFlowFuncEnter();
-
+
+    /*
+     * Allocate a message.
+     */
     int rc;
-
-    PSHCLCLIENTMSG pMsgReadData = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_READ_DATA,
-                                                  VBOX_SHCL_CPARMS_READ_DATA_REQ);
-    if (pMsgReadData)
-    {
-        const SHCLEVENTID uEvent = ShClEventIDGenerate(&pClient->EventSrc);
-
-        LogFlowFunc(("uFmt=0x%x\n", pDataReq->uFmt));
-
-        HGCMSvcSetU64(&pMsgReadData->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
-                                                                          pClient->EventSrc.uID, uEvent));
-        HGCMSvcSetU32(&pMsgReadData->paParms[1], 0 /* fFlags */);
-        HGCMSvcSetU32(&pMsgReadData->paParms[2], pDataReq->uFmt);
-        HGCMSvcSetU32(&pMsgReadData->paParms[3], pClient->State.cbChunkSize);
-
-        rc = shClSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
-        if (RT_SUCCESS(rc))
-        {
-            rc = ShClEventRegister(&pClient->EventSrc, uEvent);
-            if (RT_SUCCESS(rc))
-            {
-                rc = shClSvcClientWakeup(pClient);
-                if (RT_SUCCESS(rc))
-                {
-                    if (puEvent)
-                        *puEvent = uEvent;
-                }
-                else
-                    ShClEventUnregister(&pClient->EventSrc, uEvent);
-            }
-        }
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient,
+                                          pClient->State.fGuestFeatures0 & VBOX_SHCL_GF_0_CONTEXT_ID
+                                          ? VBOX_SHCL_HOST_MSG_READ_DATA_CID : VBOX_SHCL_HOST_MSG_READ_DATA,
+                                          2);
+    if (pMsg)
+    {
+        /*
+         * Enter the critical section and generate an event.
+         */
+        RTCritSectEnter(&pClient->CritSect);
+
+        const SHCLEVENTID idEvent = ShClEventIdGenerateAndRegister(&pClient->EventSrc);
+        if (idEvent != 0)
+        {
+            LogFlowFunc(("fFormat=%#x idEvent=%#x\n", fFormat, idEvent));
+
+            /*
+             * Format the message
+             */
+            if (pMsg->idMsg == VBOX_SHCL_HOST_MSG_READ_DATA_CID)
+                HGCMSvcSetU64(&pMsg->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pClient->EventSrc.uID, idEvent));
+            else
+                HGCMSvcSetU32(&pMsg->aParms[0], VBOX_SHCL_HOST_MSG_READ_DATA);
+            HGCMSvcSetU32(&pMsg->aParms[1], fFormat);
+
+            /*
+             * Queue it and wake up the client if it's waiting on a message.
+             */
+            shClSvcMsgAddAndWakeupClient(pClient, pMsg);
+            if (pidEvent)
+                *pidEvent = idEvent;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_TRY_AGAIN;
+
+        RTCritSectLeave(&pClient->CritSect);
     }
     else
@@ -1300,65 +1249,60 @@
  * @returns VBox status code.
  * @param   pClient             Client to request to read data form.
- * @param   pFormats            Formats to report.
- */
-int ShClSvcFormatsReport(PSHCLCLIENT pClient, PSHCLFORMATDATA pFormats)
-{
+ * @param   fFormats            The formats to report (VBOX_SHCL_FMT_XXX), zero
+ *                              is okay (empty the clipboard).
+ */
+int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats)
+{
+    LogFlowFuncEnter();
     AssertPtrReturn(pClient,  VERR_INVALID_POINTER);
-    AssertPtrReturn(pFormats, VERR_INVALID_POINTER);
-
-    LogFlowFuncEnter();
-
-    uint32_t fFormats = pFormats->Formats;
-    uint32_t fFlags   = pFormats->fFlags;
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-    /* If transfer mode is set to disabled, don't report the URI list format to the guest. */
+    /*
+     * If transfer mode is set to disabled, don't report the URI list format to the guest.
+     */
     if (!(g_fTransferMode & VBOX_SHCL_TRANSFER_MODE_ENABLED))
+    {
+        LogFlowFunc(("fFormats=%#x -> %#x\n", fFormats, fFormats & ~VBOX_SHCL_FMT_URI_LIST));
         fFormats &= ~VBOX_SHCL_FMT_URI_LIST;
+    }
 #endif
-
-    LogFlowFunc(("fFormats=0x%x -> 0x%x\n", pFormats->Formats, fFormats));
-
-    /* Nothing to report? Bail out early. */
-    if (fFormats == VBOX_SHCL_FMT_NONE)
-        return VINF_SUCCESS;
-
-    LogRel2(("Shared Clipboard: Reporting formats 0x%x to guest\n", fFormats));
-
+    LogRel2(("Shared Clipboard: Reporting formats %#x to guest\n", fFormats));
+
+    /*
+     * Allocate a message, populate parameters and post it to the client.
+     */
     int rc;
-
-    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(VBOX_SHCL_HOST_MSG_FORMATS_REPORT, 3);
+    PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_FORMATS_REPORT, 2);
     if (pMsg)
     {
-        const SHCLEVENTID uEvent = ShClEventIDGenerate(&pClient->EventSrc);
-
-        HGCMSvcSetU64(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
-                                                                  pClient->EventSrc.uID, uEvent));
-        HGCMSvcSetU32(&pMsg->paParms[1], fFormats);
-        HGCMSvcSetU32(&pMsg->paParms[2], fFlags);
-
-        rc = shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
-        if (RT_SUCCESS(rc))
-        {
+        HGCMSvcSetU32(&pMsg->aParms[0], VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
+        HGCMSvcSetU32(&pMsg->aParms[1], fFormats);
+
+        RTCritSectEnter(&pClient->CritSect);
+        shClSvcMsgAddAndWakeupClient(pClient, pMsg);
+        RTCritSectLeave(&pClient->CritSect);
+
+        /*
+         * ...
+         */
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-            /* If we announce an URI list, create a transfer locally and also tell the guest to create
-             * a transfer on the guest side. */
-            if (fFormats & VBOX_SHCL_FMT_URI_LIST)
-            {
-                rc = shClSvcTransferStart(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
-                                          NULL /* pTransfer */);
-                if (RT_FAILURE(rc))
-                    LogRel(("Shared Clipboard: Initializing host write transfer failed with %Rrc\n", rc));
-            }
-            else
-            {
+# error fixme
+        /* If we announce an URI list, create a transfer locally and also tell the guest to create
+         * a transfer on the guest side. */
+        if (fFormats & VBOX_SHCL_FMT_URI_LIST)
+        {
+            rc = shClSvcTransferStart(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
+                                      NULL /* pTransfer */);
+            if (RT_FAILURE(rc))
+                LogRel(("Shared Clipboard: Initializing host write transfer failed with %Rrc\n", rc));
+        }
+        else
 #endif
-                pClient->State.fFlags |= SHCLCLIENTSTATE_FLAGS_READ_ACTIVE;
-
-                rc = shClSvcClientWakeup(pClient);
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-            }
-#endif
-        }
+        {
+            pClient->State.fFlags |= SHCLCLIENTSTATE_FLAGS_READ_ACTIVE;
+            rc = VINF_SUCCESS;
+        }
+        /** @todo r=bird: shouldn't we also call shClSvcSetSource(pClient, SHCLSOURCE_LOCAL) here??
+         * Looks like the caller of this function does it, but only on windows.  Very helpful. */
     }
     else
@@ -1575,6 +1519,6 @@
         /* Read clipboard data from the extension. */
         rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_READ, &parms, sizeof(parms));
-        LogRelFlowFunc(("DATA/Ext: fDelayedAnnouncement=%RTbool uDelayedFormats=%#x cbData=%RU32->%RU32 rc=%Rrc\n",
-                        g_ExtState.fDelayedAnnouncement, g_ExtState.uDelayedFormats, dataBlock.cbData, parms.cbData, rc));
+        LogRelFlowFunc(("DATA/Ext: fDelayedAnnouncement=%RTbool fDelayedFormats=%#x cbData=%RU32->%RU32 rc=%Rrc\n",
+                        g_ExtState.fDelayedAnnouncement, g_ExtState.fDelayedFormats, dataBlock.cbData, parms.cbData, rc));
 
         /* Did the extension send the clipboard formats yet?
@@ -1582,14 +1526,9 @@
         if (g_ExtState.fDelayedAnnouncement)
         {
-            SHCLFORMATDATA FormatData;
-            FormatData.fFlags  = 0;
-            FormatData.Formats = g_ExtState.uDelayedFormats;
-            Assert(FormatData.Formats != VBOX_SHCL_FMT_NONE); /* There better is *any* format here now. */
-
-            int rc2 = ShClSvcFormatsReport(pClient, &FormatData);
+            int rc2 = ShClSvcHostReportFormats(pClient, g_ExtState.fDelayedFormats);
             AssertRC(rc2);
 
             g_ExtState.fDelayedAnnouncement = false;
-            g_ExtState.uDelayedFormats = 0;
+            g_ExtState.fDelayedFormats = 0;
         }
 
@@ -2224,5 +2163,5 @@
 static SSMFIELD const s_aShClSSMClientMsgHdr[] =
 {
-    SSMFIELD_ENTRY(SHCLCLIENTMSG, uMsg),
+    SSMFIELD_ENTRY(SHCLCLIENTMSG, idMsg),
     SSMFIELD_ENTRY(SHCLCLIENTMSG, cParms),
     SSMFIELD_ENTRY_TERM()
@@ -2230,9 +2169,10 @@
 
 /**
- * SSM descriptor table for the VBOXSHCLMSGCTX structure.
+ * SSM descriptor table for what used to be the VBOXSHCLMSGCTX structure but is
+ * now part of SHCLCLIENTMSG.
  */
 static SSMFIELD const s_aShClSSMClientMsgCtx[] =
 {
-    SSMFIELD_ENTRY(SHCLMSGCTX, uContextID),
+    SSMFIELD_ENTRY(SHCLCLIENTMSG, idContext),
     SSMFIELD_ENTRY_TERM()
 };
@@ -2269,23 +2209,21 @@
 
     /* Serialize the client's internal message queue. */
-    rc = SSMR3PutU64(pSSM, (uint64_t)pClient->queueMsg.size());
+    uint32_t cMsgs = 0;
+    PSHCLCLIENTMSG pMsg;
+    RTListForEach(&pClient->MsgQueue, pMsg, SHCLCLIENTMSG, ListEntry)
+    {
+        cMsgs += 1;
+    }
+
+    rc = SSMR3PutU64(pSSM, cMsgs);
     AssertRCReturn(rc, rc);
 
-    for (size_t i = 0; i < pClient->queueMsg.size(); i++)
-    {
-        PSHCLCLIENTMSG pMsg = pClient->queueMsg.at(i);
-        AssertPtr(pMsg);
-
-        rc = SSMR3PutStructEx(pSSM, pMsg, sizeof(SHCLCLIENTMSG), 0 /*fFlags*/, &s_aShClSSMClientMsgHdr[0], NULL);
-        AssertRCReturn(rc, rc);
-
-        rc = SSMR3PutStructEx(pSSM, &pMsg->Ctx, sizeof(SHCLMSGCTX), 0 /*fFlags*/, &s_aShClSSMClientMsgCtx[0], NULL);
-        AssertRCReturn(rc, rc);
-
-        for (uint32_t p = 0; p < pMsg->cParms; p++)
-        {
-            rc = HGCMSvcSSMR3Put(&pMsg->paParms[p], pSSM);
-            AssertRCReturn(rc, rc);
-        }
+    RTListForEach(&pClient->MsgQueue, pMsg, SHCLCLIENTMSG, ListEntry)
+    {
+        SSMR3PutStructEx(pSSM, pMsg, sizeof(SHCLCLIENTMSG), 0 /*fFlags*/, &s_aShClSSMClientMsgHdr[0], NULL);
+        SSMR3PutStructEx(pSSM, pMsg, sizeof(SHCLCLIENTMSG), 0 /*fFlags*/, &s_aShClSSMClientMsgCtx[0], NULL);
+
+        for (uint32_t iParm = 0; iParm < pMsg->cParms; iParm++)
+            HGCMSvcSSMR3Put(&pMsg->aParms[iParm], pSSM);
     }
 
@@ -2375,27 +2313,29 @@
         for (uint64_t i = 0; i < cMsgs; i++)
         {
-            PSHCLCLIENTMSG pMsg = (PSHCLCLIENTMSG)RTMemAlloc(sizeof(SHCLCLIENTMSG));
+            union
+            {
+                SHCLCLIENTMSG Msg;
+                uint8_t abPadding[RT_UOFFSETOF(SHCLCLIENTMSG, aParms) + sizeof(VBOXHGCMSVCPARM) * 2];
+            } u;
+
+            SSMR3GetStructEx(pSSM, &u.Msg, RT_UOFFSETOF(SHCLCLIENTMSG, aParms), 0 /*fFlags*/, &s_aShClSSMClientMsgHdr[0], NULL);
+            rc = SSMR3GetStructEx(pSSM, &u.Msg, RT_UOFFSETOF(SHCLCLIENTMSG, aParms), 0 /*fFlags*/, &s_aShClSSMClientMsgCtx[0], NULL);
+            AssertRCReturn(rc, rc);
+
+            AssertLogRelMsgReturn(u.Msg.cParms <= VMMDEV_MAX_HGCM_PARMS,
+                                  ("Too many HGCM message parameters: %u (%#x)\n", u.Msg.cParms, u.Msg.cParms),
+                                  VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
+
+            PSHCLCLIENTMSG pMsg = shClSvcMsgAlloc(pClient, u.Msg.idMsg, u.Msg.cParms);
             AssertReturn(pMsg, VERR_NO_MEMORY);
-
-            SSMR3GetStructEx(pSSM, pMsg, sizeof(SHCLCLIENTMSG), 0 /*fFlags*/, &s_aShClSSMClientMsgHdr[0], NULL);
-            rc = SSMR3GetStructEx(pSSM, &pMsg->Ctx, sizeof(SHCLMSGCTX), 0 /*fFlags*/, &s_aShClSSMClientMsgCtx[0], NULL);
-            AssertRCReturnStmt(rc, RTMemFree(pMsg), rc);
-
-            AssertLogRelMsgReturnStmt(pMsg->cParms <= VMMDEV_MAX_HGCM_PARMS,
-                                      ("Too many HGCM message parameters: %u (%#x)\n", pMsg->cParms, pMsg->cParms),
-                                      RTMemFree(pMsg),
-                                      VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
-
-            pMsg->paParms = (PVBOXHGCMSVCPARM)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * pMsg->cParms);
-            AssertReturnStmt(pMsg->paParms, RTMemFree(pMsg), VERR_NO_MEMORY);
+            pMsg->idContext = u.Msg.idContext;
 
             for (uint32_t p = 0; p < pMsg->cParms; p++)
             {
-                rc = HGCMSvcSSMR3Get(&pMsg->paParms[p], pSSM);
-                AssertRCReturn(rc, rc); /* we'll leak stuff here, oh well... */
+                rc = HGCMSvcSSMR3Get(&pMsg->aParms[p], pSSM);
+                AssertRCReturnStmt(rc, shClSvcMsgFree(pClient, pMsg), rc);
             }
 
-            rc = shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
-            AssertRCReturn(rc, rc);
+            shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
         }
     }
@@ -2436,19 +2376,12 @@
             {
                 LogFlowFunc(("VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE: g_ExtState.fReadingData=%RTbool\n", g_ExtState.fReadingData));
-                if (g_ExtState.fReadingData)
+                if (!g_ExtState.fReadingData)
+                    rc = ShClSvcHostReportFormats(pClient, u32Format);
+                else
                 {
                     g_ExtState.fDelayedAnnouncement = true;
-                    g_ExtState.uDelayedFormats = u32Format;
+                    g_ExtState.fDelayedFormats = u32Format;
+                    rc = VINF_SUCCESS;
                 }
-                else if (u32Format != VBOX_SHCL_FMT_NONE)
-                {
-                    SHCLFORMATDATA formatData;
-                    RT_ZERO(formatData);
-
-                    formatData.Formats = u32Format;
-
-                    rc = ShClSvcFormatsReport(pClient, &formatData);
-                }
-
                 break;
             }
@@ -2456,14 +2389,6 @@
             /* The service extension wants read data from the guest. */
             case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
-            {
-                SHCLDATAREQ dataReq;
-                RT_ZERO(dataReq);
-
-                dataReq.uFmt   = u32Format;
-                dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
-
-                rc = ShClSvcDataReadRequest(pClient, &dataReq, NULL /* puEvent */);
+                rc = ShClSvcDataReadRequest(pClient, u32Format, NULL /* puEvent */);
                 break;
-            }
 
             default:
Index: /trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp	(revision 82526)
+++ /trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp	(revision 82527)
@@ -128,12 +128,7 @@
 
 /* Adds a host data read request message to the client's message queue. */
-static void testMsgAddReadData(PSHCLCLIENT pClient, uint32_t uFormat)
-{
-    SHCLDATAREQ dataReq;
-    RT_ZERO(dataReq);
-
-    dataReq.uFmt = uFormat;
-
-    int rc = ShClSvcDataReadRequest(pClient, &dataReq, NULL /* puEvent */);
+static void testMsgAddReadData(PSHCLCLIENT pClient, uint32_t fFormat)
+{
+    int rc = ShClSvcDataReadRequest(pClient, fFormat, NULL /* puEvent */);
     RTTESTI_CHECK_RC_OK(rc);
 }
