Index: trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 80993)
+++ trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 81025)
@@ -60,4 +60,10 @@
     /** Windows-specific context data. */
     SHCLWINCTX            Win;
+    /** Thread handle for window thread. */
+    RTTHREAD              hThread;
+    /** Start indicator flag. */
+    bool                  fStarted;
+    /** Shutdown indicator flag. */
+    bool                  fShutdown;
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     /** Associated transfer data. */
@@ -65,18 +71,4 @@
 #endif
 } SHCLCONTEXT, *PSHCLCONTEXT;
-
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-typedef struct _SHCLREADTHREADCTX
-{
-    PSHCLCONTEXT     pClipboardCtx;
-    PSHCLTRANSFER pTransfer;
-} SHCLREADTHREADCTX, *PSHCLREADTHREADCTX;
-
-typedef struct _SHCLWRITETHREADCTX
-{
-    PSHCLCONTEXT     pClipboardCtx;
-    PSHCLTRANSFER pTransfer;
-} SHCLWRITETHREADCTX, *PSHCLWRITETHREADCTX;
-#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
 
 
@@ -109,4 +101,6 @@
 static void vboxClipboardTransferCallbackCleanup(PSHCLTRANSFERCALLBACKDATA pData)
 {
+    LogFlowFuncEnter();
+
     PSHCLTRANSFERCTX pCtx = (PSHCLTRANSFERCTX)pData->pvUser;
     AssertPtr(pCtx);
@@ -146,14 +140,17 @@
     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pData->pvUser;
     AssertPtr(pCtx);
-
-    LogFlowFunc(("pCtx=%p\n", pCtx));
+    Assert(pData->cbUser == sizeof(SHCLCONTEXT));
 
     PSHCLTRANSFER pTransfer = pData->pTransfer;
     AssertPtr(pTransfer);
 
+    const SHCLTRANSFERDIR enmDir = SharedClipboardTransferGetDir(pTransfer);
+
+    LogFlowFunc(("pCtx=%p, idTransfer=%RU16, enmDir=%RU32\n", pCtx, SharedClipboardTransferGetID(pTransfer), enmDir));
+
     int rc;
 
     /* The guest wants to write local data to the host? */
-    if (SharedClipboardTransferGetDir(pTransfer) == SHCLTRANSFERDIR_WRITE)
+    if (enmDir == SHCLTRANSFERDIR_WRITE)
     {
         Assert(SharedClipboardTransferGetSource(pTransfer) == SHCLSOURCE_LOCAL); /* Sanity. */
@@ -194,17 +191,14 @@
     }
     /* The guest wants to read data from a remote source. */
-    else if (SharedClipboardTransferGetDir(pTransfer) == SHCLTRANSFERDIR_READ)
-    {
-        /* The IDataObject must be created in our window thread, so post a message to it, which
-         * then in turn takes care of the creation. */
-        ::PostMessage(pCtx->Win.hWnd, SHCL_WIN_WM_URI_TRANSFER_START,
-                      0 /* wParm */, (LPARAM)pTransfer /* lParm */);
-
-        rc = VINF_SUCCESS;
+    else if (enmDir == SHCLTRANSFERDIR_READ)
+    {
+        Assert(SharedClipboardTransferGetSource(pTransfer) == SHCLSOURCE_REMOTE); /* Sanity. */
+
+        rc = SharedClipboardWinTransferCreate(&pCtx->Win, pTransfer);
     }
     else
         AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
 
-    LogFlowFuncLeaveRC(rc);
+    LogFlowFunc(("LEAVE: idTransfer=%RU16, rc=%Rrc\n", SharedClipboardTransferGetID(pTransfer), rc));
     return rc;
 }
@@ -251,5 +245,5 @@
         case WM_CLIPBOARDUPDATE:
         {
-            LogFunc(("WM_CLIPBOARDUPDATE\n"));
+            LogFunc(("WM_CLIPBOARDUPDATE: pWinCtx=%p\n", pWinCtx));
 
             int rc = RTCritSectEnter(&pWinCtx->CritSect);
@@ -269,5 +263,5 @@
                      * Report available formats to the host. */
                     SHCLFORMATDATA Formats;
-                    int rc = SharedClipboardWinGetFormats(&pCtx->Win, &Formats);
+                    int rc = SharedClipboardWinGetFormats(pWinCtx, &Formats);
                     if (RT_SUCCESS(rc))
                     {
@@ -298,5 +292,5 @@
         case WM_DRAWCLIPBOARD:
         {
-            LogFlowFunc(("WM_DRAWCLIPBOARD\n"));
+            LogFlowFunc(("WM_DRAWCLIPBOARD: pWinCtx=%p\n", pWinCtx));
 
             int rc = RTCritSectEnter(&pWinCtx->CritSect);
@@ -517,35 +511,38 @@
             Assert(pEvent->enmType == VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS);
 
-            const SHCLFORMATS fFormats =  pEvent->u.ReportedFormats.uFormats;
+            const SHCLFORMATS fFormats = pEvent->u.ReportedFormats.uFormats;
 
             if (fFormats != VBOX_SHCL_FMT_NONE) /* Could arrive with some older GA versions. */
             {
-                int rc = SharedClipboardWinOpen(hwnd);
-                if (RT_SUCCESS(rc))
-                {
-                    SharedClipboardWinClear();
-
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-                    if (fFormats & VBOX_SHCL_FMT_URI_LIST)
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+                if (fFormats & VBOX_SHCL_FMT_URI_LIST)
+                {
+                    LogFunc(("VBOX_SHCL_FMT_URI_LIST\n"));
+
+                    /*
+                     * Creating and starting the actual transfer will be done in vbglR3ClipboardTransferStart() as soon
+                     * as the host announces the start of the transfer via a VBOX_SHCL_HOST_MSG_TRANSFER_STATUS message.
+                     * Transfers always are controlled and initiated on the host side!
+                     *
+                     * So don't announce the transfer to the OS here yet. Don't touch the clipboard in any here; otherwise
+                     * this will trigger a WM_DRAWCLIPBOARD or friends, which will result in fun bugs coming up.
+                     */
+                }
+                else
+                {
+#endif
+                    int rc = SharedClipboardWinOpen(hwnd);
+                    if (RT_SUCCESS(rc))
                     {
-                        LogFunc(("VBOX_SHCL_FMT_URI_LIST\n"));
-
-                        /*
-                         * Creating and starting the actual transfer will be done in vbglR3ClipboardTransferStart() as soon
-                         * as the host announces the start of the transfer via a VBOX_SHCL_HOST_MSG_TRANSFER_STATUS message.
-                         * Transfers always are controlled and initiated on the host side!
-                         *
-                         * So don't announce the transfer to the OS here yet.
-                         */
+                        SharedClipboardWinClear();
+
+                        rc = SharedClipboardWinAnnounceFormats(pWinCtx, fFormats);
                     }
-                    else
-                    {
-#endif
-                        rc = SharedClipboardWinAnnounceFormats(pWinCtx, fFormats);
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-                    }
-#endif
+
                     SharedClipboardWinClose();
-                }
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+                }
+#endif
             }
 
@@ -651,8 +648,8 @@
         }
 
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-        case SHCL_WIN_WM_URI_TRANSFER_START:
-        {
-            LogFunc(("SHCL_WIN_WM_URI_TRANSFER_CREATE\n"));
+#if 0
+        case SHCL_WIN_WM_TRANSFER_START:
+        {
+            LogFunc(("SHCL_WIN_WM_TRANSFER_START\n"));
 
             PSHCLTRANSFER pTransfer = (PSHCLTRANSFER)lParam;
@@ -661,5 +658,5 @@
             Assert(SharedClipboardTransferGetSource(pTransfer) == SHCLSOURCE_REMOTE); /* Sanity. */
 
-            int rc2 = SharedClipboardWinTransferCreate(&pCtx->Win, pTransfer);
+            int rc2 = SharedClipboardWinTransferCreate(pWinCtx, pTransfer);
             AssertRC(rc2);
             break;
@@ -707,6 +704,8 @@
 
     /* Register the Window Class. */
-    WNDCLASSEX wc = { 0 };
-    wc.cbSize     = sizeof(WNDCLASSEX);
+    WNDCLASSEX wc;
+    RT_ZERO(wc);
+
+    wc.cbSize = sizeof(WNDCLASSEX);
 
     if (!GetClassInfoEx(hInstance, s_szClipWndClassName, &wc))
@@ -741,7 +740,10 @@
                          SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
 
-            SharedClipboardWinChainAdd(pWinCtx);
-            if (!SharedClipboardWinIsNewAPI(&pWinCtx->newAPI))
-                pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000 /* 10s */, NULL);
+            rc = SharedClipboardWinChainAdd(pWinCtx);
+            if (RT_SUCCESS(rc))
+            {
+                if (!SharedClipboardWinIsNewAPI(&pWinCtx->newAPI))
+                    pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000 /* 10s */, NULL);
+            }
         }
     }
@@ -751,7 +753,82 @@
 }
 
+static int vboxClipboardWindowThread(RTTHREAD hThread, void *pvUser)
+{
+    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pvUser;
+    AssertPtr(pCtx);
+
+    HRESULT hr;
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+    hr = OleInitialize(NULL);
+    if (FAILED(hr))
+    {
+        LogRel(("Shared Clipboard: Initializing OLE in window thread failed (%Rhrc) -- file transfers unavailable\n", hr));
+        /* Not critical, the rest of the clipboard might work. */
+    }
+    else
+        LogRel(("Shared Clipboard: Initialized OLE in window thread\n"));
+#endif
+
+    int rc = vboxClipboardCreateWindow(pCtx);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("Shared Clipboard: Unable to create window, rc=%Rrc\n", rc));
+        return rc;
+    }
+
+    pCtx->fStarted = true; /* Set started indicator. */
+
+    int rc2 = RTThreadUserSignal(hThread);
+    bool fSignalled = RT_SUCCESS(rc2);
+
+    LogRel2(("Shared Clipboard: Window thread running\n"));
+
+    if (RT_SUCCESS(rc))
+    {
+        for (;;)
+        {
+            MSG uMsg;
+            BOOL fRet;
+            while ((fRet = GetMessage(&uMsg, 0, 0, 0)) > 0)
+            {
+                TranslateMessage(&uMsg);
+                DispatchMessage(&uMsg);
+            }
+            Assert(fRet >= 0);
+
+            if (ASMAtomicReadBool(&pCtx->fShutdown))
+                break;
+
+            /** @todo Immediately drop on failure? */
+        }
+    }
+
+    if (!fSignalled)
+    {
+        rc2 = RTThreadUserSignal(hThread);
+        AssertRC(rc2);
+    }
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+    OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
+    OleUninitialize();
+#endif
+
+    LogRel(("Shared Clipboard: Window thread ended\n"));
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
 static void vboxClipboardDestroy(PSHCLCONTEXT pCtx)
 {
     AssertPtrReturnVoid(pCtx);
+
+    LogFlowFunc(("pCtx=%p\n", pCtx));
+
+    LogRel2(("Shared Clipboard: Destroying ...\n"));
+
+    pCtx->fShutdown = true;
 
     const PSHCLWINCTX pWinCtx = &pCtx->Win;
@@ -763,7 +840,18 @@
     }
 
+    if (pCtx->hThread != NIL_RTTHREAD)
+    {
+        int rcThread = VERR_WRONG_ORDER;
+        int rc = RTThreadWait(pCtx->hThread, 60 * 1000 /* Timeout in ms */, &rcThread);
+        LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n",
+                     rc, rcThread));
+        RT_NOREF(rc);
+    }
+
     UnregisterClass(s_szClipWndClassName, pCtx->pEnv->hInstance);
 
     SharedClipboardWinCtxDestroy(&pCtx->Win);
+
+    LogRel2(("Shared Clipboard: Destroyed\n"));
 }
 
@@ -797,34 +885,26 @@
     }
 
-    pCtx->pEnv = pEnv;
+    pCtx->pEnv      = pEnv;
+    pCtx->hThread   = NIL_RTTHREAD;
+    pCtx->fStarted  = false;
+    pCtx->fShutdown = false;
 
     int rc = VINF_SUCCESS;
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-    HRESULT hr = OleInitialize(NULL);
-    if (FAILED(hr))
-    {
-        LogRel(("Shared Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n", hr));
-        /* Not critical, the rest of the clipboard might work. */
-    }
-    else
-    {
-        LogRel(("Shared Clipboard: Initialized OLE\n"));
-
-        /* Install callbacks. */
-        RT_ZERO(pCtx->CmdCtx.Transfers.Callbacks);
-
-        pCtx->CmdCtx.Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
-
-        pCtx->CmdCtx.Transfers.Callbacks.pfnTransferInitialize = vboxClipboardOnTransferInitCallback;
-        pCtx->CmdCtx.Transfers.Callbacks.pfnTransferStart      = vboxClipboardOnTransferStartCallback;
-        pCtx->CmdCtx.Transfers.Callbacks.pfnTransferComplete   = vboxClipboardOnTransferCompleteCallback;
-        pCtx->CmdCtx.Transfers.Callbacks.pfnTransferError      = vboxClipboardOnTransferErrorCallback;
-    }
+    /* Install callbacks. */
+    RT_ZERO(pCtx->CmdCtx.Transfers.Callbacks);
+
+    pCtx->CmdCtx.Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
+    pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
+
+    pCtx->CmdCtx.Transfers.Callbacks.pfnTransferInitialize = vboxClipboardOnTransferInitCallback;
+    pCtx->CmdCtx.Transfers.Callbacks.pfnTransferStart      = vboxClipboardOnTransferStartCallback;
+    pCtx->CmdCtx.Transfers.Callbacks.pfnTransferComplete   = vboxClipboardOnTransferCompleteCallback;
+    pCtx->CmdCtx.Transfers.Callbacks.pfnTransferError      = vboxClipboardOnTransferErrorCallback;
 #endif
 
     if (RT_SUCCESS(rc))
     {
-        /* Check if new Clipboard API is available. */
         rc = SharedClipboardWinCtxInit(&pCtx->Win);
         if (RT_SUCCESS(rc))
@@ -832,19 +912,34 @@
         if (RT_SUCCESS(rc))
         {
-            rc = vboxClipboardCreateWindow(pCtx);
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+            rc = SharedClipboardTransferCtxInit(&pCtx->TransferCtx);
+#endif
             if (RT_SUCCESS(rc))
             {
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-                rc = SharedClipboardTransferCtxInit(&pCtx->TransferCtx);
+                /* Message pump thread for our proxy window. */
+                rc = RTThreadCreate(&pCtx->hThread, vboxClipboardWindowThread, pCtx /* pvUser */,
+                                    0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
+                                    "shclwnd");
                 if (RT_SUCCESS(rc))
-#endif
-                    *ppInstance = pCtx;
+                {
+                    int rc2 = RTThreadUserWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */);
+                    AssertRC(rc2);
+
+                    if (!pCtx->fStarted) /* Did the thread fail to start? */
+                        rc = VERR_NOT_SUPPORTED; /* Report back Shared Clipboard as not being supported. */
+                }
+            }
+
+            if (RT_SUCCESS(rc))
+            {
+                *ppInstance = pCtx;
             }
             else
-            {
                 VbglR3ClipboardDisconnectEx(&pCtx->CmdCtx);
-            }
-        }
-    }
+        }
+    }
+
+    if (RT_FAILURE(rc))
+        LogRel(("Shared Clipboard: Unable to initialize, rc=%Rrc\n", rc));
 
     LogFlowFuncLeaveRC(rc);
@@ -856,11 +951,4 @@
     AssertPtr(pInstance);
     LogFlowFunc(("pInstance=%p\n", pInstance));
-
-    HRESULT hr = OleInitialize(NULL);
-    if (FAILED(hr))
-    {
-        LogRel(("Shared Clipboard: Initializing OLE in worker thread failed (%Rhrc) -- file transfers unavailable\n", hr));
-        /* Not critical, the rest of the clipboard might work. */
-    }
 
     /*
@@ -875,7 +963,20 @@
     const PSHCLWINCTX pWinCtx = &pCtx->Win;
 
+    LogRel2(("Shared Clipboard: Worker loop running, using protocol v%RU32\n", pCtx->CmdCtx.uProtocolVer));
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+    HRESULT hr = OleInitialize(NULL);
+    if (FAILED(hr))
+    {
+        LogRel(("Shared Clipboard: Initializing OLE in worker thread failed (%Rhrc) -- file transfers unavailable\n", hr));
+        /* Not critical, the rest of the clipboard might work. */
+    }
+    else
+        LogRel(("Shared Clipboard: Initialized OLE in worker thraed\n"));
+#endif
+
     int rc;
 
-    LogFlowFunc(("Using protocol %RU32\n", pCtx->CmdCtx.uProtocolVer));
+    LogFlowFunc(("uProtocolVer=%RU32\n", pCtx->CmdCtx.uProtocolVer));
 
     uint32_t uMsg;
@@ -946,4 +1047,6 @@
         if (RT_FAILURE(rc))
         {
+            LogFlowFunc(("Getting next event failed with %Rrc\n", rc));
+
             VbglR3ClipboardEventFree(pEvent);
             pEvent = NULL;
@@ -987,6 +1090,5 @@
                 case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
                 {
-                    /* The host is terminating. */
-                    LogRel(("Shared Clipboard: Terminating ...\n"));
+                    LogRel2(("Shared Clipboard: Host requested termination\n"));
                     ASMAtomicXchgBool(pfShutdown, true);
                     break;
@@ -994,18 +1096,21 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-                case VBGLR3CLIPBOARDEVENTTYPE_URI_TRANSFER_STATUS:
+                case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:
                 {
                     /* Nothing to do here. */
+                    rc = VINF_SUCCESS;
                     break;
                 }
 #endif
-                case VBGLR3CLIPBOARDEVENTTYPE_INVALID:
+                case VBGLR3CLIPBOARDEVENTTYPE_NONE:
+                {
+                    /* Nothing to do here. */
+                    rc = VINF_SUCCESS;
+                    break;
+                }
+
                 default:
                 {
-                    /* Wait a bit before retrying. */
-                    RTThreadSleep(1000);
-
-                    rc = VERR_NOT_SUPPORTED;
-                    break;
+                    AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED);
                 }
             }
@@ -1022,4 +1127,6 @@
     }
 
+    LogRel(("Shared Clipboard: Worker loop ended\n"));
+
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
@@ -1060,7 +1167,4 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-    OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
-    OleUninitialize();
-
     SharedClipboardTransferCtxDestroy(&pCtx->TransferCtx);
 #endif
