Index: /trunk/include/VBox/HostServices/DragAndDropSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/DragAndDropSvc.h	(revision 50304)
+++ /trunk/include/VBox/HostServices/DragAndDropSvc.h	(revision 50305)
@@ -68,5 +68,8 @@
     HOST_DND_SET_MODE                  = 100,
 
-    /* H->G */
+    /*
+     * Host -> Guest messages
+     */
+
     HOST_DND_HG_EVT_ENTER              = 200,
     HOST_DND_HG_EVT_MOVE,
@@ -78,10 +81,15 @@
     HOST_DND_HG_SND_DATA,
     /** Sent when the actual buffer for HOST_DND_HG_SND_DATA
-     *  was too small. */
+     *  was too small, issued by the DnD host service. */
     HOST_DND_HG_SND_MORE_DATA,
+    /** Directory entry to be handled on the guest. */
     HOST_DND_HG_SND_DIR,
+    /** File entry to be handled on the guest. */
     HOST_DND_HG_SND_FILE,
 
-    /* G->H */
+    /*
+     * Guest -> Host messages
+     */
+
     /** The host asks the guest whether a DnD operation
      *  is in progress when the mouse leaves the guest window. */
@@ -90,5 +98,8 @@
      *  has been started and that the host wants the data in
      *  a specific mime-type. */
-    HOST_DND_GH_EVT_DROPPED
+    HOST_DND_GH_EVT_DROPPED,
+
+    HOST_DND_GH_RECV_DIR               = 650,
+    HOST_DND_GH_RECV_FILE
 };
 
@@ -107,5 +118,10 @@
 
     /* H->G */
+    /** The guest acknowledges that the pending DnD data from
+     *  the host can be dropped on the currently selected source
+     *  on the guest. */
     GUEST_DND_HG_ACK_OP                = 400,
+    /** The guest requests the actual DnD data to be sent
+     *  from the host. */
     GUEST_DND_HG_REQ_DATA,
     GUEST_DND_HG_EVT_PROGRESS,
@@ -119,5 +135,8 @@
     GUEST_DND_GH_ACK_PENDING           = 500,
     GUEST_DND_GH_SND_DATA,
-    GUEST_DND_GH_EVT_ERROR
+    GUEST_DND_GH_EVT_ERROR,
+
+    GUEST_DND_GH_SND_DIR               = 700,
+    GUEST_DND_GH_SND_FILE
 };
 
Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 50304)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 50305)
@@ -4,5 +4,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -722,5 +722,5 @@
 VBGLR3DECL(int)     VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat);
 #  ifdef VBOX_WITH_DRAG_AND_DROP_GH
-VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormat);
+VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats);
 VBGLR3DECL(int)     VbglR3DnDGHSendData(uint32_t u32ClientId, void *pvData, uint32_t cbData);
 VBGLR3DECL(int)     VbglR3DnDGHErrorEvent(uint32_t u32ClientId, int rcOp);
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp	(revision 50304)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp	(revision 50305)
@@ -515,4 +515,40 @@
                     reset();
                     rc = VINF_SUCCESS; /** @todo GUEST_DND_GH_EVT_ERROR */
+#else
+                    rc = VERR_NOT_SUPPORTED;
+#endif
+                    break;
+                }
+
+                case DragAndDropSvc::HOST_DND_GH_RECV_DIR:
+                {
+                    LogFlowThisFunc(("HOST_DND_GH_RECV_DIR\n"));
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+                    if (mMode == GH)
+                    {
+                        rc = OnGhSendDir(pEvent->Event.pszFormats,
+                                         pEvent->Event.cbFormats,
+                                         pEvent->Event.u.a.uDefAction);
+                    }
+                    else
+                        rc = VERR_WRONG_ORDER;
+#else
+                    rc = VERR_NOT_SUPPORTED;
+#endif
+                    break;
+                }
+
+                case DragAndDropSvc::HOST_DND_GH_RECV_FILE:
+                {
+                    LogFlowThisFunc(("HOST_DND_GH_RECV_FILE\n"));
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+                    if (mMode == GH)
+                    {
+                        rc = OnGhSendFile(pEvent->Event.pszFormats,
+                                          pEvent->Event.cbFormats,
+                                          pEvent->Event.u.a.uDefAction);
+                    }
+                    else
+                        rc = VERR_WRONG_ORDER;
 #else
                     rc = VERR_NOT_SUPPORTED;
@@ -934,5 +970,4 @@
 #endif
 
-#if 1
         /** @todo Multi-monitor setups? */
         int iScreenX = GetSystemMetrics(SM_CXSCREEN) - 1;
@@ -963,7 +998,4 @@
         else
             LogFlowFunc(("Unable to send input, error=0x%x\n", GetLastError()));
-#else
-        SetCursorPos(p.x, p.y);
-#endif
 
 #ifdef DEBUG_andy
@@ -981,22 +1013,20 @@
     if (RT_SUCCESS(rc))
     {
+        uint32_t uDefAction = DND_IGNORE_ACTION;
+
         AssertPtr(pDropTarget);
-
-        uint32_t uDefAction = DND_IGNORE_ACTION;
-        RTCString strFormat = "unknown";
-        if (pDropTarget->HasData())
+        RTCString strFormats = pDropTarget->Formats();
+        if (!strFormats.isEmpty())
         {
             uDefAction = DND_COPY_ACTION;
             uAllActions = uDefAction;
 
-            /** @todo There can be more than one format, separated
-             *        with \r\n. */
-            strFormat = "text/plain;charset=utf-8";
-
-            LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormat=%s\n",
-                         pDropTarget, uDefAction, uAllActions, strFormat.c_str()));
+            LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormats=%s\n",
+                         pDropTarget, uDefAction, uAllActions, strFormats.c_str()));
             rc = VbglR3DnDGHAcknowledgePending(mClientID,
-                                               uDefAction, uAllActions, strFormat.c_str());
-        }
+                                               uDefAction, uAllActions, strFormats.c_str());
+        }
+        else
+            LogFlowFunc(("No format data available yet\n"));
     }
 
@@ -1008,11 +1038,24 @@
                             uint32_t uDefAction)
 {
-    LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, cbFormats=%RU32, uDefAction=0x%x\n",
-                     mMode, mState, pDropTarget, cbFormats, uDefAction));
+    AssertPtrReturn(pszFormats, VERR_INVALID_POINTER);
+    AssertReturn(cbFormats, VERR_INVALID_PARAMETER);
+
+    LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, uDefAction=0x%x\n",
+                     mMode, mState, pDropTarget, uDefAction));
+#ifdef DEBUG
+    RTCList<RTCString> lstFormats =
+        RTCString(pszFormats, cbFormats - 1).split("\r\n");
+
+    LogFlow(("cbFormats=%RU32: ", cbFormats));
+    for (size_t i = 0; i < lstFormats.size(); i++)
+        LogFlow(("'%s' ", lstFormats.at(i).c_str()));
+    LogFlow(("\n"));
+#endif
+
     int rc;
     if (mState == Dragging)
     {
         AssertPtr(pDropTarget);
-        rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout */);
+        rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout in ms */);
         if (RT_SUCCESS(rc))
         {
@@ -1035,4 +1078,20 @@
         rc = VERR_WRONG_ORDER;
 
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int VBoxDnDWnd::OnGhSendDir(const char *pszFormats, uint32_t cbFormats,
+                            uint32_t uDefAction)
+{
+    int rc = 0;
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int VBoxDnDWnd::OnGhSendFile(const char *pszFormats, uint32_t cbFormats,
+                             uint32_t uDefAction)
+{
+    int rc = 0;
     LogFlowFuncLeaveRC(rc);
     return rc;
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h	(revision 50304)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h	(revision 50305)
@@ -155,7 +155,7 @@
 public:
 
-    bool HasData(void) { return RT_BOOL(mFormatEtc.cfFormat != 0); }
     void *DataMutableRaw(void) { return mpvData; }
     uint32_t DataSize(void) { return mcbData; }
+    RTCString Formats(void);
     int WaitForDrop(RTMSINTERVAL msTimeout);
 
@@ -170,4 +170,5 @@
      *        DVTARGETDEVICE here! */
     FORMATETC mFormatEtc;
+    RTCString mFormats;
     void *mpvData;
     uint32_t mcbData;
@@ -338,4 +339,6 @@
     int OnGhIsDnDPending(uint32_t uScreenID);
     int OnGhDropped(const char *pszFormats, uint32_t cbFormats, uint32_t uDefAction);
+    int OnGhSendDir(const char *pszFormats, uint32_t cbFormats, uint32_t uDefAction);
+    int OnGhSendFile(const char *pszFormats, uint32_t cbFormats, uint32_t uDefAction);
 #endif
 
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp	(revision 50304)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp	(revision 50305)
@@ -17,4 +17,5 @@
 #include <windows.h>
 #include <new> /* For bad_alloc. */
+#include <Shlobj.h> /* For DROPFILES and friends. */
 
 #include "VBoxTray.h"
@@ -107,10 +108,15 @@
     reset();
 
+    /** @todo At the moment we only support one DnD format at a time. */
+
     /* Try different formats. CF_HDROP is the most common one, so start
      * with this. */
-    /** @todo At the moment we only support TYMED_HGLOBAL. */
     FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
     HRESULT hr = pDataObject->QueryGetData(&fmtEtc);
-    if (hr != S_OK)
+    if (hr == S_OK)
+    {
+        mFormats = "text/uri-list";
+    }
+    else
     {
         LogFlowFunc(("CF_HDROP not supported, hr=%Rhrc\n", hr));
@@ -125,4 +131,8 @@
             fmtEtc.cfFormat = 0; /* Mark it to not supported. */
         }
+        else
+        {
+            mFormats = "text/plain;charset=utf-8";
+        }
     }
 
@@ -130,9 +140,10 @@
     if (fmtEtc.cfFormat)
     {
-        LogFlowFunc(("Found supported format %RI16\n", fmtEtc.cfFormat));
+        LogFlowFunc(("Found supported format %RI16 (%s)\n",
+                     fmtEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(fmtEtc.cfFormat)));
 
         /* Make a copy of the FORMATETC structure so that we later can
          * use this for comparrison and stuff. */
-        /** Note: The DVTARGETDEVICE member only is a shallow copy! */
+        /** Note: The DVTARGETDEVICE member only is a shallow copy for now! */
         memcpy(&mFormatEtc, &fmtEtc, sizeof(FORMATETC));
 
@@ -164,10 +175,11 @@
                     while (pEnumFormats->Next(1, &curFormatEtc,
                                               NULL /* pceltFetched */) == S_OK)
-                	{
+                    {
                         WCHAR wszCfName[128]; /* 128 chars should be enough, rest will be truncated. */
                         hr2 = GetClipboardFormatNameW(curFormatEtc.cfFormat, wszCfName,
                                                       sizeof(wszCfName) / sizeof(WCHAR));
-                        LogRel(("\tcfFormat=%RI16, tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
+                        LogRel(("\tcfFormat=%RI16 (%s), tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
                                 curFormatEtc.cfFormat,
+                                VBoxDnDDataObject::ClipboardFormatToString(curFormatEtc.cfFormat),
                                 curFormatEtc.tymed,
                                 curFormatEtc.dwAspect,
@@ -176,5 +188,5 @@
 
                     pEnumFormats->Release();
-            	}
+                }
 
                 break;
@@ -236,6 +248,7 @@
 
 #ifdef DEBUG
-    LogFlowFunc(("mFormatEtc.cfFormat=%RI16, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
-                 mFormatEtc.cfFormat, pDataObject, grfKeyState, pt.x, pt.y));
+    LogFlowFunc(("mFormatEtc.cfFormat=%RI16 (%s), pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
+                 mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat),
+                 pDataObject, grfKeyState, pt.x, pt.y));
 #endif
     HRESULT hr = S_OK;
@@ -248,7 +261,10 @@
         hr = pDataObject->QueryGetData(&mFormatEtc);
         AssertMsg(SUCCEEDED(hr),
-                  ("Data format changed between DragEnter() and Drop(), cfFormat=%RI16, hr=%Rhrc\n",
-                  mFormatEtc.cfFormat, hr));
-    }
+                  ("Data format changed between DragEnter() and Drop(), cfFormat=%RI16 (%s), hr=%Rhrc\n",
+                  mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat),
+                  hr));
+    }
+
+    int rc = VINF_SUCCESS;
 
     if (SUCCEEDED(hr))
@@ -272,5 +288,6 @@
                         LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n",
                                      RTErrConvertFromWin32(GetLastError())));
-                        hr = ERROR_INVALID_HANDLE;
+                        rc = VERR_INVALID_HANDLE;
+                        hr = E_INVALIDARG; /* Set special hr for OLE. */
                     }
                     break;
@@ -279,9 +296,10 @@
                     AssertMsgFailed(("Storage medium type %RI32 supported\n",
                                      mFormatEtc.tymed));
-                    hr = ERROR_NOT_SUPPORTED;
+                    rc = VERR_NOT_SUPPORTED;
+                    hr = DV_E_TYMED; /* Set special hr for OLE. */
                     break;
             }
 
-            if (SUCCEEDED(hr))
+            if (RT_SUCCESS(rc))
             {
                 /* Second stage: Do the actual copying of the data object's data,
@@ -289,21 +307,142 @@
                 switch (mFormatEtc.cfFormat)
                 {
+                    /* Handling CF_TEXT means that the system already did some marshalling
+                     * to convert RTF or unicode text to plain ANSI text. */
                     case CF_TEXT:
                     {
-                        LogFlowFunc(("pvData=%s\n", (char*)pvData));
-
-                        uint32_t cbSize = strlen((char*)pvData); /** @todo Evil hack, fix this! */
-                        mpvData = RTMemDup(pvData, cbSize);
-                        mcbData = cbSize;
+                        AssertPtr(pvData);
+                        size_t cbSize = GlobalSize(pvData);
+                        LogFlowFunc(("CF_TEXT 0x%p got %zu bytes\n", pvData, cbSize));
+                        if (cbSize)
+                        {
+                            char *pszText = NULL;
+                            rc = RTStrCurrentCPToUtf8(&pszText, (char *)pvData);
+                            if (RT_SUCCESS(rc))
+                            {
+                                mpvData = (void *)pszText;
+                                mcbData = strlen(pszText) + 1;
+                            }
+                        }
+
                         break;
                     }
 
                     case CF_HDROP:
+                    {
+                        AssertPtr(pvData);
+
+                        /* Convert to a string list, separated by \r\n. */
+                        DROPFILES *pDropFiles = (DROPFILES *)pvData;
+                        AssertPtr(pDropFiles);
+                        bool fUnicode = RT_BOOL(pDropFiles->fWide);
+
+                        /* Get the offset of the file list. */
+                        Assert(pDropFiles->pFiles >= sizeof(DROPFILES));
+                        /* Note: This is *not* pDropFiles->pFiles! DragQueryFile only
+                         *       will work with the plain storage medium pointer! */
+                        HDROP hDrop = (HDROP)(pvData);
+
+                        /* First, get the file count. */
+                        /** @todo Does this work on Windows 2000 / NT4? */
+                        char *pszFiles = NULL;
+                        uint32_t cchFiles = 0;
+                        UINT cFiles = DragQueryFile(hDrop, UINT32_MAX /* iFile */,
+                                                    NULL /* lpszFile */, 0 /* cchFile */);
+                        LogFlowFunc(("CF_HDROP got %RU16 file(s)\n", cFiles));
+
+                        for (UINT i = 0; i < cFiles; i++)
+                        {
+                            UINT cch = DragQueryFile(hDrop, i /* File index */,
+                                                     NULL /* Query size first */,
+                                                     0 /* cchFile */);
+                            Assert(cch);
+
+                            /* Add separation between filenames. */
+                            if (i > 0)
+                            {
+                                rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */,
+                                                     "\r\n", 2 /* Bytes */);
+                                if (RT_SUCCESS(rc))
+                                    cchFiles += 2; /* Include \r\n */
+                            }
+
+                            if (RT_FAILURE(rc))
+                                return rc;
+
+                            char *pszFile = NULL; /* UTF-8 version. */
+                            UINT cchFile = 0;
+                            if (fUnicode)
+                            {
+                                /* Allocate enough space (including terminator). */
+                                WCHAR *pwszFile = (WCHAR *)RTMemAlloc((cch + 1) * sizeof(WCHAR));
+                                if (pwszFile)
+                                {
+                                    cchFile = DragQueryFileW(hDrop, i /* File index */,
+                                                             pwszFile, cch + 1 /* Include terminator */);
+                                    AssertMsg(cchFile == cch, ("cchCopied (%RU16) does not match cchFile (%RU16)\n",
+                                                               cchFile, cch));
+                                    int rc2 = RTUtf16ToUtf8(pwszFile, &pszFile);
+                                    AssertRC(rc2);
+                                }
+                                else
+                                    rc = VERR_NO_MEMORY;
+                            }
+                            else /* ANSI */
+                            {
+                                /* Allocate enough space (including terminator). */
+                                pszFile = (char *)RTMemAlloc((cch + 1) * sizeof(char));
+                                if (pszFile)
+                                {
+                                    cchFile = DragQueryFileA(hDrop, i /* File index */,
+                                                             pszFile, cchFile + 1 /* Include terminator */);
+                                    AssertMsg(cchFile == cch, ("cchCopied (%RU16) does not match cchFile (%RU16)\n",
+                                                               cchFile, cch));
+                                }
+                                else
+                                    rc = VERR_NO_MEMORY;
+                            }
+
+                            if (RT_SUCCESS(rc))
+                            {
+                                LogFlowFunc(("\tFile: %s (%RU32 characters)\n",
+                                             pszFile, cchFile));
+
+                                rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */,
+                                                     pszFile, cchFile);
+                            }
+
+                            /* Termination. */
+                            pszFiles[cchFiles] = '\0';
+
+                            if (pszFile)
+                                RTMemFree(pszFile);
+
+                            if (RT_FAILURE(rc))
+                                break;
+                        }
+
+                        if (RT_SUCCESS(rc))
+                        {
+                            uint32_t cbSize = cchFiles * sizeof(char);
+                            Assert(cbSize);
+
+                            mpvData = RTMemDup(pszFiles, cbSize);
+                            mcbData = cbSize;
+                        }
+
+                        LogFlowFunc(("Building CF_HDROP list rc=%Rrc, pszFiles=0x%p, cFiles=%RU16, cchFiles=%RU32\n",
+                                     rc, pszFiles, cFiles, cchFiles));
+
+                        if (pszFiles)
+                            RTStrFree(pszFiles);
                         break;
+                    }
 
                     default:
-                        AssertMsgFailed(("Format of type %RI16 supported\n",
-                                         mFormatEtc.cfFormat));
+                        AssertMsgFailed(("Format of type %RI16 (%s) not supported\n",
+                                         mFormatEtc.cfFormat,
+                                         VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat)));
                         hr = ERROR_NOT_SUPPORTED;
+                        hr = DV_E_CLIPFORMAT; /* Set special hr for OLE. */
                         break;
                 }
@@ -320,7 +459,5 @@
 
                 default:
-                    AssertMsgFailed(("Storage medium type %RI32 supported\n",
-                                     mFormatEtc.tymed));
-                    hr = ERROR_NOT_SUPPORTED;
+                    AssertMsgFailed(("Really should not happen -- see init stage!\n"));
                     break;
             }
@@ -329,5 +466,6 @@
             ReleaseStgMedium(&stgMed);
 
-            if (SUCCEEDED(hr))
+            /** @todo Signal in any case to avoid hangs/timeouts? */
+            if (RT_SUCCESS(rc))
             {
                 RTSemEventSignal(hEventDrop);
@@ -349,6 +487,8 @@
         mpWndParent->hide();
 
-    LogFlowFunc(("Returning with mFormatEtc.cfFormat=%RI16, fCanDrop=%RTbool, *pdwEffect=%RI32\n",
-                 mFormatEtc.cfFormat, fCanDrop, *pdwEffect));
+    LogFlowFunc(("Returning with rc=%Rrc, mFormatEtc.cfFormat=%RI16 (%s), fCanDrop=%RTbool, *pdwEffect=%RI32\n",
+                 rc, mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat),
+                 fCanDrop, *pdwEffect));
+
     return hr;
 }
@@ -395,4 +535,10 @@
     mcbData = 0;
     RT_ZERO(mFormatEtc);
+    mFormats = "";
+}
+
+RTCString VBoxDnDDropTarget::Formats(void)
+{
+    return mFormats;
 }
 
Index: /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 50304)
+++ /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 50305)
@@ -329,5 +329,5 @@
         return VERR_NO_MEMORY;
 
-    /* Create and query the drop target directory. */
+    /* Create and query the (unique) drop target directory. */
     char pszDropDir[RTPATH_MAX];
     int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir));
@@ -486,5 +486,6 @@
     } /* while */
 
-    RTMemFree(pvTmpData);
+    if (pvTmpData)
+        RTMemFree(pvTmpData);
 
     /* Cleanup on failure or if the user has canceled. */
@@ -509,5 +510,5 @@
                                                  void     *pvData,
                                                  uint32_t  cbData,
-                                                 uint32_t *pcbDataRecv)
+                                                 uint32_t *pcbDataTotal)
 {
     AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
@@ -517,5 +518,5 @@
     AssertPtrReturn(pvData,        VERR_INVALID_POINTER);
     AssertReturn(cbData,           VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pcbDataRecv,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pcbDataTotal,  VERR_INVALID_POINTER);
 
     DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
@@ -535,5 +536,5 @@
     {
         rc = Msg.hdr.result;
-        if (RT_SUCCESS(rc)
+        if (   RT_SUCCESS(rc)
             || rc == VERR_BUFFER_OVERFLOW)
         {
@@ -541,8 +542,8 @@
             rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
             rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
-            rc = Msg.cData.GetUInt32(pcbDataRecv);     AssertRC(rc);
+            rc = Msg.cData.GetUInt32(pcbDataTotal);     AssertRC(rc);
             /* A little bit paranoia */
             AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
-            AssertReturn(cbData   >= *pcbDataRecv,   VERR_TOO_MUCH_DATA);
+            AssertReturn(cbData   >= *pcbDataTotal,  VERR_TOO_MUCH_DATA);
         }
     }
@@ -664,7 +665,10 @@
     if (RT_SUCCESS(rc))
     {
-        /* Check if this is a uri-event. If so, let VbglR3 do all the actual
+        /* Check if this is an URI event. If so, let VbglR3 do all the actual
          * data transfer + file /directory creation internally without letting
-         * the caller know. */
+         * the caller know.
+         *
+         * This keeps the actual (guest OS-)dependent client (like VBoxClient /
+         * VBoxTray) small by not having too much redundant code. */
         if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0)
             rc = vbglR3DnDHGProcessURIMessages(uClientId,
@@ -953,7 +957,7 @@
 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId,
                                               uint32_t uDefAction, uint32_t uAllActions,
-                                              const char* pcszFormat)
-{
-    AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
+                                              const char* pcszFormats)
+{
+    AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
 
     DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
@@ -966,5 +970,5 @@
     Msg.uDefAction.SetUInt32(uDefAction);
     Msg.uAllActions.SetUInt32(uAllActions);
-    Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
+    Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
     /* Do request */
     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
@@ -979,14 +983,4 @@
     AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     AssertReturn(cbData,    VERR_INVALID_PARAMETER);
-
-    /** @todo Add URI support. Currently only data is send over to the host. For URI
-     *        support basically the same as in the H->G case (see
-     *        HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:
-     *        1. Parse the urilist
-     *        2. Recursively send "create dir" and "transfer file" msg to the host
-     *        3. Patch the urilist by removing all base dirnames
-     *        4. On the host all needs to received and the urilist patched afterwards
-     *           to point to the new location
-     */
 
     DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
@@ -1042,2 +1036,8 @@
     return rc;
 }
+
+VBGLR3DECL(int) VbglR3DnDGHSendFile(uint32_t u32ClientId, const char *pszPath)
+{
+    return 0;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk	(revision 50304)
+++ /trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk	(revision 50305)
@@ -451,4 +451,6 @@
 
 ifdef VBOX_WITH_DRAG_AND_DROP
+ VirtualBox_QT_MOCHDRS += \
+	src/runtime/UIDnDHandler.h
  ifdef VBOX_WITH_DRAG_AND_DROP_GH
   VirtualBox_QT_MOCHDRS += \
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp	(revision 50304)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp	(revision 50305)
@@ -23,4 +23,5 @@
 #include <QStringList>
 #include <QTimer>
+#include <QUrl>
 
 #ifdef LOG_GROUP
@@ -168,5 +169,5 @@
      * Do guest -> host format conversion, if needed.
      * On X11 this already maps to the Xdnd protocol.
-     ** @todo What about MacOS X Carbon Drag Manager?
+     ** @todo What about the MacOS Carbon Drag Manager? Needs testing.
      *
      * See: https://www.iana.org/assignments/media-types/media-types.xhtml
@@ -176,15 +177,26 @@
     for (int i = 0; i < vecFmtGuest.size(); i++)
     {
-        const QString &strFmt = vecFmtGuest.at(i);
+        const QString &strFmtGuest = vecFmtGuest.at(i);
         LogFlowFunc(("\tFormat %d: %s\n", i,
-                     strFmt.toAscii().constData()));
+                     strFmtGuest.toAscii().constData()));
 #ifdef RT_OS_WINDOWS
-        if (   strFmt.contains("text", Qt::CaseInsensitive)
+        /* CF_TEXT */
+        if (   strFmtGuest.contains("text/plain", Qt::CaseInsensitive)
             && !lstFmtNative.contains("text/plain"))
         {
             lstFmtNative << "text/plain";
         }
+        /* CF_HDROP */
+        else if (   strFmtGuest.contains("text/uri-list", Qt::CaseInsensitive)
+                 && !lstFmtNative.contains("text/uri-list"))
+        {
+            lstFmtNative << "text/uri-list";
+        }
 #else
-        lstFmtNative << strFmt;
+        /* On non-Windows just do a 1:1 mapping. */
+        lstFmtNative << strFmtGuest;
+# ifdef RT_OS_MACOS
+        /** @todo Does the mapping apply here? Don't think so ... */
+# endif
 #endif
     }
@@ -204,7 +216,12 @@
 
             /* pMData is transfered to the QDrag object, so no need for deletion. */
-            UIDnDMimeData *pMData = new UIDnDMimeData(session, lstFmtNative,
+            pMData = new UIDnDMimeData(session, lstFmtNative,
                                                       toQtDnDAction(defaultAction),
                                                       toQtDnDActions(vecActions), pParent);
+
+            /* Inform this object that MIME data from the guest is available so that
+             * it can update the MIME data object accordingly. */
+            connect(pMData, SIGNAL(sigDataAvailable(QString)),
+                    this, SLOT(sltDataAvailable(QString)), Qt::DirectConnection);
 
             /* Inform the MIME data object of any changes in the current action. */
@@ -218,6 +235,15 @@
              * is finished. */
             pDrag->setMimeData(pMData);
-            pDrag->exec(toQtDnDActions(vecActions), toQtDnDAction(defaultAction));
-
+            Qt::DropAction dropAction =
+                 pDrag->exec(toQtDnDActions(vecActions), toQtDnDAction(defaultAction));
+            LogFlowFunc(("dropAction=%ld\n", toVBoxDnDAction(dropAction)));
+#ifdef RT_OS_WINDOWS
+            /* Since the QDrag::exec() call above was blocking on Windows, decide what
+             * to do now, e.g. if there was a "drop" action.
+             *
+             * Note: The UIDnDMimeData object will not be not accessible here anymore,
+             *       since QDrag had its ownership and deleted it after the (blocking)
+             *       QDrag::exec() call. */
+#endif
             rc = VINF_SUCCESS;
         }
@@ -310,4 +336,13 @@
 }
 
+void UIDnDHandler::sltDataAvailable(const QString &mimeType)
+{
+    LogFlowFunc(("pMData=0x%p, mimeType=%s\n",
+                 pMData, mimeType.toAscii().constData()));
+
+    if (pMData)
+        pMData->setData(mimeType);
+}
+
 #include "UIDnDHandler.moc"
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h	(revision 50304)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h	(revision 50305)
@@ -24,12 +24,14 @@
 #include "COMEnums.h"
 
-/* Forward declarations. */
+/* Forward declarations: */
 class QMimeData;
 class CSession;
 class CGuest;
+class UIDnDMimeData;
 
-/** @todo Check for making this a full static class when possible. */
 class UIDnDHandler: public QObject
 {
+    Q_OBJECT;
+
 public:
     /* Singleton factory. */
@@ -58,4 +60,8 @@
     int            dragGHPending(CSession &session, ulong screenId, QWidget *pParent = NULL);
 
+public slots:
+
+    void sltDataAvailable(const QString &mimetype);
+
 private:
     static UIDnDHandler *m_pInstance;
@@ -70,4 +76,6 @@
     static Qt::DropActions             toQtDnDActions(const QVector<KDragAndDropAction> &vecActions);
 
+    UIDnDMimeData *pMData;
+
     friend class UIDnDMimeData;
 };
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp	(revision 50304)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp	(revision 50305)
@@ -24,4 +24,5 @@
 #include <QStringList>
 #include <QTimer>
+#include <QUrl>
 
 #ifdef LOG_GROUP
@@ -107,6 +108,7 @@
                                      QVariant::Type type) const
 {
-    LogFlowFunc(("m_enmState=%d, mimeType=%s, type=%d\n",
-                 m_enmState, mimeType.toStdString().c_str(), type));
+    LogFlowFunc(("m_enmState=%d, mimeType=%s, type=%d (%s)\n",
+                 m_enmState, mimeType.toStdString().c_str(),
+                 type, QVariant::typeToName(type)));
 
     bool fCanDrop = true;
@@ -132,5 +134,5 @@
      * So just update our internal state to reflect the same as on other
      * platforms. */
-    m_enmState = Dropped;
+    fCanDrop = true;
 #else
     /* Mouse button released? See eventFilter for more information. */
@@ -139,8 +141,4 @@
 #endif
 
-#if defined (RT_OS_WINDOWS) || defined (RT_OS_MACOS)
-    /* Special MIME handling. Later. */
-#endif
-
     /* Do we support the requested MIME type? */
     if (   fCanDrop
@@ -154,5 +152,6 @@
     /* Supported types. See below in the switch statement. */
     if (   fCanDrop
-        && !(   /* Regular text. */
+        && !(
+             /* Plain text. */
                 type == QVariant::String
              /* Binary data. */
@@ -170,67 +169,80 @@
         LogFlowFunc(("Skipping request, m_enmState=%d ...\n",
                      m_enmState));
-        return QVariant();
-    }
-
-    CGuest guest = m_session.GetConsole().GetGuest();
-    /* Start getting the data from the guest. First inform the guest we
-     * want the data in the specified MIME type. */
-    CProgress progress = guest.DragGHDropped(mimeType,
-                                             UIDnDHandler::toVBoxDnDAction(m_defAction));
-    if (guest.isOk())
-    {
-        msgCenter().showModalProgressDialog(progress,
-                                            tr("Retrieving data ..."), ":/progress_dnd_gh_90px.png",
-                                            m_pParent);
-        if (!progress.GetCanceled())
-        {
-            if (   progress.isOk()
-                && progress.GetResultCode() == 0)
-            {
-                /** @todo What about retrieving bigger files? Loop? */
-
-                /* After the data successfully arrived from the guest, we query it from Main. */
-                QVector<uint8_t> data = guest.DragGHGetData();
-                if (!data.isEmpty())
+        return QMimeData::retrieveData(mimeType, type);
+    }
+
+    if (m_enmState == Dragging)
+    {
+        int rc = VINF_SUCCESS;
+
+        CGuest guest = m_session.GetConsole().GetGuest();
+        /* Start getting the data from the guest. First inform the guest we
+         * want the data in the specified MIME type. */
+        CProgress progress = guest.DragGHDropped(mimeType,
+                                                 UIDnDHandler::toVBoxDnDAction(m_defAction));
+        if (guest.isOk())
+        {
+            msgCenter().showModalProgressDialog(progress,
+                                                tr("Retrieving data ..."), ":/progress_dnd_gh_90px.png",
+                                                m_pParent);
+            if (!progress.GetCanceled())
+            {
+                if (   progress.isOk()
+                    && progress.GetResultCode() == 0)
                 {
-                    switch (type)
+                    /** @todo What about retrieving bigger files? Loop? */
+
+                    /* After the data successfully arrived from the guest, we query it from Main. */
+                    QVector<uint8_t> data = guest.DragGHGetData();
+                    if (!data.isEmpty())
                     {
-                        case QVariant::String:
+                        switch (type)
                         {
-                            m_data = QVariant(QString(reinterpret_cast<const char*>(data.data())));
-                            break;
+                            case QVariant::String:
+                            {
+                                m_data = QVariant(QString(reinterpret_cast<const char*>(data.data())));
+                                break;
+                            }
+
+                            case QVariant::ByteArray:
+                            {
+                                QByteArray ba(reinterpret_cast<const char*>(data.constData()), data.size());
+                                m_data = QVariant(ba);
+                                break;
+                            }
+
+                            case QVariant::List:
+                            {
+                                QString strData = QString(reinterpret_cast<const char*>(data.data()));
+                                QStringList lstString = strData.split("\r\n", QString::SkipEmptyParts);
+
+                                m_data = QVariant(lstString);
+                                break;
+                            }
+
+                            default:
+                                AssertMsgFailed(("Should never happen, d'oh!\n"));
+                                rc = VERR_NOT_SUPPORTED;
+                                break;
                         }
-
-                        case QVariant::ByteArray:
-                        {
-                            QByteArray ba(reinterpret_cast<const char*>(data.constData()), data.size());
-                            m_data = QVariant(ba);
-                            break;
-                        }
-
-                        case QVariant::List:
-                        {
-                            /** @todo Support URIs. */
-                            break;
-                        }
-
-                        default:
-                            AssertMsgFailed(("Should never happen, d'oh!\n"));
-                            break;
                     }
+                    /** @todo How often to retry on empty data received? */
+
+                    if (RT_SUCCESS(rc))
+                        emit sigDataAvailable(mimeType);
+
+                    m_enmState = DataRetrieved;
                 }
-                /** @todo How often to retry on empty data received? */
-
-                m_enmState = Finished;
+                else
+                    msgCenter().cannotDropData(progress, m_pParent);
             }
             else
-                msgCenter().cannotDropData(progress, m_pParent);
+                m_enmState = Canceled;
         }
         else
-            m_enmState = Canceled;
-    }
-    else
-        msgCenter().cannotDropData(guest, m_pParent);
-
+            msgCenter().cannotDropData(guest, m_pParent);
+    }
+
+    //return QMimeData::retrieveData(mimeType, type);
     return m_data;
 }
@@ -288,2 +300,51 @@
 #endif /* RT_OS_WINDOWS */
 
+int UIDnDMimeData::setData(const QString &mimeType)
+{
+    LogFlowFunc(("mimeType=%s, dataType=%s\n",
+                 mimeType.toAscii().constData(), m_data.typeName()));
+
+    int rc = VINF_SUCCESS;
+
+    switch (m_data.type())
+    {
+        case QVariant::String: /* Plain text. */
+        {
+            QMimeData::setText(m_data.toString());
+            break;
+        }
+
+        case QVariant::ByteArray: /* Raw byte data. */
+        {
+            QMimeData::setData(mimeType, m_data.toByteArray());
+            break;
+        }
+
+        case QVariant::StringList: /* URI. */
+        {
+            QList<QVariant> lstData = m_data.toList();
+            QList<QUrl> lstURL;
+            for (int i = 0; i < lstData.size(); i++)
+            {
+                QString strURL = lstData.at(i).toString();
+                LogFlowFunc(("\tURL: %s\n",
+                             strURL.toAscii().constData()));
+                lstURL << QUrl(strURL.toAscii());
+            }
+            LogFlowFunc(("Number of URLs: %d\n",  lstURL.size()));
+
+            QMimeData::setUrls(f);
+            break;
+        }
+
+        default:
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+#include "UIDnDMIMEData.moc"
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.h	(revision 50304)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.h	(revision 50305)
@@ -46,6 +46,6 @@
     {
         Dragging = 0,
+        DataRetrieved,
         Dropped,
-        Finished,
         Canceled
     };
@@ -56,4 +56,6 @@
                   Qt::DropAction defAction,
                   Qt::DropActions actions, QWidget *pParent);
+
+    int setData(const QString &mimeType);
 
 public slots:
@@ -74,4 +76,8 @@
 #endif
     /** @}  */
+
+signals:
+
+    void sigDataAvailable(const QString &mimeType) const;
 
 private slots:
