Index: /trunk/include/VBox/GuestHost/SharedClipboard-transfers.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-transfers.h	(revision 87610)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-transfers.h	(revision 87611)
@@ -612,22 +612,10 @@
 /**
  * Shared Clipboard transfer provider interface table.
+ *
+ * A transfer provider inteface implementation realizes all low level functions
+ * needed for making a Shared Clipboard transfer happen.
  */
 typedef struct _SHCLTXPROVIDERIFACE
 {
-    /** Called when the transfer gets initialized. */
-    DECLCALLBACKMEMBER(int,  pfnInitialize,(PSHCLTXPROVIDERCTX pCtx));
-    /** Called before the transfer will be started. */
-    DECLCALLBACKMEMBER(int,  pfnStart,(PSHCLTXPROVIDERCTX pCtx));
-    /** Called when the transfer has been complete. */
-    DECLCALLBACKMEMBER(void, pfnCompleted,(PSHCLTXPROVIDERCTX pCtx, int rc));
-    /** Called when the transfer has been canceled. */
-    DECLCALLBACKMEMBER(void, pfnCanceled,(PSHCLTXPROVIDERCTX pCtx));
-    /** Called when transfer resulted in an unrecoverable error. */
-    DECLCALLBACKMEMBER(void, pfnError,(PSHCLTXPROVIDERCTX pCtx, int rc));
-    /** Called when transfer got registered to a transfer context. */
-    DECLCALLBACKMEMBER(void, pfnRegistered,(PSHCLTXPROVIDERCTX pCtx, PSHCLTRANSFERCTX pTransferCtx));
-    /** Called when transfer got unregistered from a transfer context. */
-    DECLCALLBACKMEMBER(void, pfnUnregistered,(PSHCLTXPROVIDERCTX pCtx, PSHCLTRANSFERCTX pTransferCtx));
-
     DECLCALLBACKMEMBER(int, pfnRootsGet,(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList));
     DECLCALLBACKMEMBER(int, pfnListOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList));
@@ -661,4 +649,72 @@
 
 /**
+ * Structure maintaining clipboard transfer callback context data.
+ */
+typedef struct _SHCLTRANSFERCALLBACKCTX
+{
+    /** Pointer to the related Shared Clipboard transfer. */
+    PSHCLTRANSFER pTransfer;
+    /** User-defined data pointer. Can be NULL if not needed. */
+    void         *pvUser;
+    /** Size (in bytes) of data at user pointer. */
+    size_t        cbUser;
+} SHCLTRANSFERCALLBACKCTX, *PSHCLTRANSFERCALLBACKCTX;
+
+/**
+ * Shared Clipboard transfer callback table.
+ *
+ * All callbacks are optional and can provide additional information / feedback to a frontend.
+ */
+typedef struct _SHCLTRANSFERCALLBACKTABLE
+{
+    /**
+     * Called when the transfer gets initialized.
+     *
+     * @param   pCbCtx              Pointer to callback context to use.
+     */
+    DECLCALLBACKMEMBER(int,  pfnOnInitialize,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
+    /**
+     * Called before the transfer will be started.
+     *
+     * @param   pCbCtx              Pointer to callback context to use.
+     */
+    DECLCALLBACKMEMBER(int,  pfnOnStart,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
+    /**
+     * Called when the transfer has been complete.
+     *
+     * @param   pCbCtx              Pointer to callback context to use.
+     * @param   rcCompletion        Completion result.
+     *                              VERR_CANCELED if transfer has been canceled.
+     */
+    DECLCALLBACKMEMBER(void, pfnOnCompleted,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion));
+    /**
+     * Called when transfer resulted in an unrecoverable error.
+     *
+     * @param   pCbCtx              Pointer to callback context to use.
+     * @param   rcError             Error reason, IPRT-style.
+     */
+    DECLCALLBACKMEMBER(void, pfnOnError,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError));
+    /**
+     * Called when transfer got registered to a transfer context.
+     *
+     * @param   pCbCtx              Pointer to callback context to use.
+     * @param   pTransferCtx        Transfer context transfer was registered to.
+     */
+    DECLCALLBACKMEMBER(void, pfnOnRegistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx));
+    /**
+     * Called when transfer got unregistered from a transfer context.
+     *
+     * @param   pCbCtx              Pointer to callback context to use.
+     * @param   pTransferCtx        Transfer context transfer was unregistered from.
+     */
+    DECLCALLBACKMEMBER(void, pfnOnUnregistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx));
+
+    /** User-provided callback data. Can be NULL if not used. */
+    void  *pvUser;
+    /** Size (in bytes) of data pointer at \a pvUser. */
+    size_t cbUser;
+} SHCLTRANSFERCALLBACKTABLE, *PSHCLTRANSFERCALLBACKTABLE;
+
+/**
  * Structure for thread-related members for a single Shared Clipboard transfer.
  */
@@ -684,47 +740,51 @@
 {
     /** The node member for using this struct in a RTList. */
-    RTLISTNODE               Node;
+    RTLISTNODE                Node;
     /** The transfer's state (for SSM, later). */
-    SHCLTRANSFERSTATE        State;
+    SHCLTRANSFERSTATE         State;
     /** Absolute path to root entries. */
-    char                    *pszPathRootAbs;
+    char                     *pszPathRootAbs;
     /** Timeout (in ms) for waiting of events. Default is 30s. */
-    RTMSINTERVAL             uTimeoutMs;
+    RTMSINTERVAL              uTimeoutMs;
     /** Maximum data chunk size (in bytes) to transfer. Default is 64K. */
-    uint32_t                 cbMaxChunkSize;
+    uint32_t                  cbMaxChunkSize;
     /** The transfer's own event source. */
-    SHCLEVENTSOURCE          Events;
+    SHCLEVENTSOURCE           Events;
     /** Current number of concurrent list handles. */
-    uint32_t                 cListHandles;
+    uint32_t                  cListHandles;
     /** Maximum number of concurrent list handles. */
-    uint32_t                 cMaxListHandles;
+    uint32_t                  cMaxListHandles;
     /** Next upcoming list handle. */
-    SHCLLISTHANDLE           uListHandleNext;
+    SHCLLISTHANDLE            uListHandleNext;
     /** List of all list handles elated to this transfer. */
-    RTLISTANCHOR             lstList;
+    RTLISTANCHOR              lstList;
     /** Number of root entries in list. */
-    uint64_t                 cRoots;
+    uint64_t                  cRoots;
     /** List of root entries of this transfer. */
-    RTLISTANCHOR             lstRoots;
+    RTLISTANCHOR              lstRoots;
     /** Current number of concurrent object handles. */
-    uint32_t                 cObjHandles;
+    uint32_t                  cObjHandles;
     /** Maximum number of concurrent object handles. */
-    uint32_t                 cMaxObjHandles;
+    uint32_t                  cMaxObjHandles;
     /** Next upcoming object handle. */
-    SHCLOBJHANDLE            uObjHandleNext;
+    SHCLOBJHANDLE             uObjHandleNext;
     /** Map of all objects handles related to this transfer. */
-    RTLISTANCHOR             lstObj;
+    RTLISTANCHOR              lstObj;
     /** The transfer's own provider context. */
-    SHCLTXPROVIDERCTX        ProviderCtx;
+    SHCLTXPROVIDERCTX         ProviderCtx;
     /** The transfer's provider interface. */
-    SHCLTXPROVIDERIFACE      ProviderIface;
+    SHCLTXPROVIDERIFACE       ProviderIface;
+    /** The transfer's callback context. */
+    SHCLTRANSFERCALLBACKCTX   CallbackCtx;
+    /** The transfer's callback table. */
+    SHCLTRANSFERCALLBACKTABLE Callbacks;
     /** Opaque pointer to implementation-specific parameters. */
-    void                    *pvUser;
+    void                     *pvUser;
     /** Size (in bytes) of implementation-specific parameters. */
-    size_t                   cbUser;
+    size_t                    cbUser;
     /** Contains thread-related attributes. */
-    SHCLTRANSFERTHREAD       Thread;
+    SHCLTRANSFERTHREAD        Thread;
     /** Critical section for serializing access. */
-    RTCRITSECT               CritSect;
+    RTCRITSECT                CritSect;
 } SHCLTRANSFER, *PSHCLTRANSFER;
 
@@ -863,4 +923,5 @@
 bool ShClTransferListEntryIsValid(PSHCLLISTENTRY pListEntry);
 
+void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKTABLE pCallbacks);
 int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDERCREATIONCTX pCreationCtx);
 int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots);
Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 87610)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 87611)
@@ -589,4 +589,6 @@
      * This is set by VbglR3ClipboardConnectEx(). */
     uint32_t                    cbMaxChunkSize;
+    /** Optional callbacks to invoke. */
+    SHCLTRANSFERCALLBACKTABLE   Callbacks;
 } VBGLR3SHCLTRANSFERCTX;
 /** Pointer to a Shared Clipboard transfer context. */
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 87610)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 87611)
@@ -97,15 +97,13 @@
  * Cleanup helper function for transfer callbacks.
  *
- * @param   pData               Callback data to cleanup.
+ * @param   pTransferCtx        Pointer to transfer context that the transfer contains.
+ * @param   pTransfer           Pointer to transfer to cleanup.
  */
-static void vboxClipboardTransferCallbackCleanup(PSHCLTXPROVIDERCTX pCtx)
+static void vboxClipboardTransferCallbackCleanup(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer)
 {
     LogFlowFuncEnter();
 
-    PSHCLTRANSFERCTX pCtx = (PSHCLTRANSFERCTX)pData->pvUser;
-    AssertPtr(pCtx);
-
-    PSHCLTRANSFER pTransfer = pData->pTransfer;
-    AssertPtr(pTransfer);
+    if (!pTransferCtx || !pTransfer)
+        return;
 
     if (pTransfer->pvUser) /* SharedClipboardWinTransferCtx */
@@ -115,5 +113,5 @@
     }
 
-    int rc2 = ShClTransferCtxTransferUnregister(pCtx, pTransfer->State.uID);
+    int rc2 = ShClTransferCtxTransferUnregister(pTransferCtx, pTransfer->State.uID);
     AssertRC(rc2);
 
@@ -124,23 +122,24 @@
 }
 
-static DECLCALLBACK(int)  vboxClipboardOnTransferInitCallback(PSHCLTXPROVIDERCTX pCtx)
-{
-    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pData->pvUser;
+/** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnInitialize */
+static DECLCALLBACK(int) vboxClipboardOnTransferInitCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
+{
+    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     AssertPtr(pCtx);
 
     LogFlowFunc(("pCtx=%p\n", pCtx));
 
-    RT_NOREF(pData, pCtx);
+    RT_NOREF(pCtx);
 
     return VINF_SUCCESS;
 }
 
-static DECLCALLBACK(int) vboxClipboardOnTransferStartCallback(PSHCLTXPROVIDERCTX pCtx)
-{
-    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pData->pvUser;
+/** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnStart */
+static DECLCALLBACK(int) vboxClipboardOnTransferStartCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
+{
+    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     AssertPtr(pCtx);
-    Assert(pData->cbUser == sizeof(SHCLCONTEXT));
-
-    PSHCLTRANSFER pTransfer = pData->pTransfer;
+
+    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     AssertPtr(pTransfer);
 
@@ -192,30 +191,25 @@
 }
 
-static DECLCALLBACK(void) vboxClipboardOnTransferCompleteCallback(PSHCLTXPROVIDERCTX pCtx, int rc)
-{
-    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pData->pvUser;
+/** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnCompleted */
+static DECLCALLBACK(void) vboxClipboardOnTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion)
+{
+    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     AssertPtr(pCtx);
 
-    RT_NOREF(pCtx, rc);
-
-    LogFlowFunc(("pCtx=%p, rc=%Rrc\n", pCtx, rc));
-
-    LogRel2(("Shared Clipboard: Transfer to destination complete\n"));
-
-    vboxClipboardTransferCallbackCleanup(pData);
-}
-
-static DECLCALLBACK(void) vboxClipboardOnTransferErrorCallback(PSHCLTXPROVIDERCTX pCtx, int rc)
-{
-    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pData->pvUser;
+    LogRel2(("Shared Clipboard: Transfer to destination %s\n",
+             rcCompletion == VERR_CANCELLED ? "canceled" : "complete"));
+
+    vboxClipboardTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer);
+}
+
+/** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnError */
+static DECLCALLBACK(void) vboxClipboardOnTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError)
+{
+    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     AssertPtr(pCtx);
 
-    RT_NOREF(pCtx, rc);
-
-    LogFlowFunc(("pCtx=%p, rc=%Rrc\n", pCtx, rc));
-
-    LogRel(("Shared Clipboard: Transfer to destination failed with %Rrc\n", rc));
-
-    vboxClipboardTransferCallbackCleanup(pData);
+    LogRel(("Shared Clipboard: Transfer to destination failed with %Rrc\n", rcError));
+
+    vboxClipboardTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer);
 }
 
@@ -883,5 +877,8 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
-    /* Install callbacks. */
+    /*
+     * Set callbacks.
+     * Those will be registered within VbglR3 when a new transfer gets initialized.
+     */
     RT_ZERO(pCtx->CmdCtx.Transfers.Callbacks);
 
@@ -889,8 +886,8 @@
     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;
+    pCtx->CmdCtx.Transfers.Callbacks.pfnOnInitialize = vboxClipboardOnTransferInitCallback;
+    pCtx->CmdCtx.Transfers.Callbacks.pfnOnStart      = vboxClipboardOnTransferStartCallback;
+    pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted  = vboxClipboardOnTransferCompletedCallback;
+    pCtx->CmdCtx.Transfers.Callbacks.pfnOnError      = vboxClipboardOnTransferErrorCallback;
 #endif
 
Index: /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 87610)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 87611)
@@ -1803,4 +1803,6 @@
     if (RT_SUCCESS(rc))
     {
+        ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
+
         rc = ShClTransferInit(pTransfer, enmDir, enmSource);
         if (RT_SUCCESS(rc))
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 87610)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 87611)
@@ -353,5 +353,5 @@
 
     PSHCLROOTLIST pRootList;
-    rc = ShClTransferRootsGet(pTransfer, &pRootList);
+    int rc = ShClTransferRootsGet(pTransfer, &pRootList);
     if (RT_SUCCESS(rc))
     {
@@ -967,3 +967,2 @@
     logFormat(pFormatEtc->cfFormat);
 }
-
Index: /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp	(revision 87610)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp	(revision 87611)
@@ -1267,6 +1267,6 @@
         pTransfer->uObjHandleNext  = 1;
 
-        if (pTransfer->ProviderIface.pfnInitialize)
-            rc = pTransfer->ProviderIface.pfnInitialize(&pTransfer->ProviderCtx);
+        if (pTransfer->Callbacks.pfnOnInitialize)
+            rc = pTransfer->Callbacks.pfnOnInitialize(&pTransfer->CallbackCtx);
     }
 
@@ -2016,4 +2016,36 @@
 
 /**
+ * Sets or unsets the callback table to be used for a Shared Clipboard transfer.
+ *
+ * @returns VBox status code.
+ * @param   pTransfer           Clipboard transfer to set callbacks for.
+ * @param   pCallbacks          Pointer to callback table to set.
+ */
+void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer,
+                              PSHCLTRANSFERCALLBACKTABLE pCallbacks)
+{
+    AssertPtrReturnVoid(pTransfer);
+    AssertPtrReturnVoid(pCallbacks);
+
+    LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
+
+#define SET_CALLBACK(a_pfnCallback)             \
+    if (pCallbacks->a_pfnCallback)              \
+        pTransfer->Callbacks.a_pfnCallback = pCallbacks->a_pfnCallback
+
+    SET_CALLBACK(pfnOnInitialize);
+    SET_CALLBACK(pfnOnStart);
+    SET_CALLBACK(pfnOnCompleted);
+    SET_CALLBACK(pfnOnError);
+    SET_CALLBACK(pfnOnRegistered);
+    SET_CALLBACK(pfnOnUnregistered);
+
+#undef SET_CALLBACK
+
+    pTransfer->Callbacks.pvUser = pCallbacks->pvUser;
+    pTransfer->Callbacks.cbUser = pCallbacks->cbUser;
+}
+
+/**
  * Sets the transfer provider interface for a given transfer.
  *
@@ -2484,7 +2516,7 @@
     int rc;
 
-    if (pTransfer->ProviderIface.pfnStart)
-    {
-        rc = pTransfer->ProviderIface.pfnStart(&pTransfer->ProviderCtx);
+    if (pTransfer->Callbacks.pfnOnStart)
+    {
+        rc = pTransfer->Callbacks.pfnOnStart(&pTransfer->CallbackCtx);
     }
     else
@@ -2788,6 +2820,6 @@
     pTransferCtx->cTransfers++;
 
-    if (pTransfer->ProviderIface.pfnRegistered)
-        pTransfer->ProviderIface.pfnRegistered(&pTransfer->ProviderCtx, pTransferCtx);
+    if (pTransfer->Callbacks.pfnOnRegistered)
+        pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx);
 
     if (pidTransfer)
@@ -2820,6 +2852,6 @@
             pTransfer->State.uID = idTransfer;
 
-            if (pTransfer->ProviderIface.pfnRegistered)
-                pTransfer->ProviderIface.pfnRegistered(&pTransfer->ProviderCtx, pTransferCtx);
+            if (pTransfer->Callbacks.pfnOnRegistered)
+                pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx);
 
             pTransferCtx->cTransfers++;
@@ -2849,6 +2881,6 @@
     Assert(pTransferCtx->cTransfers >= pTransferCtx->cRunning);
 
-    if (pTransfer->ProviderIface.pfnUnregistered)
-        pTransfer->ProviderIface.pfnUnregistered(&pTransfer->ProviderCtx, pTransferCtx);
+    if (pTransfer->Callbacks.pfnOnUnregistered)
+        pTransfer->Callbacks.pfnOnUnregistered(&pTransfer->CallbackCtx, pTransferCtx);
 
     LogFlowFunc(("Now %RU32 transfers left\n", pTransferCtx->cTransfers));
