Index: trunk/src/VBox/HostServices/DragAndDrop/Makefile.kmk
===================================================================
--- trunk/src/VBox/HostServices/DragAndDrop/Makefile.kmk	(revision 74204)
+++ trunk/src/VBox/HostServices/DragAndDrop/Makefile.kmk	(revision 74205)
@@ -5,5 +5,5 @@
 
 #
-# Copyright (C) 2011-2017 Oracle Corporation
+# Copyright (C) 2011-2018 Oracle Corporation
 #
 # This file is part of VirtualBox Open Source Edition (OSE), as
@@ -39,4 +39,8 @@
 	dndmanager.cpp
 
+VBoxDragAndDropSvc_SOURCES += \
+    ../common/client.cpp \
+    ../common/message.cpp
+
 VBoxDragAndDropSvc_SOURCES.win = \
 	VBoxDragAndDropSvc.rc
Index: trunk/src/VBox/HostServices/DragAndDrop/service.cpp
===================================================================
--- trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 74204)
+++ trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 74205)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2011-2017 Oracle Corporation
+ * Copyright (C) 2011-2018 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -51,8 +51,6 @@
 public:
 
-    DragAndDropClient(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle = NULL,
-                      uint32_t uMsg = 0, uint32_t cParms = 0, VBOXHGCMSVCPARM aParms[] = NULL)
-        : HGCM::Client(uClientId, hHandle, uMsg, cParms, aParms)
-        , m_fDeferred(false)
+    DragAndDropClient(uint32_t uClientID)
+        : HGCM::Client(uClientID)
     {
         RT_ZERO(m_SvcCtx);
@@ -66,18 +64,5 @@
 public:
 
-    void complete(VBOXHGCMCALLHANDLE hHandle, int rcOp);
-    void completeDeferred(int rcOp);
     void disconnect(void);
-    bool isDeferred(void) const { return m_fDeferred; }
-    void setDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
-    void setSvcContext(const HGCM::VBOXHGCMSVCTX &SvcCtx) { m_SvcCtx = SvcCtx; }
-
-protected:
-
-    /** The HGCM service context this client is bound to. */
-    HGCM::VBOXHGCMSVCTX m_SvcCtx;
-    /** Flag indicating whether this client currently is deferred mode,
-     *  meaning that it did not return to the caller yet. */
-    bool                m_fDeferred;
 };
 
@@ -137,34 +122,4 @@
 
 /**
- * Completes the call by returning the control back to the guest
- * side code.
- */
-void DragAndDropClient::complete(VBOXHGCMCALLHANDLE hHandle, int rcOp)
-{
-    LogFlowThisFunc(("uClientID=%RU32\n", m_uClientId));
-
-    if (   m_SvcCtx.pHelpers
-        && m_SvcCtx.pHelpers->pfnCallComplete)
-    {
-        m_SvcCtx.pHelpers->pfnCallComplete(hHandle, rcOp);
-    }
-}
-
-/**
- * Completes a deferred call by returning the control back to the guest
- * side code.
- */
-void DragAndDropClient::completeDeferred(int rcOp)
-{
-    AssertMsg(m_fDeferred, ("Client %RU32 is not in deferred mode\n", m_uClientId));
-    Assert(m_hHandle != NULL);
-
-    LogFlowThisFunc(("uClientID=%RU32\n", m_uClientId));
-
-    complete(m_hHandle, rcOp);
-    m_fDeferred = false;
-}
-
-/**
  * Called when the HGCM client disconnected on the guest side.
  * This function takes care of the client's data cleanup and also lets the host
@@ -174,8 +129,8 @@
 void DragAndDropClient::disconnect(void)
 {
-    LogFlowThisFunc(("uClient=%RU32\n", m_uClientId));
-
-    if (isDeferred())
-        completeDeferred(VERR_INTERRUPTED);
+    LogFlowThisFunc(("uClient=%RU32\n", m_uClientID));
+
+    if (IsDeferred())
+        CompleteDeferred(VERR_INTERRUPTED);
 
     /*
@@ -191,26 +146,8 @@
         int rc2 = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, GUEST_DND_DISCONNECT, &data, sizeof(data));
         if (RT_FAILURE(rc2))
-            LogFlowFunc(("Warning: Unable to notify host about client %RU32 disconnect, rc=%Rrc\n", m_uClientId, rc2));
+            LogFlowFunc(("Warning: Unable to notify host about client %RU32 disconnect, rc=%Rrc\n", m_uClientID, rc2));
         /* Not fatal. */
     }
 }
-
-/**
- * Set the client's status to deferred, meaning that it does not return to the caller
- * on the guest side yet.
- */
-void DragAndDropClient::setDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
-{
-    LogFlowThisFunc(("uClient=%RU32\n", m_uClientId));
-
-    AssertMsg(m_fDeferred == false, ("Client already in deferred mode\n"));
-    m_fDeferred = true;
-
-    m_hHandle = hHandle;
-    m_uMsg    = u32Function;
-    m_cParms  = cParms;
-    m_paParms = paParms;
-}
-
 
 /*********************************************************************************************************************************
@@ -288,5 +225,5 @@
         {
             DragAndDropClient *pClient = new DragAndDropClient(u32ClientID);
-            pClient->setSvcContext(m_SvcCtx);
+            pClient->SetSvcContext(m_SvcCtx);
             m_clientMap[u32ClientID] = pClient;
         }
@@ -553,5 +490,5 @@
                         rc = paParms[idxProto + 1].getUInt32(&data.uFlags);
                     if (RT_SUCCESS(rc))
-                        rc = pClient->SetProtocolVer(data.uProtocol);
+                        pClient->SetProtocolVer(data.uProtocol);
                     if (RT_SUCCESS(rc))
                     {
@@ -1088,5 +1025,5 @@
         {
             AssertPtr(pClient);
-            pClient->setDeferred(callHandle, u32Function, cParms, paParms);
+            pClient->SetDeferred(callHandle, u32Function, cParms, paParms);
             m_clientQueue.push_back(u32ClientID);
         }
@@ -1098,5 +1035,5 @@
     }
     else if (pClient)
-        pClient->complete(callHandle, rc);
+        pClient->Complete(callHandle, rc);
     else
     {
@@ -1163,8 +1100,8 @@
                     AssertPtr(pClient);
 
-                    int rc2 = pClient->addMessageInfo(HOST_DND_HG_EVT_CANCEL,
-                                                      /* Protocol v3+ also contains the context ID. */
-                                                      pClient->GetProtocolVer() >= 3 ? 1 : 0);
-                    pClient->completeDeferred(rc2);
+                    int rc2 = pClient->SetDeferredMsgInfo(HOST_DND_HG_EVT_CANCEL,
+                                                          /* Protocol v3+ also contains the context ID. */
+                                                          pClient->GetProtocolVer() >= 3 ? 1 : 0);
+                    pClient->CompleteDeferred(rc2);
 
                     m_clientQueue.erase(itQueue);
@@ -1246,8 +1183,8 @@
                 if (uMsgClient == GUEST_DND_GET_NEXT_HOST_MSG)
                 {
-                    rc = pClient->addMessageInfo(uMsgNext, cParmsNext);
+                    rc = pClient->SetDeferredMsgInfo(uMsgNext, cParmsNext);
 
                     /* Note: Report the current rc back to the guest. */
-                    pClient->completeDeferred(rc);
+                    pClient->CompleteDeferred(rc);
                 }
                 /*
@@ -1260,5 +1197,5 @@
 
                     /* Note: Report the current rc back to the guest. */
-                    pClient->completeDeferred(rc);
+                    pClient->CompleteDeferred(rc);
                 }
                 else /* Should not happen; cancel the operation on the guest. */
@@ -1267,5 +1204,5 @@
                              pClient->GetClientID(), uMsgClient, uMsgNext));
 
-                    pClient->completeDeferred(VERR_CANCELLED);
+                    pClient->CompleteDeferred(VERR_CANCELLED);
                 }
 
Index: trunk/src/VBox/HostServices/common/client.cpp
===================================================================
--- trunk/src/VBox/HostServices/common/client.cpp	(revision 74205)
+++ trunk/src/VBox/HostServices/common/client.cpp	(revision 74205)
@@ -0,0 +1,256 @@
+/** @file
+ * Base class for a host-guest service.
+ */
+
+/*
+ * Copyright (C) 2011-2018 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 contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <VBox/log.h>
+#include <VBox/hgcmsvc.h>
+
+#include <iprt/assert.h>
+#include <iprt/alloc.h>
+#include <iprt/cpp/utils.h>
+
+#include <VBox/HostServices/Service.h>
+
+using namespace HGCM;
+
+Client::Client(uint32_t uClientID)
+    : m_uClientID(uClientID)
+    , m_uProtocolVer(0)
+    , m_fDeferred(false)
+{
+    RT_ZERO(m_Deferred);
+    RT_ZERO(m_SvcCtx);
+}
+
+Client::~Client(void)
+{
+
+}
+
+/**
+ * Completes a guest call by returning the control back to the guest side,
+ * together with a status code, internal version.
+ *
+ * @returns IPRT status code.
+ * @param   hHandle             Call handle to complete guest call for.
+ * @param   rcOp                Return code to return to the guest side.
+ */
+int Client::completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp)
+{
+    LogFlowThisFunc(("uClientID=%RU32\n", m_uClientID));
+
+    if (   m_SvcCtx.pHelpers
+        && m_SvcCtx.pHelpers->pfnCallComplete)
+    {
+        m_SvcCtx.pHelpers->pfnCallComplete(hHandle, rcOp);
+
+        reset();
+        return VINF_SUCCESS;
+    }
+
+    return VERR_NOT_AVAILABLE;
+}
+
+/**
+ * Resets the client's internal state.
+ */
+void Client::reset(void)
+{
+   m_fDeferred = false;
+
+   RT_ZERO(m_Deferred);
+}
+
+/**
+ * Completes a guest call by returning the control back to the guest side,
+ * together with a status code.
+ *
+ * @returns IPRT status code.
+ * @param   hHandle             Call handle to complete guest call for.
+ * @param   rcOp                Return code to return to the guest side.
+ */
+int Client::Complete(VBOXHGCMCALLHANDLE hHandle, int rcOp /* = VINF_SUCCESS */)
+{
+    return completeInternal(hHandle, rcOp);
+}
+
+/**
+ * Completes a deferred guest call by returning the control back to the guest side,
+ * together with a status code.
+ *
+ * @returns IPRT status code. VERR_INVALID_STATE if the client is not in deferred mode.
+ * @param   rcOp                Return code to return to the guest side.
+ */
+int Client::CompleteDeferred(int rcOp)
+{
+    if (m_fDeferred)
+    {
+        Assert(m_Deferred.hHandle != NULL);
+
+        int rc = completeInternal(m_Deferred.hHandle, rcOp);
+        if (RT_SUCCESS(rc))
+            m_fDeferred = false;
+
+        return rc;
+    }
+
+    AssertMsg(m_fDeferred, ("Client %RU32 is not in deferred mode\n", m_uClientID));
+    return VERR_INVALID_STATE;
+}
+
+/**
+ * Returns the HGCM call handle of the client.
+ *
+ * @returns HGCM handle.
+ */
+VBOXHGCMCALLHANDLE Client::GetHandle(void) const
+{
+    return m_Deferred.hHandle;
+}
+
+/**
+ * Returns the HGCM call handle of the client.
+ *
+ * @returns HGCM handle.
+ */
+uint32_t Client::GetMsgType(void) const
+{
+    return m_Deferred.uType;
+}
+
+uint32_t Client::GetMsgParamCount(void) const
+{
+    return m_Deferred.cParms;
+}
+
+/**
+ * Returns the client's (HGCM) ID.
+ *
+ * @returns The client's (HGCM) ID.
+ */
+uint32_t Client::GetClientID(void) const
+{
+    return m_uClientID;
+}
+
+/**
+ * Returns the client's used protocol version.
+ *
+ * @returns Protocol version, or 0 if not set.
+ */
+uint32_t Client::GetProtocolVer(void) const
+{
+    return m_uProtocolVer;
+}
+
+/**
+ * Returns whether the client currently is in deferred mode or not.
+ *
+ * @returns \c True if in deferred mode, \c False if not.
+ */
+bool Client::IsDeferred(void) const
+{
+    return m_fDeferred;
+}
+
+/**
+ * Set the client's status to deferred, meaning that it does not return to the caller
+ * until CompleteDeferred() has been called.
+ */
+void Client::SetDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    LogFlowThisFunc(("uClient=%RU32\n", m_uClientID));
+
+    AssertMsg(m_fDeferred == false, ("Client already in deferred mode\n"));
+    m_fDeferred = true;
+
+    m_Deferred.hHandle = hHandle;
+    m_Deferred.uType   = u32Function;
+    m_Deferred.cParms  = cParms;
+    m_Deferred.paParms = paParms;
+}
+
+/**
+ * Sets the client's protocol version. The protocol version is purely optional and bound
+ * to a specific HGCM service.
+ *
+ * @param   uVersion            Version number to set.
+ */
+void Client::SetProtocolVer(uint32_t uVersion)
+{
+    m_uProtocolVer = uVersion;
+}
+
+/**
+ * Sets the HGCM service context.
+ *
+ * @param   SvcCtx              Service context to set.
+ */
+void Client::SetSvcContext(const VBOXHGCMSVCTX &SvcCtx)
+{
+    m_SvcCtx = SvcCtx;
+}
+
+/**
+ * Sets the deferred parameters to a specific message type and
+ * required parameters. That way the client can re-request that message with
+ * the right amount of parameters from the service.
+ *
+ * @returns IPRT status code.
+ * @param   uMsg                Message type (number) to set.
+ * @param   cParms              Number of parameters the message needs.
+ */
+int Client::SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms)
+{
+    if (m_fDeferred)
+    {
+        if (m_Deferred.cParms < 2)
+            return VERR_INVALID_PARAMETER;
+
+        AssertPtrReturn(m_Deferred.paParms, VERR_BUFFER_OVERFLOW);
+
+        m_Deferred.paParms[0].setUInt32(uMsg);
+        m_Deferred.paParms[1].setUInt32(cParms);
+
+        return VINF_SUCCESS;
+    }
+
+    AssertFailed();
+    return VERR_INVALID_STATE;
+}
+
+/**
+ * Sets the deferred parameters to a specific message type and
+ * required parameters. That way the client can re-request that message with
+ * the right amount of parameters from the service.
+ *
+ * @returns IPRT status code.
+ * @param   pMessage            Message to get message type and required parameters from.
+ */
+int Client::SetDeferredMsgInfo(const Message *pMessage)
+{
+    AssertPtrReturn(pMessage, VERR_INVALID_POINTER);
+    return SetDeferredMsgInfo(pMessage->GetType(), pMessage->GetParamCount());
+}
+
Index: trunk/src/VBox/HostServices/common/message.cpp
===================================================================
--- trunk/src/VBox/HostServices/common/message.cpp	(revision 74205)
+++ trunk/src/VBox/HostServices/common/message.cpp	(revision 74205)
@@ -0,0 +1,304 @@
+/** @file
+ * Base class for wrapping HCGM messages.
+ */
+
+/*
+ * Copyright (C) 2018 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 contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <VBox/HostServices/Service.h>
+
+using namespace HGCM;
+
+Message::Message(void)
+    : m_uMsg(0)
+    , m_cParms(0)
+    , m_paParms(NULL) { }
+
+Message::Message(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
+    : m_uMsg(0)
+    , m_cParms(0)
+    , m_paParms(NULL)
+{
+    initData(uMsg, cParms, aParms);
+}
+
+Message::~Message(void)
+{
+    reset();
+}
+
+/**
+ * Resets the message by free'ing all allocated parameters and resetting the rest.
+ */
+void Message::reset(void)
+{
+    if (m_paParms)
+    {
+        for (uint32_t i = 0; i < m_cParms; ++i)
+        {
+            switch (m_paParms[i].type)
+            {
+                case VBOX_HGCM_SVC_PARM_PTR:
+                    if (m_paParms[i].u.pointer.size)
+                        RTMemFree(m_paParms[i].u.pointer.addr);
+                    break;
+            }
+        }
+        RTMemFree(m_paParms);
+        m_paParms = 0;
+    }
+    m_cParms = 0;
+    m_uMsg = 0;
+}
+
+/**
+ * Returns the parameter count of this message.
+ *
+ * @returns Parameter count.
+ */
+uint32_t Message::GetParamCount(void) const
+{
+    return m_cParms;
+}
+
+/**
+ * Retrieves the raw HGCM parameter data
+ *
+ * @returns IPRT status code.
+ * @param   uMsg            Message type to retrieve the parameter data for. Needed for sanity.
+ * @param   cParms          Size (in parameters) of @a aParms array.
+ * @param   aParms          Where to store the HGCM parameter data.
+ */
+int Message::GetData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) const
+{
+    if (m_uMsg != uMsg)
+    {
+        LogFlowFunc(("Stored message type (%RU32) does not match request (%RU32)\n", m_uMsg, uMsg));
+        return VERR_INVALID_PARAMETER;
+    }
+    if (m_cParms > cParms)
+    {
+        LogFlowFunc(("Stored parameter count (%RU32) exceeds request buffer (%RU32)\n", m_cParms, cParms));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    return Message::CopyParms(&aParms[0], cParms, m_paParms, m_cParms, false /* fDeepCopy */);
+}
+
+/**
+ * Retrieves a specific parameter value as uint32_t.
+ *
+ * @returns IPRT status code.
+ * @param   uParm           Index of parameter to retrieve.
+ * @param   pu32Info        Where to store the parameter value.
+ */
+int Message::GetParmU32(uint32_t uParm, uint32_t *pu32Info) const
+{
+    AssertPtrNullReturn(pu32Info, VERR_INVALID_PARAMETER);
+    AssertReturn(uParm < m_cParms, VERR_INVALID_PARAMETER);
+    AssertReturn(m_paParms[uParm].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_INVALID_PARAMETER);
+
+    *pu32Info = m_paParms[uParm].u.uint32;
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Retrieves a specific parameter value as uint64_t.
+ *
+ * @returns IPRT status code.
+ * @param   uParm           Index of parameter to retrieve.
+ * @param   pu64Info        Where to store the parameter value.
+ */
+int Message::GetParmU64(uint32_t uParm, uint64_t *pu64Info) const
+{
+    AssertPtrNullReturn(pu64Info, VERR_INVALID_PARAMETER);
+    AssertReturn(uParm < m_cParms, VERR_INVALID_PARAMETER);
+    AssertReturn(m_paParms[uParm].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_INVALID_PARAMETER);
+
+    *pu64Info = m_paParms[uParm].u.uint64;
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Retrieves a specific parameter value as a data address + size.
+ *
+ * @returns IPRT status code.
+ * @param   uParm           Index of parameter to retrieve.
+ * @param   ppvAddr         Where to store the data address.
+ * @param   pcbSize         Where to store the data size (in bytes).
+ *
+ * @remarks Does not copy (store) the actual content of the pointer (deep copy).
+ */
+int Message::GetParmPtr(uint32_t uParm, void **ppvAddr, uint32_t *pcbSize) const
+{
+    AssertPtrNullReturn(ppvAddr, VERR_INVALID_PARAMETER);
+    AssertPtrNullReturn(pcbSize, VERR_INVALID_PARAMETER);
+    AssertReturn(uParm < m_cParms, VERR_INVALID_PARAMETER);
+    AssertReturn(m_paParms[uParm].type == VBOX_HGCM_SVC_PARM_PTR, VERR_INVALID_PARAMETER);
+
+    *ppvAddr = m_paParms[uParm].u.pointer.addr;
+    *pcbSize = m_paParms[uParm].u.pointer.size;
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Returns the type of this message.
+ *
+ * @returns Message type.
+ */
+uint32_t Message::GetType(void) const
+{
+    return m_uMsg;
+}
+
+/**
+ * Copies HGCM parameters from source to destination.
+ *
+ * @returns IPRT status code.
+ * @param   paParmsDst      Destination array to copy parameters to.
+ * @param   cParmsDst       Size (in parameters) of destination array.
+ * @param   paParmsSrc      Source array to copy parameters from.
+ * @param   cParmsSrc       Size (in parameters) of source array.
+ * @param   fDeepCopy       Whether to perform a deep copy of pointer parameters or not.
+ *
+ * @remark Static convenience function.
+ */
+/* static */
+int Message::CopyParms(PVBOXHGCMSVCPARM paParmsDst, uint32_t cParmsDst,
+                       PVBOXHGCMSVCPARM paParmsSrc, uint32_t cParmsSrc,
+                       bool fDeepCopy)
+{
+    AssertPtrReturn(paParmsSrc, VERR_INVALID_POINTER);
+    AssertPtrReturn(paParmsDst, VERR_INVALID_POINTER);
+
+    if (cParmsSrc > cParmsDst)
+        return VERR_BUFFER_OVERFLOW;
+
+    int rc = VINF_SUCCESS;
+    for (uint32_t i = 0; i < cParmsSrc; i++)
+    {
+        paParmsDst[i].type = paParmsSrc[i].type;
+        switch (paParmsSrc[i].type)
+        {
+            case VBOX_HGCM_SVC_PARM_32BIT:
+            {
+                paParmsDst[i].u.uint32 = paParmsSrc[i].u.uint32;
+                break;
+            }
+            case VBOX_HGCM_SVC_PARM_64BIT:
+            {
+                paParmsDst[i].u.uint64 = paParmsSrc[i].u.uint64;
+                break;
+            }
+            case VBOX_HGCM_SVC_PARM_PTR:
+            {
+                /* Do we have to perform a deep copy? */
+                if (fDeepCopy)
+                {
+                    /* Yes, do so. */
+                    paParmsDst[i].u.pointer.size = paParmsSrc[i].u.pointer.size;
+                    if (paParmsDst[i].u.pointer.size > 0)
+                    {
+                        paParmsDst[i].u.pointer.addr = RTMemAlloc(paParmsDst[i].u.pointer.size);
+                        if (!paParmsDst[i].u.pointer.addr)
+                        {
+                            rc = VERR_NO_MEMORY;
+                            break;
+                        }
+                    }
+                }
+                else
+                {
+                    /* No, but we have to check if there is enough room. */
+                    if (paParmsDst[i].u.pointer.size < paParmsSrc[i].u.pointer.size)
+                    {
+                        rc = VERR_BUFFER_OVERFLOW;
+                        break;
+                    }
+                }
+
+                if (paParmsSrc[i].u.pointer.size)
+                {
+                    if (   paParmsDst[i].u.pointer.addr
+                        && paParmsDst[i].u.pointer.size)
+                    {
+                        memcpy(paParmsDst[i].u.pointer.addr,
+                               paParmsSrc[i].u.pointer.addr,
+                               RT_MIN(paParmsDst[i].u.pointer.size, paParmsSrc[i].u.pointer.size));
+                    }
+                    else
+                        rc = VERR_INVALID_POINTER;
+                }
+                break;
+            }
+            default:
+            {
+                AssertMsgFailed(("Unknown HGCM type %u\n", paParmsSrc[i].type));
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+        }
+        if (RT_FAILURE(rc))
+            break;
+    }
+    return rc;
+}
+
+/**
+ * Initializes the message with a message type and parameters.
+ *
+ * @returns IPRT status code.
+ * @param   uMsg            Message type to set.
+ * @param   cParms          Number of parameters to set.
+ * @param   aParms          Array of parameters to set.
+ */
+int Message::initData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
+{
+    AssertReturn(cParms < 256, VERR_INVALID_PARAMETER);
+    AssertPtrNullReturn(aParms, VERR_INVALID_PARAMETER);
+
+    /* Cleanup any eventual old stuff. */
+    reset();
+
+    m_uMsg   = uMsg;
+    m_cParms = cParms;
+
+    int rc = VINF_SUCCESS;
+
+    if (cParms)
+    {
+        m_paParms = (VBOXHGCMSVCPARM*)RTMemAllocZ(sizeof(VBOXHGCMSVCPARM) * m_cParms);
+        if (m_paParms)
+        {
+            rc = Message::CopyParms(m_paParms, m_cParms, &aParms[0], cParms, true /* fDeepCopy */);
+            if (RT_FAILURE(rc))
+                reset();
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+
+    return rc;
+}
+
