Index: /trunk/src/VBox/Frontends/VBoxBFE/HGCM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/HGCM.cpp	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/HGCM.cpp	(revision 5979)
@@ -0,0 +1,2256 @@
+/** @file
+ *
+ * HGCM (Host-Guest Communication Manager)
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
+#include "Logging.h"
+
+#include "HGCM.h"
+#include "HGCMThread.h"
+
+#include <VBox/err.h>
+#include <VBox/hgcmsvc.h>
+
+#include <iprt/alloc.h>
+#include <iprt/alloca.h>
+#include <iprt/avl.h>
+#include <iprt/critsect.h>
+#include <iprt/asm.h>
+#include <iprt/ldr.h>
+#include <iprt/string.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+
+#include <VBox/VBoxGuest.h>
+
+/**
+ * A service gets one thread, which synchronously delivers messages to
+ * the service. This is good for serialization.
+ *
+ * Some services may want to process messages asynchronously, and will want
+ * a next message to be delivered, while a previous message is still being
+ * processed.
+ *
+ * The dedicated service thread delivers a next message when service
+ * returns after fetching a previous one. The service will call a message
+ * completion callback when message is actually processed. So returning
+ * from the service call means only that the service is processing message.
+ *
+ * 'Message processed' condition is indicated by service, which call the
+ * callback, even if the callback is called synchronously in the dedicated
+ * thread.
+ *
+ * This message completion callback is only valid for Call requests.
+ * Connect and Disconnect are processed synchronously by the service.
+ */
+
+
+/* The maximum allowed size of a service name in bytes. */
+#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
+
+struct _HGCMSVCEXTHANDLEDATA
+{
+    char *pszServiceName;
+    /* The service name follows. */
+};
+
+/** Internal helper service object. HGCM code would use it to
+ *  hold information about services and communicate with services.
+ *  The HGCMService is an (in future) abstract class that implements
+ *  common functionality. There will be derived classes for specific
+ *  service types.
+ */
+
+class HGCMService
+{
+    private:
+        VBOXHGCMSVCHELPERS m_svcHelpers;
+
+        static HGCMService *sm_pSvcListHead;
+        static HGCMService *sm_pSvcListTail;
+
+        static int sm_cServices;
+
+        HGCMTHREADHANDLE m_thread;
+        friend DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser);
+
+        uint32_t volatile m_u32RefCnt;
+
+        HGCMService *m_pSvcNext;
+        HGCMService *m_pSvcPrev;
+
+        char *m_pszSvcName;
+        char *m_pszSvcLibrary;
+        
+        RTLDRMOD m_hLdrMod;
+        PFNVBOXHGCMSVCLOAD m_pfnLoad;
+
+        VBOXHGCMSVCFNTABLE m_fntable;
+
+        int m_cClients;
+        int m_cClientsAllocated;
+
+        uint32_t *m_paClientIds;
+        
+        HGCMSVCEXTHANDLE m_hExtension;
+
+        int loadServiceDLL (void);
+        void unloadServiceDLL (void);
+
+        /*
+         * Main HGCM thread methods.
+         */
+        int instanceCreate (const char *pszServiceLibrary, const char *pszServiceName);
+        void instanceDestroy (void);
+
+        int saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
+        int loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
+
+        HGCMService ();
+        ~HGCMService () {};
+
+        static DECLCALLBACK(void) svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc);
+        
+    public:
+
+        /*
+         * Main HGCM thread methods.
+         */
+        static int LoadService (const char *pszServiceLibrary, const char *pszServiceName);
+        void UnloadService (void);
+
+        static void UnloadAll (void);
+
+        static int ResolveService (HGCMService **ppsvc, const char *pszServiceName);
+        void ReferenceService (void);
+        void ReleaseService (void);
+
+        static void Reset (void);
+
+        static int SaveState (PSSMHANDLE pSSM);
+        static int LoadState (PSSMHANDLE pSSM);
+
+        int CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn);
+        int DisconnectClient (uint32_t u32ClientId);
+
+        int HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
+
+        uint32_t SizeOfClient (void) { return m_fntable.cbClient; };
+
+        int RegisterExtension (HGCMSVCEXTHANDLE handle, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
+        void UnregisterExtension (HGCMSVCEXTHANDLE handle);
+
+        /*
+         * The service thread methods.
+         */
+
+        int GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
+};
+
+
+class HGCMClient: public HGCMObject
+{
+    public:
+        HGCMClient () : HGCMObject(HGCMOBJ_CLIENT) {};
+        ~HGCMClient ();
+
+        int Init (HGCMService *pSvc);
+
+        /** Service that the client is connected to. */
+        HGCMService *pService;
+
+        /** Client specific data. */
+        void *pvData;
+};
+
+HGCMClient::~HGCMClient ()
+{
+    RTMemFree (pvData);
+}
+
+int HGCMClient::Init (HGCMService *pSvc)
+{
+    pService = pSvc;
+
+    if (pService->SizeOfClient () > 0)
+    {
+        pvData = RTMemAllocZ (pService->SizeOfClient ());
+
+        if (!pvData)
+        {
+           return VERR_NO_MEMORY;
+        }
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+#define HGCM_CLIENT_DATA(pService, pClient) (pClient->pvData)
+
+
+
+HGCMService *HGCMService::sm_pSvcListHead = NULL;
+HGCMService *HGCMService::sm_pSvcListTail = NULL;
+int HGCMService::sm_cServices = 0;
+
+HGCMService::HGCMService ()
+    :
+    m_thread     (0),
+    m_u32RefCnt  (0),
+    m_pSvcNext   (NULL),
+    m_pSvcPrev   (NULL),
+    m_pszSvcName (NULL),
+    m_pszSvcLibrary (NULL),
+    m_hLdrMod    (NIL_RTLDRMOD),
+    m_pfnLoad    (NULL),
+    m_cClients   (0),
+    m_cClientsAllocated (0),
+    m_paClientIds (NULL),
+    m_hExtension (NULL)
+{
+    memset (&m_fntable, 0, sizeof (m_fntable));
+}
+
+
+static bool g_fResetting = false;
+static bool g_fSaveState = false;
+
+
+
+/** Helper function to load a local service DLL.
+ *
+ *  @return VBox code
+ */
+int HGCMService::loadServiceDLL (void)
+{
+    LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
+
+    if (m_pszSvcLibrary == NULL)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    rc = RTLdrLoad (m_pszSvcLibrary, &m_hLdrMod);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        LogFlowFunc(("successfully loaded the library.\n"));
+
+        m_pfnLoad = NULL;
+
+        rc = RTLdrGetSymbol (m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
+
+        if (VBOX_FAILURE (rc) || !m_pfnLoad)
+        {
+            Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n", VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
+
+            if (VBOX_SUCCESS(rc))
+            {
+                /* m_pfnLoad was NULL */
+                rc = VERR_SYMBOL_NOT_FOUND;
+            }
+        }
+
+        if (VBOX_SUCCESS(rc))
+        {
+            memset (&m_fntable, 0, sizeof (m_fntable));
+
+            m_fntable.cbSize     = sizeof (m_fntable);
+            m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
+            m_fntable.pHelpers   = &m_svcHelpers;
+
+            rc = m_pfnLoad (&m_fntable);
+
+            LogFlowFunc(("m_pfnLoad rc = %Vrc\n", rc));
+
+            if (VBOX_SUCCESS (rc))
+            {
+                if (   m_fntable.pfnUnload == NULL
+                    || m_fntable.pfnConnect == NULL
+                    || m_fntable.pfnDisconnect == NULL
+                    || m_fntable.pfnCall == NULL
+                   )
+                {
+                    Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
+
+                    rc = VERR_INVALID_PARAMETER;
+
+                    if (m_fntable.pfnUnload)
+                    {
+                        m_fntable.pfnUnload ();
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        LogRel(("HGCM: Failed to load the service library: [%s], rc = %Vrc. The service will be not available.\n", m_pszSvcLibrary, rc));
+        m_hLdrMod = NIL_RTLDRMOD;
+    }
+
+    if (VBOX_FAILURE(rc))
+    {
+        unloadServiceDLL ();
+    }
+
+    return rc;
+}
+
+/** Helper function to free a local service DLL.
+ *
+ *  @return VBox code
+ */
+void HGCMService::unloadServiceDLL (void)
+{
+    if (m_hLdrMod)
+    {
+        RTLdrClose (m_hLdrMod);
+    }
+
+    memset (&m_fntable, 0, sizeof (m_fntable));
+    m_pfnLoad = NULL;
+    m_hLdrMod = NIL_RTLDRMOD;
+}
+
+/*
+ * Messages processed by service threads. These threads only call the service entry points.
+ */
+
+#define SVC_MSG_LOAD       (0)  /* Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
+#define SVC_MSG_UNLOAD     (1)  /* call pfnUnload and unload the service library. */
+#define SVC_MSG_CONNECT    (2)  /* pfnConnect */
+#define SVC_MSG_DISCONNECT (3)  /* pfnDisconnect */
+#define SVC_MSG_GUESTCALL  (4)  /* pfnGuestCall */
+#define SVC_MSG_HOSTCALL   (5)  /* pfnHostCall */
+#define SVC_MSG_LOADSTATE  (6)  /* pfnLoadState. */
+#define SVC_MSG_SAVESTATE  (7)  /* pfnSaveState. */
+#define SVC_MSG_QUIT       (8)  /* Terminate the thread. */
+#define SVC_MSG_REGEXT     (9)  /* pfnRegisterExtension */
+#define SVC_MSG_UNREGEXT   (10) /* pfnRegisterExtension */
+
+class HGCMMsgSvcLoad: public HGCMMsgCore
+{
+};
+
+class HGCMMsgSvcUnload: public HGCMMsgCore
+{
+};
+
+class HGCMMsgSvcConnect: public HGCMMsgCore
+{
+    public:
+        /* client identifier */
+        uint32_t u32ClientId;
+};
+
+class HGCMMsgSvcDisconnect: public HGCMMsgCore
+{
+    public:
+        /* client identifier */
+        uint32_t u32ClientId;
+};
+
+class HGCMMsgHeader: public HGCMMsgCore
+{
+    public:
+        HGCMMsgHeader () : pCmd (NULL), pHGCMPort (NULL) {};
+        
+        /* Command pointer/identifier. */
+        PVBOXHGCMCMD pCmd;
+
+        /* Port to be informed on message completion. */
+        PPDMIHGCMPORT pHGCMPort;
+};
+
+
+class HGCMMsgCall: public HGCMMsgHeader
+{
+    public:
+        /* client identifier */
+        uint32_t u32ClientId;
+
+        /* function number */
+        uint32_t u32Function;
+
+        /* number of parameters */
+        uint32_t cParms;
+
+        VBOXHGCMSVCPARM *paParms;
+};
+
+class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
+{
+    public:
+        uint32_t    u32ClientId;
+        PSSMHANDLE  pSSM;
+};
+
+class HGCMMsgHostCallSvc: public HGCMMsgCore
+{
+    public:
+        /* function number */
+        uint32_t u32Function;
+
+        /* number of parameters */
+        uint32_t cParms;
+
+        VBOXHGCMSVCPARM *paParms;
+};
+
+class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
+{
+    public:
+        /* Handle of the extension to be registered. */
+        HGCMSVCEXTHANDLE handle;
+        /* The extension entry point. */
+        PFNHGCMSVCEXT pfnExtension;
+        /* The extension pointer. */
+        void *pvExtension;
+};
+
+class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
+{
+    public:
+        /* Handle of the registered extension. */
+        HGCMSVCEXTHANDLE handle;
+};
+
+static HGCMMsgCore *hgcmMessageAllocSvc (uint32_t u32MsgId)
+{
+    switch (u32MsgId)
+    {
+        case SVC_MSG_LOAD:        return new HGCMMsgSvcLoad ();
+        case SVC_MSG_UNLOAD:      return new HGCMMsgSvcUnload ();
+        case SVC_MSG_CONNECT:     return new HGCMMsgSvcConnect ();
+        case SVC_MSG_DISCONNECT:  return new HGCMMsgSvcDisconnect ();
+        case SVC_MSG_HOSTCALL:    return new HGCMMsgHostCallSvc ();
+        case SVC_MSG_GUESTCALL:   return new HGCMMsgCall ();
+        case SVC_MSG_LOADSTATE:      
+        case SVC_MSG_SAVESTATE:   return new HGCMMsgLoadSaveStateClient ();
+        case SVC_MSG_REGEXT:      return new HGCMMsgSvcRegisterExtension ();
+        case SVC_MSG_UNREGEXT:    return new HGCMMsgSvcUnregisterExtension ();
+        default:
+            AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
+    }
+
+    return NULL;
+}
+
+/*
+ * The service thread. Loads the service library and calls the service entry points.
+ */
+DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
+{
+    HGCMService *pSvc = (HGCMService *)pvUser;
+    AssertRelease(pSvc != NULL);
+
+    bool fQuit = false;
+
+    while (!fQuit)
+    {
+        HGCMMsgCore *pMsgCore;
+        int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
+
+        if (VBOX_FAILURE (rc))
+        {
+            /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
+            AssertMsgFailed (("%Vrc\n", rc));
+            break;
+        }
+
+        /* Cache required information to avoid unnecessary pMsgCore access. */
+        uint32_t u32MsgId = pMsgCore->MsgId ();
+
+        switch (u32MsgId)
+        {
+            case SVC_MSG_LOAD:
+            {
+                LogFlowFunc(("SVC_MSG_LOAD\n"));
+                rc = pSvc->loadServiceDLL ();
+            } break;
+
+            case SVC_MSG_UNLOAD:
+            {
+                LogFlowFunc(("SVC_MSG_UNLOAD\n"));
+                if (pSvc->m_fntable.pfnUnload)
+                {
+                    pSvc->m_fntable.pfnUnload ();
+                }
+
+                pSvc->unloadServiceDLL ();
+                fQuit = true;
+            } break;
+
+            case SVC_MSG_CONNECT:
+            {
+                HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
+
+                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
+
+                if (pClient)
+                {
+                    rc = pSvc->m_fntable.pfnConnect (pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
+
+                    hgcmObjDereference (pClient);
+                }
+                else
+                {
+                    rc = VERR_HGCM_INVALID_CLIENT_ID;
+                }
+            } break;
+
+            case SVC_MSG_DISCONNECT:
+            {
+                HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
+
+                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
+
+                if (pClient)
+                {
+                    rc = pSvc->m_fntable.pfnDisconnect (pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
+
+                    hgcmObjDereference (pClient);
+                }
+                else
+                {
+                    rc = VERR_HGCM_INVALID_CLIENT_ID;
+                }
+            } break;
+
+            case SVC_MSG_GUESTCALL:
+            {
+                HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
+                             pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
+
+                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
+
+                if (pClient)
+                {
+                    pSvc->m_fntable.pfnCall ((VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
+
+                    hgcmObjDereference (pClient);
+                }
+                else
+                {
+                    rc = VERR_HGCM_INVALID_CLIENT_ID;
+                }
+            } break;
+
+            case SVC_MSG_HOSTCALL:
+            {
+                HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n", pMsg->u32Function, pMsg->cParms, pMsg->paParms));
+
+                rc = pSvc->m_fntable.pfnHostCall (pMsg->u32Function, pMsg->cParms, pMsg->paParms);
+            } break;
+
+            case SVC_MSG_LOADSTATE:
+            {
+                HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
+
+                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
+
+                if (pClient)
+                {
+                    if (pSvc->m_fntable.pfnLoadState)
+                    {
+                        rc = pSvc->m_fntable.pfnLoadState (pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
+                    }
+
+                    hgcmObjDereference (pClient);
+                }
+                else
+                {
+                    rc = VERR_HGCM_INVALID_CLIENT_ID;
+                }
+            } break;
+
+            case SVC_MSG_SAVESTATE:
+            {
+                HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
+
+                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
+
+                rc = VINF_SUCCESS;
+
+                if (pClient)
+                {
+                    if (pSvc->m_fntable.pfnSaveState)
+                    {
+                        g_fSaveState = true;
+                        rc = pSvc->m_fntable.pfnSaveState (pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
+                        g_fSaveState = false;
+                    }
+
+                    hgcmObjDereference (pClient);
+                }
+                else
+                {
+                    rc = VERR_HGCM_INVALID_CLIENT_ID;
+                }
+            } break;
+            
+            case SVC_MSG_REGEXT:
+            {
+                HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
+                
+                if (pSvc->m_hExtension)
+                {
+                    rc = VERR_NOT_SUPPORTED;
+                }
+                else
+                {
+                    if (pSvc->m_fntable.pfnRegisterExtension)
+                    {
+                        rc = pSvc->m_fntable.pfnRegisterExtension (pMsg->pfnExtension, pMsg->pvExtension);
+                    }
+                    else
+                    {
+                        rc = VERR_NOT_SUPPORTED;
+                    }
+                    
+                    if (VBOX_SUCCESS (rc))
+                    {
+                        pSvc->m_hExtension = pMsg->handle;
+                    }
+                }
+            } break;
+
+            case SVC_MSG_UNREGEXT:
+            {
+                HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
+                
+                if (pSvc->m_hExtension != pMsg->handle)
+                {
+                    rc = VERR_NOT_SUPPORTED;
+                }
+                else
+                {
+                    if (pSvc->m_fntable.pfnRegisterExtension)
+                    {
+                        rc = pSvc->m_fntable.pfnRegisterExtension (NULL, NULL);
+                    }
+                    else
+                    {
+                        rc = VERR_NOT_SUPPORTED;
+                    }
+                    
+                    pSvc->m_hExtension = NULL;
+                }
+            } break;
+
+            default:
+            {
+                AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
+                rc = VERR_NOT_SUPPORTED;
+            } break;
+        }
+
+        if (u32MsgId != SVC_MSG_GUESTCALL)
+        {
+            /* For SVC_MSG_GUESTCALL the service calls the completion helper.
+             * Other messages have to be completed here.
+             */
+            hgcmMsgComplete (pMsgCore, rc);
+        }
+    }
+}
+
+/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc)
+{
+   HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
+
+   if (pMsgCore->MsgId () == SVC_MSG_GUESTCALL)
+   {
+       /* Only call the completion for these messages. The helper 
+        * is called by the service, and the service does not get
+        * any other messages.
+        */
+       hgcmMsgComplete (pMsgCore, rc);
+   }
+   else
+   {
+       AssertFailed ();
+   }
+}
+
+static DECLCALLBACK(void) hgcmMsgCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
+{
+    /* Call the VMMDev port interface to issue IRQ notification. */
+    HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
+
+    LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
+
+    if (pMsgHdr->pHGCMPort && !g_fResetting)
+    {
+        pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
+    }
+}
+
+/*
+ * The main HGCM methods of the service.
+ */
+
+int HGCMService::instanceCreate (const char *pszServiceLibrary, const char *pszServiceName)
+{
+    LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
+
+    /* The maximum length of the thread name, allowed by the RT is 15. */
+    char achThreadName[16];
+
+    strncpy (achThreadName, pszServiceName, 15);
+    achThreadName[15] = 0;
+
+    int rc = hgcmThreadCreate (&m_thread, achThreadName, hgcmServiceThread, this);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        m_pszSvcName    = RTStrDup (pszServiceName);
+        m_pszSvcLibrary = RTStrDup (pszServiceLibrary);
+
+        if (!m_pszSvcName || !m_pszSvcLibrary)
+        {
+            RTStrFree (m_pszSvcLibrary);
+            m_pszSvcLibrary = NULL;
+            
+            RTStrFree (m_pszSvcName);
+            m_pszSvcName = NULL;
+            
+            rc = VERR_NO_MEMORY;
+        }
+        else
+        {
+            /* Initialize service helpers table. */
+            m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
+            m_svcHelpers.pvInstance      = this;
+            
+            /* Execute the load request on the service thread. */
+            HGCMMSGHANDLE hMsg;
+            rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
+
+            if (VBOX_SUCCESS(rc))
+            {
+                rc = hgcmMsgSend (hMsg);
+            }
+        }
+    }
+
+    if (VBOX_FAILURE(rc))
+    {
+        instanceDestroy ();
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+void HGCMService::instanceDestroy (void)
+{
+    LogFlowFunc(("%s\n", m_pszSvcName));
+
+    HGCMMSGHANDLE hMsg;
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        rc = hgcmMsgSend (hMsg);
+
+        if (VBOX_SUCCESS (rc))
+        {
+            hgcmThreadWait (m_thread);
+        }
+    }
+
+    RTStrFree (m_pszSvcLibrary);
+    m_pszSvcLibrary = NULL;
+
+    RTStrFree (m_pszSvcName);
+    m_pszSvcName = NULL;
+}
+
+int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
+{
+    LogFlowFunc(("%s\n", m_pszSvcName));
+
+    HGCMMSGHANDLE hMsg;
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->u32ClientId = u32ClientId;
+        pMsg->pSSM        = pSSM;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+int HGCMService::loadClientState (uint32_t u32ClientId, PSSMHANDLE pSSM)
+{
+    LogFlowFunc(("%s\n", m_pszSvcName));
+
+    HGCMMSGHANDLE hMsg;
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+
+        AssertRelease(pMsg);
+
+        pMsg->u32ClientId = u32ClientId;
+        pMsg->pSSM        = pSSM;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+
+/** The method creates a service and references it.
+ *
+ * @param pszServcieLibrary  The library to be loaded.
+ * @param pszServiceName     The name of the service.
+ * @return VBox rc.
+ * @thread main HGCM
+ */
+/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName)
+{
+    LogFlowFunc(("name = %s, lib %s\n", pszServiceName, pszServiceLibrary));
+
+    /* Look at already loaded services to avoid double loading. */
+
+    HGCMService *pSvc;
+    int rc = HGCMService::ResolveService (&pSvc, pszServiceName);
+    
+    if (VBOX_SUCCESS (rc))
+    {
+        /* The service is already loaded. */
+        pSvc->ReleaseService ();
+        rc = VERR_HGCM_SERVICE_EXISTS;
+    }
+    else
+    {
+        /* Create the new service. */
+        pSvc = new HGCMService ();
+
+        if (!pSvc)
+        {
+            rc = VERR_NO_MEMORY;
+        }
+        else
+        {
+            /* Load the library and call the initialization entry point. */
+            rc = pSvc->instanceCreate (pszServiceLibrary, pszServiceName);
+
+            if (VBOX_SUCCESS(rc))
+            {
+                /* Insert the just created service to list for future references. */
+                pSvc->m_pSvcNext = sm_pSvcListHead;
+                pSvc->m_pSvcPrev = NULL;
+                
+                if (sm_pSvcListHead)
+                {
+                    sm_pSvcListHead->m_pSvcPrev = pSvc;
+                }
+                else
+                {
+                    sm_pSvcListTail = pSvc;
+                }
+
+                sm_pSvcListHead = pSvc;
+
+                sm_cServices++;
+
+                /* Reference the service (for first time) until it is unloaded on HGCM termination. */
+                AssertRelease (pSvc->m_u32RefCnt == 0);
+                pSvc->ReferenceService ();
+
+                LogFlowFunc(("service %p\n", pSvc));
+            }
+        }
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/** The method unloads a service.
+ *
+ * @thread main HGCM
+ */
+void HGCMService::UnloadService (void)
+{
+    LogFlowFunc(("name = %s\n", m_pszSvcName));
+
+    /* Remove the service from the list. */
+    if (m_pSvcNext)
+    {
+        m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
+    }
+    else
+    {
+        sm_pSvcListTail = m_pSvcPrev;
+    }
+
+    if (m_pSvcPrev)
+    {
+        m_pSvcPrev->m_pSvcNext = m_pSvcNext;
+    }
+    else
+    {
+        sm_pSvcListHead = m_pSvcNext;
+    }
+
+    sm_cServices--;
+
+    /* The service must be unloaded only if all clients were disconnected. */
+    LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
+    AssertRelease (m_u32RefCnt == 1);
+
+    /* Now the service can be released. */
+    ReleaseService ();
+}
+
+/** The method unloads all services.
+ *
+ * @thread main HGCM
+ */
+/* static */ void HGCMService::UnloadAll (void)
+{
+    while (sm_pSvcListHead)
+    {
+        sm_pSvcListHead->UnloadService ();
+    }
+}
+
+/** The method obtains a referenced pointer to the service with
+ *  specified name. The caller must call ReleaseService when
+ *  the pointer is no longer needed.
+ *
+ * @param ppSvc          Where to store the pointer to the service.
+ * @param pszServiceName The name of the service.
+ * @return VBox rc.
+ * @thread main HGCM
+ */
+/* static */ int HGCMService::ResolveService (HGCMService **ppSvc, const char *pszServiceName)
+{
+    LogFlowFunc(("ppSvc = %p name = %s\n",
+                 ppSvc, pszServiceName));
+
+    if (!ppSvc || !pszServiceName)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    HGCMService *pSvc = sm_pSvcListHead;
+
+    while (pSvc)
+    {
+        if (strcmp (pSvc->m_pszSvcName, pszServiceName) == 0)
+        {
+            break;
+        }
+
+        pSvc = pSvc->m_pSvcNext;
+    }
+
+    LogFlowFunc(("lookup in the list is %p\n", pSvc));
+
+    if (pSvc == NULL)
+    {
+        return VERR_HGCM_SERVICE_NOT_FOUND;
+    }
+
+    pSvc->ReferenceService ();
+
+    *ppSvc = pSvc;
+
+    return VINF_SUCCESS;
+}
+
+/** The method increases reference counter.
+ *
+ * @thread main HGCM
+ */
+void HGCMService::ReferenceService (void)
+{
+    ASMAtomicIncU32 (&m_u32RefCnt);
+    LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
+}       
+
+/** The method dereferences a service and deletes it when no more refs.
+ *
+ * @thread main HGCM
+ */
+void HGCMService::ReleaseService (void)
+{
+    LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
+    uint32_t u32RefCnt = ASMAtomicDecU32 (&m_u32RefCnt);
+    AssertRelease(u32RefCnt != ~0U);
+
+    LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
+
+    if (u32RefCnt == 0)
+    {
+        instanceDestroy ();
+        delete this;
+    }
+}
+
+/** The method is called when the VM is being reset or terminated
+ *  and disconnects all clients from all services.
+ *
+ * @thread main HGCM
+ */
+/* static */ void HGCMService::Reset (void)
+{
+    g_fResetting = true;
+
+    HGCMService *pSvc = sm_pSvcListHead;
+
+    while (pSvc)
+    {
+        while (pSvc->m_cClients && pSvc->m_paClientIds)
+        {
+            LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
+            pSvc->DisconnectClient (pSvc->m_paClientIds[0]);
+        }
+
+        pSvc = pSvc->m_pSvcNext;
+    }
+
+    g_fResetting = false;
+}
+
+/** The method saves the HGCM state.
+ *
+ * @param pSSM  The saved state context.
+ * @return VBox rc.
+ * @thread main HGCM
+ */
+/* static */ int HGCMService::SaveState (PSSMHANDLE pSSM)
+{
+    /* Save the current handle count and restore afterwards to avoid client id conflicts. */
+    int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
+    AssertRCReturn(rc, rc);
+
+    LogFlowFunc(("%d services to be saved:\n", sm_cServices));
+    
+    /* Save number of services. */
+    rc = SSMR3PutU32(pSSM, sm_cServices);
+    AssertRCReturn(rc, rc);
+
+    /* Save every service. */
+    HGCMService *pSvc = sm_pSvcListHead;
+
+    while (pSvc)
+    {
+        LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
+
+        /* Save the length of the service name. */
+        rc = SSMR3PutU32(pSSM, strlen(pSvc->m_pszSvcName) + 1);
+        AssertRCReturn(rc, rc);
+
+        /* Save the name of the service. */
+        rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
+        AssertRCReturn(rc, rc);
+
+        /* Save the number of clients. */
+        rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
+        AssertRCReturn(rc, rc);
+
+        /* Call the service for every client. Normally a service must not have
+         * a global state to be saved: only per client info is relevant.
+         * The global state of a service is configured during VM startup.
+         */
+        int i;
+
+        for (i = 0; i < pSvc->m_cClients; i++)
+        {
+            uint32_t u32ClientId = pSvc->m_paClientIds[i];
+
+            Log(("client id 0x%08X\n", u32ClientId));
+
+            /* Save the client id. */
+            rc = SSMR3PutU32(pSSM, u32ClientId);
+            AssertRCReturn(rc, rc);
+
+            /* Call the service, so the operation is executed by the service thread. */
+            rc = pSvc->saveClientState (u32ClientId, pSSM);
+            AssertRCReturn(rc, rc);
+        }
+
+        pSvc = pSvc->m_pSvcNext;
+    }
+
+    return VINF_SUCCESS;
+}
+
+/** The method loads saved HGCM state.
+ *
+ * @param pSSM  The saved state context.
+ * @return VBox rc.
+ * @thread main HGCM
+ */
+/* static */ int HGCMService::LoadState (PSSMHANDLE pSSM)
+{
+    /* Restore handle count to avoid client id conflicts. */
+    uint32_t u32;
+
+    int rc = SSMR3GetU32(pSSM, &u32);
+    AssertRCReturn(rc, rc);
+
+    hgcmObjSetHandleCount(u32);
+
+    /* Get the number of services. */
+    uint32_t cServices;
+
+    rc = SSMR3GetU32(pSSM, &cServices);
+    AssertRCReturn(rc, rc);
+    
+    LogFlowFunc(("%d services to be restored:\n", cServices));
+
+    while (cServices--)
+    {
+        /* Get the length of the service name. */
+        rc = SSMR3GetU32(pSSM, &u32);
+        AssertRCReturn(rc, rc);
+        AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
+        
+        char *pszServiceName = (char *)alloca (u32);
+
+        /* Get the service name. */
+        rc = SSMR3GetStrZ(pSSM, pszServiceName, u32);
+        AssertRCReturn(rc, rc);
+        
+        LogFlowFunc(("Restoring service [%s]\n", pszServiceName));
+    
+        /* Resolve the service instance. */
+        HGCMService *pSvc; 
+        rc = ResolveService (&pSvc, pszServiceName);
+        AssertReturn(pSvc, VERR_SSM_UNEXPECTED_DATA);
+            
+        /* Get the number of clients. */
+        uint32_t cClients;
+        rc = SSMR3GetU32(pSSM, &cClients);
+        if (VBOX_FAILURE(rc))
+        {
+            pSvc->ReleaseService ();
+            AssertFailed();
+            return rc;
+        }
+
+        while (cClients--)
+        {
+            /* Get the client id. */
+            uint32_t u32ClientId;
+            rc = SSMR3GetU32(pSSM, &u32ClientId);
+            if (VBOX_FAILURE(rc))
+            {
+                pSvc->ReleaseService ();
+                AssertFailed();
+                return rc;
+            }
+
+            /* Connect the client. */
+            rc = pSvc->CreateAndConnectClient (NULL, u32ClientId);
+            if (VBOX_FAILURE(rc))
+            {
+                pSvc->ReleaseService ();
+                AssertFailed();
+                return rc;
+            }
+
+            /* Call the service, so the operation is executed by the service thread. */
+            rc = pSvc->loadClientState (u32ClientId, pSSM);
+            if (VBOX_FAILURE(rc))
+            {
+                pSvc->ReleaseService ();
+                AssertFailed();
+                return rc;
+            }
+        }
+
+        pSvc->ReleaseService ();
+    }
+
+    return VINF_SUCCESS;
+}
+
+/* Create a new client instance and connect it to the service.
+ *
+ * @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
+ *                        If NULL, use the given 'u32ClientIdIn' handle.
+ * @param u32ClientIdIn   The handle for the client, when 'pu32ClientIdOut' is NULL.
+ * @return VBox rc.
+ */
+int HGCMService::CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
+{
+    LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
+
+    /* Allocate a client information structure. */
+    HGCMClient *pClient = new HGCMClient ();
+
+    if (!pClient)
+    {
+        LogWarningFunc(("Could not allocate HGCMClient!!!\n"));
+        return VERR_NO_MEMORY;
+    }
+
+    uint32_t handle;
+    
+    if (pu32ClientIdOut != NULL)
+    {
+        handle = hgcmObjGenerateHandle (pClient);
+    }
+    else
+    {
+        handle = hgcmObjAssignHandle (pClient, u32ClientIdIn);
+    }
+
+    LogFlowFunc(("client id = %d\n", handle));
+
+    AssertRelease(handle);
+
+    /* Initialize the HGCM part of the client. */
+    int rc = pClient->Init (this);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Call the service. */
+        HGCMMSGHANDLE hMsg;
+
+        rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
+
+        if (VBOX_SUCCESS(rc))
+        {
+            HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+            AssertRelease(pMsg);
+
+            pMsg->u32ClientId = handle;
+
+            hgcmObjDereference (pMsg);
+
+            rc = hgcmMsgSend (hMsg);
+        
+            if (VBOX_SUCCESS (rc))
+            {
+                /* Add the client Id to the array. */
+                if (m_cClients == m_cClientsAllocated)
+                {
+                    m_paClientIds = (uint32_t *)RTMemRealloc (m_paClientIds, (m_cClientsAllocated + 64) * sizeof (m_paClientIds[0]));
+                    Assert(m_paClientIds);
+                    m_cClientsAllocated += 64;
+                }
+            
+                m_paClientIds[m_cClients] = handle;
+                m_cClients++;
+            }
+        }
+    }
+
+    if (VBOX_FAILURE(rc))
+    {
+        hgcmObjDeleteHandle (handle);
+    }
+    else
+    {
+        if (pu32ClientIdOut != NULL)
+        {
+            *pu32ClientIdOut = handle;
+        }
+
+        ReferenceService ();
+    }
+    
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/* Disconnect the client from the service and delete the client handle.
+ *
+ * @param u32ClientId  The handle of the client.
+ * @return VBox rc.
+ */
+int HGCMService::DisconnectClient (uint32_t u32ClientId)
+{
+    LogFlowFunc(("client id = %d\n", u32ClientId));
+
+    /* Call the service. */
+    HGCMMSGHANDLE hMsg;
+
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->u32ClientId = u32ClientId;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+        
+        /* Remove the client id from the array in any case. */
+        int i;
+
+        for (i = 0; i < m_cClients; i++)
+        {
+            if (m_paClientIds[i] == u32ClientId)
+            {
+                m_cClients--;
+                
+                if (m_cClients > i)
+                {
+                    memmove (&m_paClientIds[i], &m_paClientIds[i + 1], m_cClients - i);
+                }
+                
+                break;
+            }
+        }
+
+        /* Delete the client handle. */
+        hgcmObjDeleteHandle (u32ClientId);
+
+        /* The service must be released. */
+        ReleaseService ();
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+int HGCMService::RegisterExtension (HGCMSVCEXTHANDLE handle,
+                                    PFNHGCMSVCEXT pfnExtension,
+                                    void *pvExtension)
+{
+    LogFlowFunc(("%s\n", handle->pszServiceName));
+
+    /* Forward the message to the service thread. */
+    HGCMMSGHANDLE hMsg = 0;
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->handle       = handle;
+        pMsg->pfnExtension = pfnExtension;
+        pMsg->pvExtension  = pvExtension;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+void HGCMService::UnregisterExtension (HGCMSVCEXTHANDLE handle)
+{
+    /* Forward the message to the service thread. */
+    HGCMMSGHANDLE hMsg = 0;
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->handle = handle;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+}
+
+/* Perform a guest call to the service.
+ *
+ * @param pHGCMPort      The port to be used for completion confirmation.
+ * @param pCmd           The VBox HGCM context.
+ * @param u32ClientId    The client handle to be disconnected and deleted.
+ * @param u32Function    The function number.
+ * @param cParms         Number of parameters.
+ * @param paParms        Pointer to array of parameters.
+ * @return VBox rc.
+ */
+int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    HGCMMSGHANDLE hMsg = 0;
+
+    LogFlow(("MAIN::HGCMService::Call\n"));
+
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_GUESTCALL, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgCall *pMsg = (HGCMMsgCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+
+        AssertRelease(pMsg);
+
+        pMsg->pCmd      = pCmd;
+        pMsg->pHGCMPort = pHGCMPort;
+
+        pMsg->u32ClientId = u32ClientId;
+        pMsg->u32Function = u32Function;
+        pMsg->cParms      = cParms;
+        pMsg->paParms     = paParms;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
+    }
+    else
+    {
+        Log(("MAIN::HGCMService::Call: Message allocation failed: %Vrc\n", rc));
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/* Perform a host call the service.
+ *
+ * @param u32Function    The function number.
+ * @param cParms         Number of parameters.
+ * @param paParms        Pointer to array of parameters.
+ * @return VBox rc.
+ */
+int HGCMService::HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
+{
+    LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
+                 m_pszSvcName, u32Function, cParms, paParms));
+
+    HGCMMSGHANDLE hMsg = 0;
+    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->u32Function      = u32Function;
+        pMsg->cParms           = cParms;
+        pMsg->paParms          = paParms;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+
+/* 
+ * Main HGCM thread that manages services.
+ */
+ 
+/* Messages processed by the main HGCM thread. */
+#define HGCM_MSG_CONNECT    (10)  /* Connect a client to a service. */
+#define HGCM_MSG_DISCONNECT (11)  /* Disconnect the specified client id. */
+#define HGCM_MSG_LOAD       (12)  /* Load the service. */
+#define HGCM_MSG_HOSTCALL   (13)  /* Call the service. */
+#define HGCM_MSG_LOADSTATE  (14)  /* Load saved state for the specified service. */
+#define HGCM_MSG_SAVESTATE  (15)  /* Save state for the specified service. */
+#define HGCM_MSG_RESET      (16)  /* Disconnect all clients from the specified service. */
+#define HGCM_MSG_QUIT       (17)  /* Unload all services and terminate the thread. */
+#define HGCM_MSG_REGEXT     (18)  /* Register a service extension. */
+#define HGCM_MSG_UNREGEXT   (19)  /* Unregister a service extension. */
+
+class HGCMMsgMainConnect: public HGCMMsgHeader
+{
+    public:
+        /* Service name. */
+        const char *pszServiceName;
+        /* Where to store the client handle. */
+        uint32_t *pu32ClientId;
+};
+
+class HGCMMsgMainDisconnect: public HGCMMsgHeader
+{
+    public:
+        /* Handle of the client to be disconnected. */
+        uint32_t u32ClientId;
+};
+
+class HGCMMsgMainLoad: public HGCMMsgCore
+{
+    public:
+        /* Name of the library to be loaded. */
+        const char *pszServiceLibrary;
+        /* Name to be assigned to the service. */
+        const char *pszServiceName;
+};
+
+class HGCMMsgMainHostCall: public HGCMMsgCore
+{
+    public:
+        /* Which service to call. */
+        const char *pszServiceName;
+        /* Function number. */
+        uint32_t u32Function;
+        /* Number of the function parameters. */
+        uint32_t cParms;
+        /* Pointer to array of the function parameters. */
+        VBOXHGCMSVCPARM *paParms;
+};
+
+class HGCMMsgMainLoadSaveState: public HGCMMsgCore
+{
+    public:
+        /* SSM context. */
+        PSSMHANDLE pSSM;
+};
+
+class HGCMMsgMainReset: public HGCMMsgCore
+{
+};
+
+class HGCMMsgMainQuit: public HGCMMsgCore
+{
+};
+
+class HGCMMsgMainRegisterExtension: public HGCMMsgCore
+{
+    public:
+        /* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
+        HGCMSVCEXTHANDLE *pHandle;
+        /* Name of the service. */
+        const char *pszServiceName;
+        /* The extension entry point. */
+        PFNHGCMSVCEXT pfnExtension;
+        /* The extension pointer. */
+        void *pvExtension;
+};
+
+class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
+{
+    public:
+        /* Handle of the registered extension. */
+        HGCMSVCEXTHANDLE handle;
+};
+
+static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
+{
+    switch (u32MsgId)
+    {
+        case HGCM_MSG_CONNECT:    return new HGCMMsgMainConnect ();
+        case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect ();
+        case HGCM_MSG_LOAD:       return new HGCMMsgMainLoad ();
+        case HGCM_MSG_HOSTCALL:   return new HGCMMsgMainHostCall ();
+        case HGCM_MSG_LOADSTATE:      
+        case HGCM_MSG_SAVESTATE:  return new HGCMMsgMainLoadSaveState ();
+        case HGCM_MSG_RESET:      return new HGCMMsgMainReset ();
+        case HGCM_MSG_QUIT:       return new HGCMMsgMainQuit ();
+        case HGCM_MSG_REGEXT:     return new HGCMMsgMainRegisterExtension ();
+        case HGCM_MSG_UNREGEXT:   return new HGCMMsgMainUnregisterExtension ();
+        default:
+            AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
+    }
+
+    return NULL;
+}
+
+
+/* The main HGCM thread handler. */
+static DECLCALLBACK(void) hgcmThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
+{
+    LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
+                 ThreadHandle, pvUser));
+
+    NOREF(pvUser);
+
+    bool fQuit = false;
+
+    while (!fQuit)
+    {
+        HGCMMsgCore *pMsgCore;
+        int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
+
+        if (VBOX_FAILURE (rc))
+        {
+            /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
+            AssertMsgFailed (("%Vrc\n", rc));
+            break;
+        }
+
+        uint32_t u32MsgId = pMsgCore->MsgId ();
+
+        switch (u32MsgId)
+        {
+            case HGCM_MSG_CONNECT:
+            {
+                HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
+
+                LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
+                             pMsg->pszServiceName, pMsg->pu32ClientId));
+
+                /* Resolve the service name to the pointer to service instance.
+                 */
+                HGCMService *pService;
+                rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
+
+                if (VBOX_SUCCESS (rc))
+                {
+                    /* Call the service instance method. */
+                    rc = pService->CreateAndConnectClient (pMsg->pu32ClientId, 0);
+
+                    /* Release the service after resolve. */
+                    pService->ReleaseService ();
+                }
+            } break;
+
+            case HGCM_MSG_DISCONNECT:
+            {
+                HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
+
+                LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
+                             pMsg->u32ClientId));
+
+                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
+
+                if (!pClient)
+                {
+                    rc = VERR_HGCM_INVALID_CLIENT_ID;
+                    break;
+                }
+
+                /* The service the client belongs to. */
+                HGCMService *pService = pClient->pService;
+
+                /* Call the service instance to disconnect the client. */
+                rc = pService->DisconnectClient (pMsg->u32ClientId);
+
+                hgcmObjDereference (pClient);
+            } break;
+
+            case HGCM_MSG_LOAD:
+            {
+                HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
+
+                LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s\n",
+                             pMsg->pszServiceName, pMsg->pszServiceLibrary));
+
+                rc = HGCMService::LoadService (pMsg->pszServiceName, pMsg->pszServiceLibrary);
+            } break;
+
+            case HGCM_MSG_HOSTCALL:
+            {
+                HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
+
+                LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
+                             pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
+
+                /* Resolve the service name to the pointer to service instance. */
+                HGCMService *pService;
+                rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
+
+                if (VBOX_SUCCESS (rc))
+                {
+                    rc = pService->HostCall (pMsg->u32Function, pMsg->cParms, pMsg->paParms);
+
+                    pService->ReleaseService ();
+                }
+            } break;
+
+            case HGCM_MSG_RESET:
+            {
+                LogFlowFunc(("HGCM_MSG_RESET\n"));
+
+                HGCMService::Reset ();
+            } break;
+
+            case HGCM_MSG_LOADSTATE:
+            {
+                HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
+
+                LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
+
+                rc = HGCMService::LoadState (pMsg->pSSM);
+            } break;
+
+            case HGCM_MSG_SAVESTATE:
+            {
+                HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
+
+                LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
+
+                rc = HGCMService::SaveState (pMsg->pSSM);
+            } break;
+
+            case HGCM_MSG_QUIT:
+            {
+                LogFlowFunc(("HGCM_MSG_QUIT\n"));
+
+                HGCMService::UnloadAll ();
+
+                fQuit = true;
+            } break;
+
+            case HGCM_MSG_REGEXT:
+            {
+                HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
+                
+                LogFlowFunc(("HGCM_MSG_REGEXT\n"));
+                
+                /* Allocate the handle data. */
+                HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ (sizeof (struct _HGCMSVCEXTHANDLEDATA)
+                                                                         + strlen (pMsg->pszServiceName)
+                                                                         + sizeof (char));
+                
+                if (handle == NULL)
+                {
+                    rc = VERR_NO_MEMORY;
+                }
+                else
+                {
+                    handle->pszServiceName = (char *)((uint8_t *)handle + sizeof (struct _HGCMSVCEXTHANDLEDATA));
+                    strcpy (handle->pszServiceName, pMsg->pszServiceName);
+                    
+                    HGCMService *pService;
+                    rc = HGCMService::ResolveService (&pService, handle->pszServiceName);
+
+                    if (VBOX_SUCCESS (rc))
+                    {
+                        pService->RegisterExtension (handle, pMsg->pfnExtension, pMsg->pvExtension);
+
+                        pService->ReleaseService ();
+                    }
+                    
+                    if (VBOX_FAILURE (rc))
+                    {
+                        RTMemFree (handle);
+                    }
+                    else
+                    {
+                        *pMsg->pHandle = handle;
+                    }
+                }
+            } break;
+
+            case HGCM_MSG_UNREGEXT:
+            {
+                HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
+
+                LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
+
+                HGCMService *pService;
+                rc = HGCMService::ResolveService (&pService, pMsg->handle->pszServiceName);
+
+                if (VBOX_SUCCESS (rc))
+                {
+                    pService->UnregisterExtension (pMsg->handle);
+
+                    pService->ReleaseService ();
+                }
+                
+                RTMemFree (pMsg->handle);
+            } break;
+
+            default:
+            {
+                AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
+                rc = VERR_NOT_SUPPORTED;
+            } break;
+        }
+
+        /* Complete the message processing. */
+        hgcmMsgComplete (pMsgCore, rc);
+
+        LogFlowFunc(("message processed %Vrc\n", rc));
+    }
+}
+
+
+/*
+ * The HGCM API.
+ */
+
+/* The main hgcm thread. */
+static HGCMTHREADHANDLE g_hgcmThread = 0;
+
+/*
+ * Public HGCM functions.
+ *
+ * hgcmGuest* - called as a result of the guest HGCM requests.
+ * hgcmHost*  - called by the host.
+ */
+
+/* Load a HGCM service from the specified library.
+ * Assign the specified name to the service.
+ *
+ * @param pszServiceName     The name to be assigned to the service.
+ * @param pszServiceLibrary  The library to be loaded.
+ * @return VBox rc.
+ */
+int HGCMHostLoad (const char *pszServiceName,
+                  const char *pszServiceLibrary)
+{
+    LogFlowFunc(("name = %s, lib = %s\n", pszServiceName, pszServiceLibrary));
+
+    if (!pszServiceName || !pszServiceLibrary)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /* Forward the request to the main hgcm thread. */
+    HGCMMSGHANDLE hMsg = 0;
+
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
+        HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->pszServiceName    = pszServiceName;
+        pMsg->pszServiceLibrary = pszServiceLibrary;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/* Register a HGCM service extension.
+ *
+ * @param pHandle            Returned handle for the registered extension.
+ * @param pszServiceName     The name of the service.
+ * @param pfnExtension       The extension callback.
+ * @return VBox rc.
+ */
+int HGCMHostRegisterServiceExtension (HGCMSVCEXTHANDLE *pHandle,
+                                      const char *pszServiceName,
+                                      PFNHGCMSVCEXT pfnExtension,
+                                      void *pvExtension)
+{
+    LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
+
+    if (!pHandle || !pszServiceName || !pfnExtension)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /* Forward the request to the main hgcm thread. */
+    HGCMMSGHANDLE hMsg = 0;
+
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
+        HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->pHandle        = pHandle;
+        pMsg->pszServiceName = pszServiceName;
+        pMsg->pfnExtension   = pfnExtension;
+        pMsg->pvExtension    = pvExtension;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("*pHandle = %p, rc = %Vrc\n", *pHandle, rc));
+    return rc;
+}
+
+void HGCMHostUnregisterServiceExtension (HGCMSVCEXTHANDLE handle)
+{
+    LogFlowFunc(("handle = %p\n", handle));
+
+    /* Forward the request to the main hgcm thread. */
+    HGCMMSGHANDLE hMsg = 0;
+
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Initialize the message. */
+        HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->handle = handle;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return;
+}
+
+/* Find a service and inform it about a client connection, create a client handle.
+ *
+ * @param pHGCMPort      The port to be used for completion confirmation.
+ * @param pCmd           The VBox HGCM context.
+ * @param pszServiceName The name of the service to be connected to.
+ * @param pu32ClientId   Where the store the created client handle.
+ * @return VBox rc.
+ */
+int HGCMGuestConnect (PPDMIHGCMPORT pHGCMPort,
+                      PVBOXHGCMCMD pCmd,
+                      const char *pszServiceName,
+                      uint32_t *pu32ClientId)
+{
+    LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
+                 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
+
+    if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /* Forward the request to the main hgcm thread. */
+    HGCMMSGHANDLE hMsg = 0;
+
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
+         * will not be deallocated by the caller until the message is completed,
+         * use the supplied pointers.
+         */
+        HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->pHGCMPort      = pHGCMPort;
+        pMsg->pCmd           = pCmd;
+        pMsg->pszServiceName = pszServiceName;
+        pMsg->pu32ClientId   = pu32ClientId;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/* Tell a service that the client is disconnecting, destroy the client handle.
+ *
+ * @param pHGCMPort      The port to be used for completion confirmation.
+ * @param pCmd           The VBox HGCM context.
+ * @param u32ClientId    The client handle to be disconnected and deleted.
+ * @return VBox rc.
+ */
+int HGCMGuestDisconnect (PPDMIHGCMPORT pHGCMPort,
+                         PVBOXHGCMCMD pCmd,
+                         uint32_t u32ClientId)
+{
+    LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
+                  pHGCMPort, pCmd, u32ClientId));
+
+    if (!pHGCMPort || !pCmd || !u32ClientId)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /* Forward the request to the main hgcm thread. */
+    HGCMMSGHANDLE hMsg = 0;
+
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Initialize the message. */
+        HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->pCmd        = pCmd;
+        pMsg->pHGCMPort   = pHGCMPort;
+        pMsg->u32ClientId = u32ClientId;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
+ *
+ * @param pSSM     The SSM handle.
+ * @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
+ * @return VBox rc.
+ */
+static int hgcmHostLoadSaveState (PSSMHANDLE pSSM,
+                                  uint32_t u32MsgId)
+{
+    LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
+
+    HGCMMSGHANDLE hMsg = 0;
+
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, u32MsgId, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+
+        pMsg->pSSM = pSSM;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/* Save the state of services.
+ *
+ * @param pSSM     The SSM handle.
+ * @return VBox rc.
+ */
+int HGCMHostSaveState (PSSMHANDLE pSSM)
+{
+    return hgcmHostLoadSaveState (pSSM, HGCM_MSG_SAVESTATE);
+}
+
+/* Load the state of services.
+ *
+ * @param pSSM     The SSM handle.
+ * @return VBox rc.
+ */
+int HGCMHostLoadState (PSSMHANDLE pSSM)
+{
+    return hgcmHostLoadSaveState (pSSM, HGCM_MSG_LOADSTATE);
+}
+
+/* The guest calls the service.
+ *
+ * @param pHGCMPort      The port to be used for completion confirmation.
+ * @param pCmd           The VBox HGCM context.
+ * @param u32ClientId    The client handle to be disconnected and deleted.
+ * @param u32Function    The function number.
+ * @param cParms         Number of parameters.
+ * @param paParms        Pointer to array of parameters.
+ * @return VBox rc.
+ */
+int HGCMGuestCall (PPDMIHGCMPORT pHGCMPort,
+                   PVBOXHGCMCMD pCmd,
+                   uint32_t u32ClientId,
+                   uint32_t u32Function,
+                   uint32_t cParms,
+                   VBOXHGCMSVCPARM *paParms)
+{
+    LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
+                  pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
+
+    if (!pHGCMPort || !pCmd || u32ClientId == 0)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    int rc = VERR_HGCM_INVALID_CLIENT_ID;
+
+    /* Resolve the client handle to the client instance pointer. */
+    HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientId, HGCMOBJ_CLIENT);
+
+    if (pClient)
+    {
+        AssertRelease(pClient->pService);
+
+        /* Forward the message to the service thread. */
+        rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms);
+
+        hgcmObjDereference (pClient);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+/* The host calls the service.
+ *
+ * @param pszServiceName The service name to be called.
+ * @param u32Function    The function number.
+ * @param cParms         Number of parameters.
+ * @param paParms        Pointer to array of parameters.
+ * @return VBox rc.
+ */
+int HGCMHostCall (const char *pszServiceName,
+                  uint32_t u32Function,
+                  uint32_t cParms,
+                  VBOXHGCMSVCPARM *paParms)
+{
+    LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
+                 pszServiceName, u32Function, cParms, paParms));
+
+    if (!pszServiceName)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    HGCMMSGHANDLE hMsg = 0;
+
+    /* Host calls go to main HGCM thread that resolves the service name to the
+     * service instance pointer and then, using the service pointer, forwards
+     * the message to the service thread.
+     * So it is slow but host calls are intended mostly for configuration and
+     * other non-time-critical functions.
+     */
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+        AssertRelease(pMsg);
+        
+        pMsg->pszServiceName = (char *)pszServiceName;
+        pMsg->u32Function    = u32Function;
+        pMsg->cParms         = cParms;
+        pMsg->paParms        = paParms;
+
+        hgcmObjDereference (pMsg);
+
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+int HGCMHostReset (void)
+{
+    LogFlowFunc(("\n"));
+    
+    /* Disconnect all clients.
+     */
+
+    HGCMMSGHANDLE hMsg = 0;
+
+    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        rc = hgcmMsgSend (hMsg);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+int HGCMHostInit (void)
+{
+    LogFlowFunc(("\n"));
+
+    int rc = hgcmThreadInit ();
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /*
+         * Start main HGCM thread.
+         */
+
+        rc = hgcmThreadCreate (&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL);
+
+        if (VBOX_FAILURE (rc))
+        {
+            LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Vrc\n", rc));
+        }
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+int HGCMHostShutdown (void)
+{
+    LogFlowFunc(("\n"));
+
+    /*
+     * Do HGCMReset and then unload all services.
+     */
+
+    int rc = HGCMHostReset ();
+
+    if (VBOX_SUCCESS (rc))
+    {
+        /* Send the quit message to the main hgcmThread. */
+        HGCMMSGHANDLE hMsg = 0;
+
+        rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
+
+        if (VBOX_SUCCESS(rc))
+        {
+            rc = hgcmMsgSend (hMsg);
+
+            if (VBOX_SUCCESS (rc))
+            {
+                /* Wait for the thread termination. */
+                hgcmThreadWait (g_hgcmThread);
+                g_hgcmThread = 0;
+
+                hgcmThreadUninit ();
+            }
+        }
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
Index: /trunk/src/VBox/Frontends/VBoxBFE/HGCM.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/HGCM.h	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/HGCM.h	(revision 5979)
@@ -0,0 +1,57 @@
+/** @file
+ *
+ * HGCM - Host-Guest Communication Manager
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+#ifndef __HGCM_h__
+#define __HGCM_h__
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <VBox/pdm.h>
+
+#include <VBox/VBoxGuest.h>
+#include <VBox/hgcmsvc.h>
+
+/* HGCM saved state version */
+#define HGCM_SSM_VERSION    2
+
+/* Handle of a HGCM service extension. */
+struct _HGCMSVCEXTHANDLEDATA;
+typedef struct _HGCMSVCEXTHANDLEDATA *HGCMSVCEXTHANDLE;
+
+__BEGIN_DECLS
+int HGCMHostInit (void);
+int HGCMHostShutdown (void);
+
+int HGCMHostReset (void);
+
+int HGCMHostLoad (const char *pszServiceName, const char *pszServiceLibrary);
+
+int HGCMHostRegisterServiceExtension (HGCMSVCEXTHANDLE *pHandle, const char *pszServiceName, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
+void HGCMHostUnregisterServiceExtension (HGCMSVCEXTHANDLE handle);
+
+int HGCMGuestConnect (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmdPtr, const char *pszServiceName, uint32_t *pClientID);
+int HGCMGuestDisconnect (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmdPtr, uint32_t clientID);
+int HGCMGuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmdPtr, uint32_t clientID, uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
+
+int HGCMHostCall (const char *pszServiceName, uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
+
+int HGCMHostSaveState (PSSMHANDLE pSSM);
+int HGCMHostLoadState (PSSMHANDLE pSSM);
+
+__END_DECLS
+
+#endif /* __HGCM_h__ */
Index: /trunk/src/VBox/Frontends/VBoxBFE/HGCMObjects.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/HGCMObjects.cpp	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/HGCMObjects.cpp	(revision 5979)
@@ -0,0 +1,287 @@
+/** @file
+ *
+ * HGCM (Host-Guest Communication Manager):
+ * HGCMObjects - Host-Guest Communication Manager objects
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
+#include "Logging.h"
+
+#include "HGCMObjects.h"
+
+#include <string.h>
+
+#include <VBox/err.h>
+
+
+static RTCRITSECT g_critsect;
+
+/* There are internal handles, which are not saved,
+ * and client handles, which are saved.
+ * They use different range of values:
+ *     1..7FFFFFFF for clients,
+ *     0x80000001..0xFFFFFFFF for other handles.
+ */
+static uint32_t volatile g_u32InternalHandleCount;
+static uint32_t volatile g_u32ClientHandleCount;
+
+static PAVLULNODECORE g_pTree;
+
+
+DECLINLINE(int) hgcmObjEnter (void)
+{
+    return RTCritSectEnter (&g_critsect);
+}
+
+DECLINLINE(void) hgcmObjLeave (void)
+{
+    RTCritSectLeave (&g_critsect);
+}
+
+int hgcmObjInit (void)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlow(("MAIN::hgcmObjInit\n"));
+
+    g_u32InternalHandleCount = 0x80000000;
+    g_u32ClientHandleCount = 0;
+    g_pTree = NULL;
+
+    rc = RTCritSectInit (&g_critsect);
+
+    LogFlow(("MAIN::hgcmObjInit: rc = %Vrc\n", rc));
+
+    return rc;
+}
+
+void hgcmObjUninit (void)
+{
+    if (RTCritSectIsInitialized (&g_critsect))
+    {
+        RTCritSectDelete (&g_critsect);
+    }
+}
+
+uint32_t hgcmObjMake (HGCMObject *pObject, uint32_t u32HandleIn)
+{
+    int handle = 0;
+
+    LogFlow(("MAIN::hgcmObjGenerateHandle: pObject %p\n", pObject));
+
+    int rc = hgcmObjEnter ();
+
+    if (VBOX_SUCCESS(rc))
+    {
+        ObjectAVLCore *pCore = &pObject->Core;
+
+        /* Generate a new handle value. */
+        
+        uint32_t volatile *pu32HandleCountSource = pObject->Type () == HGCMOBJ_CLIENT?
+                                                       &g_u32ClientHandleCount:
+                                                       &g_u32InternalHandleCount;
+
+        uint32_t u32Start = *pu32HandleCountSource;
+
+        for (;;)
+        {
+            uint32_t Key; 
+            
+            if (u32HandleIn == 0)
+            {
+                Key = ASMAtomicIncU32 (pu32HandleCountSource);
+
+                if (Key == u32Start)
+                {
+                    /* Rollover. Something is wrong. */
+                    AssertReleaseFailed ();
+                    break;
+                }
+
+                /* 0 and 0x80000000 are not valid handles. */
+                if ((Key & 0x7FFFFFFF) == 0)
+                {
+                    /* Over the invalid value, reinitialize the source. */
+                    *pu32HandleCountSource = pObject->Type () == HGCMOBJ_CLIENT?
+                                                 0:
+                                                 0x80000000;
+                    continue;
+                }
+            }
+            else
+            {
+                Key = u32HandleIn;
+            }
+
+            /* Insert object to AVL tree. */
+            pCore->AvlCore.Key = Key;
+
+            bool bRC = RTAvlULInsert(&g_pTree, &pCore->AvlCore);
+
+            /* Could not insert a handle. */
+            if (!bRC)
+            {
+                if (u32HandleIn == 0)
+                {
+                    /* Try another generated handle. */
+                    continue;
+                }
+                else
+                {
+                    /* Could not use the specified handle. */
+                    break;
+                }
+            }
+
+            /* Initialize backlink. */
+            pCore->pSelf = pObject;
+
+            /* Reference the object for time while it resides in the tree. */
+            pObject->Reference ();
+
+            /* Store returned handle. */
+            handle = Key;
+            
+            Log(("Object key inserted 0x%08X\n", Key));
+
+            break;
+        }
+
+        hgcmObjLeave ();
+    }
+    else
+    {
+        AssertReleaseMsgFailed (("MAIN::hgcmObjGenerateHandle: Failed to acquire object pool semaphore"));
+    }
+
+    LogFlow(("MAIN::hgcmObjGenerateHandle: handle = 0x%08X, rc = %Vrc, return void\n", handle, rc));
+
+    return handle;
+}
+
+uint32_t hgcmObjGenerateHandle (HGCMObject *pObject)
+{
+    return hgcmObjMake (pObject, 0);
+}
+
+uint32_t hgcmObjAssignHandle (HGCMObject *pObject, uint32_t u32Handle)
+{
+    return hgcmObjMake (pObject, u32Handle);
+}
+
+void hgcmObjDeleteHandle (uint32_t handle)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlow(("MAIN::hgcmObjDeleteHandle: handle 0x%08X\n", handle));
+
+    if (handle)
+    {
+        rc = hgcmObjEnter ();
+
+        if (VBOX_SUCCESS(rc))
+        {
+            ObjectAVLCore *pCore = (ObjectAVLCore *)RTAvlULRemove (&g_pTree, handle);
+
+            if (pCore)
+            {
+                AssertRelease(pCore->pSelf);
+
+                pCore->pSelf->Dereference ();
+            }
+
+            hgcmObjLeave ();
+        }
+        else
+        {
+            AssertReleaseMsgFailed (("Failed to acquire object pool semaphore, rc = %Vrc", rc));
+        }
+    }
+
+    LogFlow(("MAIN::hgcmObjDeleteHandle: rc = %Vrc, return void\n", rc));
+
+    return;
+}
+
+HGCMObject *hgcmObjReference (uint32_t handle, HGCMOBJ_TYPE enmObjType)
+{
+    LogFlow(("MAIN::hgcmObjReference: handle 0x%08X\n", handle));
+
+    HGCMObject *pObject = NULL;
+
+    if ((handle & 0x7FFFFFFF) == 0)
+    {
+        return pObject;
+    }
+
+    int rc = hgcmObjEnter ();
+
+    if (VBOX_SUCCESS(rc))
+    {
+        ObjectAVLCore *pCore = (ObjectAVLCore *)RTAvlULGet (&g_pTree, handle);
+
+        Assert(!pCore || (pCore->pSelf && pCore->pSelf->Type() == enmObjType));
+        if (    pCore 
+            &&  pCore->pSelf
+            &&  pCore->pSelf->Type() == enmObjType)
+        {
+            pObject = pCore->pSelf;
+
+            AssertRelease(pObject);
+
+            pObject->Reference ();
+        }
+
+        hgcmObjLeave ();
+    }
+    else
+    {
+        AssertReleaseMsgFailed (("Failed to acquire object pool semaphore, rc = %Vrc", rc));
+    }
+
+    LogFlow(("MAIN::hgcmObjReference: return pObject %p\n", pObject));
+
+    return pObject;
+}
+
+void hgcmObjDereference (HGCMObject *pObject)
+{
+    LogFlow(("MAIN::hgcmObjDereference: pObject %p\n", pObject));
+
+    AssertRelease(pObject);
+
+    pObject->Dereference ();
+
+    LogFlow(("MAIN::hgcmObjDereference: return\n"));
+}
+
+uint32_t hgcmObjQueryHandleCount ()
+{
+    return g_u32ClientHandleCount;
+}
+
+void hgcmObjSetHandleCount (uint32_t u32ClientHandleCount)
+{
+    Assert(g_u32ClientHandleCount <= u32ClientHandleCount);
+
+    int rc = hgcmObjEnter ();
+
+    if (VBOX_SUCCESS(rc))
+    {
+        if (g_u32ClientHandleCount <= u32ClientHandleCount)
+            g_u32ClientHandleCount = u32ClientHandleCount;
+        hgcmObjLeave ();
+   }
+}
Index: /trunk/src/VBox/Frontends/VBoxBFE/HGCMObjects.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/HGCMObjects.h	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/HGCMObjects.h	(revision 5979)
@@ -0,0 +1,114 @@
+/** @file
+ *
+ * HGCMObjects - Host-Guest Communication Manager objects header.
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+#ifndef __HGCMOBJECTS__H
+#define __HGCMOBJECTS__H
+
+#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
+#include "Logging.h"
+
+#include <iprt/assert.h>
+#include <iprt/avl.h>
+#include <iprt/critsect.h>
+#include <iprt/asm.h>
+
+class HGCMObject;
+
+typedef struct _ObjectAVLCore
+{
+    AVLULNODECORE AvlCore;
+    HGCMObject *pSelf;
+} ObjectAVLCore;
+
+typedef enum
+{
+    HGCMOBJ_CLIENT,
+    HGCMOBJ_THREAD,
+    HGCMOBJ_MSG,
+    HGCMOBJ_SizeHack   = 0x7fffffff
+} HGCMOBJ_TYPE;
+
+class HGCMObject
+{
+    private:
+    friend uint32_t hgcmObjMake (HGCMObject *pObject, uint32_t u32HandleIn);
+
+        int32_t volatile cRef;
+        HGCMOBJ_TYPE     enmObjType;
+
+        ObjectAVLCore Core;
+
+    protected:
+        virtual ~HGCMObject (void) {};
+
+    public:
+        HGCMObject (HGCMOBJ_TYPE enmObjType) : cRef (0)
+        {
+            this->enmObjType  = enmObjType;
+        };
+
+        void Reference (void)
+        {
+            int32_t refCnt = ASMAtomicIncS32 (&cRef);
+            NOREF(refCnt);
+            Log(("Reference: refCnt = %d\n", refCnt));
+        }
+
+        void Dereference (void)
+        {
+            int32_t refCnt = ASMAtomicDecS32 (&cRef);
+
+            Log(("Dereference: refCnt = %d\n", refCnt));
+            
+            AssertRelease(refCnt >= 0);
+
+            if (refCnt)
+            {
+                return;
+            }
+
+            delete this;
+        }
+
+        uint32_t Handle (void)
+        {
+            return Core.AvlCore.Key;
+        };
+
+        HGCMOBJ_TYPE Type (void)
+        {
+            return enmObjType;
+        };
+};
+
+int hgcmObjInit (void);
+
+void hgcmObjUninit (void);
+
+uint32_t hgcmObjGenerateHandle (HGCMObject *pObject);
+uint32_t hgcmObjAssignHandle (HGCMObject *pObject, uint32_t u32Handle);
+
+void hgcmObjDeleteHandle (uint32_t handle);
+
+HGCMObject *hgcmObjReference (uint32_t handle, HGCMOBJ_TYPE enmObjType);
+
+void hgcmObjDereference (HGCMObject *pObject);
+
+uint32_t hgcmObjQueryHandleCount ();
+void     hgcmObjSetHandleCount (uint32_t u32HandleCount);
+
+#endif /* __HGCMOBJECTS__H */
Index: /trunk/src/VBox/Frontends/VBoxBFE/HGCMThread.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/HGCMThread.cpp	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/HGCMThread.cpp	(revision 5979)
@@ -0,0 +1,821 @@
+/** @file
+ *
+ * HGCM (Host-Guest Communication Manager):
+ * HGCMThread - Host-Guest Communication Manager Threads
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
+#include "Logging.h"
+
+#include "HGCMThread.h"
+
+#include <VBox/err.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/string.h>
+
+
+/* HGCM uses worker threads, which process messages from other threads.
+ * A message consists of the message header and message specific data.
+ * Message header is opaque for callers, but message data is defined
+ * and used by them.
+ *
+ * Messages are distinguished by message identifier and worker thread
+ * they are allocated for.
+ *
+ * Messages are allocated for a worker thread and belong to
+ * the thread. A worker thread holds the queue of messages.
+ *
+ * The calling thread creates a message, specifying which worker thread
+ * the message is created for, then, optionally, initializes message
+ * specific data and, also optionally, references the message.
+ *
+ * Message then is posted or sent to worker thread by inserting
+ * it to the worker thread message queue and referencing the message.
+ * Worker thread then again may fetch next message.
+ *
+ * Upon processing the message the worker thread dereferences it.
+ * Dereferencing also automatically deletes message from the thread
+ * queue and frees memory allocated for the message, if no more
+ * references left. If there are references, the message remains
+ * in the queue.
+ *
+ */
+
+/* Version of HGCM message header */
+#define HGCMMSG_VERSION (1)
+
+/* Thread is initializing. */
+#define HGCMMSG_TF_INITIALIZING        (0x00000001)
+/* Thread must be terminated. */
+#define HGCMMSG_TF_TERMINATE           (0x00000002)
+/* Thread has been terminated. */
+#define HGCMMSG_TF_TERMINATED          (0x00000004)
+
+/** @todo consider use of RTReq */
+
+static DECLCALLBACK(int) hgcmWorkerThreadFunc (RTTHREAD ThreadSelf, void *pvUser);
+
+class HGCMThread: public HGCMObject
+{
+    private:
+    friend DECLCALLBACK(int) hgcmWorkerThreadFunc (RTTHREAD ThreadSelf, void *pvUser);
+
+        /* Worker thread function. */
+        PFNHGCMTHREAD m_pfnThread;
+
+        /* A user supplied thread parameter. */
+        void *m_pvUser;
+
+        /* The thread runtime handle. */
+        RTTHREAD m_thread;
+
+        /* Event the thread waits for, signalled when a message
+         * to process is posted to the thread.
+         */
+        RTSEMEVENTMULTI m_eventThread;
+
+        /* A caller thread waits for completion of a SENT message on this event. */
+        RTSEMEVENTMULTI m_eventSend;
+
+        /* Critical section for accessing the thread data, mostly for message queues. */
+        RTCRITSECT m_critsect;
+
+        /* thread state/operation flags */
+        uint32_t m_fu32ThreadFlags;
+
+        /* Message queue variables. Messages are inserted at tail of message
+         * queue. They are consumed by worker thread sequently. If a message was
+         * consumed, it is removed from message queue.
+         */
+
+        /* Head of message queue. */
+        HGCMMsgCore *m_pMsgInputQueueHead;
+        /* Message which another message will be inserted after. */
+        HGCMMsgCore *m_pMsgInputQueueTail;
+
+        /* Head of messages being processed queue. */
+        HGCMMsgCore *m_pMsgInProcessHead;
+        /* Message which another message will be inserted after. */
+        HGCMMsgCore *m_pMsgInProcessTail;
+
+        /* Head of free message structures list. */
+        HGCMMsgCore *m_pFreeHead;
+        /* Tail of free message structures list. */
+        HGCMMsgCore *m_pFreeTail;
+
+        HGCMTHREADHANDLE m_handle;
+
+        inline int Enter (void);
+        inline void Leave (void);
+
+        HGCMMsgCore *FetchFreeListHead (void);
+
+    protected:
+        virtual ~HGCMThread (void);
+
+    public:
+
+        HGCMThread ();
+
+        int WaitForTermination (void);
+
+        int Initialize (HGCMTHREADHANDLE handle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser);
+
+        int MsgAlloc (HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage);
+        int MsgGet (HGCMMsgCore **ppMsg);
+        int MsgPost (HGCMMsgCore *pMsg, PHGCMMSGCALLBACK pfnCallback, bool bWait);
+        void MsgComplete (HGCMMsgCore *pMsg, int32_t result);
+};
+
+
+/*
+ * HGCMMsgCore implementation.
+ */
+
+#define HGCM_MSG_F_PROCESSED  (0x00000001)
+#define HGCM_MSG_F_WAIT       (0x00000002)
+#define HGCM_MSG_F_IN_PROCESS (0x00000004)
+
+void HGCMMsgCore::InitializeCore (uint32_t u32MsgId, HGCMTHREADHANDLE hThread)
+{
+    m_u32Version  = HGCMMSG_VERSION;
+    m_u32Msg      = u32MsgId;
+    m_pfnCallback = NULL;
+    m_pNext       = NULL;
+    m_pPrev       = NULL;
+    m_fu32Flags   = 0;
+    m_rcSend      = VINF_SUCCESS;
+
+    m_pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
+    AssertRelease (m_pThread);
+}
+
+/* virtual */ HGCMMsgCore::~HGCMMsgCore ()
+{
+    if (m_pThread)
+    {
+        hgcmObjDereference (m_pThread);
+        m_pThread = NULL;
+    }
+}
+
+/*
+ * HGCMThread implementation.
+ */
+
+static DECLCALLBACK(int) hgcmWorkerThreadFunc (RTTHREAD ThreadSelf, void *pvUser)
+{
+    int rc = VINF_SUCCESS;
+
+    HGCMThread *pThread = (HGCMThread *)pvUser;
+
+    LogFlow(("MAIN::hgcmWorkerThreadFunc: starting HGCM thread %p\n", pThread));
+
+    AssertRelease(pThread);
+
+    pThread->m_thread = ThreadSelf;
+    pThread->m_fu32ThreadFlags &= ~HGCMMSG_TF_INITIALIZING;
+    rc = RTThreadUserSignal (ThreadSelf);
+    AssertRC (rc);
+
+    pThread->m_pfnThread (pThread->Handle (), pThread->m_pvUser);
+
+    pThread->m_fu32ThreadFlags |= HGCMMSG_TF_TERMINATED;
+
+    hgcmObjDeleteHandle (pThread->Handle ());
+
+    pThread->m_thread = NIL_RTTHREAD;
+
+    LogFlow(("MAIN::hgcmWorkerThreadFunc: completed HGCM thread %p\n", pThread));
+
+    return rc;
+}
+
+HGCMThread::HGCMThread () 
+    :
+    HGCMObject(HGCMOBJ_THREAD),
+    m_pfnThread (NULL),
+    m_pvUser (NULL),
+    m_thread (NIL_RTTHREAD),
+    m_eventThread (0),
+    m_eventSend (0),
+    m_fu32ThreadFlags (0),
+    m_pMsgInputQueueHead (NULL),
+    m_pMsgInputQueueTail (NULL),
+    m_pMsgInProcessHead (NULL),
+    m_pMsgInProcessTail (NULL),
+    m_pFreeHead (NULL),
+    m_pFreeTail (NULL),
+    m_handle (0)
+{
+    memset (&m_critsect, 0, sizeof (m_critsect));
+}
+
+HGCMThread::~HGCMThread ()
+{
+    /*
+     * Free resources allocated for the thread.
+     */
+
+    Assert(m_fu32ThreadFlags & HGCMMSG_TF_TERMINATED);
+
+    if (RTCritSectIsInitialized (&m_critsect))
+    {
+        RTCritSectDelete (&m_critsect);
+    }
+
+    if (m_eventSend)
+    {
+        RTSemEventMultiDestroy (m_eventSend);
+    }
+
+    if (m_eventThread)
+    {
+        RTSemEventMultiDestroy (m_eventThread);
+    }
+
+    return;
+}
+
+int HGCMThread::WaitForTermination (void)
+{
+    int rc = VINF_SUCCESS;
+    LogFlowFunc(("\n"));
+
+    if (m_thread != NIL_RTTHREAD)
+    {
+        rc = RTThreadWait (m_thread, 5000, NULL);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+int HGCMThread::Initialize (HGCMTHREADHANDLE handle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser)
+{
+    int rc = VINF_SUCCESS;
+
+    rc = RTSemEventMultiCreate (&m_eventThread);
+
+    if (VBOX_SUCCESS(rc))
+    {
+        rc = RTSemEventMultiCreate (&m_eventSend);
+
+        if (VBOX_SUCCESS(rc))
+        {
+            rc = RTCritSectInit (&m_critsect);
+
+            if (VBOX_SUCCESS(rc))
+            {
+                m_pfnThread = pfnThread;
+                m_pvUser    = pvUser;
+                m_handle    = handle;
+
+                m_fu32ThreadFlags = HGCMMSG_TF_INITIALIZING;
+
+                RTTHREAD thread;
+                rc = RTThreadCreate (&thread, hgcmWorkerThreadFunc, this, 0, /* default stack size; some service may need quite a bit */
+                                     RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
+                                     pszThreadName);
+
+                if (VBOX_SUCCESS(rc))
+                {
+                    /* Wait until the thread is ready. */
+                    rc = RTThreadUserWait (thread, 30000);
+                    AssertRC (rc);
+                    Assert (!(m_fu32ThreadFlags & HGCMMSG_TF_INITIALIZING) || VBOX_FAILURE (rc));
+                }
+                else
+                {
+                    m_thread = NIL_RTTHREAD;
+                    Log(("hgcmThreadCreate: FAILURE: Can't start worker thread.\n"));
+                }
+            }
+            else
+            {
+                Log(("hgcmThreadCreate: FAILURE: Can't init a critical section for a hgcm worker thread.\n"));
+                memset (&m_critsect, 0, sizeof (m_critsect));
+            }
+        }
+        else
+        {
+            Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a sent messages.\n"));
+            m_eventSend = 0;
+        }
+    }
+    else
+    {
+        Log(("hgcmThreadCreate: FAILURE: Can't create an event semaphore for a hgcm worker thread.\n"));
+        m_eventThread = 0;
+    }
+
+    return rc;
+}
+
+inline int HGCMThread::Enter (void)
+{
+    int rc = RTCritSectEnter (&m_critsect);
+
+#ifdef LOG_ENABLED
+    if (VBOX_FAILURE (rc))
+    {
+        Log(("HGCMThread::MsgPost: FAILURE: could not obtain worker thread mutex, rc = %Vrc!!!\n", rc));
+    }
+#endif /* LOG_ENABLED */
+
+    return rc;
+}
+
+inline void HGCMThread::Leave (void)
+{
+    RTCritSectLeave (&m_critsect);
+}
+
+
+int HGCMThread::MsgAlloc (HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
+{
+    int rc = VINF_SUCCESS;
+
+    HGCMMsgCore *pmsg = NULL;
+
+    bool fFromFreeList = false;
+
+    if (!pmsg && VBOX_SUCCESS(rc))
+    {
+        /* We have to allocate a new memory block. */
+        pmsg = pfnNewMessage (u32MsgId);
+
+        if (pmsg == NULL)
+        {
+            rc = VERR_NO_MEMORY;
+        }
+    }
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Initialize just allocated message core */
+        pmsg->InitializeCore (u32MsgId, m_handle);
+
+        /* and the message specific data. */
+        pmsg->Initialize ();
+
+        LogFlow(("MAIN::hgcmMsgAlloc: allocated message %p\n", pmsg));
+
+        /** Get handle of the message. The message will be also referenced
+         *  until the handle is deleted.
+         */
+        *pHandle = hgcmObjGenerateHandle (pmsg);
+
+        if (fFromFreeList)
+        {
+            /* Message was referenced in the free list, now dereference it. */
+            pmsg->Dereference ();
+        }
+    }
+
+    return rc;
+}
+
+int HGCMThread::MsgPost (HGCMMsgCore *pMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlow(("HGCMThread::MsgPost: thread = %p, pMsg = %p, pfnCallback = %p\n", this, pMsg, pfnCallback));
+
+    rc = Enter ();
+
+    if (VBOX_SUCCESS(rc))
+    {
+        pMsg->m_pfnCallback = pfnCallback;
+
+        /* Insert the message to the queue tail. */
+        pMsg->m_pNext = NULL;
+        pMsg->m_pPrev = m_pMsgInputQueueTail;
+
+        if (m_pMsgInputQueueTail)
+        {
+            m_pMsgInputQueueTail->m_pNext = pMsg;
+        }
+        else
+        {
+            m_pMsgInputQueueHead = pMsg;
+        }
+
+        m_pMsgInputQueueTail = pMsg;
+
+        Leave ();
+
+        LogFlow(("HGCMThread::MsgPost: going to inform the thread %p about message, fWait = %d\n", this, fWait));
+
+        if (fWait)
+        {
+            pMsg->m_fu32Flags |= HGCM_MSG_F_WAIT;
+        }
+
+        /* Inform the worker thread that there is a message. */
+        RTSemEventMultiSignal (m_eventThread);
+
+        LogFlow(("HGCMThread::MsgPost: event signalled\n"));
+
+        if (fWait)
+        {
+            while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0)
+            {
+                RTSemEventMultiWait (m_eventSend, RT_INDEFINITE_WAIT);
+                RTSemEventMultiReset (m_eventSend);
+
+                LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags));
+            }
+
+            rc = pMsg->m_rcSend;
+        }
+    }
+
+    LogFlow(("HGCMThread::MsgPost: rc = %Vrc\n", rc));
+
+    return rc;
+}
+
+
+int HGCMThread::MsgGet (HGCMMsgCore **ppMsg)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlow(("HGCMThread::MsgGet: thread = %p, ppMsg = %p\n", this, ppMsg));
+
+    for (;;)
+    {
+        if (m_fu32ThreadFlags & HGCMMSG_TF_TERMINATE)
+        {
+            rc = VERR_INTERRUPTED;
+            break;
+        }
+
+        LogFlow(("MAIN::hgcmMsgGet: m_pMsgInputQueueHead = %p\n", m_pMsgInputQueueHead));
+
+        if (m_pMsgInputQueueHead)
+        {
+            /* Move the message to the m_pMsgInProcessHead list */
+            rc = Enter ();
+
+            if (VBOX_FAILURE (rc))
+            {
+                break;
+            }
+
+            HGCMMsgCore *pMsg = m_pMsgInputQueueHead;
+
+            /* Remove the message from the head of Queue list. */
+            Assert (m_pMsgInputQueueHead->m_pPrev == NULL);
+
+            if (m_pMsgInputQueueHead->m_pNext)
+            {
+                m_pMsgInputQueueHead = m_pMsgInputQueueHead->m_pNext;
+                m_pMsgInputQueueHead->m_pPrev = NULL;
+            }
+            else
+            {
+                Assert (m_pMsgInputQueueHead == m_pMsgInputQueueTail);
+
+                m_pMsgInputQueueHead = NULL;
+                m_pMsgInputQueueTail = NULL;
+            }
+
+            /* Insert the message to the tail of the m_pMsgInProcessHead list. */
+            pMsg->m_pNext = NULL;
+            pMsg->m_pPrev = m_pMsgInProcessTail;
+
+            if (m_pMsgInProcessTail)
+            {
+                m_pMsgInProcessTail->m_pNext = pMsg;
+            }
+            else
+            {
+                m_pMsgInProcessHead = pMsg;
+            }
+
+            m_pMsgInProcessTail = pMsg;
+
+            pMsg->m_fu32Flags |= HGCM_MSG_F_IN_PROCESS;
+
+            Leave ();
+
+            /* Return the message to the caller. */
+            *ppMsg = pMsg;
+
+            LogFlow(("MAIN::hgcmMsgGet: got message %p\n", *ppMsg));
+
+            break;
+        }
+
+        /* Wait for an event. */
+        RTSemEventMultiWait (m_eventThread, RT_INDEFINITE_WAIT);
+        RTSemEventMultiReset (m_eventThread);
+    }
+
+    LogFlow(("HGCMThread::MsgGet: *ppMsg = %p, return rc = %Vrc\n", *ppMsg, rc));
+
+    return rc;
+}
+
+void HGCMThread::MsgComplete (HGCMMsgCore *pMsg, int32_t result)
+{
+    LogFlow(("HGCMThread::MsgComplete: thread = %p, pMsg = %p\n", this, pMsg));
+
+    int rc = VINF_SUCCESS;
+
+    AssertRelease(pMsg->m_pThread == this);
+    AssertReleaseMsg((pMsg->m_fu32Flags & HGCM_MSG_F_IN_PROCESS) != 0, ("%p %x\n", pMsg, pMsg->m_fu32Flags));
+
+    if (pMsg->m_pfnCallback)
+    {
+        /** @todo call callback with error code in MsgPost in case of errors */
+
+        pMsg->m_pfnCallback (result, pMsg);
+
+        LogFlow(("HGCMThread::MsgComplete: callback executed. pMsg = %p, thread = %p\n", pMsg, this));
+    }
+
+    /* Message processing has been completed. */
+
+    rc = Enter ();
+
+    if (VBOX_SUCCESS(rc))
+    {
+        /* Remove the message from the InProcess queue. */
+
+        if (pMsg->m_pNext)
+        {
+            pMsg->m_pNext->m_pPrev = pMsg->m_pPrev;
+        }
+        else
+        {
+            m_pMsgInProcessTail = pMsg->m_pPrev;
+        }
+
+        if (pMsg->m_pPrev)
+        {
+            pMsg->m_pPrev->m_pNext = pMsg->m_pNext;
+        }
+        else
+        {
+            m_pMsgInProcessHead = pMsg->m_pNext;
+        }
+
+        pMsg->m_pNext = NULL;
+        pMsg->m_pPrev = NULL;
+
+        bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0);
+
+        /* The message is now completed. */
+        pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS;
+        pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT;
+        pMsg->m_fu32Flags |= HGCM_MSG_F_PROCESSED;
+
+        hgcmObjDeleteHandle (pMsg->Handle ());
+
+        Leave ();
+
+        if (fWaited)
+        {
+            /* If message is being waited, then it is referenced by the waiter and the pointer 
+             * if valid even after hgcmObjDeleteHandle.
+             */
+            pMsg->m_rcSend = result;
+
+            /* Wake up all waiters. so they can decide if their message has been processed. */
+            RTSemEventMultiSignal (m_eventSend);
+        }
+    }
+
+    return;
+}
+
+/*
+ * Thread API. Public interface.
+ */
+
+int hgcmThreadCreate (HGCMTHREADHANDLE *pHandle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlow(("MAIN::hgcmThreadCreate\n"));
+
+    HGCMTHREADHANDLE handle = 0;
+
+    /* Allocate memory for a new thread object. */
+    HGCMThread *pThread = new HGCMThread ();
+
+    if (pThread)
+    {
+        /* Put just created object to pool and obtain handle for it. */
+        handle = hgcmObjGenerateHandle (pThread);
+
+        /* Initialize the object. */
+        rc = pThread->Initialize (handle, pszThreadName, pfnThread, pvUser);
+    }
+    else
+    {
+        Log(("hgcmThreadCreate: FAILURE: Can't allocate memory for a hgcm worker thread.\n"));
+        rc = VERR_NO_MEMORY;
+    }
+
+    if (VBOX_SUCCESS (rc))
+    {
+        *pHandle = handle;
+    }
+    else
+    {
+        Log(("hgcmThreadCreate: FAILURE: rc = %Vrc.\n", rc));
+
+        if (handle != 0)
+        {
+            /* Delete allocated handle, this will also free the object memory. */
+            hgcmObjDeleteHandle (handle);
+        }
+    }
+
+    LogFlow(("MAIN::hgcmThreadCreate: rc = %Vrc\n", rc));
+
+    return rc;
+}
+
+int hgcmThreadWait (HGCMTHREADHANDLE hThread)
+{
+    int rc = VERR_INVALID_HANDLE;
+    LogFlowFunc(("0x%08X\n", hThread));
+
+    HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
+
+    if (pThread)
+    {
+        rc = pThread->WaitForTermination ();
+
+        hgcmObjDereference (pThread);
+    }
+
+    LogFlowFunc(("rc = %Vrc\n", rc));
+    return rc;
+}
+
+int hgcmMsgAlloc (HGCMTHREADHANDLE hThread, HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage)
+{
+    LogFlow(("hgcmMsgAlloc: thread handle = 0x%08X, pHandle = %p, sizeof (HGCMMsgCore) = %d\n", hThread, pHandle, sizeof (HGCMMsgCore)));
+
+    if (!pHandle)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
+
+    if (!pThread)
+    {
+        rc = VERR_INVALID_HANDLE;
+    }
+    else
+    {
+        rc = pThread->MsgAlloc (pHandle, u32MsgId, pfnNewMessage);
+
+        hgcmObjDereference (pThread);
+    }
+
+    LogFlow(("MAIN::hgcmMsgAlloc: handle 0x%08X, rc = %Vrc\n", *pHandle, rc));
+
+    return rc;
+}
+
+static int hgcmMsgPostInternal (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback, bool fWait)
+{
+    LogFlow(("MAIN::hgcmMsgPostInternal: hMsg = 0x%08X, pfnCallback = %p, fWait = %d\n", hMsg, pfnCallback, fWait));
+
+    int rc = VINF_SUCCESS;
+
+    HGCMMsgCore *pMsg = (HGCMMsgCore *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
+
+    if (!pMsg)
+    {
+        rc = VERR_INVALID_HANDLE;
+    }
+    else
+    {
+        rc = pMsg->Thread()->MsgPost (pMsg, pfnCallback, fWait);
+
+        hgcmObjDereference (pMsg);
+    }
+
+    LogFlow(("MAIN::hgcmMsgPostInternal: hMsg 0x%08X, rc = %Vrc\n", hMsg, rc));
+
+    return rc;
+}
+
+
+/* Post message to worker thread with a flag indication if this is a Send or Post.
+ *
+ * @thread any
+ */
+
+int hgcmMsgPost (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback)
+{
+    int rc = hgcmMsgPostInternal (hMsg, pfnCallback, false);
+
+    if (VBOX_SUCCESS (rc))
+    {
+        rc = VINF_HGCM_ASYNC_EXECUTE;
+    }
+
+    return rc;
+}
+
+/* Send message to worker thread. Sending thread will block until message is processed.
+ *
+ * @thread any
+ */
+
+int hgcmMsgSend (HGCMMSGHANDLE hMsg)
+{
+    return hgcmMsgPostInternal (hMsg, NULL, true);
+}
+
+
+int hgcmMsgGet (HGCMTHREADHANDLE hThread, HGCMMsgCore **ppMsg)
+{
+    LogFlow(("MAIN::hgcmMsgGet: hThread = 0x%08X, ppMsg = %p\n", hThread, ppMsg));
+
+    if (!hThread || !ppMsg)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    HGCMThread *pThread = (HGCMThread *)hgcmObjReference (hThread, HGCMOBJ_THREAD);
+
+    if (!pThread)
+    {
+        rc = VERR_INVALID_HANDLE;
+    }
+    else
+    {
+        rc = pThread->MsgGet (ppMsg);
+
+        hgcmObjDereference (pThread);
+    }
+
+    LogFlow(("MAIN::hgcmMsgGet: *ppMsg = %p, rc = %Vrc\n", *ppMsg, rc));
+
+    return rc;
+}
+
+
+void hgcmMsgComplete (HGCMMsgCore *pMsg, int32_t u32Result)
+{
+    LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p\n", pMsg));
+
+    if (!pMsg)
+    {
+        return;
+    }
+
+    pMsg->Thread()->MsgComplete (pMsg, u32Result);
+
+    LogFlow(("MAIN::hgcmMsgComplete: pMsg = %p, rc = void\n", pMsg));
+
+    return;
+}
+
+
+int hgcmThreadInit (void)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlow(("MAIN::hgcmThreadInit\n"));
+
+    /** @todo error processing. */
+
+    rc = hgcmObjInit ();
+
+    LogFlow(("MAIN::hgcmThreadInit: rc = %Vrc\n", rc));
+
+    return rc;
+}
+
+void hgcmThreadUninit (void)
+{
+    hgcmObjUninit ();
+}
Index: /trunk/src/VBox/Frontends/VBoxBFE/HGCMThread.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/HGCMThread.h	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/HGCMThread.h	(revision 5979)
@@ -0,0 +1,198 @@
+/** @file
+ *
+ * HGCMThread - Host-Guest Communication Manager worker threads header.
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+#ifndef __HGCMThread_h__
+#define __HGCMThread_h__
+
+#include <VBox/types.h>
+
+#include "HGCMObjects.h"
+
+/** A handle for HGCM message. */
+typedef uint32_t HGCMMSGHANDLE;
+
+/** A handle for HGCM worker threads. */
+typedef uint32_t HGCMTHREADHANDLE;
+
+/* Forward declaration of message core class. */
+class HGCMMsgCore;
+
+/** @todo comment */
+
+typedef HGCMMsgCore *FNHGCMNEWMSGALLOC(uint32_t u32MsgId);
+typedef FNHGCMNEWMSGALLOC *PFNHGCMNEWMSGALLOC;
+
+/** Function that is called after message processing by worker thread,
+ *  or if an error occured during message handling after successfully
+ *  posting (hgcmMsgPost) the message to worker thread.
+ *
+ * @param result    Return code either from the service which actually processed the message
+ *                  or from HGCM.
+ * @param pMsgCore  Pointer to just processed message.
+ */
+typedef DECLCALLBACK(void) HGCMMSGCALLBACK (int32_t result, HGCMMsgCore *pMsgCore);
+typedef HGCMMSGCALLBACK *PHGCMMSGCALLBACK;
+
+/* Forward declaration of the worker thread class. */
+class HGCMThread;
+
+/** HGCM core message. */
+class HGCMMsgCore: public HGCMObject
+{
+    private:
+        friend class HGCMThread;
+
+        /** Version of message header. */
+        uint32_t m_u32Version;
+
+        /** Thread the message belongs to, referenced by the message. */
+        HGCMThread *m_pThread;
+
+        /** Message number/identifier. */
+        uint32_t m_u32Msg;
+
+        /** Callback function pointer. */
+        PHGCMMSGCALLBACK m_pfnCallback;
+
+        /** Next element in a message queue. */
+        HGCMMsgCore *m_pNext;
+        /** @todo seems not necessary. Previous element in a message queue. */
+        HGCMMsgCore *m_pPrev;
+
+        /** Various internal flags. */
+        uint32_t m_fu32Flags;
+
+        /** Result code for a Send */
+        int32_t m_rcSend;
+
+        void InitializeCore (uint32_t u32MsgId, HGCMTHREADHANDLE hThread);
+
+    protected:
+        virtual ~HGCMMsgCore ();
+
+    public:
+        HGCMMsgCore () : HGCMObject(HGCMOBJ_MSG) {};
+
+        uint32_t MsgId (void) { return m_u32Msg; };
+
+        HGCMThread *Thread (void) { return m_pThread; };
+
+        /** Initialize message after it was allocated. */
+        virtual void Initialize (void) {};
+
+        /** Uninitialize message. */
+        virtual void Uninitialize (void) {};
+
+};
+
+
+/** HGCM worker thread function.
+ *
+ *  @param ThreadHandle  Handle of the thread.
+ *  @param pvUser        User specified thread parameter.
+ */
+typedef DECLCALLBACK(void) FNHGCMTHREAD (HGCMTHREADHANDLE ThreadHandle, void *pvUser);
+typedef FNHGCMTHREAD *PFNHGCMTHREAD;
+
+
+/**
+ * Thread API.
+ * Based on thread handles. Internals of a thread are not exposed to users.
+ */
+
+/** Initialize threads.
+ *
+ * @return VBox error code
+ */
+int hgcmThreadInit (void);
+void hgcmThreadUninit (void);
+
+
+/** Create a HGCM worker thread.
+ *
+ * @param pHandle       Where to store the returned worker thread handle.
+ * @param pszThreadName Name of the thread, needed by runtime.
+ * @param pfnThread     The worker thread function.
+ * @param pvUser        A pointer passed to worker thread.
+ *
+ * @return VBox error code
+ */
+int hgcmThreadCreate (HGCMTHREADHANDLE *pHandle, const char *pszThreadName, PFNHGCMTHREAD pfnThread, void *pvUser);
+
+/** Wait for termination of a HGCM worker thread.
+ *
+ * @param handle The HGCM thread handle.
+ *
+ * @return VBox error code
+ */
+int hgcmThreadWait (HGCMTHREADHANDLE handle);
+
+/** Allocate a message to be posted to HGCM worker thread.
+ *
+ * @param hThread       Worker thread handle.
+ * @param pHandle       Where to store the returned message handle.
+ * @param u32MsgId      Message identifier.
+ * @param pfnNewMessage New message allocation callback.
+ *
+ * @return VBox error code
+ */
+int hgcmMsgAlloc (HGCMTHREADHANDLE hThread, HGCMMSGHANDLE *pHandle, uint32_t u32MsgId, PFNHGCMNEWMSGALLOC pfnNewMessage);
+
+/** Post a message to HGCM worker thread.
+ *
+ * @param hMsg          Message handle.
+ * @param pfnCallback   Message completion callback.
+ *
+ * @return VBox error code
+ */
+int hgcmMsgPost (HGCMMSGHANDLE hMsg, PHGCMMSGCALLBACK pfnCallback);
+
+/** Send a message to HGCM worker thread.
+ *  The function will return after message is processed by thread.
+ *
+ * @param hMsg          Message handle.
+ *
+ * @return VBox error code
+ */
+int hgcmMsgSend (HGCMMSGHANDLE hMsg);
+
+
+/* Wait for and get a message.
+ *
+ * @param hThread       The thread handle.
+ * @param ppMsg         Where to store returned message pointer.
+ *
+ * @return VBox error code
+ *
+ * @thread worker thread
+ */
+int hgcmMsgGet (HGCMTHREADHANDLE hThread, HGCMMsgCore **ppMsg);
+
+
+/** Worker thread has processed a message previuosly obtained with hgcmMsgGet.
+ *
+ * @param pMsg          Processed message pointer.
+ * @param result        Result code, VBox erro code.
+ *
+ * @return VBox error code
+ *
+ * @thread worker thread
+ */
+void hgcmMsgComplete (HGCMMsgCore *pMsg, int32_t result);
+
+
+#endif /* __HGCMThread_h__ */
Index: /trunk/src/VBox/Frontends/VBoxBFE/VMControl.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/VMControl.cpp	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/VMControl.cpp	(revision 5979)
@@ -0,0 +1,193 @@
+/** @file
+ *
+ * VBox frontends: Basic Frontend (BFE):
+ * VBoxBFE VM control routines
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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 <iprt/stream.h>
+#include <VBox/err.h>
+#include "DisplayImpl.h"
+#include "ConsoleImpl.h"
+#include "VBoxBFE.h"
+#include "VMControl.h"
+
+/**
+ * Fullscreen / Windowed toggle.
+ */
+int
+VMCtrlToggleFullscreen(void)
+{
+    /* not allowed */
+    if (!gfAllowFullscreenToggle)
+        return VERR_ACCESS_DENIED;
+
+    gFramebuffer->setFullscreen(!gFramebuffer->getFullscreen());
+
+    /*
+     * We have switched from/to fullscreen, so request a full
+     * screen repaint, just to be sure.
+     */
+    gDisplay->InvalidateAndUpdate();
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Pause the VM.
+ */
+int
+VMCtrlPause(void)
+{
+    if (machineState != VMSTATE_RUNNING)
+        return VERR_VM_INVALID_VM_STATE;
+
+    if (gConsole->inputGrabbed())
+        gConsole->inputGrabEnd();
+
+    PVMREQ pReq;
+    int rcVBox = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
+                             (PFNRT)VMR3Suspend, 1, pVM);
+    AssertRC(rcVBox);
+    if (VBOX_SUCCESS(rcVBox))
+    {
+        rcVBox = pReq->iStatus;
+        VMR3ReqFree(pReq);
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * Resume the VM.
+ */
+int
+VMCtrlResume(void)
+{
+    if (machineState != VMSTATE_SUSPENDED)
+        return VERR_VM_INVALID_VM_STATE;
+
+    PVMREQ pReq;
+    int rcVBox = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
+                             (PFNRT)VMR3Resume, 1, pVM);
+    AssertRC(rcVBox);
+    if (VBOX_SUCCESS(rcVBox))
+    {
+        rcVBox = pReq->iStatus;
+        VMR3ReqFree(pReq);
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * Reset the VM
+ */
+int
+VMCtrlReset(void)
+{
+    PVMREQ pReq;
+    int rcVBox = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
+                             (PFNRT)VMR3Reset, 1, pVM);
+    AssertRC(rcVBox);
+    if (VBOX_SUCCESS(rcVBox))
+    {
+        rcVBox = pReq->iStatus;
+        VMR3ReqFree(pReq);
+    }
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Send ACPI power button press event
+ */
+int
+VMCtrlACPIButton(void)
+{
+    PPDMIBASE pBase;
+    int vrc = PDMR3QueryDeviceLun (pVM, "acpi", 0, 0, &pBase);
+    if (VBOX_SUCCESS (vrc))
+    {
+        Assert (pBase);
+        PPDMIACPIPORT pPort =
+            (PPDMIACPIPORT) pBase->pfnQueryInterface(pBase, PDMINTERFACE_ACPI_PORT);
+        vrc = pPort ? pPort->pfnPowerButtonPress(pPort) : VERR_INVALID_POINTER;
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * Worker thread while saving the VM
+ */
+DECLCALLBACK(int) VMSaveThread(RTTHREAD Thread, void *pvUser)
+{
+    PVMREQ pReq;
+    void (*pfnQuit)(void) = (void(*)(void))pvUser;
+    int rc;
+
+    startProgressInfo("Saving");
+    rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
+                     (PFNRT)VMR3Save, 4, pVM, g_pszStateFile, &callProgressInfo, NULL);
+    endProgressInfo();
+    if (VBOX_SUCCESS(rc))
+    {
+        rc = pReq->iStatus;
+        VMR3ReqFree(pReq);
+    }
+    pfnQuit();
+
+    return 0;
+}
+
+/*
+ * Save the machine's state
+ */
+int
+VMCtrlSave(void (*pfnQuit)(void))
+{
+    int rc;
+
+    if (!g_pszStateFile || !*g_pszStateFile)
+        return VERR_INVALID_PARAMETER;
+
+    gConsole->resetKeys();
+    RTThreadYield();
+    if (gConsole->inputGrabbed())
+        gConsole->inputGrabEnd();
+    RTThreadYield();
+
+    if (machineState == VMSTATE_RUNNING)
+    {
+        PVMREQ pReq;
+        rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
+                         (PFNRT)VMR3Suspend, 1, pVM);
+        AssertRC(rc);
+        if (VBOX_SUCCESS(rc))
+        {
+            rc = pReq->iStatus;
+            VMR3ReqFree(pReq);
+        }
+    }
+
+    RTTHREAD thread;
+    rc = RTThreadCreate(&thread, VMSaveThread, (void*)pfnQuit, 0,
+                        RTTHREADTYPE_MAIN_WORKER, 0, "Save");
+    if (VBOX_FAILURE(rc))
+    {
+        RTPrintf("Error: Thread creation failed with %d\n", rc);
+        return rc;
+    }
+
+    return VINF_SUCCESS;
+}
Index: /trunk/src/VBox/Frontends/VBoxBFE/VMControl.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBFE/VMControl.h	(revision 5979)
+++ /trunk/src/VBox/Frontends/VBoxBFE/VMControl.h	(revision 5979)
@@ -0,0 +1,30 @@
+/** @file
+ *
+ * VBox frontends: Basic Frontend (BFE):
+ * VBoxBFE VM control routines header
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+#ifndef ____H_VMCONTROL
+#define ____H_VMCONTROL
+
+int  VMCtrlToggleFullscreen(void);
+int  VMCtrlPause(void);
+int  VMCtrlResume(void);
+int  VMCtrlReset(void);
+int  VMCtrlACPIButton(void);
+int  VMCtrlSave(void (*pfnQuit)(void));
+
+#endif
