Index: /trunk/include/VBox/GuestHost/SharedClipboard-win.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 100411)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 100412)
@@ -295,4 +295,7 @@
     static int Thread(RTTHREAD hThread, void *pvUser);
 
+    inline int lock(void);
+    inline int unlock(void);
+
     int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath);
 
@@ -304,4 +307,5 @@
     void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
                         LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
+    int setTransferLocked(PSHCLTRANSFER pTransfer);
     int setStatusLocked(Status enmStatus, int rc = VINF_SUCCESS);
 
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 100411)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 100412)
@@ -206,10 +206,24 @@
     switch(ShClTransferGetDir(pCbCtx->pTransfer))
     {
-        case SHCLTRANSFERDIR_FROM_REMOTE:
-        {
-            AssertPtrBreak(pCtx->Win.pDataObjInFlight);
-            rc = pCtx->Win.pDataObjInFlight->SetTransfer(pCbCtx->pTransfer);
-            if (RT_SUCCESS(rc))
-                rc = pCtx->Win.pDataObjInFlight->SetStatus(SharedClipboardWinDataObject::Running);
+        case SHCLTRANSFERDIR_TO_REMOTE: /* G->H */
+        {
+            rc = SharedClipboardWinTransferGetRootsFromClipboard(&pCtx->Win, pCbCtx->pTransfer);
+            break;
+        }
+
+        case SHCLTRANSFERDIR_FROM_REMOTE: /* H->G */
+        {
+            SharedClipboardWinDataObject *pObj = pCtx->Win.pDataObjInFlight;
+            if (pObj)
+            {
+                rc = pObj->SetTransfer(pCbCtx->pTransfer);
+                if (RT_SUCCESS(rc))
+                    rc = pObj->SetStatus(SharedClipboardWinDataObject::Running);
+
+                pCtx->Win.pDataObjInFlight = NULL; /* Hand off to Windows. */
+            }
+            else
+                AssertMsgFailed(("No data object in flight!\n"));
+
             break;
         }
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 100411)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 100412)
@@ -188,4 +188,7 @@
     AssertReturnVoid(m_lRefCount == 0);
 
+    /* Make sure to release the transfer. */
+    setTransferLocked(NULL);
+
     int rc = RTCritSectDelete(&m_CritSect);
     AssertRC(rc);
@@ -310,4 +313,20 @@
     GlobalFree(hGlobal);
     return VERR_ACCESS_DENIED;
+}
+
+inline int SharedClipboardWinDataObject::lock(void)
+{
+    int rc = RTCritSectEnter(&m_CritSect);
+    AssertRCReturn(rc, rc);
+
+    return rc;
+}
+
+inline int SharedClipboardWinDataObject::unlock(void)
+{
+    int rc = RTCritSectLeave(&m_CritSect);
+    AssertRCReturn(rc, rc);
+
+    return rc;
 }
 
@@ -675,6 +694,5 @@
     AssertPtrReturn(pMedium, DV_E_FORMATETC);
 
-    int rc2 = RTCritSectEnter(&m_CritSect);
-    AssertRCReturn(rc2, E_UNEXPECTED);
+    lock();
 
     LogFlowFunc(("lIndex=%RI32, enmStatus=%#x\n", pFormatEtc->lindex, m_enmStatus));
@@ -702,6 +720,5 @@
 
                 /* Leave lock while requesting + waiting. */
-                rc2 = RTCritSectLeave(&m_CritSect);
-                AssertRCBreak(rc);
+                unlock();
 
                 /* Start the transfer. */
@@ -715,9 +732,13 @@
                  *       Windows Explorer unresponsive (i.e. "ghost window") when waiting for too long. */
                 rc = RTSemEventWait(m_EventStatusChanged, RT_MS_10SEC);
-                AssertRCBreak(rc);
 
                 /* Re-acquire lock. */
-                rc = RTCritSectEnter(&m_CritSect);
-                AssertRCBreak(rc);
+                lock();
+
+                if (RT_FAILURE(rc))
+                {
+                    LogRel(("Shared Clipboard: Waiting for IDataObject status status failed, rc=%Rrc\n", rc));
+                    break;
+                }
 
                 if (m_enmStatus != Running)
@@ -757,6 +778,5 @@
 
                             /* Leave lock while waiting. */
-                            rc = RTCritSectLeave(&m_CritSect);
-                            AssertRCReturn(rc, E_UNEXPECTED);
+                            unlock();
 
                             /* Don't block for too long here, as this also will screw other apps running on the OS. */
@@ -765,6 +785,5 @@
 
                             /* Re-acquire lock. */
-                            rc = RTCritSectEnter(&m_CritSect);
-                            AssertRCReturn(rc, E_UNEXPECTED);
+                            lock();
                         }
                     }
@@ -847,6 +866,5 @@
     }
 
-    rc2 = RTCritSectLeave(&m_CritSect);
-    AssertRCReturn(rc2, E_UNEXPECTED);
+    unlock();
 
     LogFlowFunc(("hr=%Rhrc\n", hr));
@@ -1012,17 +1030,21 @@
 
 /**
- * Assigns a transfer object for the data object.
+ * Assigns a transfer object for the data object, internal version.
  *
  * @returns VBox status code.
  * @param   pTransfer           Transfer to assign.
- *                              Must be in started state.
- */
-int SharedClipboardWinDataObject::SetTransfer(PSHCLTRANSFER pTransfer)
-{
-    AssertReturn(m_pTransfer == NULL, VERR_WRONG_ORDER); /* Transfer already set? */
-
-    int rc = RTCritSectEnter(&m_CritSect);
-    if (RT_SUCCESS(rc))
-    {
+ *                              Must be in INITIALIZED state.
+ *                              When set to NULL, the transfer will be released from the object.
+ */
+int SharedClipboardWinDataObject::setTransferLocked(PSHCLTRANSFER pTransfer)
+{
+    LogFlowFunc(("pTransfer=%p\n", pTransfer));
+
+    int rc = VINF_SUCCESS;
+
+    if (pTransfer) /* Set */
+    {
+        Assert(m_pTransfer == NULL); /* Transfer already set? */
+
         if (m_enmStatus == Initialized)
         {
@@ -1039,7 +1061,32 @@
         else
             AssertFailedStmt(rc = VERR_WRONG_ORDER);
-
-        RTCritSectLeave(&m_CritSect);
-    }
+    }
+    else /* Unset */
+    {
+        if (m_pTransfer)
+        {
+            ShClTransferRelease(m_pTransfer);
+            m_pTransfer = NULL;
+        }
+    }
+
+    return rc;
+}
+
+/**
+ * Assigns a transfer object for the data object.
+ *
+ * @returns VBox status code.
+ * @param   pTransfer           Transfer to assign.
+ *                              Must be in INITIALIZED state.
+ *                              When set to NULL, the transfer will be released from the object.
+ */
+int SharedClipboardWinDataObject::SetTransfer(PSHCLTRANSFER pTransfer)
+{
+    lock();
+
+    int rc = setTransferLocked(pTransfer);
+
+    unlock();
 
     return rc;
@@ -1057,12 +1104,9 @@
 int SharedClipboardWinDataObject::SetStatus(Status enmStatus, int rcSts /* = VINF_SUCCESS */)
 {
-    int rc = RTCritSectEnter(&m_CritSect);
-    if (RT_SUCCESS(rc))
-    {
-        rc = setStatusLocked(enmStatus, rcSts);
-
-        RTCritSectLeave(&m_CritSect);
-    }
-
+    lock();
+
+    int rc = setStatusLocked(enmStatus, rcSts);
+
+    unlock();
     return rc;
 }
@@ -1141,36 +1185,32 @@
     RT_NOREF(rc);
 
-    int rc2 = RTCritSectEnter(&m_CritSect);
-    if (RT_SUCCESS(rc2))
-    {
-        LogFlowFunc(("enmStatus=%#x (current is: %#x)\n", enmStatus, m_enmStatus));
-
-        switch (enmStatus)
-        {
-            case Completed:
-            {
-                LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size()));
-
-                const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */;
-                if (fComplete)
-                    m_enmStatus = Completed;
-                break;
-            }
-
-            default:
-            {
-                m_enmStatus = enmStatus;
-                break;
-            }
-        }
-
-        if (RT_FAILURE(rc))
-            LogRel(("Shared Clipboard: Data object received error %Rrc (status %#x)\n", rc, enmStatus));
-
-        if (m_EventStatusChanged != NIL_RTSEMEVENT)
-            rc2 = RTSemEventSignal(m_EventStatusChanged);
-
-        RTCritSectLeave(&m_CritSect);
-    }
+    LogFlowFunc(("enmStatus=%#x (current is: %#x)\n", enmStatus, m_enmStatus));
+
+    int rc2 = VINF_SUCCESS;
+
+    switch (enmStatus)
+    {
+        case Completed:
+        {
+            LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size()));
+
+            const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */;
+            if (fComplete)
+                m_enmStatus = Completed;
+            break;
+        }
+
+        default:
+        {
+            m_enmStatus = enmStatus;
+            break;
+        }
+    }
+
+    if (RT_FAILURE(rc))
+        LogRel(("Shared Clipboard: Data object received error %Rrc (status %#x)\n", rc, enmStatus));
+
+    if (m_EventStatusChanged != NIL_RTSEMEVENT)
+        rc2 = RTSemEventSignal(m_EventStatusChanged);
 
     return rc2;
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 100411)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 100412)
@@ -301,4 +301,6 @@
 static DECLCALLBACK(void) shClSvcWinTransferOnInitializedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
 {
+    LogFlowFuncEnter();
+
     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     AssertPtr(pCtx);
@@ -317,8 +319,14 @@
             {
                 SharedClipboardWinDataObject *pObj = pCtx->Win.pDataObjInFlight;
-                AssertPtrReturnVoid(pObj);
-                rc = pObj->SetTransfer(pTransfer);
-
-                pCtx->Win.pDataObjInFlight = NULL; /* Hand off to Windows. */
+                if (pObj)
+                {
+                    rc = pObj->SetTransfer(pTransfer);
+                    if (RT_SUCCESS(rc))
+                        rc = pObj->SetStatus(SharedClipboardWinDataObject::Running);
+
+                    pCtx->Win.pDataObjInFlight = NULL; /* Hand off to Windows. */
+                }
+                else
+                    AssertMsgFailed(("No data object in flight!\n"));
 
                 int rc2 = RTCritSectLeave(&pCtx->Win.CritSect);
@@ -350,4 +358,6 @@
 static DECLCALLBACK(void) shClSvcWinTransferOnDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
 {
+    LogFlowFuncEnter();
+
     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     AssertPtr(pCtx);
@@ -360,21 +370,31 @@
 
 /**
- * @copydoc SHCLTRANSFERCALLBACKS::pfnOnStarted
+ * @copydoc SharedClipboardWinDataObject::CALLBACKS::pfnTransferStart
+ *
+ * Called by SharedClipboardWinDataObject::GetData() when the user wants to paste data.
+ * This then creates and initializes a new transfer on the host + lets the guest know about that new transfer.
  *
  * @thread  Service main thread.
  */
-static DECLCALLBACK(void) shClSvcWinTransferOnStartedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
-{
+static DECLCALLBACK(int) shClSvcWinDataObjectTransferStartCallback(SharedClipboardWinDataObject::PCALLBACKCTX pCbCtx)
+{
+    LogFlowFuncEnter();
+
     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     AssertPtr(pCtx);
 
-    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
-    AssertPtr(pTransfer);
-
-    if (ShClTransferGetDir(pTransfer) ==  SHCLTRANSFERDIR_FROM_REMOTE) /* G->H */
-    {
-        /* Report to the guest that we now entered the STARTED state. */
-        ShClSvcTransferStart(pCtx->pClient, pTransfer);
-    }
+    PSHCLTRANSFER pTransfer;
+    int rc = ShClSvcTransferCreate(pCtx->pClient, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
+                                   NIL_SHCLTRANSFERID /* Creates a new transfer ID */, &pTransfer);
+    if (RT_SUCCESS(rc))
+    {
+        /* Initialize the transfer on the host side. */
+        rc = ShClSvcTransferInit(pCtx->pClient, pTransfer);
+        if (RT_FAILURE(rc))
+             ShClSvcTransferDestroy(pCtx->pClient, pTransfer);
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
 }
 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
@@ -545,7 +565,21 @@
 
             int rc = SharedClipboardWinClearAndAnnounceFormats(pWinCtx, fFormats, hWnd);
-            if (RT_FAILURE(rc))
-                LogRel(("Shared Clipboard: Reporting clipboard formats %#x to Windows host failed with %Rrc\n", fFormats, rc));
-
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+            if (   RT_SUCCESS(rc)
+                && fFormats & VBOX_SHCL_FMT_URI_LIST)
+            {
+                /*
+                 * Create our IDataObject implementation and push it to the Windows clibpoard.
+                 * That way Windows will recognize that there is a data transfer available.
+                 */
+                SharedClipboardWinDataObject::CALLBACKS Callbacks;
+                RT_ZERO(Callbacks);
+                Callbacks.pfnTransferStart = shClSvcWinDataObjectTransferStartCallback;
+
+                rc = SharedClipboardWinTransferCreateAndSetDataObject(pWinCtx, pCtx, &Callbacks);
+            }
+#else
+            RT_NOREF(rc);
+#endif
             LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: lastErr=%ld\n", GetLastError()));
             break;
@@ -828,5 +862,4 @@
         pClient->Transfers.Callbacks.pfnOnCreated     = shClSvcWinTransferOnCreatedCallback;
         pClient->Transfers.Callbacks.pfnOnInitialized = shClSvcWinTransferOnInitializedCallback;
-        pClient->Transfers.Callbacks.pfnOnStarted     = shClSvcWinTransferOnStartedCallback;
         pClient->Transfers.Callbacks.pfnOnDestroy     = shClSvcWinTransferOnDestroyCallback;
 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
