Index: /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 59841)
+++ /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 59842)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2011-2015 Oracle Corporation
+ * Copyright (C) 2011-2016 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -641,5 +641,5 @@
     for (size_t i = 0; i < lstFormatsWanted.size(); i++)
     {
-        /* Only keep allowed format types. */
+        /* Only keep supported format types. */
         if (std::find(lstFormatsSupported.begin(),
                       lstFormatsSupported.end(), lstFormatsWanted.at(i)) != lstFormatsSupported.end())
@@ -927,16 +927,6 @@
 int GuestDnDBase::sendCancel(void)
 {
-    int rc;
-    try
-    {
-        GuestDnDMsg *pMsgCancel = new GuestDnDMsg();
-        pMsgCancel->setType(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL);
-
-        rc = msgQueueAdd(pMsgCancel);
-    }
-    catch(std::bad_alloc & /*e*/)
-    {
-        rc = VERR_NO_MEMORY;
-    }
+    int rc = GuestDnDInst()->hostCall(HOST_DND_HG_EVT_CANCEL,
+                                      0 /* cParms */, NULL /* paParms */);
 
     LogFlowFunc(("Generated cancelling request, rc=%Rrc\n", rc));
@@ -975,4 +965,6 @@
 
     int rc;
+
+    LogFlowFunc(("msTimeout=%RU32\n", msTimeout));
 
     uint64_t tsStart = RTTimeMilliTS();
Index: /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 59841)
+++ /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 59842)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2014-2015 Oracle Corporation
+ * Copyright (C) 2014-2016 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -257,5 +257,6 @@
 
     /* Default is ignoring the action. */
-    DnDAction_T defaultAction = DnDAction_Ignore;
+    if (aDefaultAction)
+        *aDefaultAction = DnDAction_Ignore;
 
     HRESULT hr = S_OK;
@@ -275,5 +276,5 @@
         bool fFetchResult = true;
 
-        rc = pResp->waitForGuestResponse(5000 /* Timeout in ms */);
+        rc = pResp->waitForGuestResponse(100 /* Timeout in ms */);
         if (RT_FAILURE(rc))
             fFetchResult = false;
@@ -286,7 +287,4 @@
         if (fFetchResult)
         {
-            defaultAction   = GuestDnD::toMainAction(pResp->defAction());
-            aAllowedActions = GuestDnD::toMainActions(pResp->allActions());
-
             /*
              * In the GuestDnDSource case the source formats are from the guest,
@@ -295,24 +293,24 @@
              * which are not supported by the host.
              */
-            aFormats        = GuestDnD::toFilteredFormatList(m_lstFmtSupported, pResp->formats());
-
-            /* Save the (filtered) formats. */
-            m_lstFmtOffered = aFormats;
-
-            if (m_lstFmtOffered.size())
+            GuestDnDMIMEList lstFiltered  = GuestDnD::toFilteredFormatList(m_lstFmtSupported, pResp->formats());
+            if (lstFiltered.size())
             {
-                LogRelMax(3, ("DnD: Offered formats:\n"));
-                for (size_t i = 0; i < m_lstFmtOffered.size(); i++)
-                    LogRelMax(3, ("DnD:\tFormat #%zu: %s\n", i, m_lstFmtOffered.at(i).c_str()));
+                LogRel3(("DnD: Host offered the following formats:\n"));
+                for (size_t i = 0; i < lstFiltered.size(); i++)
+                    LogRel3(("DnD:\tFormat #%zu: %s\n", i, lstFiltered.at(i).c_str()));
+
+                aFormats            = lstFiltered;
+                aAllowedActions     = GuestDnD::toMainActions(pResp->allActions());
+                if (aDefaultAction)
+                    *aDefaultAction = GuestDnD::toMainAction(pResp->defAction());
+
+                /* Apply the (filtered) formats list. */
+                m_lstFmtOffered     = lstFiltered;
             }
             else
-                LogRelMax(3, ("DnD: No compatible format between guest and host found, drag and drop to host not possible\n"));
-        }
-
-        LogFlowFunc(("fFetchResult=%RTbool, defaultAction=0x%x, allActions=0x%x\n",
-                     fFetchResult, defaultAction, pResp->allActions()));
-
-        if (aDefaultAction)
-            *aDefaultAction = defaultAction;
+                LogRel2(("DnD: Negotiation of formats between guest and host failed, drag and drop to host not possible\n"));
+        }
+
+        LogFlowFunc(("fFetchResult=%RTbool, allActions=0x%x\n", fFetchResult, pResp->allActions()));
     }
 
@@ -330,4 +328,6 @@
     AutoCaller autoCaller(this);
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    LogFunc(("aFormat=%s, aAction=%RU32\n", aFormat.c_str(), aAction));
 
     /* Input validation. */
@@ -379,5 +379,6 @@
         }
 
-        //this function delete pTask in case of exceptions, so there is no need in the call of delete operator
+        /* This function delete pTask in case of exceptions,
+         * so there is no need in the call of delete operator. */
         hr = pTask->createThread(&threadRcv);
 
@@ -651,4 +652,6 @@
                     }
                 }
+                else /* Raw data. */
+                    rc = updateProgress(pData, pCtx->mpResp, cbData);
             }
         }
@@ -790,14 +793,19 @@
             }
         }
-
-        /*
-         * Create new intermediate object to work with.
-         */
-        rc = objCtx.createIntermediate();
+        else
+        {
+            /*
+             * Create new intermediate object to work with.
+             */
+            rc = objCtx.createIntermediate();
+        }
+
         if (RT_SUCCESS(rc))
         {
             pObj = objCtx.getObj();
+            AssertPtr(pObj);
 
             const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
+            AssertPtr(pszDroppedFilesDir);
 
             char pszPathAbs[RTPATH_MAX];
@@ -963,40 +971,65 @@
      * Do we need to receive a different format than initially requested?
      *
-     * For example, receiving a file link as "text/plain"  requires still to receive
+     * For example, receiving a file link as "text/plain" requires still to receive
      * the file from the guest as "text/uri-list" first, then pointing to
      * the file path on the host in the "text/plain" data returned.
      */
 
-    /* Plain text needed? */
-    if (pCtx->mFmtReq.equalsIgnoreCase("text/plain"))
+    bool fFoundFormat = true; /* Whether we've found a common format between host + guest. */
+
+    LogFlowFunc(("mFmtReq=%s, mFmtRecv=%s, mAction=0x%x\n",
+                 pCtx->mFmtReq.c_str(), pCtx->mFmtRecv.c_str(), pCtx->mAction));
+
+    /* Plain text wanted? */
+    if (   pCtx->mFmtReq.equalsIgnoreCase("text/plain")
+        || pCtx->mFmtReq.equalsIgnoreCase("text/plain;charset=utf-8"))
     {
         /* Did the guest offer a file? Receive a file instead. */
         if (GuestDnD::isFormatInFormatList("text/uri-list", pCtx->mFmtOffered))
             pCtx->mFmtRecv = "text/uri-list";
+        /* Guest only offers (plain) text. */
+        else
+            pCtx->mFmtRecv = "text/plain;charset=utf-8";
 
         /** @todo Add more conversions here. */
     }
-
-    if (pCtx->mFmtRecv.isEmpty())
-        pCtx->mFmtRecv = pCtx->mFmtReq;
-
-    if (!pCtx->mFmtRecv.equals(pCtx->mFmtReq))
-        LogRel3(("DnD: Requested data in format '%s', receiving in intermediate format '%s' now\n",
-                 pCtx->mFmtReq.c_str(), pCtx->mFmtRecv.c_str()));
-
-    /*
-     * Call the appropriate receive handler based on the data format to handle.
-     */
-    bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length());
-    LogFlowFunc(("strFormatReq=%s, strFormatRecv=%s, uAction=0x%x, fHasURIList=%RTbool\n",
-                 pCtx->mFmtReq.c_str(), pCtx->mFmtRecv.c_str(), pCtx->mAction, fHasURIList));
-
-    if (fHasURIList)
-    {
-        rc = i_receiveURIData(pCtx, msTimeout);
-    }
-    else
-    {
-        rc = i_receiveRawData(pCtx, msTimeout);
+    /* File(s) wanted? */
+    else if (pCtx->mFmtReq.equalsIgnoreCase("text/uri-list"))
+    {
+        /* Does the guest support sending files? */
+        if (GuestDnD::isFormatInFormatList("text/uri-list", pCtx->mFmtOffered))
+            pCtx->mFmtRecv = "text/uri-list";
+        else /* Bail out. */
+            fFoundFormat = false;
+    }
+
+    if (fFoundFormat)
+    {
+        Assert(!pCtx->mFmtReq.isEmpty());
+        Assert(!pCtx->mFmtRecv.isEmpty());
+
+        if (!pCtx->mFmtRecv.equals(pCtx->mFmtReq))
+            LogRel3(("DnD: Requested data in format '%s', receiving in intermediate format '%s' now\n",
+                     pCtx->mFmtReq.c_str(), pCtx->mFmtRecv.c_str()));
+
+        /*
+         * Call the appropriate receive handler based on the data format to handle.
+         */
+        bool fURIData = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length());
+        if (fURIData)
+        {
+            rc = i_receiveURIData(pCtx, msTimeout);
+        }
+        else
+        {
+            rc = i_receiveRawData(pCtx, msTimeout);
+        }
+    }
+    else /* Just inform the user (if verbose release logging is enabled). */
+    {
+        LogRel2(("DnD: The guest does not support format '%s':\n", pCtx->mFmtReq.c_str()));
+        LogRel2(("DnD: Guest offered the following formats:\n"));
+        for (size_t i = 0; i < pCtx->mFmtOffered.size(); i++)
+            LogRel2(("DnD:\tFormat #%zu: %s\n", i, pCtx->mFmtOffered.at(i).c_str()));
     }
 
@@ -1040,4 +1073,6 @@
 
     int rc;
+
+    LogFlowFuncEnter();
 
     GuestDnDResponse *pResp = pCtx->mpResp;
@@ -1053,7 +1088,9 @@
         return rc;
 
-#define UNREGISTER_CALLBACK(x) \
-    rc = pCtx->mpResp->setCallback(x, NULL); \
-    AssertRC(rc);
+#define UNREGISTER_CALLBACK(x)                                  \
+    {                                                           \
+        int rc2 = pResp->setCallback(x, NULL);                  \
+        AssertRC(rc2);                                          \
+    }
 
     /*
@@ -1063,4 +1100,6 @@
     REGISTER_CALLBACK(GUEST_DND_DISCONNECT);
     REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
+    if (mDataBase.m_uProtocolVersion >= 3)
+        REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
 
@@ -1096,4 +1135,6 @@
     UNREGISTER_CALLBACK(GUEST_DND_DISCONNECT);
     UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
+    if (mDataBase.m_uProtocolVersion >= 3)
+        UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
 
@@ -1105,5 +1146,5 @@
         if (rc == VERR_CANCELLED)
         {
-            int rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
+            int rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED);
             AssertRC(rc2);
 
@@ -1127,4 +1168,6 @@
 
     int rc;
+
+    LogFlowFuncEnter();
 
     GuestDnDResponse *pResp = pCtx->mpResp;
@@ -1220,5 +1263,5 @@
         if (rc == VERR_CANCELLED)
         {
-            rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
+            rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED);
             AssertRC(rc2);
 
@@ -1260,5 +1303,5 @@
 
     int rcCallback = VINF_SUCCESS; /* rc for the callback. */
-    bool fNotify = false;
+    bool fNotify   = false;
 
     switch (uMsg)
@@ -1303,8 +1346,18 @@
 
             if (RT_SUCCESS(pCBData->rc))
+            {
+                AssertMsgFailed(("Received guest error with no error code set\n"));
                 pCBData->rc = VERR_GENERAL_FAILURE; /* Make sure some error is set. */
-
-            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
-                                           GuestDnDSource::i_guestErrorToString(pCBData->rc));
+            }
+            else if (pCBData->rc == VERR_WRONG_ORDER)
+            {
+                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED);
+            }
+            else
+                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
+                                               GuestDnDSource::i_guestErrorToString(pCBData->rc));
+
+            LogRel3(("DnD: Guest reported data transfer error: %Rrc\n", pCBData->rc));
+
             if (RT_SUCCESS(rc))
                 rcCallback = VERR_GSTDND_GUEST_ERROR;
@@ -1317,7 +1370,45 @@
     }
 
+    if (   RT_FAILURE(rc)
+        || RT_FAILURE(rcCallback))
+    {
+        fNotify = true;
+        if (RT_SUCCESS(rcCallback))
+            rcCallback = rc;
+    }
+
     if (RT_FAILURE(rc))
     {
-        int rc2 = pCtx->mCBEvent.Notify(rc);
+        switch (rc)
+        {
+            case VERR_NO_DATA:
+                LogRel2(("DnD: Data transfer to host complete\n"));
+                break;
+
+            case VERR_CANCELLED:
+                LogRel2(("DnD: Data transfer to host canceled\n"));
+                break;
+
+            default:
+                LogRel(("DnD: Error %Rrc occurred, aborting data transfer to host\n", rc));
+                break;
+        }
+
+        /* Unregister this callback. */
+        AssertPtr(pCtx->mpResp);
+        int rc2 = pCtx->mpResp->setCallback(uMsg, NULL /* PFNGUESTDNDCALLBACK */);
+        AssertRC(rc2);
+    }
+
+    /* All data processed? */
+    if (pCtx->mData.isComplete())
+        fNotify = true;
+
+    LogFlowFunc(("cbProcessed=%RU64, cbToProcess=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",
+                 pCtx->mData.getProcessed(), pCtx->mData.getTotal(), fNotify, rcCallback, rc));
+
+    if (fNotify)
+    {
+        int rc2 = pCtx->mCBEvent.Notify(rcCallback);
         AssertRC(rc2);
     }
@@ -1430,8 +1521,18 @@
 
             if (RT_SUCCESS(pCBData->rc))
+            {
+                AssertMsgFailed(("Received guest error with no error code set\n"));
                 pCBData->rc = VERR_GENERAL_FAILURE; /* Make sure some error is set. */
-
-            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
-                                           GuestDnDSource::i_guestErrorToString(pCBData->rc));
+            }
+            else if (pCBData->rc == VERR_WRONG_ORDER)
+            {
+                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED);
+            }
+            else
+                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
+                                               GuestDnDSource::i_guestErrorToString(pCBData->rc));
+
+            LogRel3(("DnD: Guest reported file transfer error: %Rrc\n", pCBData->rc));
+
             if (RT_SUCCESS(rc))
                 rcCallback = VERR_GSTDND_GUEST_ERROR;
@@ -1457,13 +1558,13 @@
         {
             case VERR_NO_DATA:
-                LogRel2(("DnD: Transfer to host complete\n"));
+                LogRel2(("DnD: File transfer to host complete\n"));
                 break;
 
             case VERR_CANCELLED:
-                LogRel2(("DnD: Transfer to host canceled\n"));
+                LogRel2(("DnD: File transfer to host canceled\n"));
                 break;
 
             default:
-                LogRel(("DnD: Error %Rrc occurred, aborting transfer to host\n", rc));
+                LogRel(("DnD: Error %Rrc occurred, aborting file transfer to host\n", rc));
                 break;
         }
