Index: trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
===================================================================
--- trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 103484)
+++ trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 103615)
@@ -219,8 +219,8 @@
 
         lock();
-
-        /* Make sure to release the transfer. */
-        setTransferLocked(NULL);
-    }
+    }
+
+    /* Make sure to release the transfer in any state. */
+    setTransferLocked(NULL);
 
     unlock();
@@ -280,7 +280,4 @@
         m_pStgMedium = NULL;
     }
-
-    if (m_pTransfer)
-        ShClTransferRelease(m_pTransfer);
 
     FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin();
@@ -566,6 +563,4 @@
             if (RT_SUCCESS(rc))
             {
-                pThis->lock();
-
                 AssertReleaseMsg(pThis->m_lstEntries.size(),
                                  ("Shared Clipboard: No transfer root entries found -- should not happen, please file a bug report\n"));
@@ -578,11 +573,6 @@
                         break;
 
-                    pThis->unlock();
-
                     /* Transferring stuff can take a while, so don't use any timeout here. */
                     rc = RTSemEventWait(pThis->m_EventStatusChanged, RT_INDEFINITE_WAIT);
-
-                    pThis->lock();
-
                     if (RT_FAILURE(rc))
                         break;
@@ -620,6 +610,4 @@
                             break;
                     }
-
-                    pThis->unlock();
 
                     if (pThis->m_Callbacks.pfnTransferEnd)
@@ -630,10 +618,6 @@
                     }
 
-                    pThis->lock();
-
                     break;
-                }
-
-                pThis->unlock();
+                } /* for */
             }
         }
@@ -806,8 +790,4 @@
     int rc = VINF_SUCCESS;
 
-    /* Pre-check -- see if the data object still is alive. */
-    if (m_enmStatus == Uninitialized)
-        rc = VERR_OBJECT_DESTROYED;
-
     if (    RT_SUCCESS(rc)
         && (   pFormatEtc->cfFormat == m_cfFileDescriptorA
@@ -841,4 +821,6 @@
                 lock();
 
+                LogFunc(("Wait resulted in %Rrc and status %#x\n", rc, m_enmStatus));
+
                 if (RT_FAILURE(rc))
                 {
@@ -864,6 +846,8 @@
                 const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW;
 
+                /* Leave lock while waiting. */
+                unlock();
+
                 SHCLTRANSFERSTATUS const enmTransferStatus = ShClTransferGetStatus(m_pTransfer);
-                RT_NOREF(enmTransferStatus);
 
                 LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s\n",
@@ -871,5 +855,5 @@
 
                 /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
-                if (ShClTransferGetStatus(m_pTransfer) != SHCLTRANSFERSTATUS_STARTED)
+                if (enmTransferStatus != SHCLTRANSFERSTATUS_STARTED)
                 {
                     /* Start the transfer + run it asynchronously in a separate thread. */
@@ -880,7 +864,4 @@
                         if (RT_SUCCESS(rc))
                         {
-                            /* Leave lock while waiting. */
-                            unlock();
-
                             /* Don't block for too long here, as this also will screw other apps running on the OS. */
                             LogRel2(("Shared Clipboard: Waiting for IDataObject listing to arrive ...\n"));
@@ -893,10 +874,14 @@
                                 || m_enmStatus != Running) /* Still in running state? */
                             {
-                                rc = VERR_OBJECT_DESTROYED;
+                                rc = VERR_SHCLPB_NO_DATA;
                                 break;
                             }
+
+                            unlock();
                         }
                     }
                 }
+
+                lock();
 
                 if (RT_SUCCESS(rc))
@@ -1147,5 +1132,4 @@
  * @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.
  */
@@ -1154,5 +1138,5 @@
     AssertReturn(RTCritSectIsOwned(&m_CritSect), VERR_WRONG_ORDER);
 
-    LogFlowFunc(("pTransfer=%p\n", pTransfer));
+    LogFunc(("pTransfer=%p\n", pTransfer));
 
     int rc = VINF_SUCCESS;
@@ -1164,18 +1148,12 @@
         if (m_enmStatus == Initialized)
         {
-            SHCLTRANSFERSTATUS const enmSts = ShClTransferGetStatus(pTransfer);
-            AssertMsgStmt(enmSts == SHCLTRANSFERSTATUS_INITIALIZED, /* Transfer must not be started yet. */
-                          ("Transfer has wrong status (%#x)\n", enmSts), rc = VERR_WRONG_ORDER);
-            if (RT_SUCCESS(rc))
-            {
-                m_pTransfer = pTransfer;
-
-                SharedClipboardWinTransferCtx *pWinURITransferCtx = (SharedClipboardWinTransferCtx *)pTransfer->pvUser;
-                AssertPtr(pWinURITransferCtx);
-
-                pWinURITransferCtx->pDataObj = this; /* Save a backref to this object. */
-
-                ShClTransferAcquire(pTransfer);
-            }
+            m_pTransfer = pTransfer;
+
+            SharedClipboardWinTransferCtx *pWinURITransferCtx = (SharedClipboardWinTransferCtx *)pTransfer->pvUser;
+            AssertPtr(pWinURITransferCtx);
+
+            pWinURITransferCtx->pDataObj = this; /* Save a backref to this object. */
+
+            ShClTransferAcquire(pTransfer);
         }
         else
@@ -1208,5 +1186,4 @@
  * @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.
  */
Index: trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp
===================================================================
--- trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp	(revision 103484)
+++ trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp	(revision 103615)
@@ -1234,7 +1234,7 @@
 
     int rc = VINF_SUCCESS;
+
     if (pTransfer->Callbacks.pfnOnInitialize)
         rc = pTransfer->Callbacks.pfnOnInitialize(&pTransfer->CallbackCtx);
-
     if (RT_SUCCESS(rc))
     {
@@ -1244,15 +1244,17 @@
             AssertMsgStmt(ShClTransferRootsCount(pTransfer), ("Transfer has no root entries set\n"), rc = VERR_WRONG_ORDER);
 
-        rc = shClTransferSetStatus(pTransfer, SHCLTRANSFERSTATUS_INITIALIZED);
-
-        if (   RT_SUCCESS(rc)
-            && pTransfer->Callbacks.pfnOnInitialized)
-            pTransfer->Callbacks.pfnOnInitialized(&pTransfer->CallbackCtx);
+        if (RT_SUCCESS(rc))
+            rc = shClTransferSetStatus(pTransfer, SHCLTRANSFERSTATUS_INITIALIZED);
     }
 
     shClTransferUnlock(pTransfer);
 
+    /* Note: Callback will be called after we unlocked the transfer, as the caller might access the transfer right away. */
+    if (   RT_SUCCESS(rc)
+        && pTransfer->Callbacks.pfnOnInitialized)
+        pTransfer->Callbacks.pfnOnInitialized(&pTransfer->CallbackCtx);
+
     if (RT_FAILURE(rc))
-        LogRel2(("Shared Clipboard: Initialziation of transfer failed with %Rrc\n", rc));
+        LogRel(("Shared Clipboard: Initialziation of transfer failed with %Rrc\n", rc));
 
     LogFlowFuncLeaveRC(rc);
Index: trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp
===================================================================
--- trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp	(revision 103484)
+++ trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp	(revision 103615)
@@ -1192,14 +1192,28 @@
 
 /**
- * Hands off a transfer to the current data object in-flight.
+ * Initializes a Windows transfer for a given data object.
  *
  * @returns VBox status code.
  * @param   pWinCtx             Windows context to use.
- * @param   pTransfer           Transfer to hand off to the data object.
- *
- * @note    The data object will be put into running state on success and handed over to Windows.
- *          Our data object pointer will be invalid afterwards.
- */
-int SharedClipboardWinTransferHandOffToDataObject(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)
+ * @param   pTransfer           Transfer to initialize for the data object.
+ * @param   pObj                Data object to initialize transfer for.
+ */
+static int sharedClipboardWinTransferInitializeInternal(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer,
+                                                        SharedClipboardWinDataObject *pObj)
+{
+    RT_NOREF(pWinCtx);
+
+    return pObj->SetTransfer(pTransfer);
+}
+
+/**
+ * Initializes a Windows transfer for the current data object in-flight.
+ *
+ * @returns VBox status code.
+ * @retval  VERR_WRONG_ORDER if no current in-flight data object is available.
+ * @param   pWinCtx             Windows context to use.
+ * @param   pTransfer           Transfer to initialize for the data object.
+ */
+int SharedClipboardWinTransferInitialize(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)
 {
     int rc = RTCritSectEnter(&pWinCtx->CritSect);
@@ -1209,15 +1223,56 @@
         if (pObj)
         {
-            rc = pObj->SetTransfer(pTransfer);
+            rc = sharedClipboardWinTransferInitializeInternal(pWinCtx, pTransfer, pObj);
+        }
+        else /* No current in-flight data object. */
+            rc = VERR_WRONG_ORDER;
+
+        int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
+        AssertRC(rc2);
+    }
+
+    return rc;
+}
+
+/**
+ * Starts a Windows transfer for a given data object.
+ *
+ * @returns VBox status code.
+ * @param   pWinCtx             Windows context to use.
+ * @param   pObj                Data object to start transfer for.
+ */
+static int sharedClipboardWinTransferStartInternal(PSHCLWINCTX pWinCtx, SharedClipboardWinDataObject *pObj)
+{
+    RT_NOREF(pWinCtx);
+
+    return pObj->SetStatus(SharedClipboardWinDataObject::Running);
+}
+
+/**
+ * Starts a Windows transfer for the current data object in-flight.
+ *
+ * This hands off the data object in-flight to Windows on success.
+ *
+ * @returns VBox status code.
+ * @retval  VERR_WRONG_ORDER if no current in-flight data object is available.
+ * @param   pWinCtx             Windows context to use.
+ * @param   pTransfer           Transfer to initialize for the data object.
+ */
+int SharedClipboardWinTransferStart(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)
+{
+    RT_NOREF(pTransfer);
+
+    int rc = RTCritSectEnter(&pWinCtx->CritSect);
+    if (RT_SUCCESS(rc))
+    {
+        SharedClipboardWinDataObject *pObj = pWinCtx->pDataObjInFlight;
+        if (pObj)
+        {
+            rc = sharedClipboardWinTransferStartInternal(pWinCtx, pObj);
             if (RT_SUCCESS(rc))
-                rc = pObj->SetStatus(SharedClipboardWinDataObject::Running);
-
-            pWinCtx->pDataObjInFlight = NULL; /* Hand off to Windows. */
-        }
-        else
-        {
-            AssertMsgFailed(("No data object in flight (yet)!\n"));
+                pWinCtx->pDataObjInFlight = NULL; /* Hand off to Windows on success. */
+        }
+        else /* No current in-flight data object. */
             rc = VERR_WRONG_ORDER;
-        }
 
         int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
