Index: /trunk/src/VBox/HostServices/HostChannel/Makefile.kmk
===================================================================
--- /trunk/src/VBox/HostServices/HostChannel/Makefile.kmk	(revision 76965)
+++ /trunk/src/VBox/HostServices/HostChannel/Makefile.kmk	(revision 76966)
@@ -29,9 +29,9 @@
 
 VBoxHostChannel_SOURCES = \
-	service.cpp \
+	VBoxHostChannelSvc.cpp \
 	HostChannel.cpp
 
 VBoxHostChannel_SOURCES.win = \
-	VBoxHostChannel.rc
+	VBoxHostChannelSvc.rc
 
 VBoxHostChannel_LIBS = \
Index: unk/src/VBox/HostServices/HostChannel/VBoxHostChannel.rc
===================================================================
--- /trunk/src/VBox/HostServices/HostChannel/VBoxHostChannel.rc	(revision 76965)
+++ 	(revision )
@@ -1,51 +1,0 @@
-/* $Id$ */
-/** @file
- * VBoxHostChannel - Resource file containing version info and icon.
- */
-
-/*
- * Copyright (C) 2015-2019 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#include <windows.h>
-#include <VBox/version.h>
-
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-
-VS_VERSION_INFO VERSIONINFO
-  FILEVERSION      VBOX_RC_FILE_VERSION
-  PRODUCTVERSION   VBOX_RC_FILE_VERSION
-  FILEFLAGSMASK    VS_FFI_FILEFLAGSMASK
-  FILEFLAGS        VBOX_RC_FILE_FLAGS
-  FILEOS           VBOX_RC_FILE_OS
-  FILETYPE         VBOX_RC_TYPE_DLL
-  FILESUBTYPE      VFT2_UNKNOWN
-BEGIN
-  BLOCK "StringFileInfo"
-  BEGIN
-    BLOCK "040904b0" // Lang=US English, CharSet=Unicode
-    BEGIN
-      VALUE "FileDescription",  "VirtualBox Host Channel Service\0"
-      VALUE "InternalName",     "VBoxHostChannel\0"
-      VALUE "OriginalFilename", "VBoxHostChannel.dll\0"
-      VALUE "CompanyName",      VBOX_RC_COMPANY_NAME
-      VALUE "FileVersion",      VBOX_RC_FILE_VERSION_STR
-      VALUE "LegalCopyright",   VBOX_RC_LEGAL_COPYRIGHT
-      VALUE "ProductName",      VBOX_RC_PRODUCT_NAME_STR
-      VALUE "ProductVersion",   VBOX_RC_PRODUCT_VERSION_STR
-      VBOX_RC_MORE_STRINGS
-    END
-  END
-  BLOCK "VarFileInfo"
-  BEGIN
-    VALUE "Translation", 0x409, 1200
-  END
-END
Index: /trunk/src/VBox/HostServices/HostChannel/VBoxHostChannelSvc.cpp
===================================================================
--- /trunk/src/VBox/HostServices/HostChannel/VBoxHostChannelSvc.cpp	(revision 76966)
+++ /trunk/src/VBox/HostServices/HostChannel/VBoxHostChannelSvc.cpp	(revision 76966)
@@ -0,0 +1,901 @@
+/* $Id$ */
+/* @file
+ * Host Channel: Host service entry points.
+ */
+
+/*
+ * Copyright (C) 2012-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*
+ * The HostChannel host service provides a generic proxy between a host's
+ * channel provider and a client running in the guest.
+ *
+ * Host providers must register via a HostCall.
+ *
+ * A guest client can connect to a host provider and send/receive data.
+ *
+ * GuestCalls:
+ *    * Attach      - attach to a host channel
+ *    * Detach      - completely detach from a channel
+ *    * Send        - send data from the guest to the channel
+ *    * Recv        - non blocking read of available data from the channel
+ *    * Control     - generic channel specific command exchange
+ *    * EventWait   - wait for a host event
+ *    * EventCancel - make the blocking EventWait call to return
+ * HostCalls:
+ *    * Register    - register a host channel
+ *    * Unregister  - unregister it
+ *
+ * The guest HGCM client connects to the service. The client can attach multiple channels.
+ *
+ */
+
+#include <iprt/alloc.h>
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <VBox/vmm/ssm.h>
+
+#include "HostChannel.h"
+
+
+static void VBoxHGCMParmUInt32Set(VBOXHGCMSVCPARM *pParm, uint32_t u32)
+{
+    pParm->type = VBOX_HGCM_SVC_PARM_32BIT;
+    pParm->u.uint32 = u32;
+}
+
+static int VBoxHGCMParmUInt32Get(VBOXHGCMSVCPARM *pParm, uint32_t *pu32)
+{
+    if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT)
+    {
+        *pu32 = pParm->u.uint32;
+        return VINF_SUCCESS;
+    }
+
+    AssertFailed();
+    return VERR_INVALID_PARAMETER;
+}
+
+#if 0 /* unused */
+static void VBoxHGCMParmPtrSet(VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
+{
+    pParm->type             = VBOX_HGCM_SVC_PARM_PTR;
+    pParm->u.pointer.size   = cb;
+    pParm->u.pointer.addr   = pv;
+}
+#endif
+
+static int VBoxHGCMParmPtrGet(VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb)
+{
+    if (pParm->type == VBOX_HGCM_SVC_PARM_PTR)
+    {
+        *ppv = pParm->u.pointer.addr;
+        *pcb = pParm->u.pointer.size;
+        return VINF_SUCCESS;
+    }
+
+    AssertFailed();
+    return VERR_INVALID_PARAMETER;
+}
+
+
+static PVBOXHGCMSVCHELPERS g_pHelpers = NULL;
+
+static RTCRITSECT g_critsect;
+
+/*
+ * Helpers.
+ */
+
+int vboxHostChannelLock(void)
+{
+    return RTCritSectEnter(&g_critsect);
+}
+
+void vboxHostChannelUnlock(void)
+{
+    RTCritSectLeave(&g_critsect);
+}
+
+void vboxHostChannelEventParmsSet(VBOXHGCMSVCPARM *paParms,
+                                  uint32_t u32ChannelHandle,
+                                  uint32_t u32Id,
+                                  const void *pvEvent,
+                                  uint32_t cbEvent)
+{
+    if (cbEvent > 0)
+    {
+        void *pvParm = NULL;
+        uint32_t cbParm = 0;
+
+        VBoxHGCMParmPtrGet(&paParms[2], &pvParm, &cbParm);
+
+        uint32_t cbToCopy = RT_MIN(cbParm, cbEvent);
+        if (cbToCopy > 0)
+        {
+            Assert(pvParm);
+            memcpy(pvParm, pvEvent, cbToCopy);
+        }
+    }
+
+    VBoxHGCMParmUInt32Set(&paParms[0], u32ChannelHandle);
+    VBoxHGCMParmUInt32Set(&paParms[1], u32Id);
+    VBoxHGCMParmUInt32Set(&paParms[3], cbEvent);
+}
+
+/* This is called under the lock. */
+void vboxHostChannelReportAsync(VBOXHOSTCHCLIENT *pClient,
+                                uint32_t u32ChannelHandle,
+                                uint32_t u32Id,
+                                const void *pvEvent,
+                                uint32_t cbEvent)
+{
+    Assert(RTCritSectIsOwner(&g_critsect));
+
+    vboxHostChannelEventParmsSet(pClient->async.paParms,
+                                 u32ChannelHandle,
+                                 u32Id,
+                                 pvEvent,
+                                 cbEvent);
+
+    LogRelFlow(("svcCall: CallComplete for pending\n"));
+
+    g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS);
+}
+
+
+/*
+ *  Service entry points.
+ */
+
+static DECLCALLBACK(int) svcUnload(void *pvService)
+{
+    NOREF(pvService);
+    vboxHostChannelDestroy();
+    RTCritSectDelete(&g_critsect);
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) svcDisconnect(void *pvService, uint32_t u32ClientID, void *pvClient)
+{
+    RT_NOREF2(pvService, u32ClientID);
+
+    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
+
+    vboxHostChannelClientDisconnect(pClient);
+
+    memset(pClient, 0, sizeof(VBOXHOSTCHCLIENT));
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) svcConnect(void *pvService, uint32_t u32ClientID, void *pvClient, uint32_t fRequestor, bool fRestoring)
+{
+    RT_NOREF(pvService, fRequestor, fRestoring);
+    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
+
+    /* Register the client. */
+    memset(pClient, 0, sizeof(VBOXHOSTCHCLIENT));
+
+    pClient->u32ClientID = u32ClientID;
+
+    int rc = vboxHostChannelClientConnect(pClient);
+
+    LogRel2(("svcConnect: rc = %Rrc\n", rc));
+
+    return rc;
+}
+
+static DECLCALLBACK(void) svcCall(void *pvService,
+                                  VBOXHGCMCALLHANDLE callHandle,
+                                  uint32_t u32ClientID,
+                                  void *pvClient,
+                                  uint32_t u32Function,
+                                  uint32_t cParms,
+                                  VBOXHGCMSVCPARM paParms[],
+                                  uint64_t tsArrival)
+{
+    RT_NOREF(pvService, tsArrival);
+
+    int rc = VINF_SUCCESS;
+
+    LogRel2(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
+             u32ClientID, u32Function, cParms, paParms));
+
+    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
+
+    bool fAsynchronousProcessing = false;
+
+#ifdef DEBUG
+    uint32_t i;
+
+    for (i = 0; i < cParms; i++)
+    {
+        /** @todo parameters other than 32 bit */
+        LogRel2(("    pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
+    }
+#endif
+
+    switch (u32Function)
+    {
+        case VBOX_HOST_CHANNEL_FN_ATTACH:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_ATTACH\n"));
+
+            if (cParms != 3)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR     /* name */
+                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* flags */
+                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                uint32_t u32Flags;
+                void *pvName;
+                uint32_t cbName;
+
+                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
+
+                if (RT_SUCCESS(rc))
+                {
+                    rc = VBoxHGCMParmUInt32Get(&paParms[1], &u32Flags);
+
+                    if (RT_SUCCESS(rc))
+                    {
+                        uint32_t u32Handle = 0;
+
+                        /** @todo make sure that pvName is a nul terminated */
+                        rc = vboxHostChannelAttach(pClient, &u32Handle, (const char *)pvName, u32Flags);
+
+                        if (RT_SUCCESS(rc))
+                        {
+                            VBoxHGCMParmUInt32Set(&paParms[2], u32Handle);
+                        }
+                    }
+                }
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_FN_DETACH:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_DETACH\n"));
+
+            if (cParms != 1)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                uint32_t u32Handle;
+
+                rc = VBoxHGCMParmUInt32Get(&paParms[0], &u32Handle);
+
+                if (RT_SUCCESS(rc))
+                {
+                    rc = vboxHostChannelDetach(pClient, u32Handle);
+                }
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_FN_SEND:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_SEND\n"));
+
+            if (cParms != 2)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
+                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                uint32_t u32Handle;
+                void *pvData;
+                uint32_t cbData;
+
+                rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
+
+                if (RT_SUCCESS (rc))
+                {
+                    rc = VBoxHGCMParmPtrGet (&paParms[1], &pvData, &cbData);
+
+                    if (RT_SUCCESS (rc))
+                    {
+                        rc = vboxHostChannelSend(pClient, u32Handle, pvData, cbData);
+                    }
+                }
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_FN_RECV:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_RECV\n"));
+
+            if (cParms != 4)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
+                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
+                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeReceived */
+                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeRemaining */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                uint32_t u32Handle;
+                void *pvData;
+                uint32_t cbData;
+
+                rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
+
+                if (RT_SUCCESS (rc))
+                {
+                    rc = VBoxHGCMParmPtrGet (&paParms[1], &pvData, &cbData);
+
+                    if (RT_SUCCESS (rc))
+                    {
+                        uint32_t u32SizeReceived = 0;
+                        uint32_t u32SizeRemaining = 0;
+
+                        rc = vboxHostChannelRecv(pClient, u32Handle,
+                                                 pvData, cbData,
+                                                 &u32SizeReceived, &u32SizeRemaining);
+
+                        if (RT_SUCCESS(rc))
+                        {
+                            VBoxHGCMParmUInt32Set(&paParms[2], u32SizeReceived);
+                            VBoxHGCMParmUInt32Set(&paParms[3], u32SizeRemaining);
+                        }
+                    }
+                }
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_FN_CONTROL:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_CONTROL\n"));
+
+            if (cParms != 5)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
+                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* code */
+                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR     /* parm */
+                     || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
+                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeDataReturned */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                uint32_t u32Handle;
+                uint32_t u32Code;
+                void *pvParm;
+                uint32_t cbParm;
+                void *pvData;
+                uint32_t cbData;
+
+                rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
+
+                if (RT_SUCCESS (rc))
+                {
+                    rc = VBoxHGCMParmUInt32Get (&paParms[1], &u32Code);
+
+                    if (RT_SUCCESS (rc))
+                    {
+                        rc = VBoxHGCMParmPtrGet (&paParms[2], &pvParm, &cbParm);
+
+                        if (RT_SUCCESS (rc))
+                        {
+                            rc = VBoxHGCMParmPtrGet (&paParms[3], &pvData, &cbData);
+
+                            if (RT_SUCCESS (rc))
+                            {
+                                uint32_t u32SizeDataReturned = 0;
+
+                                rc = vboxHostChannelControl(pClient, u32Handle, u32Code,
+                                                            pvParm, cbParm,
+                                                            pvData, cbData, &u32SizeDataReturned);
+                                if (RT_SUCCESS(rc))
+                                {
+                                    VBoxHGCMParmUInt32Set(&paParms[4], u32SizeDataReturned);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_FN_EVENT_WAIT:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_WAIT\n"));
+
+            if (cParms != 4)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
+                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* id */
+                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR     /* parm */
+                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeReturned */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                bool fEvent = false;
+
+                rc = vboxHostChannelEventWait(pClient, &fEvent, callHandle, paParms);
+
+                if (RT_SUCCESS(rc))
+                {
+                    if (!fEvent)
+                    {
+                        /* No event available at the time. Process asynchronously. */
+                        fAsynchronousProcessing = true;
+
+                        LogRel2(("svcCall: async.\n"));
+                    }
+                }
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_FN_EVENT_CANCEL:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_CANCEL\n"));
+
+            if (cParms != 0)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                rc = vboxHostChannelEventCancel(pClient);
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_FN_QUERY:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_QUERY\n"));
+
+            if (cParms != 5)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR     /* channel name */
+                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* code */
+                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR     /* parm */
+                     || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
+                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeDataReturned */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                void *pvName;
+                uint32_t cbName;
+                uint32_t u32Code;
+                void *pvParm;
+                uint32_t cbParm;
+                void *pvData;
+                uint32_t cbData;
+
+                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
+
+                if (RT_SUCCESS (rc))
+                {
+                    rc = VBoxHGCMParmUInt32Get (&paParms[1], &u32Code);
+
+                    if (RT_SUCCESS (rc))
+                    {
+                        rc = VBoxHGCMParmPtrGet (&paParms[2], &pvParm, &cbParm);
+
+                        if (RT_SUCCESS (rc))
+                        {
+                            rc = VBoxHGCMParmPtrGet (&paParms[3], &pvData, &cbData);
+
+                            if (RT_SUCCESS (rc))
+                            {
+                                uint32_t u32SizeDataReturned = 0;
+
+                                /** @todo make sure that pvName is a nul terminated */
+                                rc = vboxHostChannelQuery(pClient, (const char *)pvName, u32Code,
+                                                          pvParm, cbParm,
+                                                          pvData, cbData, &u32SizeDataReturned);
+                                if (RT_SUCCESS(rc))
+                                {
+                                    VBoxHGCMParmUInt32Set(&paParms[4], u32SizeDataReturned);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } break;
+
+        default:
+        {
+            rc = VERR_NOT_IMPLEMENTED;
+        }
+    }
+
+    LogRelFlow(("svcCall: rc = %Rrc, async %d\n", rc, fAsynchronousProcessing));
+
+    if (!fAsynchronousProcessing)
+    {
+        g_pHelpers->pfnCallComplete(callHandle, rc);
+    }
+}
+
+static DECLCALLBACK(int) svcHostCall(void *pvService,
+                                     uint32_t u32Function,
+                                     uint32_t cParms,
+                                     VBOXHGCMSVCPARM paParms[])
+{
+    NOREF(pvService);
+
+    int rc = VINF_SUCCESS;
+
+    LogRel2(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
+             u32Function, cParms, paParms));
+
+    switch (u32Function)
+    {
+        case VBOX_HOST_CHANNEL_HOST_FN_REGISTER:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_REGISTER\n"));
+
+            if (cParms != 2)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
+                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* iface */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                void *pvName;
+                uint32_t cbName;
+                void *pvInterface;
+                uint32_t cbInterface;
+
+                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
+
+                if (RT_SUCCESS(rc))
+                {
+                    rc = VBoxHGCMParmPtrGet(&paParms[1], &pvInterface, &cbInterface);
+
+                    if (RT_SUCCESS(rc))
+                    {
+                        rc = vboxHostChannelRegister((const char *)pvName,
+                                                     (VBOXHOSTCHANNELINTERFACE *)pvInterface, cbInterface);
+                    }
+                }
+            }
+        } break;
+
+        case VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER:
+        {
+            LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER\n"));
+
+            if (cParms != 1)
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
+                    )
+            {
+                rc = VERR_INVALID_PARAMETER;
+            }
+            else
+            {
+                void *pvName;
+                uint32_t cbName;
+
+                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
+
+                if (RT_SUCCESS(rc))
+                {
+                    rc = vboxHostChannelUnregister((const char *)pvName);
+                }
+            }
+        } break;
+
+        default:
+            break;
+    }
+
+    LogRelFlow(("svcHostCall: rc = %Rrc\n", rc));
+    return rc;
+}
+
+#if 0
+/** If the client in the guest is waiting for a read operation to complete
+ * then complete it, otherwise return.  See the protocol description in the
+ * shared clipboard module description. */
+void vboxSvcClipboardCompleteReadData(VBOXHOSTCHCLIENT *pClient, int rc, uint32_t cbActual)
+{
+    VBOXHGCMCALLHANDLE callHandle = NULL;
+    VBOXHGCMSVCPARM *paParms = NULL;
+    bool fReadPending = false;
+    if (vboxSvcClipboardLock())  /* if not can we do anything useful? */
+    {
+        callHandle   = pClient->asyncRead.callHandle;
+        paParms      = pClient->asyncRead.paParms;
+        fReadPending = pClient->fReadPending;
+        pClient->fReadPending = false;
+        vboxSvcClipboardUnlock();
+    }
+    if (fReadPending)
+    {
+        VBoxHGCMParmUInt32Set (&paParms[2], cbActual);
+        g_pHelpers->pfnCallComplete (callHandle, rc);
+    }
+}
+
+/**
+ * SSM descriptor table for the VBOXHOSTCHCLIENT structure.
+ */
+static SSMFIELD const g_aClipboardClientDataFields[] =
+{
+    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32ClientID),  /* for validation purposes */
+    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgQuit),
+    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgReadData),
+    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgFormats),
+    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32RequestedFormat),
+    SSMFIELD_ENTRY_TERM()
+};
+
+static DECLCALLBACK(int) svcSaveState(void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
+{
+    NOREF(pvService);
+
+    /* If there are any pending requests, they must be completed here. Since
+     * the service is single threaded, there could be only requests
+     * which the service itself has postponed.
+     *
+     * HGCM knows that the state is being saved and that the pfnComplete
+     * calls are just clean ups. These requests are saved by the VMMDev.
+     *
+     * When the state will be restored, these requests will be reissued
+     * by VMMDev. The service therefore must save state as if there were no
+     * pending request.
+     */
+    LogRel2 (("svcSaveState: u32ClientID = %d\n", u32ClientID));
+
+    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)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));
+    int rc = SSMR3PutStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
+    AssertRCReturn (rc, rc);
+
+    if (pClient->fAsync)
+    {
+        g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
+        pClient->fAsync = false;
+    }
+
+    vboxSvcClipboardCompleteReadData (pClient, VINF_SUCCESS, 0);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * This structure corresponds to the original layout of the
+ * VBOXHOSTCHCLIENT structure.  As the structure was saved as a whole
+ * when saving state, we need to remember it forever in order to preserve
+ * compatibility.
+ *
+ * (Starting with 3.1 this is no longer used.)
+ *
+ * @remarks Putting this outside svcLoadState to avoid visibility warning caused
+ *          by -Wattributes.
+ */
+typedef struct CLIPSAVEDSTATEDATA
+{
+    struct CLIPSAVEDSTATEDATA *pNext;
+    struct CLIPSAVEDSTATEDATA *pPrev;
+
+    VBOXCLIPBOARDCONTEXT *pCtx;
+
+    uint32_t u32ClientID;
+
+    bool fAsync: 1; /* Guest is waiting for a message. */
+
+    bool fMsgQuit: 1;
+    bool fMsgReadData: 1;
+    bool fMsgFormats: 1;
+
+    struct {
+        VBOXHGCMCALLHANDLE callHandle;
+        VBOXHGCMSVCPARM *paParms;
+    } async;
+
+    struct {
+         void *pv;
+         uint32_t cb;
+         uint32_t u32Format;
+    } data;
+
+    uint32_t u32AvailableFormats;
+    uint32_t u32RequestedFormat;
+
+} CLIPSAVEDSTATEDATA;
+
+static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
+{
+    LogRel2 (("svcLoadState: u32ClientID = %d\n", u32ClientID));
+
+    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
+
+    /* Existing client can not be in async state yet. */
+    Assert (!pClient->fAsync);
+
+    /* Save the client ID for data validation. */
+    /** @todo isn't this the same as u32ClientID? Playing safe for now... */
+    uint32_t const u32ClientIDOld = pClient->u32ClientID;
+
+    /* Restore the client data. */
+    uint32_t lenOrVer;
+    int rc = SSMR3GetU32 (pSSM, &lenOrVer);
+    AssertRCReturn (rc, rc);
+    if (lenOrVer == UINT32_C (0x80000002))
+    {
+        rc = SSMR3GetStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
+        AssertRCReturn (rc, rc);
+    }
+    else if (lenOrVer == (SSMR3HandleHostBits (pSSM) == 64 ? 72 : 48))
+    {
+        /**
+         * SSM descriptor table for the CLIPSAVEDSTATEDATA structure.
+         */
+        static SSMFIELD const s_aClipSavedStateDataFields30[] =
+        {
+            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, pNext),
+            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, pPrev),
+            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, pCtx),
+            SSMFIELD_ENTRY(                 CLIPSAVEDSTATEDATA, u32ClientID),
+            SSMFIELD_ENTRY_CUSTOM(fMsgQuit+fMsgReadData+fMsgFormats, RT_OFFSETOF(CLIPSAVEDSTATEDATA, u32ClientID) + 4, 4),
+            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, async.callHandle),
+            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, async.paParms),
+            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, data.pv),
+            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, data.cb),
+            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, data.u32Format),
+            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, u32AvailableFormats),
+            SSMFIELD_ENTRY(                 CLIPSAVEDSTATEDATA, u32RequestedFormat),
+            SSMFIELD_ENTRY_TERM()
+        };
+
+        CLIPSAVEDSTATEDATA savedState;
+        RT_ZERO (savedState);
+        rc = SSMR3GetStructEx (pSSM, &savedState, sizeof(savedState), SSMSTRUCT_FLAGS_MEM_BAND_AID,
+                               &s_aClipSavedStateDataFields30[0], NULL);
+        AssertRCReturn (rc, rc);
+
+        pClient->fMsgQuit           = savedState.fMsgQuit;
+        pClient->fMsgReadData       = savedState.fMsgReadData;
+        pClient->fMsgFormats        = savedState.fMsgFormats;
+        pClient->u32RequestedFormat = savedState.u32RequestedFormat;
+    }
+    else
+    {
+        LogRel (("Client data size mismatch: got %#x\n", lenOrVer));
+        return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
+    }
+
+    /* Verify the client ID. */
+    if (pClient->u32ClientID != u32ClientIDOld)
+    {
+        LogRel (("Client ID mismatch: expected %d, got %d\n", u32ClientIDOld, pClient->u32ClientID));
+        pClient->u32ClientID = u32ClientIDOld;
+        return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
+    }
+
+    /* Actual host data are to be reported to guest (SYNC). */
+    vboxClipboardSync (pClient);
+
+    return VINF_SUCCESS;
+}
+#endif
+
+static int svcInit(void)
+{
+    int rc = RTCritSectInit(&g_critsect);
+
+    if (RT_SUCCESS (rc))
+    {
+        rc = vboxHostChannelInit();
+
+        /* Clean up on failure, because 'svnUnload' will not be called
+         * if the 'svcInit' returns an error.
+         */
+        if (RT_FAILURE(rc))
+        {
+            RTCritSectDelete(&g_critsect);
+        }
+    }
+
+    return rc;
+}
+
+extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
+{
+    int rc = VINF_SUCCESS;
+
+    LogRelFlowFunc(("pTable = %p\n", pTable));
+
+    if (!pTable)
+    {
+        rc = VERR_INVALID_PARAMETER;
+    }
+    else
+    {
+        LogRel2(("VBoxHGCMSvcLoad: pTable->cbSize = %d, pTable->u32Version = 0x%08X\n",
+                  pTable->cbSize, pTable->u32Version));
+
+        if (   pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
+            || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
+        {
+            rc = VERR_INVALID_PARAMETER;
+        }
+        else
+        {
+            g_pHelpers = pTable->pHelpers;
+
+            pTable->cbClient = sizeof(VBOXHOSTCHCLIENT);
+
+            pTable->pfnUnload     = svcUnload;
+            pTable->pfnConnect    = svcConnect;
+            pTable->pfnDisconnect = svcDisconnect;
+            pTable->pfnCall       = svcCall;
+            pTable->pfnHostCall   = svcHostCall;
+            pTable->pfnSaveState  = NULL; // svcSaveState;
+            pTable->pfnLoadState  = NULL; // svcLoadState;
+            pTable->pfnRegisterExtension  = NULL;
+            pTable->pvService     = NULL;
+
+            /* Service specific initialization. */
+            rc = svcInit();
+        }
+    }
+
+    return rc;
+}
Index: /trunk/src/VBox/HostServices/HostChannel/VBoxHostChannelSvc.rc
===================================================================
--- /trunk/src/VBox/HostServices/HostChannel/VBoxHostChannelSvc.rc	(revision 76966)
+++ /trunk/src/VBox/HostServices/HostChannel/VBoxHostChannelSvc.rc	(revision 76966)
@@ -0,0 +1,51 @@
+/* $Id$ */
+/** @file
+ * VBoxHostChannel - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION      VBOX_RC_FILE_VERSION
+  PRODUCTVERSION   VBOX_RC_FILE_VERSION
+  FILEFLAGSMASK    VS_FFI_FILEFLAGSMASK
+  FILEFLAGS        VBOX_RC_FILE_FLAGS
+  FILEOS           VBOX_RC_FILE_OS
+  FILETYPE         VBOX_RC_TYPE_DLL
+  FILESUBTYPE      VFT2_UNKNOWN
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+    BEGIN
+      VALUE "FileDescription",  "VirtualBox Host Channel Service\0"
+      VALUE "InternalName",     "VBoxHostChannel\0"
+      VALUE "OriginalFilename", "VBoxHostChannel.dll\0"
+      VALUE "CompanyName",      VBOX_RC_COMPANY_NAME
+      VALUE "FileVersion",      VBOX_RC_FILE_VERSION_STR
+      VALUE "LegalCopyright",   VBOX_RC_LEGAL_COPYRIGHT
+      VALUE "ProductName",      VBOX_RC_PRODUCT_NAME_STR
+      VALUE "ProductVersion",   VBOX_RC_PRODUCT_VERSION_STR
+      VBOX_RC_MORE_STRINGS
+    END
+  END
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x409, 1200
+  END
+END
Index: unk/src/VBox/HostServices/HostChannel/service.cpp
===================================================================
--- /trunk/src/VBox/HostServices/HostChannel/service.cpp	(revision 76965)
+++ 	(revision )
@@ -1,901 +1,0 @@
-/* $Id$ */
-/* @file
- * Host Channel: Host service entry points.
- */
-
-/*
- * Copyright (C) 2012-2019 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*
- * The HostChannel host service provides a generic proxy between a host's
- * channel provider and a client running in the guest.
- *
- * Host providers must register via a HostCall.
- *
- * A guest client can connect to a host provider and send/receive data.
- *
- * GuestCalls:
- *    * Attach      - attach to a host channel
- *    * Detach      - completely detach from a channel
- *    * Send        - send data from the guest to the channel
- *    * Recv        - non blocking read of available data from the channel
- *    * Control     - generic channel specific command exchange
- *    * EventWait   - wait for a host event
- *    * EventCancel - make the blocking EventWait call to return
- * HostCalls:
- *    * Register    - register a host channel
- *    * Unregister  - unregister it
- *
- * The guest HGCM client connects to the service. The client can attach multiple channels.
- *
- */
-
-#include <iprt/alloc.h>
-#include <iprt/string.h>
-#include <iprt/assert.h>
-#include <iprt/critsect.h>
-#include <VBox/vmm/ssm.h>
-
-#include "HostChannel.h"
-
-
-static void VBoxHGCMParmUInt32Set(VBOXHGCMSVCPARM *pParm, uint32_t u32)
-{
-    pParm->type = VBOX_HGCM_SVC_PARM_32BIT;
-    pParm->u.uint32 = u32;
-}
-
-static int VBoxHGCMParmUInt32Get(VBOXHGCMSVCPARM *pParm, uint32_t *pu32)
-{
-    if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT)
-    {
-        *pu32 = pParm->u.uint32;
-        return VINF_SUCCESS;
-    }
-
-    AssertFailed();
-    return VERR_INVALID_PARAMETER;
-}
-
-#if 0 /* unused */
-static void VBoxHGCMParmPtrSet(VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
-{
-    pParm->type             = VBOX_HGCM_SVC_PARM_PTR;
-    pParm->u.pointer.size   = cb;
-    pParm->u.pointer.addr   = pv;
-}
-#endif
-
-static int VBoxHGCMParmPtrGet(VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb)
-{
-    if (pParm->type == VBOX_HGCM_SVC_PARM_PTR)
-    {
-        *ppv = pParm->u.pointer.addr;
-        *pcb = pParm->u.pointer.size;
-        return VINF_SUCCESS;
-    }
-
-    AssertFailed();
-    return VERR_INVALID_PARAMETER;
-}
-
-
-static PVBOXHGCMSVCHELPERS g_pHelpers = NULL;
-
-static RTCRITSECT g_critsect;
-
-/*
- * Helpers.
- */
-
-int vboxHostChannelLock(void)
-{
-    return RTCritSectEnter(&g_critsect);
-}
-
-void vboxHostChannelUnlock(void)
-{
-    RTCritSectLeave(&g_critsect);
-}
-
-void vboxHostChannelEventParmsSet(VBOXHGCMSVCPARM *paParms,
-                                  uint32_t u32ChannelHandle,
-                                  uint32_t u32Id,
-                                  const void *pvEvent,
-                                  uint32_t cbEvent)
-{
-    if (cbEvent > 0)
-    {
-        void *pvParm = NULL;
-        uint32_t cbParm = 0;
-
-        VBoxHGCMParmPtrGet(&paParms[2], &pvParm, &cbParm);
-
-        uint32_t cbToCopy = RT_MIN(cbParm, cbEvent);
-        if (cbToCopy > 0)
-        {
-            Assert(pvParm);
-            memcpy(pvParm, pvEvent, cbToCopy);
-        }
-    }
-
-    VBoxHGCMParmUInt32Set(&paParms[0], u32ChannelHandle);
-    VBoxHGCMParmUInt32Set(&paParms[1], u32Id);
-    VBoxHGCMParmUInt32Set(&paParms[3], cbEvent);
-}
-
-/* This is called under the lock. */
-void vboxHostChannelReportAsync(VBOXHOSTCHCLIENT *pClient,
-                                uint32_t u32ChannelHandle,
-                                uint32_t u32Id,
-                                const void *pvEvent,
-                                uint32_t cbEvent)
-{
-    Assert(RTCritSectIsOwner(&g_critsect));
-
-    vboxHostChannelEventParmsSet(pClient->async.paParms,
-                                 u32ChannelHandle,
-                                 u32Id,
-                                 pvEvent,
-                                 cbEvent);
-
-    LogRelFlow(("svcCall: CallComplete for pending\n"));
-
-    g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS);
-}
-
-
-/*
- *  Service entry points.
- */
-
-static DECLCALLBACK(int) svcUnload(void *pvService)
-{
-    NOREF(pvService);
-    vboxHostChannelDestroy();
-    RTCritSectDelete(&g_critsect);
-    return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) svcDisconnect(void *pvService, uint32_t u32ClientID, void *pvClient)
-{
-    RT_NOREF2(pvService, u32ClientID);
-
-    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
-
-    vboxHostChannelClientDisconnect(pClient);
-
-    memset(pClient, 0, sizeof(VBOXHOSTCHCLIENT));
-
-    return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) svcConnect(void *pvService, uint32_t u32ClientID, void *pvClient, uint32_t fRequestor, bool fRestoring)
-{
-    RT_NOREF(pvService, fRequestor, fRestoring);
-    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
-
-    /* Register the client. */
-    memset(pClient, 0, sizeof(VBOXHOSTCHCLIENT));
-
-    pClient->u32ClientID = u32ClientID;
-
-    int rc = vboxHostChannelClientConnect(pClient);
-
-    LogRel2(("svcConnect: rc = %Rrc\n", rc));
-
-    return rc;
-}
-
-static DECLCALLBACK(void) svcCall(void *pvService,
-                                  VBOXHGCMCALLHANDLE callHandle,
-                                  uint32_t u32ClientID,
-                                  void *pvClient,
-                                  uint32_t u32Function,
-                                  uint32_t cParms,
-                                  VBOXHGCMSVCPARM paParms[],
-                                  uint64_t tsArrival)
-{
-    RT_NOREF(pvService, tsArrival);
-
-    int rc = VINF_SUCCESS;
-
-    LogRel2(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
-             u32ClientID, u32Function, cParms, paParms));
-
-    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
-
-    bool fAsynchronousProcessing = false;
-
-#ifdef DEBUG
-    uint32_t i;
-
-    for (i = 0; i < cParms; i++)
-    {
-        /** @todo parameters other than 32 bit */
-        LogRel2(("    pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
-    }
-#endif
-
-    switch (u32Function)
-    {
-        case VBOX_HOST_CHANNEL_FN_ATTACH:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_ATTACH\n"));
-
-            if (cParms != 3)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR     /* name */
-                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* flags */
-                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                uint32_t u32Flags;
-                void *pvName;
-                uint32_t cbName;
-
-                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
-
-                if (RT_SUCCESS(rc))
-                {
-                    rc = VBoxHGCMParmUInt32Get(&paParms[1], &u32Flags);
-
-                    if (RT_SUCCESS(rc))
-                    {
-                        uint32_t u32Handle = 0;
-
-                        /** @todo make sure that pvName is a nul terminated */
-                        rc = vboxHostChannelAttach(pClient, &u32Handle, (const char *)pvName, u32Flags);
-
-                        if (RT_SUCCESS(rc))
-                        {
-                            VBoxHGCMParmUInt32Set(&paParms[2], u32Handle);
-                        }
-                    }
-                }
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_FN_DETACH:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_DETACH\n"));
-
-            if (cParms != 1)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                uint32_t u32Handle;
-
-                rc = VBoxHGCMParmUInt32Get(&paParms[0], &u32Handle);
-
-                if (RT_SUCCESS(rc))
-                {
-                    rc = vboxHostChannelDetach(pClient, u32Handle);
-                }
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_FN_SEND:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_SEND\n"));
-
-            if (cParms != 2)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
-                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                uint32_t u32Handle;
-                void *pvData;
-                uint32_t cbData;
-
-                rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
-
-                if (RT_SUCCESS (rc))
-                {
-                    rc = VBoxHGCMParmPtrGet (&paParms[1], &pvData, &cbData);
-
-                    if (RT_SUCCESS (rc))
-                    {
-                        rc = vboxHostChannelSend(pClient, u32Handle, pvData, cbData);
-                    }
-                }
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_FN_RECV:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_RECV\n"));
-
-            if (cParms != 4)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
-                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
-                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeReceived */
-                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeRemaining */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                uint32_t u32Handle;
-                void *pvData;
-                uint32_t cbData;
-
-                rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
-
-                if (RT_SUCCESS (rc))
-                {
-                    rc = VBoxHGCMParmPtrGet (&paParms[1], &pvData, &cbData);
-
-                    if (RT_SUCCESS (rc))
-                    {
-                        uint32_t u32SizeReceived = 0;
-                        uint32_t u32SizeRemaining = 0;
-
-                        rc = vboxHostChannelRecv(pClient, u32Handle,
-                                                 pvData, cbData,
-                                                 &u32SizeReceived, &u32SizeRemaining);
-
-                        if (RT_SUCCESS(rc))
-                        {
-                            VBoxHGCMParmUInt32Set(&paParms[2], u32SizeReceived);
-                            VBoxHGCMParmUInt32Set(&paParms[3], u32SizeRemaining);
-                        }
-                    }
-                }
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_FN_CONTROL:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_CONTROL\n"));
-
-            if (cParms != 5)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
-                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* code */
-                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR     /* parm */
-                     || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
-                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeDataReturned */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                uint32_t u32Handle;
-                uint32_t u32Code;
-                void *pvParm;
-                uint32_t cbParm;
-                void *pvData;
-                uint32_t cbData;
-
-                rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
-
-                if (RT_SUCCESS (rc))
-                {
-                    rc = VBoxHGCMParmUInt32Get (&paParms[1], &u32Code);
-
-                    if (RT_SUCCESS (rc))
-                    {
-                        rc = VBoxHGCMParmPtrGet (&paParms[2], &pvParm, &cbParm);
-
-                        if (RT_SUCCESS (rc))
-                        {
-                            rc = VBoxHGCMParmPtrGet (&paParms[3], &pvData, &cbData);
-
-                            if (RT_SUCCESS (rc))
-                            {
-                                uint32_t u32SizeDataReturned = 0;
-
-                                rc = vboxHostChannelControl(pClient, u32Handle, u32Code,
-                                                            pvParm, cbParm,
-                                                            pvData, cbData, &u32SizeDataReturned);
-                                if (RT_SUCCESS(rc))
-                                {
-                                    VBoxHGCMParmUInt32Set(&paParms[4], u32SizeDataReturned);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_FN_EVENT_WAIT:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_WAIT\n"));
-
-            if (cParms != 4)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT   /* handle */
-                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* id */
-                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR     /* parm */
-                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeReturned */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                bool fEvent = false;
-
-                rc = vboxHostChannelEventWait(pClient, &fEvent, callHandle, paParms);
-
-                if (RT_SUCCESS(rc))
-                {
-                    if (!fEvent)
-                    {
-                        /* No event available at the time. Process asynchronously. */
-                        fAsynchronousProcessing = true;
-
-                        LogRel2(("svcCall: async.\n"));
-                    }
-                }
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_FN_EVENT_CANCEL:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_CANCEL\n"));
-
-            if (cParms != 0)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                rc = vboxHostChannelEventCancel(pClient);
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_FN_QUERY:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_QUERY\n"));
-
-            if (cParms != 5)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR     /* channel name */
-                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT   /* code */
-                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR     /* parm */
-                     || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR     /* data */
-                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT   /* sizeDataReturned */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                void *pvName;
-                uint32_t cbName;
-                uint32_t u32Code;
-                void *pvParm;
-                uint32_t cbParm;
-                void *pvData;
-                uint32_t cbData;
-
-                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
-
-                if (RT_SUCCESS (rc))
-                {
-                    rc = VBoxHGCMParmUInt32Get (&paParms[1], &u32Code);
-
-                    if (RT_SUCCESS (rc))
-                    {
-                        rc = VBoxHGCMParmPtrGet (&paParms[2], &pvParm, &cbParm);
-
-                        if (RT_SUCCESS (rc))
-                        {
-                            rc = VBoxHGCMParmPtrGet (&paParms[3], &pvData, &cbData);
-
-                            if (RT_SUCCESS (rc))
-                            {
-                                uint32_t u32SizeDataReturned = 0;
-
-                                /** @todo make sure that pvName is a nul terminated */
-                                rc = vboxHostChannelQuery(pClient, (const char *)pvName, u32Code,
-                                                          pvParm, cbParm,
-                                                          pvData, cbData, &u32SizeDataReturned);
-                                if (RT_SUCCESS(rc))
-                                {
-                                    VBoxHGCMParmUInt32Set(&paParms[4], u32SizeDataReturned);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        } break;
-
-        default:
-        {
-            rc = VERR_NOT_IMPLEMENTED;
-        }
-    }
-
-    LogRelFlow(("svcCall: rc = %Rrc, async %d\n", rc, fAsynchronousProcessing));
-
-    if (!fAsynchronousProcessing)
-    {
-        g_pHelpers->pfnCallComplete(callHandle, rc);
-    }
-}
-
-static DECLCALLBACK(int) svcHostCall(void *pvService,
-                                     uint32_t u32Function,
-                                     uint32_t cParms,
-                                     VBOXHGCMSVCPARM paParms[])
-{
-    NOREF(pvService);
-
-    int rc = VINF_SUCCESS;
-
-    LogRel2(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
-             u32Function, cParms, paParms));
-
-    switch (u32Function)
-    {
-        case VBOX_HOST_CHANNEL_HOST_FN_REGISTER:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_REGISTER\n"));
-
-            if (cParms != 2)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
-                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* iface */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                void *pvName;
-                uint32_t cbName;
-                void *pvInterface;
-                uint32_t cbInterface;
-
-                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
-
-                if (RT_SUCCESS(rc))
-                {
-                    rc = VBoxHGCMParmPtrGet(&paParms[1], &pvInterface, &cbInterface);
-
-                    if (RT_SUCCESS(rc))
-                    {
-                        rc = vboxHostChannelRegister((const char *)pvName,
-                                                     (VBOXHOSTCHANNELINTERFACE *)pvInterface, cbInterface);
-                    }
-                }
-            }
-        } break;
-
-        case VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER:
-        {
-            LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER\n"));
-
-            if (cParms != 1)
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else if (   paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
-                    )
-            {
-                rc = VERR_INVALID_PARAMETER;
-            }
-            else
-            {
-                void *pvName;
-                uint32_t cbName;
-
-                rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
-
-                if (RT_SUCCESS(rc))
-                {
-                    rc = vboxHostChannelUnregister((const char *)pvName);
-                }
-            }
-        } break;
-
-        default:
-            break;
-    }
-
-    LogRelFlow(("svcHostCall: rc = %Rrc\n", rc));
-    return rc;
-}
-
-#if 0
-/** If the client in the guest is waiting for a read operation to complete
- * then complete it, otherwise return.  See the protocol description in the
- * shared clipboard module description. */
-void vboxSvcClipboardCompleteReadData(VBOXHOSTCHCLIENT *pClient, int rc, uint32_t cbActual)
-{
-    VBOXHGCMCALLHANDLE callHandle = NULL;
-    VBOXHGCMSVCPARM *paParms = NULL;
-    bool fReadPending = false;
-    if (vboxSvcClipboardLock())  /* if not can we do anything useful? */
-    {
-        callHandle   = pClient->asyncRead.callHandle;
-        paParms      = pClient->asyncRead.paParms;
-        fReadPending = pClient->fReadPending;
-        pClient->fReadPending = false;
-        vboxSvcClipboardUnlock();
-    }
-    if (fReadPending)
-    {
-        VBoxHGCMParmUInt32Set (&paParms[2], cbActual);
-        g_pHelpers->pfnCallComplete (callHandle, rc);
-    }
-}
-
-/**
- * SSM descriptor table for the VBOXHOSTCHCLIENT structure.
- */
-static SSMFIELD const g_aClipboardClientDataFields[] =
-{
-    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32ClientID),  /* for validation purposes */
-    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgQuit),
-    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgReadData),
-    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgFormats),
-    SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32RequestedFormat),
-    SSMFIELD_ENTRY_TERM()
-};
-
-static DECLCALLBACK(int) svcSaveState(void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
-{
-    NOREF(pvService);
-
-    /* If there are any pending requests, they must be completed here. Since
-     * the service is single threaded, there could be only requests
-     * which the service itself has postponed.
-     *
-     * HGCM knows that the state is being saved and that the pfnComplete
-     * calls are just clean ups. These requests are saved by the VMMDev.
-     *
-     * When the state will be restored, these requests will be reissued
-     * by VMMDev. The service therefore must save state as if there were no
-     * pending request.
-     */
-    LogRel2 (("svcSaveState: u32ClientID = %d\n", u32ClientID));
-
-    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)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));
-    int rc = SSMR3PutStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
-    AssertRCReturn (rc, rc);
-
-    if (pClient->fAsync)
-    {
-        g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
-        pClient->fAsync = false;
-    }
-
-    vboxSvcClipboardCompleteReadData (pClient, VINF_SUCCESS, 0);
-
-    return VINF_SUCCESS;
-}
-
-/**
- * This structure corresponds to the original layout of the
- * VBOXHOSTCHCLIENT structure.  As the structure was saved as a whole
- * when saving state, we need to remember it forever in order to preserve
- * compatibility.
- *
- * (Starting with 3.1 this is no longer used.)
- *
- * @remarks Putting this outside svcLoadState to avoid visibility warning caused
- *          by -Wattributes.
- */
-typedef struct CLIPSAVEDSTATEDATA
-{
-    struct CLIPSAVEDSTATEDATA *pNext;
-    struct CLIPSAVEDSTATEDATA *pPrev;
-
-    VBOXCLIPBOARDCONTEXT *pCtx;
-
-    uint32_t u32ClientID;
-
-    bool fAsync: 1; /* Guest is waiting for a message. */
-
-    bool fMsgQuit: 1;
-    bool fMsgReadData: 1;
-    bool fMsgFormats: 1;
-
-    struct {
-        VBOXHGCMCALLHANDLE callHandle;
-        VBOXHGCMSVCPARM *paParms;
-    } async;
-
-    struct {
-         void *pv;
-         uint32_t cb;
-         uint32_t u32Format;
-    } data;
-
-    uint32_t u32AvailableFormats;
-    uint32_t u32RequestedFormat;
-
-} CLIPSAVEDSTATEDATA;
-
-static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
-{
-    LogRel2 (("svcLoadState: u32ClientID = %d\n", u32ClientID));
-
-    VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
-
-    /* Existing client can not be in async state yet. */
-    Assert (!pClient->fAsync);
-
-    /* Save the client ID for data validation. */
-    /** @todo isn't this the same as u32ClientID? Playing safe for now... */
-    uint32_t const u32ClientIDOld = pClient->u32ClientID;
-
-    /* Restore the client data. */
-    uint32_t lenOrVer;
-    int rc = SSMR3GetU32 (pSSM, &lenOrVer);
-    AssertRCReturn (rc, rc);
-    if (lenOrVer == UINT32_C (0x80000002))
-    {
-        rc = SSMR3GetStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
-        AssertRCReturn (rc, rc);
-    }
-    else if (lenOrVer == (SSMR3HandleHostBits (pSSM) == 64 ? 72 : 48))
-    {
-        /**
-         * SSM descriptor table for the CLIPSAVEDSTATEDATA structure.
-         */
-        static SSMFIELD const s_aClipSavedStateDataFields30[] =
-        {
-            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, pNext),
-            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, pPrev),
-            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, pCtx),
-            SSMFIELD_ENTRY(                 CLIPSAVEDSTATEDATA, u32ClientID),
-            SSMFIELD_ENTRY_CUSTOM(fMsgQuit+fMsgReadData+fMsgFormats, RT_OFFSETOF(CLIPSAVEDSTATEDATA, u32ClientID) + 4, 4),
-            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, async.callHandle),
-            SSMFIELD_ENTRY_IGN_HCPTR(       CLIPSAVEDSTATEDATA, async.paParms),
-            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, data.pv),
-            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, data.cb),
-            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, data.u32Format),
-            SSMFIELD_ENTRY_IGNORE(          CLIPSAVEDSTATEDATA, u32AvailableFormats),
-            SSMFIELD_ENTRY(                 CLIPSAVEDSTATEDATA, u32RequestedFormat),
-            SSMFIELD_ENTRY_TERM()
-        };
-
-        CLIPSAVEDSTATEDATA savedState;
-        RT_ZERO (savedState);
-        rc = SSMR3GetStructEx (pSSM, &savedState, sizeof(savedState), SSMSTRUCT_FLAGS_MEM_BAND_AID,
-                               &s_aClipSavedStateDataFields30[0], NULL);
-        AssertRCReturn (rc, rc);
-
-        pClient->fMsgQuit           = savedState.fMsgQuit;
-        pClient->fMsgReadData       = savedState.fMsgReadData;
-        pClient->fMsgFormats        = savedState.fMsgFormats;
-        pClient->u32RequestedFormat = savedState.u32RequestedFormat;
-    }
-    else
-    {
-        LogRel (("Client data size mismatch: got %#x\n", lenOrVer));
-        return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
-    }
-
-    /* Verify the client ID. */
-    if (pClient->u32ClientID != u32ClientIDOld)
-    {
-        LogRel (("Client ID mismatch: expected %d, got %d\n", u32ClientIDOld, pClient->u32ClientID));
-        pClient->u32ClientID = u32ClientIDOld;
-        return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
-    }
-
-    /* Actual host data are to be reported to guest (SYNC). */
-    vboxClipboardSync (pClient);
-
-    return VINF_SUCCESS;
-}
-#endif
-
-static int svcInit(void)
-{
-    int rc = RTCritSectInit(&g_critsect);
-
-    if (RT_SUCCESS (rc))
-    {
-        rc = vboxHostChannelInit();
-
-        /* Clean up on failure, because 'svnUnload' will not be called
-         * if the 'svcInit' returns an error.
-         */
-        if (RT_FAILURE(rc))
-        {
-            RTCritSectDelete(&g_critsect);
-        }
-    }
-
-    return rc;
-}
-
-extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
-{
-    int rc = VINF_SUCCESS;
-
-    LogRelFlowFunc(("pTable = %p\n", pTable));
-
-    if (!pTable)
-    {
-        rc = VERR_INVALID_PARAMETER;
-    }
-    else
-    {
-        LogRel2(("VBoxHGCMSvcLoad: pTable->cbSize = %d, pTable->u32Version = 0x%08X\n",
-                  pTable->cbSize, pTable->u32Version));
-
-        if (   pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
-            || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
-        {
-            rc = VERR_INVALID_PARAMETER;
-        }
-        else
-        {
-            g_pHelpers = pTable->pHelpers;
-
-            pTable->cbClient = sizeof(VBOXHOSTCHCLIENT);
-
-            pTable->pfnUnload     = svcUnload;
-            pTable->pfnConnect    = svcConnect;
-            pTable->pfnDisconnect = svcDisconnect;
-            pTable->pfnCall       = svcCall;
-            pTable->pfnHostCall   = svcHostCall;
-            pTable->pfnSaveState  = NULL; // svcSaveState;
-            pTable->pfnLoadState  = NULL; // svcLoadState;
-            pTable->pfnRegisterExtension  = NULL;
-            pTable->pvService     = NULL;
-
-            /* Service specific initialization. */
-            rc = svcInit();
-        }
-    }
-
-    return rc;
-}
