Index: trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h
===================================================================
--- trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h	(revision 80627)
+++ trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h	(revision 80637)
@@ -69,52 +69,9 @@
 } VBOXCLIPBOARDCLIENTMSG, *PVBOXCLIPBOARDCLIENTMSG;
 
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
 typedef struct VBOXCLIPBOARDCLIENTURISTATE
 {
-    /** Whether to start a new transfer. */
-    bool                          fTransferStart;
     /** Directory of the transfer to start. */
     SHAREDCLIPBOARDURITRANSFERDIR enmTransferDir;
 } VBOXCLIPBOARDCLIENTURISTATE, *PVBOXCLIPBOARDCLIENTURISTATE;
-#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
-
-/**
- * Structure for keeping the old client state tracking,
- * needed for compatbility to older Guest Additions (for now). Remove this later.
- */
-typedef struct VBOXCLIPBOARDCLIENTSTATEOLD
-{
-    /** The guest is waiting for a message. */
-    bool fAsync;
-    /** The guest is waiting for data from the host */
-    bool fReadPending;
-    /** Whether the host host has sent a quit message. */
-    bool fHostMsgQuit;
-    /** Whether the host host has requested reading clipboard data from the guest. */
-    bool fHostMsgReadData;
-    /** Whether the host host has reported its available formats. */
-    bool fHostMsgFormats;
-
-    struct {
-        VBOXHGCMCALLHANDLE callHandle;
-        uint32_t           cParms;
-        VBOXHGCMSVCPARM   *paParms;
-    } async;
-
-    struct {
-        VBOXHGCMCALLHANDLE callHandle;
-        uint32_t           cParms;
-        VBOXHGCMSVCPARM   *paParms;
-    } asyncRead;
-
-    struct {
-         void *pv;
-         uint32_t cb;
-         uint32_t u32Format;
-    } data;
-
-    uint32_t u32AvailableFormats;
-    uint32_t u32RequestedFormat;
-} VBOXCLIPBOARDCLIENTSTATEOLD;
 
 /**
@@ -136,8 +93,6 @@
     uint32_t                         cbChunkSize;
     SHAREDCLIPBOARDSOURCE            enmSource;
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
     /** The client's URI state. */
     VBOXCLIPBOARDCLIENTURISTATE      URI;
-#endif
 } VBOXCLIPBOARDCLIENTSTATE, *PVBOXCLIPBOARDCLIENTSTATE;
 
Index: trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp
===================================================================
--- trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 80627)
+++ trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 80637)
@@ -1699,5 +1699,4 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
-    pClientState->URI.fTransferStart = false;
     pClientState->URI.enmTransferDir = SHAREDCLIPBOARDURITRANSFERDIR_UNKNOWN;
 #else
@@ -1773,19 +1772,43 @@
 }
 
-#ifndef UNIT_TEST
 /**
- * SSM descriptor table for the VBOXCLIPBOARDCLIENTSTATEOLD structure.
- * Legacy, do not use anymore.
- */
-static SSMFIELD const g_aClipboardSSMFieldsV0[] =
-{
-    SSMFIELD_ENTRY_OLD(uClientID,               sizeof(uint32_t)),
-    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTSTATEOLD, fHostMsgQuit),
-    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTSTATEOLD, fHostMsgReadData),
-    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTSTATEOLD, fHostMsgFormats),
-    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTSTATEOLD, u32RequestedFormat),
+ * SSM descriptor table for the VBOXCLIPBOARDCLIENTSTATE structure.
+ */
+static SSMFIELD const s_aShClSSMClientState[] =
+{
+    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTSTATE, uProtocolVer),
+    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTSTATE, cbChunkSize),
+    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTSTATE, enmSource),
     SSMFIELD_ENTRY_TERM()
 };
-#endif
+
+/**
+ * SSM descriptor table for the VBOXCLIPBOARDCLIENTURISTATE structure.
+ */
+static SSMFIELD const s_aShClSSMClientURIState[] =
+{
+    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTURISTATE, enmTransferDir),
+    SSMFIELD_ENTRY_TERM()
+};
+
+/**
+ * SSM descriptor table for the header of the VBOXCLIPBOARDCLIENTMSG structure.
+ * The actual message parameters will be serialized separately.
+ */
+static SSMFIELD const s_aShClSSMClientMsgHdr[] =
+{
+    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTMSG, m_uMsg),
+    SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTMSG, m_cParms),
+    SSMFIELD_ENTRY_TERM()
+};
+
+/**
+ * SSM descriptor table for the VBOXSHCLMSGCTX structure.
+ */
+static SSMFIELD const s_aShClSSMClientMsgCtx[] =
+{
+    SSMFIELD_ENTRY(VBOXSHCLMSGCTX, uContextID),
+    SSMFIELD_ENTRY_TERM()
+};
 
 static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
@@ -1802,17 +1825,37 @@
     LogFunc(("u32ClientID=%RU32\n", u32ClientID));
 
-    //PVBOXCLIPBOARDCLIENT pClient = (PVBOXCLIPBOARDCLIENT)pvClient;
-    RT_NOREF(pvClient);
-
-    /* This field used to be the length. We're using it as a version field
-       with the high bit set. */
-    SSMR3PutU32(pSSM, UINT32_C(0x80000002));
-
-    VBOXCLIPBOARDCLIENTSTATEOLD Dummy;
-    RT_ZERO(Dummy);
-
-    int rc = SSMR3PutStructEx(pSSM, &Dummy, sizeof(Dummy),
-                              0 /*fFlags*/, &g_aClipboardSSMFieldsV0[0], NULL);
+    PVBOXCLIPBOARDCLIENT pClient = (PVBOXCLIPBOARDCLIENT)pvClient;
+    AssertPtr(pClient);
+
+    /* Write Shared Clipboard saved state version. */
+    SSMR3PutU32(pSSM, VBOX_SHARED_CLIPBOARD_SSM_VER_1);
+
+    int rc = SSMR3PutStructEx(pSSM, &pClient->State, sizeof(pClient->State), 0 /*fFlags*/, &s_aShClSSMClientState[0], NULL);
     AssertRCReturn(rc, rc);
+
+    rc = SSMR3PutStructEx(pSSM, &pClient->State.URI, sizeof(pClient->State.URI), 0 /*fFlags*/, &s_aShClSSMClientURIState[0], NULL);
+    AssertRCReturn(rc, rc);
+
+    /* Serialize the client's internal message queue. */
+    rc = SSMR3PutU64(pSSM, (uint64_t)pClient->queueMsg.size());
+    AssertRCReturn(rc, rc);
+
+    for (size_t i = 0; i < pClient->queueMsg.size(); i++)
+    {
+        PVBOXCLIPBOARDCLIENTMSG pMsg = pClient->queueMsg.at(i);
+        AssertPtr(pMsg);
+
+        rc = SSMR3PutStructEx(pSSM, pMsg, sizeof(VBOXCLIPBOARDCLIENTMSG), 0 /*fFlags*/, &s_aShClSSMClientMsgHdr[0], NULL);
+        AssertRCReturn(rc, rc);
+
+        rc = SSMR3PutStructEx(pSSM, &pMsg->m_Ctx, sizeof(VBOXSHCLMSGCTX), 0 /*fFlags*/, &s_aShClSSMClientMsgCtx[0], NULL);
+        AssertRCReturn(rc, rc);
+
+        for (uint32_t p = 0; p < pMsg->m_cParms; p++)
+        {
+            rc = HGCMSvcSSMR3Put(&pMsg->m_paParms[p], pSSM);
+            AssertRCReturn(rc, rc);
+        }
+    }
 
 #else  /* UNIT_TEST */
@@ -1822,4 +1865,37 @@
 }
 
+static int svcLoadStateV0(uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM, uint32_t uVersion)
+{
+    RT_NOREF(u32ClientID, pvClient, pSSM, uVersion);
+
+    uint32_t uMarker;
+    int rc = SSMR3GetU32(pSSM, &uMarker);   /* Begin marker. */
+    AssertRC(rc);
+    Assert(uMarker == UINT32_C(0x19200102)  /* SSMR3STRUCT_BEGIN */);
+
+    rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* Client ID */
+    AssertRCReturn(rc, rc);
+
+    bool fValue;
+    rc = SSMR3GetBool(pSSM, &fValue);       /* fHostMsgQuit */
+    AssertRCReturn(rc, rc);
+
+    rc = SSMR3GetBool(pSSM, &fValue);       /* fHostMsgReadData */
+    AssertRCReturn(rc, rc);
+
+    rc = SSMR3GetBool(pSSM, &fValue);       /* fHostMsgFormats */
+    AssertRCReturn(rc, rc);
+
+    uint32_t fFormats;
+    rc = SSMR3GetU32(pSSM, &fFormats);      /* u32RequestedFormat */
+    AssertRCReturn(rc, rc);
+
+    rc = SSMR3GetU32(pSSM, &uMarker);       /* End marker. */
+    AssertRCReturn(rc, rc);
+    Assert(uMarker == UINT32_C(0x19920406) /* SSMR3STRUCT_END */);
+
+    return VINF_SUCCESS;
+}
+
 static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM, uint32_t uVersion)
 {
@@ -1831,8 +1907,4 @@
     PVBOXCLIPBOARDCLIENT pClient = (PVBOXCLIPBOARDCLIENT)pvClient;
     AssertPtr(pClient);
-
-    /* Save the client ID for data validation. */
-    /** @todo isn't this the same as u32ClientID? Playing safe for now... */
-    uint32_t const u32ClientIDOld = pClient->State.u32ClientID;
 
     /* Restore the client data. */
@@ -1840,29 +1912,48 @@
     int rc = SSMR3GetU32(pSSM, &lenOrVer);
     AssertRCReturn(rc, rc);
-    if (lenOrVer == UINT32_C(0x80000002))
-    {
-        uint32_t uMarker;
-        rc = SSMR3GetU32(pSSM, &uMarker);      /* Begin marker. */
-        AssertRC(rc);
-        Assert(uMarker == UINT32_C(0x19200102) /* SSMR3STRUCT_BEGIN */);
-
-        rc = SSMR3Skip(pSSM, sizeof(uint32_t) + (3 * sizeof(bool)) + sizeof(uint32_t));
+    if (lenOrVer == VBOX_SHARED_CLIPBOARD_SSM_VER_0)
+    {
+        return svcLoadStateV0(u32ClientID, pvClient, pSSM, uVersion);
+    }
+    else if (lenOrVer == VBOX_SHARED_CLIPBOARD_SSM_VER_1)
+    {
+        rc = SSMR3GetStructEx(pSSM, &pClient->State, sizeof(pClient->State), 0 /*fFlags*/, &s_aShClSSMClientState[0], NULL);
         AssertRCReturn(rc, rc);
 
-        rc = SSMR3GetU32(pSSM, &uMarker);      /* End marker. */
-        AssertRC(rc);
-        Assert(uMarker == UINT32_C(0x19920406) /* SSMR3STRUCT_END */);
+        rc = SSMR3GetStructEx(pSSM, &pClient->State.URI, sizeof(pClient->State.URI), 0 /*fFlags*/, &s_aShClSSMClientURIState[0], NULL);
+        AssertRCReturn(rc, rc);
+
+        /* Load the client's internal message queue. */
+        uint64_t cMsg;
+        rc = SSMR3GetU64(pSSM, &cMsg);
+        AssertRCReturn(rc, rc);
+
+        for (uint64_t i = 0; i < cMsg; i++)
+        {
+            PVBOXCLIPBOARDCLIENTMSG pMsg = (PVBOXCLIPBOARDCLIENTMSG)RTMemAlloc(sizeof(VBOXCLIPBOARDCLIENTMSG));
+            AssertPtrReturn(pMsg, VERR_NO_MEMORY);
+
+            rc = SSMR3GetStructEx(pSSM, pMsg, sizeof(VBOXCLIPBOARDCLIENTMSG), 0 /*fFlags*/, &s_aShClSSMClientMsgHdr[0], NULL);
+            AssertRCReturn(rc, rc);
+
+            rc = SSMR3GetStructEx(pSSM, &pMsg->m_Ctx, sizeof(VBOXSHCLMSGCTX), 0 /*fFlags*/, &s_aShClSSMClientMsgCtx[0], NULL);
+            AssertRCReturn(rc, rc);
+
+            pMsg->m_paParms = (PVBOXHGCMSVCPARM)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * pMsg->m_cParms);
+            AssertPtrReturn(pMsg->m_paParms, VERR_NO_MEMORY);
+
+            for (uint32_t p = 0; p < pMsg->m_cParms; p++)
+            {
+                rc = HGCMSvcSSMR3Get(&pMsg->m_paParms[p], pSSM);
+                AssertRCReturn(rc, rc);
+            }
+
+            rc = vboxSvcClipboardMsgAdd(pClient, pMsg, true /* fAppend */);
+            AssertRCReturn(rc, rc);
+        }
     }
     else
     {
-        LogFunc(("Client data size mismatch: got %#x\n", lenOrVer));
-        return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
-    }
-
-    /* Verify the client ID. */
-    if (pClient->State.u32ClientID != u32ClientIDOld)
-    {
-        LogFunc(("Client ID mismatch: expected %d, got %d\n", u32ClientIDOld, pClient->State.u32ClientID));
-        pClient->State.u32ClientID = u32ClientIDOld;
+        LogRel(("Shared Clipboard: Unknown saved state version (%#x)\n", lenOrVer));
         return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
     }
