Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h	(revision 80556)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h	(revision 80557)
@@ -182,12 +182,4 @@
 
 /**
- * Structure for keeping a single (HGCM) client map entry.
- * Currently empty.
- */
-typedef struct _VBOXCLIPBOARDCLIENTMAPENTRY
-{
-} VBOXCLIPBOARDCLIENTMAPENTRY;
-
-/**
  * Structure for keeping a single event source map entry.
  * Currently empty.
@@ -197,6 +189,7 @@
 } VBOXCLIPBOARDEVENTSOURCEMAPENTRY;
 
-/** Map holding information about connected HGCM clients. Key is the (unique) HGCM client ID. */
-typedef std::map<uint32_t, VBOXCLIPBOARDCLIENTMAPENTRY> ClipboardClientMap;
+/** Map holding information about connected HGCM clients. Key is the (unique) HGCM client ID.
+ *  The value is a weak pointer to PVBOXCLIPBOARDCLIENT, which is owned by HGCM. */
+typedef std::map<uint32_t, PVBOXCLIPBOARDCLIENT> ClipboardClientMap;
 
 /** Map holding information about event sources. Key is the (unique) event source ID. */
@@ -205,4 +198,29 @@
 /** Simple queue (list) which holds deferred (waiting) clients. */
 typedef std::list<uint32_t> ClipboardClientQueue;
+
+/**
+ * Structure for keeping the Shared Clipboard service extension state.
+ *
+ * A service extension is optional, and can be installed by a host component
+ * to communicate with the Shared Clipboard host service.
+ */
+typedef struct _VBOXCLIPBOARDEXTSTATE
+{
+    /** Pointer to the actual service extension handle. */
+    PFNHGCMSVCEXT  pfnExtension;
+    /** Opaque pointer to extension-provided data. Don't touch. */
+    void          *pvExtension;
+    /** The HGCM client ID currently assigned to this service extension.
+     *  At the moment only one HGCM client can be assigned per extension. */
+    uint32_t       uClientID;
+    /** Whether the host service is reading clipboard data currently. */
+    bool           fReadingData;
+    /** Whether the service extension has sent the clipboard formats while
+     *  the the host service is reading clipboard data from it. */
+    bool           fDelayedAnnouncement;
+    /** The actual clipboard formats announced while the host service
+     *  is reading clipboard data from the extension. */
+    uint32_t       uDelayedFormats;
+} VBOXCLIPBOARDEXTSTATE, *PVBOXCLIPBOARDEXTSTATE;
 
 /*
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-uri.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-uri.cpp	(revision 80556)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-uri.cpp	(revision 80557)
@@ -40,8 +40,6 @@
 *   Externals                                                                                                                    *
 *********************************************************************************************************************************/
-extern PFNHGCMSVCEXT g_pfnExtension;
-extern void *g_pvExtension;
+extern VBOXCLIPBOARDEXTSTATE g_ExtState;
 extern PVBOXHGCMSVCHELPERS g_pHelpers;
-
 extern ClipboardClientQueue g_listClientsDeferred;
 
@@ -1238,6 +1236,6 @@
     RT_NOREF(paParms, tsArrival);
 
-    LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_pfnExtension=%p\n",
-                 pClient->uClientID, u32Function, VBoxClipboardGuestMsgToStr(u32Function), cParms, g_pfnExtension));
+    LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
+                 pClient->uClientID, u32Function, VBoxClipboardGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
 
     /* Check if we've the right mode set. */
@@ -1250,8 +1248,8 @@
     /* A (valid) service extension is needed because VBoxSVC needs to keep track of the
      * clipboard areas cached on the host. */
-    if (!g_pfnExtension)
+    if (!g_ExtState.pfnExtension)
     {
 #ifdef DEBUG_andy
-        AssertPtr(g_pfnExtension);
+        AssertPtr(g_ExtState.pfnExtension);
 #endif
         LogFunc(("Invalid / no service extension set, skipping URI handling\n"));
@@ -1918,5 +1916,5 @@
     int rc;
 
-    if (g_pfnExtension)
+    if (g_ExtState.pfnExtension)
     {
         VBOXCLIPBOARDEXTAREAPARMS parms;
@@ -1926,5 +1924,5 @@
 
         /* As the meta data is now complete, register a new clipboard on the host side. */
-        rc = g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_REGISTER, &parms, sizeof(parms));
+        rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_REGISTER, &parms, sizeof(parms));
         if (RT_SUCCESS(rc))
         {
@@ -1963,5 +1961,5 @@
     int rc = VINF_SUCCESS;
 
-    if (g_pfnExtension)
+    if (g_ExtState.pfnExtension)
     {
         VBOXCLIPBOARDEXTAREAPARMS parms;
@@ -1970,5 +1968,5 @@
         parms.uID = pTransfer->pArea->GetID();
 
-        rc = g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_UNREGISTER, &parms, sizeof(parms));
+        rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_UNREGISTER, &parms, sizeof(parms));
         if (RT_SUCCESS(rc))
         {
@@ -2016,5 +2014,5 @@
     int rc = VINF_SUCCESS;
 
-    if (g_pfnExtension)
+    if (g_ExtState.pfnExtension)
     {
         VBOXCLIPBOARDEXTAREAPARMS parms;
@@ -2027,5 +2025,5 @@
          *
          * This might fail if the host does not have a most recent clipboard area (yet). */
-        rc = g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_ATTACH, &parms, sizeof(parms));
+        rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_ATTACH, &parms, sizeof(parms));
         if (RT_SUCCESS(rc))
             rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */);
@@ -2061,5 +2059,5 @@
     int rc = VINF_SUCCESS;
 
-    if (g_pfnExtension)
+    if (g_ExtState.pfnExtension)
     {
         VBOXCLIPBOARDEXTAREAPARMS parms;
@@ -2067,5 +2065,5 @@
         parms.uID = uAreaID;
 
-        rc = g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_DETACH, &parms, sizeof(parms));
+        rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_DETACH, &parms, sizeof(parms));
 
         LogFlowFunc(("Detached client %RU32 from clipboard area %RU32 with rc=%Rrc\n",
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 80556)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 80557)
@@ -244,14 +244,9 @@
 static uint32_t g_uMode;
 
-PFNHGCMSVCEXT g_pfnExtension;
-void *g_pvExtension;
-
-/* Serialization of data reading and format announcements from the RDP client. */
-static bool g_fReadingData = false;
-static bool g_fDelayedAnnouncement = false;
-static uint32_t g_u32DelayedFormats = 0;
-
 /** Is the clipboard running in headless mode? */
 static bool g_fHeadless = false;
+
+/** Holds the service extension state. */
+VBOXCLIPBOARDEXTSTATE g_ExtState = { 0 };
 
 /** Global map of all connected clients. */
@@ -876,14 +871,14 @@
     if (RT_SUCCESS(rc))
     {
-        if (g_pfnExtension)
+        if (g_ExtState.pfnExtension)
         {
             VBOXCLIPBOARDEXTPARMS parms;
             RT_ZERO(parms);
 
-            parms.u32Format = dataBlock.uFormat;
+            parms.uFormat   = dataBlock.uFormat;
             parms.u.pvData  = dataBlock.pvData;
             parms.cbData    = dataBlock.cbData;
 
-            g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_WRITE, &parms, sizeof(parms));
+            g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_WRITE, &parms, sizeof(parms));
         }
 
@@ -1120,8 +1115,13 @@
             if (RT_SUCCESS(rc))
             {
-                VBOXCLIPBOARDCLIENTMAPENTRY ClientEntry;
-                RT_ZERO(ClientEntry);
-
-                g_mapClients[u32ClientID] = ClientEntry; /** @todo Handle OOM / collisions? */
+                /* Assign weak pointer to client map .*/
+                g_mapClients[u32ClientID] = pClient; /** @todo Handle OOM / collisions? */
+
+                /* For now we ASSUME that the first client ever connected is in charge for
+                 * communicating withe the service extension.
+                 *
+                 ** @todo This needs to be fixed ASAP w/o breaking older guest / host combos. */
+                if (g_ExtState.uClientID == 0)
+                    g_ExtState.uClientID = u32ClientID;
             }
         }
@@ -1319,37 +1319,23 @@
                     if (RT_SUCCESS(rc))
                     {
-            #if 0
-                        if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+                        if (g_ExtState.pfnExtension)
                         {
-                            /* Tell the guest that we want to start a reading transfer
-                             * (from guest to the host). */
-                            rc = vboxSvcClipboardReportMsg(pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_URI_TRANSFER_START,
-                                                           0 /* u32Formats == 0 means reading data */);
-
-                            /* Note: Announcing the actual format will be done in the
-                                     host service guest call URI handler (vboxSvcClipboardURIHandler). */
+                            VBOXCLIPBOARDEXTPARMS parms;
+                            RT_ZERO(parms);
+
+                            parms.uFormat = u32Formats;
+
+                            g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof(parms));
                         }
-                        else /* Announce simple formats to the OS-specific service implemenation. */
-            #endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
-                        {
-                            if (g_pfnExtension)
-                            {
-                                VBOXCLIPBOARDEXTPARMS parms;
-                                RT_ZERO(parms);
-                                parms.u32Format = u32Formats;
-
-                                g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof (parms));
-                            }
-
-                            VBOXCLIPBOARDCLIENTCMDCTX cmdCtx;
-                            RT_ZERO(cmdCtx);
-
-                            SHAREDCLIPBOARDFORMATDATA formatData;
-                            RT_ZERO(formatData);
-
-                            formatData.uFormats = u32Formats;
-
-                            rc = VBoxClipboardSvcImplFormatAnnounce(pClient, &cmdCtx, &formatData);
-                        }
+
+                        VBOXCLIPBOARDCLIENTCMDCTX cmdCtx;
+                        RT_ZERO(cmdCtx);
+
+                        SHAREDCLIPBOARDFORMATDATA formatData;
+                        RT_ZERO(formatData);
+
+                        formatData.uFormats = u32Formats;
+
+                        rc = VBoxClipboardSvcImplFormatAnnounce(pClient, &cmdCtx, &formatData);
                     }
                 }
@@ -1447,32 +1433,44 @@
                             uint32_t cbActual = 0;
 
-                            if (g_pfnExtension)
+                            /* If there is a service extension active, try reading data from it first. */
+                            if (g_ExtState.pfnExtension)
                             {
                                 VBOXCLIPBOARDEXTPARMS parms;
                                 RT_ZERO(parms);
 
-                                parms.u32Format = u32Format;
-                                parms.u.pvData  = pv;
-                                parms.cbData    = cb;
-
-                                g_fReadingData = true;
-
-                                rc = g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_READ, &parms, sizeof (parms));
-                                LogFlowFunc(("DATA: g_fDelayedAnnouncement = %d, g_u32DelayedFormats = 0x%x\n", g_fDelayedAnnouncement, g_u32DelayedFormats));
-
-                                if (g_fDelayedAnnouncement)
+                                parms.uFormat  = u32Format;
+                                parms.u.pvData = pv;
+                                parms.cbData   = cb;
+
+                                g_ExtState.fReadingData = true;
+
+                                /* Read clipboard data from the extension. */
+                                rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_READ,
+                                                             &parms, sizeof(parms));
+
+                                LogFlowFunc(("g_ExtState.fDelayedAnnouncement=%RTbool, g_ExtState.uDelayedFormats=0x%x\n",
+                                             g_ExtState.fDelayedAnnouncement, g_ExtState.uDelayedFormats));
+
+                                /* Did the extension send the clipboard formats yet?
+                                 * Otherwise, do this now. */
+                                if (g_ExtState.fDelayedAnnouncement)
                                 {
-                                    vboxSvcClipboardOldReportMsg(pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS_WRITE, g_u32DelayedFormats);
-                                    g_fDelayedAnnouncement = false;
-                                    g_u32DelayedFormats = 0;
+                                    vboxSvcClipboardOldReportMsg(pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS_WRITE,
+                                                                 g_ExtState.uDelayedFormats);
+
+                                    g_ExtState.fDelayedAnnouncement = false;
+                                    g_ExtState.uDelayedFormats = 0;
                                 }
 
-                                g_fReadingData = false;
-
-                                if (RT_SUCCESS (rc))
+                                g_ExtState.fReadingData = false;
+
+                                if (RT_SUCCESS(rc))
                                 {
                                     cbActual = parms.cbData;
                                 }
                             }
+
+                            /* Note: The host clipboard *always* has precedence over the service extension above,
+                             *       so data which has been read above might get overridden by the host clipboard eventually. */
 
                             /* Release any other pending read, as we only
@@ -1494,7 +1492,8 @@
                             }
 
-                            /* Remember our read request until it is completed.
-                             * See the protocol description above for more
-                             * information. */
+                            /*
+                             * Remember our read request until it is completed.
+                             * See the protocol description above for more information.
+                             */
                             if (rc == VINF_HGCM_ASYNC_EXECUTE)
                             {
@@ -1822,32 +1821,36 @@
     int rc = VINF_SUCCESS;
 
-    PVBOXCLIPBOARDCLIENT pClient = NULL; /** @todo FIX !!! */
-
-    if (pClient != NULL)
-    {
+    /* Figure out if the client in charge for the service extension still is connected. */
+    ClipboardClientMap::const_iterator itClient = g_mapClients.find(g_ExtState.uClientID);
+    if (itClient != g_mapClients.end())
+    {
+        PVBOXCLIPBOARDCLIENT pClient = itClient->second;
+        AssertPtr(pClient);
+
         switch (u32Function)
         {
+            /* The service extension announces formats to the guest. */
             case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
             {
-                LogFlowFunc(("VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE: g_fReadingData=%RTbool\n", g_fReadingData));
-                if (g_fReadingData)
-                {
-                    g_fDelayedAnnouncement = true;
-                    g_u32DelayedFormats = u32Format;
-                }
-            #if 0
+                LogFlowFunc(("VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE: g_ExtState.fReadingData=%RTbool\n", g_ExtState.fReadingData));
+                if (g_ExtState.fReadingData)
+                {
+                    g_ExtState.fDelayedAnnouncement = true;
+                    g_ExtState.uDelayedFormats = u32Format;
+                }
                 else
                 {
-                    vboxSvcClipboardReportMsg(g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS, u32Format);
-                }
-            #endif
-            } break;
-
-#if 0
+                    rc = vboxSvcClipboardOldReportMsg(pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS_WRITE, u32Format);
+                }
+
+                break;
+            }
+
+            /* The service extension wants read data from the guest. */
             case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
             {
-                vboxSvcClipboardReportMsg(g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
-            } break;
-#endif
+                rc = vboxSvcClipboardOldReportMsg(pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
+                break;
+            }
 
             default:
@@ -1856,4 +1859,6 @@
         }
     }
+    else
+        rc = VERR_NOT_FOUND;
 
     LogFlowFuncLeaveRC(rc);
@@ -1871,18 +1876,19 @@
     {
         /* Install extension. */
-        g_pfnExtension = pfnExtension;
-        g_pvExtension = pvExtension;
+        g_ExtState.pfnExtension = pfnExtension;
+        g_ExtState.pvExtension  = pvExtension;
 
         parms.u.pfnCallback = extCallback;
-        g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof(parms));
+
+        g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof(parms));
     }
     else
     {
-        if (g_pfnExtension)
-            g_pfnExtension(g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof(parms));
+        if (g_ExtState.pfnExtension)
+            g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof(parms));
 
         /* Uninstall extension. */
-        g_pfnExtension = NULL;
-        g_pvExtension = NULL;
+        g_ExtState.pfnExtension = NULL;
+        g_ExtState.pvExtension = NULL;
     }
 
