Index: /trunk/Config.kmk
===================================================================
--- /trunk/Config.kmk	(revision 42260)
+++ /trunk/Config.kmk	(revision 42261)
@@ -571,4 +571,10 @@
 # Enable S3 support (requires libcurl)
 VBOX_WITH_S3 = 1
+# Enable Host=>Guest Drag'n'Drop
+if1of ($(KBUILD_TARGET), linux)
+ VBOX_WITH_DRAG_AND_DROP = 1
+ # Guest=>Host drag'n'drop doesn't work
+ #VBOX_WITH_DRAG_AND_DROP_GH = 1
+endif
 ## @}
 
Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 42260)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 42261)
@@ -685,7 +685,9 @@
 VBGLR3DECL(int)     VbglR3DnDHGAcknowledgeOperation(uint32_t uAction);
 VBGLR3DECL(int)     VbglR3DnDHGRequestData(const char* pcszFormat);
+#  ifdef VBOX_WITH_DRAG_AND_DROP_GH
 VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormat);
 VBGLR3DECL(int)     VbglR3DnDGHSendData(void *pvData, uint32_t cbData);
 VBGLR3DECL(int)     VbglR3DnDGHErrorEvent(int rcOp);
+#  endif /* VBOX_WITH_DRAG_AND_DROP_GH */
 /** @} */
 # endif /* VBOX_WITH_DRAG_AND_DROP */
Index: /trunk/include/VBox/settings.h
===================================================================
--- /trunk/include/VBox/settings.h	(revision 42260)
+++ /trunk/include/VBox/settings.h	(revision 42261)
@@ -799,4 +799,5 @@
     SharedFoldersList   llSharedFolders;
     ClipboardMode_T     clipboardMode;
+    DragAndDropMode_T   dragAndDropMode;
 
     uint32_t            ulMemoryBalloonSize;
Index: /trunk/src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk	(revision 42260)
+++ /trunk/src/VBox/Additions/common/VBoxGuestLib/Makefile.kmk	(revision 42261)
@@ -53,5 +53,6 @@
 VBoxGuestR0Lib_TEMPLATE     = VBOXGUESTR0LIB
 VBoxGuestR0Lib_DEFS         = VBOX_WITH_HGCM \
-	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,)
+	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
 VBoxGuestR0Lib_INCS         = \
 	$(VBoxGuestR0Lib_0_OUTDIR)
@@ -73,5 +74,6 @@
 VBoxGuestR0LibBase_TEMPLATE = VBOXGUESTR0LIB
 VBoxGuestR0LibBase_DEFS     = VBOX_WITH_HGCM VBGL_VBOXGUEST \
-	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,)
+	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
 VBoxGuestR0LibBase_INCS     = $(VBoxGuestR0Lib_INCS)
 VBoxGuestR0LibBase_INCS.win = $(VBoxGuestR0Lib_INCS.win)
@@ -132,5 +134,6 @@
 ifdef VBOX_WITH_DRAG_AND_DROP
  VBoxGuestR3Lib_DEFS      += \
-    VBOX_WITH_DRAG_AND_DROP
+    VBOX_WITH_DRAG_AND_DROP \
+    $(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
  VBoxGuestR3Lib_SOURCES   += \
  	VBoxGuestR3LibDragAndDrop.cpp
@@ -173,5 +176,6 @@
 	RTMEM_NO_WRAP_TO_EF_APIS \
 	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
-	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,)
+	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
 VBoxGuestR3LibXFree86_SOURCES  = \
 	VBoxGuestR3Lib.cpp \
Index: /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 42261)
+++ /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 42261)
@@ -0,0 +1,1015 @@
+/* $Id$ */
+/** @file
+ * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Drag & Drop.
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/path.h>
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/uri.h>
+#include <iprt/thread.h>
+
+#include <iprt/cpp/list.h>
+#include <iprt/cpp/ministring.h>
+
+#include "VBGLR3Internal.h"
+#include "VBox/HostServices/DragAndDropSvc.h"
+
+#define VERBOSE 1
+
+#if defined(VERBOSE) && defined(DEBUG_poetzsch)
+# include <iprt/stream.h>
+# define DO(s) RTPrintf s
+#else
+# define DO(s) do {} while(0)
+//# define DO(s) Log s
+#endif
+
+/* Here all the communication with the host over HGCM is handled platform
+ * neutral. Also the receiving of URIs content (directory trees and files) is
+ * done here. So the platform code of the guests, should not take care of that.
+ *
+ * Todo:
+ * - Sending dirs/files in the G->H case
+ * - Maybe the EOL converting of text mime-types (not fully sure, eventually
+ *   better done on the host side)
+ */
+
+/* Not really used at the moment (only one client is possible): */
+uint32_t g_clientId = 0;
+
+/******************************************************************************
+ *    Private internal functions                                              *
+ ******************************************************************************/
+
+static int vbglR3DnDCreateDropDir(char* pszDropDir, size_t cbSize)
+{
+    /* Validate input */
+    AssertPtrReturn(pszDropDir, VERR_INVALID_POINTER);
+    AssertReturn(cbSize,        VERR_INVALID_PARAMETER);
+
+    /* Get the users document directory (usually $HOME/Documents). */
+    int rc = RTPathUserDocuments(pszDropDir, cbSize);
+    if (RT_FAILURE(rc))
+        return rc;
+    /* Append our base drop directory. */
+    rc = RTPathAppend(pszDropDir, cbSize, "VirtualBox Dropped Files");
+    if (RT_FAILURE(rc))
+        return rc;
+    /* Create it when necessary. */
+    if (!RTDirExists(pszDropDir))
+    {
+        rc = RTDirCreateFullPath(pszDropDir, RTFS_UNIX_IRWXU);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+    /* The actually drop directory consist of the current time stamp and a
+     * unique number when necessary. */
+    char pszTime[64];
+    RTTIMESPEC time;
+    if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
+        return VERR_BUFFER_OVERFLOW;
+    rc = RTPathAppend(pszDropDir, cbSize, pszTime);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /* Create it (only accessible by the current user) */
+    return RTDirCreateUniqueNumbered(pszDropDir, cbSize, RTFS_UNIX_IRWXU, 3, '-');
+}
+
+static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
+{
+    /* Validate input */
+    AssertPtrReturn(puMsg,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
+    Msg.hdr.cParms      = 3;
+    /* Initialize parameter */
+    Msg.msg.SetUInt32(0);
+    Msg.num_parms.SetUInt32(0);
+    Msg.block.SetUInt32(fWait);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (RT_SUCCESS(rc))
+        {
+            /* Fetch results */
+            rc = Msg.msg.GetUInt32(puMsg);         AssertRC(rc);
+            rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDHGProcessActionMessage(uint32_t  uClientId,
+                                           uint32_t  uMsg,
+                                           uint32_t *puScreenId,
+                                           uint32_t *puX,
+                                           uint32_t *puY,
+                                           uint32_t *puDefAction,
+                                           uint32_t *puAllActions,
+                                           char     *pszFormats,
+                                           uint32_t  cbFormats,
+                                           uint32_t *pcbFormatsRecv)
+{
+    /* Validate input */
+    AssertPtrReturn(puScreenId,     VERR_INVALID_POINTER);
+    AssertPtrReturn(puX,            VERR_INVALID_POINTER);
+    AssertPtrReturn(puY,            VERR_INVALID_POINTER);
+    AssertPtrReturn(puDefAction,    VERR_INVALID_POINTER);
+    AssertPtrReturn(puAllActions,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pszFormats,     VERR_INVALID_POINTER);
+    AssertReturn(cbFormats,         VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = uMsg;
+    Msg.hdr.cParms      = 7;
+    /* Initialize parameter */
+    Msg.uScreenId.SetUInt32(0);
+    Msg.uX.SetUInt32(0);
+    Msg.uY.SetUInt32(0);
+    Msg.uDefAction.SetUInt32(0);
+    Msg.uAllActions.SetUInt32(0);
+    Msg.pvFormats.SetPtr(pszFormats, cbFormats);
+    Msg.cFormats.SetUInt32(0);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (RT_SUCCESS(rc))
+        {
+            /* Fetch results */
+            rc = Msg.uScreenId.GetUInt32(puScreenId);     AssertRC(rc);
+            rc = Msg.uX.GetUInt32(puX);                   AssertRC(rc);
+            rc = Msg.uY.GetUInt32(puY);                   AssertRC(rc);
+            rc = Msg.uDefAction.GetUInt32(puDefAction);   AssertRC(rc);
+            rc = Msg.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
+            rc = Msg.cFormats.GetUInt32(pcbFormatsRecv);  AssertRC(rc);
+            /* A little bit paranoia */
+            AssertReturn(cbFormats >= *pcbFormatsRecv, VERR_TOO_MUCH_DATA);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDHGProcessLeaveMessage(uint32_t uClientId)
+{
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
+    Msg.hdr.cParms      = 0;
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+        rc = Msg.hdr.result;
+    return rc;
+}
+
+static int vbglR3DnDHGProcessCancelMessage(uint32_t uClientId)
+{
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
+    Msg.hdr.cParms      = 0;
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+        rc = Msg.hdr.result;
+    return rc;
+}
+
+static int vbglR3DnDHGProcessSendDirMessage(uint32_t  uClientId,
+                                            char     *pszDirname,
+                                            uint32_t  cbDirname,
+                                            uint32_t *pcbDirnameRecv,
+                                            uint32_t *pfMode)
+{
+    /* Validate input */
+    AssertPtrReturn(pszDirname,     VERR_INVALID_POINTER);
+    AssertReturn(cbDirname,         VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbDirnameRecv, VERR_INVALID_POINTER);
+    AssertPtrReturn(pfMode,         VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
+    Msg.hdr.cParms      = 3;
+    /* Initialize parameter */
+    Msg.pvName.SetPtr(pszDirname, cbDirname);
+    Msg.cName.SetUInt32(0);
+    Msg.fMode.SetUInt32(0);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (RT_SUCCESS(Msg.hdr.result))
+        {
+            /* Fetch results */
+            rc = Msg.cName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
+            rc = Msg.fMode.GetUInt32(pfMode);         AssertRC(rc);
+            /* A little bit paranoia */
+            AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDHGProcessSendFileMessage(uint32_t  uClientId,
+                                             char     *pszFilename,
+                                             uint32_t  cbFilename,
+                                             uint32_t *pcbFilenameRecv,
+                                             void     *pvData,
+                                             uint32_t  cbData,
+                                             uint32_t *pcbDataRecv,
+                                             uint32_t *pfMode)
+{
+    /* Validate input */
+    AssertPtrReturn(pszFilename,     VERR_INVALID_POINTER);
+    AssertReturn(cbFilename,         VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbFilenameRecv, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvData,          VERR_INVALID_POINTER);
+    AssertReturn(cbData,             VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbDataRecv,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pfMode,          VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGSENDFILEMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE;
+    Msg.hdr.cParms      = 5;
+    /* Initialize parameter */
+    Msg.pvName.SetPtr(pszFilename, cbFilename);
+    Msg.cName.SetUInt32(0);
+    Msg.pvData.SetPtr(pvData, cbData);
+    Msg.cData.SetUInt32(0);
+    Msg.fMode.SetUInt32(0);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (RT_SUCCESS(rc))
+        {
+            /* Fetch results */
+            rc = Msg.cName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
+            rc = Msg.cData.GetUInt32(pcbDataRecv);     AssertRC(rc);
+            rc = Msg.fMode.GetUInt32(pfMode);          AssertRC(rc);
+            /* A little bit paranoia */
+            AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
+            AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDHGProcessURIMessages(uint32_t   uClientId,
+                                         uint32_t  *puScreenId,
+                                         char      *pszFormat,
+                                         uint32_t   cbFormat,
+                                         uint32_t  *pcbFormatRecv,
+                                         void     **ppvData,
+                                         uint32_t   cbData,
+                                         size_t    *pcbDataRecv)
+{
+    /* Make a string list out of the uri data. */
+    RTCList<RTCString> uriList = RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n");
+    if (uriList.isEmpty())
+        return VINF_SUCCESS;
+
+    uint32_t cbTmpData = _1M * 10;
+    void *pvTmpData = RTMemAlloc(cbTmpData);
+    if (!pvTmpData)
+        return VERR_NO_MEMORY;
+
+    /* Create and query the drop target directory. */
+    char pszDropDir[RTPATH_MAX];
+    int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir));
+    if (RT_FAILURE(rc))
+    {
+        RTMemFree(pvTmpData);
+        return rc;
+    }
+
+    /* Patch the old drop data with the new drop directory, so the drop target
+     * can find the files. */
+    RTCList<RTCString> guestUriList;
+    for (size_t i = 0; i < uriList.size(); ++i)
+    {
+        const RTCString &strUri = uriList.at(i);
+        /* Query the path component of a file URI. If this hasn't a
+         * file scheme, null is returned. */
+        if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO))
+        {
+            RTCString strFullPath = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath);
+            char *pszNewUri = RTUriFileCreate(strFullPath.c_str());
+            if (pszNewUri)
+            {
+                guestUriList.append(pszNewUri);
+                RTStrFree(pszNewUri);
+            }
+        }
+        else
+            guestUriList.append(strUri);
+    }
+
+    /* Cleanup the old data and write the new data back to the event. */
+    RTMemFree(*ppvData);
+    RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n";
+    *ppvData = RTStrDupN(newData.c_str(), newData.length());
+    *pcbDataRecv = newData.length() + 1;
+
+    /* Lists for holding created files & directories in the case of a
+     * rollback. */
+    RTCList<RTCString> guestDirList;
+    RTCList<RTCString> guestFileList;
+    char pszPathname[RTPATH_MAX];
+    uint32_t cbPathname = 0;
+    bool fLoop = true;
+    do
+    {
+        uint32_t uNextMsg;
+        uint32_t cNextParms;
+        rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
+        DO(("%Rrc - %d\n", rc , uNextMsg));
+        if (RT_SUCCESS(rc))
+        {
+            switch(uNextMsg)
+            {
+                case DragAndDropSvc::HOST_DND_HG_SND_DIR:
+                {
+                    uint32_t fMode = 0;
+                    rc = vbglR3DnDHGProcessSendDirMessage(uClientId,
+                                                          pszPathname,
+                                                          sizeof(pszPathname),
+                                                          &cbPathname,
+                                                          &fMode);
+                    if (RT_SUCCESS(rc))
+                    {
+                        DO(("Got drop dir: %s - %o - %Rrc\n", pszPathname, fMode, rc));
+                        char *pszNewDir = RTPathJoinA(pszDropDir, pszPathname);
+                        rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
+                        if (!guestDirList.contains(pszNewDir))
+                            guestDirList.append(pszNewDir);
+                    }
+                    break;
+                }
+                case DragAndDropSvc::HOST_DND_HG_SND_FILE:
+                {
+                    uint32_t cbDataRecv;
+                    uint32_t fMode = 0;
+                    rc = vbglR3DnDHGProcessSendFileMessage(uClientId,
+                                                           pszPathname,
+                                                           sizeof(pszPathname),
+                                                           &cbPathname,
+                                                           pvTmpData,
+                                                           cbTmpData,
+                                                           &cbDataRecv,
+                                                           &fMode);
+                    if (RT_SUCCESS(rc))
+                    {
+                        char *pszNewFile = RTPathJoinA(pszDropDir, pszPathname);
+                        DO(("Got drop file: %s - %d - %o - %Rrc\n", pszPathname, cbDataRecv, fMode, rc));
+                        RTFILE hFile;
+                        rc = RTFileOpen(&hFile, pszNewFile, RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
+                        if (RT_SUCCESS(rc))
+                        {
+                            rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
+                            if (RT_SUCCESS(rc))
+                            {
+                                rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
+                                /* Valid UNIX mode? */
+                                if (   RT_SUCCESS(rc)
+                                    && (fMode & RTFS_UNIX_MASK))
+                                    rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
+                            }
+                            RTFileClose(hFile);
+                            if (!guestFileList.contains(pszNewFile))
+                                guestFileList.append(pszNewFile);
+                        }
+                    }
+                    break;
+                }
+                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
+                {
+                    rc = vbglR3DnDHGProcessCancelMessage(uClientId);
+                    if (RT_SUCCESS(rc))
+                        rc = VERR_CANCELLED;
+                    /* Break out of the loop. */
+                }
+                default: fLoop = false; break;
+            }
+        } else
+        {
+            if (rc == VERR_NO_DATA)
+                rc = VINF_SUCCESS;
+            break;
+        }
+    }while(fLoop);
+
+    RTMemFree(pvTmpData);
+    /* Cleanup on failure or if the user has canceled. */
+    if (RT_FAILURE(rc))
+    {
+        /* Remove any stuff created. */
+        for (size_t i = 0; i < guestFileList.size(); ++i)
+            RTFileDelete(guestFileList.at(i).c_str());
+        for (size_t i = 0; i < guestDirList.size(); ++i)
+            RTDirRemove(guestDirList.at(i).c_str());
+        RTDirRemove(pszDropDir);
+    }
+
+    return rc;
+}
+
+static int vbglR3DnDHGProcessDataMessageInternal(uint32_t  uClientId,
+                                                 uint32_t *puScreenId,
+                                                 char     *pszFormat,
+                                                 uint32_t  cbFormat,
+                                                 uint32_t *pcbFormatRecv,
+                                                 void     *pvData,
+                                                 uint32_t  cbData,
+                                                 uint32_t *pcbDataRecv)
+{
+    /* Validate input */
+    AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
+    AssertReturn(cbFormat,         VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvData,        VERR_INVALID_POINTER);
+    AssertReturn(cbData,           VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbDataRecv,   VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
+    Msg.hdr.cParms      = 5;
+    /* Initialize parameter */
+    Msg.uScreenId.SetUInt32(0);
+    Msg.pvFormat.SetPtr(pszFormat, cbFormat);
+    Msg.cFormat.SetUInt32(0);
+    Msg.pvData.SetPtr(pvData, cbData);
+    Msg.cData.SetUInt32(0);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (   RT_SUCCESS(rc)
+            || rc == VERR_BUFFER_OVERFLOW)
+        {
+            /* Fetch results */
+            rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
+            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
+            rc = Msg.cData.GetUInt32(pcbDataRecv);     AssertRC(rc);
+            /* A little bit paranoia */
+            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
+            AssertReturn(cbData   >= *pcbDataRecv,   VERR_TOO_MUCH_DATA);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDHGProcessMoreDataMessageInternal(uint32_t  uClientId,
+                                                     void     *pvData,
+                                                     uint32_t  cbData,
+                                                     uint32_t *pcbDataRecv)
+{
+    /* Validate input */
+    AssertPtrReturn(pvData,      VERR_INVALID_POINTER);
+    AssertReturn(cbData,         VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = g_clientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
+    Msg.hdr.cParms      = 2;
+    /* Initialize parameter */
+    Msg.pvData.SetPtr(pvData, cbData);
+    Msg.cData.SetUInt32(0);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (   RT_SUCCESS(rc)
+            || rc == VERR_BUFFER_OVERFLOW)
+        {
+            /* Fetch results */
+            rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
+            /* A little bit paranoia */
+            AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDHGProcessSendDataMessages(uint32_t  uClientId,
+                                              uint32_t *puScreenId,
+                                              char     *pszFormat,
+                                              uint32_t  cbFormat,
+                                              uint32_t *pcbFormatRecv,
+                                              void    **ppvData,
+                                              uint32_t  cbData,
+                                              size_t   *pcbDataRecv)
+{
+    uint32_t cbDataRecv = 0;
+    int rc = vbglR3DnDHGProcessDataMessageInternal(uClientId,
+                                                   puScreenId,
+                                                   pszFormat,
+                                                   cbFormat,
+                                                   pcbFormatRecv,
+                                                   *ppvData,
+                                                   cbData,
+                                                   &cbDataRecv);
+
+    size_t cbAllDataRecv = cbDataRecv;
+    while (rc == VERR_BUFFER_OVERFLOW)
+    {
+        uint32_t uNextMsg;
+        uint32_t cNextParms;
+        rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
+        if (RT_SUCCESS(rc))
+        {
+            switch(uNextMsg)
+            {
+                case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
+                {
+                    *ppvData = RTMemRealloc(*ppvData, cbAllDataRecv + cbData);
+                    if (!*ppvData)
+                    {
+                        rc = VERR_NO_MEMORY;
+                        break;
+                    }
+                    rc = vbglR3DnDHGProcessMoreDataMessageInternal(uClientId,
+                                                                   &((char*)*ppvData)[cbAllDataRecv],
+                                                                   cbData,
+                                                                   &cbDataRecv);
+                    cbAllDataRecv += cbDataRecv;
+                    break;
+                }
+                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
+                default:
+                {
+                    rc = vbglR3DnDHGProcessCancelMessage(uClientId);
+                    if (RT_SUCCESS(rc))
+                        rc = VERR_CANCELLED;
+                    break;
+                }
+            }
+        }
+    }
+    if (RT_SUCCESS(rc))
+        *pcbDataRecv = cbAllDataRecv;
+
+    return rc;
+}
+
+static int vbglR3DnDHGProcessSendDataMessage(uint32_t   uClientId,
+                                             uint32_t  *puScreenId,
+                                             char      *pszFormat,
+                                             uint32_t   cbFormat,
+                                             uint32_t  *pcbFormatRecv,
+                                             void     **ppvData,
+                                             uint32_t   cbData,
+                                             size_t    *pcbDataRecv)
+{
+    int rc = vbglR3DnDHGProcessSendDataMessages(uClientId,
+                                                puScreenId,
+                                                pszFormat,
+                                                cbFormat,
+                                                pcbFormatRecv,
+                                                ppvData,
+                                                cbData,
+                                                pcbDataRecv);
+    if (RT_SUCCESS(rc))
+    {
+        /* Check if this is a uri-event */
+        if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0)
+            rc = vbglR3DnDHGProcessURIMessages(uClientId,
+                                               puScreenId,
+                                               pszFormat,
+                                               cbFormat,
+                                               pcbFormatRecv,
+                                               ppvData,
+                                               cbData,
+                                               pcbDataRecv);
+    }
+    return rc;
+}
+
+static int vbglR3DnDGHProcessRequestPendingMessage(uint32_t  uClientId,
+                                                   uint32_t *puScreenId)
+{
+    /* Validate input */
+    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
+    Msg.hdr.cParms      = 1;
+    /* Initialize parameter */
+    Msg.uScreenId.SetUInt32(0);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (RT_SUCCESS(rc))
+        {
+            /* Fetch results */
+            rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDGHProcessDroppedMessage(uint32_t  uClientId,
+                                            char     *pszFormat,
+                                            uint32_t  cbFormat,
+                                            uint32_t *pcbFormatRecv,
+                                            uint32_t *puAction)
+{
+    /* Validate input */
+    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
+    AssertReturn(cbFormat,         VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
+    AssertPtrReturn(puAction,      VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.u32ClientID = uClientId;
+    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
+    Msg.hdr.cParms      = 3;
+    /* Initialize parameter */
+    Msg.pvFormat.SetPtr(pszFormat, cbFormat);
+    Msg.cFormat.SetUInt32(0);
+    Msg.uAction.SetUInt32(0);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (RT_SUCCESS(rc))
+        {
+            /* Fetch results */
+            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
+            rc = Msg.uAction.GetUInt32(puAction);      AssertRC(rc);
+            /* A little bit paranoia */
+            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
+        }
+    }
+    return rc;
+}
+
+/******************************************************************************
+ *    Public functions                                                        *
+ ******************************************************************************/
+
+/**
+ * Initialize Drag & Drop.
+ *
+ * This will enable the Drag & Drop events.
+ *
+ * @returns VBox status code.
+ */
+VBGLR3DECL(int) VbglR3DnDInit(void)
+{
+    return VbglR3DnDConnect(&g_clientId);
+}
+
+/**
+ * Terminate Drag and Drop.
+ *
+ * This will Drag and Drop events.
+ *
+ * @returns VBox status.
+ */
+VBGLR3DECL(int) VbglR3DnDTerm(void)
+{
+    return VbglR3DnDDisconnect(g_clientId);
+}
+
+VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId)
+{
+    /* Validate input */
+    AssertPtrReturn(pu32ClientId, VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    VBoxGuestHGCMConnectInfo Info;
+    RT_ZERO(Info.Loc.u);
+    Info.result      = VERR_WRONG_ORDER;
+    Info.u32ClientID = UINT32_MAX;  /* try make valgrind shut up. */
+    /* Initialize parameter */
+    Info.Loc.type    = VMMDevHGCMLoc_LocalHost_Existing;
+    int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc");
+    if (RT_FAILURE(rc)) return rc;
+    /* Do request */
+    rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Info.result;
+        if (RT_SUCCESS(rc))
+            *pu32ClientId = Info.u32ClientID;
+    }
+    return rc;
+}
+
+VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId)
+{
+    /* Initialize header */
+    VBoxGuestHGCMDisconnectInfo Info;
+    Info.result      = VERR_WRONG_ORDER;
+    Info.u32ClientID = u32ClientId;
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
+    if (RT_SUCCESS(rc))
+        rc = Info.result;
+    return rc;
+}
+
+VBGLR3DECL(int) VbglR3DnDProcessNextMessage(CPVBGLR3DNDHGCMEVENT pEvent)
+{
+    /* Validate input */
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+    uint32_t       uMsg       = 0;
+    uint32_t       uNumParms  = 0;
+    const uint32_t ccbFormats = _64K;
+    const uint32_t ccbData    = _1M;
+    int rc = vbglR3DnDQueryNextHostMessageType(g_clientId, &uMsg, &uNumParms, true);
+    if (RT_SUCCESS(rc))
+    {
+        DO(("Got message %d\n", uMsg));
+        switch(uMsg)
+        {
+            case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
+            case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
+            case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+            {
+                pEvent->uType = uMsg;
+                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
+                if (!pEvent->pszFormats)
+                    return VERR_NO_MEMORY;
+                rc = vbglR3DnDHGProcessActionMessage(g_clientId,
+                                                     uMsg,
+                                                     &pEvent->uScreenId,
+                                                     &pEvent->u.a.uXpos,
+                                                     &pEvent->u.a.uYpos,
+                                                     &pEvent->u.a.uDefAction,
+                                                     &pEvent->u.a.uAllActions,
+                                                     pEvent->pszFormats,
+                                                     ccbFormats,
+                                                     &pEvent->cbFormats);
+                break;
+            }
+            case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
+            {
+                pEvent->uType = uMsg;
+                rc = vbglR3DnDHGProcessLeaveMessage(g_clientId);
+                break;
+            }
+            case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+            {
+                pEvent->uType = uMsg;
+                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
+                if (!pEvent->pszFormats)
+                    return VERR_NO_MEMORY;
+                pEvent->u.b.pvData = RTMemAlloc(ccbData);
+                if (!pEvent->u.b.pvData)
+                {
+                    RTMemFree(pEvent->pszFormats);
+                    pEvent->pszFormats = NULL;
+                    return VERR_NO_MEMORY;
+                }
+                rc = vbglR3DnDHGProcessSendDataMessage(g_clientId,
+                                                       &pEvent->uScreenId,
+                                                       pEvent->pszFormats,
+                                                       ccbFormats,
+                                                       &pEvent->cbFormats,
+                                                       &pEvent->u.b.pvData,
+                                                       ccbData,
+                                                       &pEvent->u.b.cbData);
+                break;
+            }
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+            case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
+            {
+                pEvent->uType = uMsg;
+                rc = vbglR3DnDGHProcessRequestPendingMessage(g_clientId,
+                                                             &pEvent->uScreenId);
+                break;
+            }
+            case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+            {
+                pEvent->uType = uMsg;
+                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
+                if (!pEvent->pszFormats)
+                    return VERR_NO_MEMORY;
+                rc = vbglR3DnDGHProcessDroppedMessage(g_clientId,
+                                                      pEvent->pszFormats,
+                                                      ccbFormats,
+                                                      &pEvent->cbFormats,
+                                                      &pEvent->u.a.uDefAction);
+                break;
+            }
+#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
+            case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
+            {
+                pEvent->uType = uMsg;
+                rc = vbglR3DnDHGProcessCancelMessage(g_clientId);
+                if (RT_SUCCESS(rc))
+                    rc = VERR_CANCELLED;
+                break;
+            }
+            default: AssertMsgFailedReturn(("Message %u isn't expected in this context", uMsg), VERR_INVALID_PARAMETER); break;
+        }
+    }
+    return rc;
+}
+
+VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t uAction)
+{
+    DO(("ACK: %u\n", uAction));
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = g_clientId;
+    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
+    Msg.hdr.cParms      = 1;
+    /* Initialize parameter */
+    Msg.uAction.SetUInt32(uAction);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+        rc = Msg.hdr.result;
+    return rc;
+}
+
+VBGLR3DECL(int) VbglR3DnDHGRequestData(const char* pcszFormat)
+{
+    DO(("DATA_REQ: '%s'\n", pcszFormat));
+    /* Validate input */
+    AssertPtrReturn(pcszFormat, VERR_INVALID_PARAMETER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = g_clientId;
+    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
+    Msg.hdr.cParms      = 1;
+    /* Do request */
+    Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+        rc = Msg.hdr.result;
+    return rc;
+}
+
+VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormat)
+{
+    DO(("PEND: %u: %u (%s)\n", uDefAction, uAllActions, pcszFormat));
+    /* Validate input */
+    AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = g_clientId;
+    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
+    Msg.hdr.cParms      = 3;
+    /* Initialize parameter */
+    Msg.uDefAction.SetUInt32(uDefAction);
+    Msg.uAllActions.SetUInt32(uAllActions);
+    Msg.pFormat.SetPtr((void*)pcszFormat, static_cast<uint32_t>(strlen(pcszFormat) + 1));
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+        rc = Msg.hdr.result;
+    return rc;
+}
+
+VBGLR3DECL(int) VbglR3DnDGHSendData(void *pvData, uint32_t cbData)
+{
+    DO(("DATA: %x (%u)\n", pvData, cbData));
+    /* Validate input */
+    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
+
+    /* Todo: 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
+     */
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = g_clientId;
+    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
+    Msg.hdr.cParms      = 2;
+    Msg.uSize.SetUInt32(cbData);
+    int rc          = VINF_SUCCESS;
+    uint32_t cbMax  = _1M;
+    uint32_t cbSend = 0;
+    while(cbSend < cbData)
+    {
+        /* Initialize parameter */
+        uint32_t cbToSend = RT_MIN(cbData - cbSend, cbMax);
+        Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSend, cbToSend);
+        /* Do request */
+        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+        if (RT_SUCCESS(rc))
+        {
+            rc = Msg.hdr.result;
+            /* Did the host cancel the event? */
+            if (rc == VERR_CANCELLED)
+                break;
+        }
+        else
+            break;
+        cbSend += cbToSend;
+//        RTThreadSleep(500);
+    }
+    return rc;
+}
+
+VBGLR3DECL(int) VbglR3DnDGHErrorEvent(int rcOp)
+{
+    DO(("GH_ERROR\n"));
+
+    /* Initialize header */
+    DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = g_clientId;
+    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
+    Msg.hdr.cParms      = 1;
+    /* Initialize parameter */
+    Msg.uRC.SetUInt32(rcOp);
+    /* Do request */
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+        rc = Msg.hdr.result;
+    return rc;
+}
Index: /trunk/src/VBox/Additions/x11/Installer/98vboxadd-xclient
===================================================================
--- /trunk/src/VBox/Additions/x11/Installer/98vboxadd-xclient	(revision 42260)
+++ /trunk/src/VBox/Additions/x11/Installer/98vboxadd-xclient	(revision 42261)
@@ -5,5 +5,5 @@
 
 #
-# Copyright (C) 2007-2011 Oracle Corporation
+# Copyright (C) 2007-2012 Oracle Corporation
 #
 # This file is part of VirtualBox Open Source Edition (OSE), as
@@ -49,2 +49,4 @@
 test -z "$no_display" &&
     /usr/bin/VBoxClient --seamless
+test -z "$no_display" &&
+    /usr/bin/VBoxClient --draganddrop
Index: /trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk	(revision 42260)
+++ /trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk	(revision 42261)
@@ -69,5 +69,7 @@
 endif
 ifdef VBOX_WITH_DRAG_AND_DROP
- VBoxClient_DEFS += VBOX_WITH_DRAG_AND_DROP
+ VBoxClient_DEFS += \
+	VBOX_WITH_DRAG_AND_DROP \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
  VBoxClient_SOURCES += \
 	draganddrop.cpp
Index: /trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
===================================================================
--- /trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp	(revision 42261)
+++ /trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp	(revision 42261)
@@ -0,0 +1,1812 @@
+/** @file
+ * X11 guest client - Drag and Drop.
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/XTest.h>
+
+#include <iprt/thread.h>
+#include <iprt/asm.h>
+#include <iprt/time.h>
+
+#include <iprt/cpp/mtlist.h>
+#include <iprt/cpp/ministring.h>
+
+#include <limits.h>
+
+#include <VBox/log.h>
+#include <VBox/VBoxGuestLib.h>
+
+#include "VBox/HostServices/DragAndDropSvc.h"
+
+#include "VBoxClient.h"
+
+/* For X11 guest xDnD is used. See http://www.acc.umu.se/~vatten/XDND.html for
+ * a walk trough.
+ *
+ * H->G:
+ * For X11 this means mainly forwarding all the events from HGCM to the
+ * appropriate X11 events. There exists a proxy window, which is invisible and
+ * used for all the X11 communication. On a HGCM Enter event, we set our proxy
+ * window as XdndSelection owner with the given mime-types. On every HGCM move
+ * event, we move the X11 mouse cursor to the new position and query for the
+ * window below that position. Depending on if it is XdndAware, a new window or
+ * a known window, we send the appropriate X11 messages to it. On HGCM drop, we
+ * send a XdndDrop message to the current window and wait for a X11
+ * SelectionMessage from the target window. Because we didn't have the data in
+ * the requested mime-type, yet, we save that message and ask the host for the
+ * data. When the data is successfully received from the host, we put the data
+ * as a property to the window and send a X11 SelectionNotify event to the
+ * target window.
+ *
+ * G->H:
+ * This is a lot more trickery than H->G. When a pending event from HGCM
+ * arrives, we asks if there is currently an owner of the XdndSelection
+ * property. If so, our proxy window is shown (1x1, but without backing store)
+ * and some mouse event is triggered. This should be followed by an XdndEnter
+ * event send to the proxy window. From this event we can fetch the necessary
+ * info of the mime-types and allowed actions and send this back to the host.
+ * On a drop request from the host, we query for the selection and should get
+ * the data in the specified mime-type. This data is send back to the host.
+ * After that we send a XdndLeave event to the source window.
+ * Todo:
+ * - this isn't finished, yet. Currently the mouse isn't correctly released
+ * in the guest (both, when the drop was successfully or canceled).
+ * - cancel (e.g. with the ESC key) doesn't work
+ *
+ * Todo:
+ * - XdndProxy window support
+ * - INCR support
+ * - make this much more robust for crashes of the other party
+ * - really check for the Xdnd version and the supported features
+ */
+
+#define VERBOSE 1
+
+#if defined(VERBOSE) && defined(DEBUG_poetzsch)
+# include <iprt/stream.h>
+# define DO(s) RTPrintf s
+#else
+# define DO(s) do {} while(0)
+//# define DO(s) Log s
+#endif
+
+#define VBOX_XDND_VERSION    (4)
+#define VBOX_MAX_XPROPERTIES (LONG_MAX-1)
+
+/* Shared struct used for adding new X11 events and HGCM messages to a single
+ * event queue. */
+struct DnDEvent
+{
+    enum DnDEventType
+    {
+        HGCM_Type = 1,
+        X11_Type
+    };
+    DnDEventType type;
+    union
+    {
+        VBGLR3DNDHGCMEVENT hgcm;
+        XEvent x11;
+    };
+};
+
+enum XA_Type
+{
+    /* States */
+    XA_WM_STATE = 0,
+    /* Properties */
+    XA_TARGETS,
+    XA_MULTIPLE,
+    XA_INCR,
+    /* Mime Types */
+    XA_image_bmp,
+    XA_image_jpg,
+    XA_image_tiff,
+    XA_image_png,
+    XA_text_uri_list,
+    XA_text_uri,
+    XA_text_plain,
+    XA_TEXT,
+    /* xDnD */
+    XA_XdndSelection,
+    XA_XdndAware,
+    XA_XdndEnter,
+    XA_XdndLeave,
+    XA_XdndTypeList,
+    XA_XdndActionList,
+    XA_XdndPosition,
+    XA_XdndActionCopy,
+    XA_XdndActionMove,
+    XA_XdndActionLink,
+    XA_XdndStatus,
+    XA_XdndDrop,
+    XA_XdndFinished,
+    /* Our own stop marker */
+    XA_dndstop,
+    /* End marker */
+    XA_End
+};
+
+class DragAndDropService;
+
+/*******************************************************************************
+ *
+ * xHelpers Declaration
+ *
+ ******************************************************************************/
+
+class xHelpers
+{
+public:
+
+    static xHelpers *instance(Display *pDisplay = 0)
+    {
+        if (!m_pInstance)
+        {
+            AssertPtrReturn(pDisplay, 0);
+            m_pInstance = new xHelpers(pDisplay);
+        }
+        return m_pInstance;
+    }
+
+    inline Display *display()    const { return m_pDisplay; }
+    inline Atom xAtom(XA_Type e) const { return m_xAtoms[e]; }
+
+    inline Atom stringToxAtom(const char *pcszString) const
+    {
+        return XInternAtom(m_pDisplay, pcszString, False);
+    }
+    inline RTCString xAtomToString(Atom atom) const
+    {
+        if (atom == None) return "None";
+
+        char* pcsAtom = XGetAtomName(m_pDisplay, atom);
+        RTCString strAtom(pcsAtom);
+        XFree(pcsAtom);
+
+        return strAtom;
+    }
+
+    inline RTCString xAtomListToString(const RTCList<Atom> &formatList)
+    {
+        RTCString format;
+        for (size_t i = 0; i < formatList.size(); ++i)
+            format += xAtomToString(formatList.at(i)) + "\r\n";
+        return format;
+    }
+
+    RTCString xErrorToString(int xrc) const;
+    Window applicationWindowBelowCursor(Window parentWin) const;
+
+private:
+    xHelpers(Display *pDisplay)
+      : m_pDisplay(pDisplay)
+    {
+        /* Not all x11 atoms we use are defined in the headers. Create the
+         * additional one we need here. */
+        for (int i = 0; i < XA_End; ++i)
+            m_xAtoms[i] = XInternAtom(m_pDisplay, m_xAtomNames[i], False);
+    };
+
+    /* Private member vars */
+    static xHelpers   *m_pInstance;
+    Display           *m_pDisplay;
+    Atom               m_xAtoms[XA_End];
+    static const char *m_xAtomNames[XA_End];
+};
+
+/* Some xHelpers convenience defines. */
+#define gX11 xHelpers::instance()
+#define xAtom(xa) gX11->xAtom((xa))
+#define xAtomToString(xa) gX11->xAtomToString((xa))
+
+/*******************************************************************************
+ *
+ * xHelpers Implementation
+ *
+ ******************************************************************************/
+
+xHelpers *xHelpers::m_pInstance = 0;
+/* Has to be in sync with the XA_Type enum. */
+const char *xHelpers::m_xAtomNames[] =
+{
+    /* States */
+    "WM_STATE",
+    /* Properties */
+    "TARGETS",
+    "MULTIPLE",
+    "INCR",
+    /* Mime Types */
+    "image/bmp",
+    "image/jpg",
+    "image/tiff",
+    "image/png",
+    "text/uri-list",
+    "text/uri",
+    "text/plain",
+    "TEXT",
+    /* xDnD */
+    "XdndSelection",
+    "XdndAware",
+    "XdndEnter",
+    "XdndLeave",
+    "XdndTypeList",
+    "XdndActionList",
+    "XdndPosition",
+    "XdndActionCopy",
+    "XdndActionMove",
+    "XdndActionLink",
+    "XdndStatus",
+    "XdndDrop",
+    "XdndFinished",
+    /* Our own stop marker */
+    "dndstop"
+};
+
+RTCString xHelpers::xErrorToString(int xrc) const
+{
+    switch (xrc)
+    {
+        case Success:           return RTCStringFmt("%d (Success)", xrc); break;
+        case BadRequest:        return RTCStringFmt("%d (BadRequest)", xrc); break;
+        case BadValue:          return RTCStringFmt("%d (BadValue)", xrc); break;
+        case BadWindow:         return RTCStringFmt("%d (BadWindow)", xrc); break;
+        case BadPixmap:         return RTCStringFmt("%d (BadPixmap)", xrc); break;
+        case BadAtom:           return RTCStringFmt("%d (BadAtom)", xrc); break;
+        case BadCursor:         return RTCStringFmt("%d (BadCursor)", xrc); break;
+        case BadFont:           return RTCStringFmt("%d (BadFont)", xrc); break;
+        case BadMatch:          return RTCStringFmt("%d (BadMatch)", xrc); break;
+        case BadDrawable:       return RTCStringFmt("%d (BadDrawable)", xrc); break;
+        case BadAccess:         return RTCStringFmt("%d (BadAccess)", xrc); break;
+        case BadAlloc:          return RTCStringFmt("%d (BadAlloc)", xrc); break;
+        case BadColor:          return RTCStringFmt("%d (BadColor)", xrc); break;
+        case BadGC:             return RTCStringFmt("%d (BadGC)", xrc); break;
+        case BadIDChoice:       return RTCStringFmt("%d (BadIDChoice)", xrc); break;
+        case BadName:           return RTCStringFmt("%d (BadName)", xrc); break;
+        case BadLength:         return RTCStringFmt("%d (BadLength)", xrc); break;
+        case BadImplementation: return RTCStringFmt("%d (BadImplementation)", xrc); break;
+    }
+    return RTCStringFmt("%d (unknown)", xrc);
+}
+
+/* Todo: make this iterative */
+Window xHelpers::applicationWindowBelowCursor(Window parentWin) const
+{
+    /* No parent, nothing to do. */
+    if(parentWin == 0)
+        return 0;
+
+    Window appWin = 0;
+    int cProps = -1;
+    /* Fetch all x11 window properties of the parent window. */
+    Atom *pProps = XListProperties(m_pDisplay, parentWin, &cProps);
+    if (cProps > 0)
+    {
+        /* We check the window for the WM_STATE property. */
+        for(int i = 0; i < cProps; ++i)
+            if(pProps[i] == xAtom(XA_WM_STATE))
+            {
+                /* Found it. */
+                appWin = parentWin;
+                break;
+            }
+        /* Cleanup */
+        XFree(pProps);
+    }
+
+    if (!appWin)
+    {
+        Window childWin, wtmp;
+        int tmp;
+        unsigned int utmp;
+        /* Query the next child window of the parent window at the current
+         * mouse position. */
+        XQueryPointer(m_pDisplay, parentWin, &wtmp, &childWin, &tmp, &tmp, &tmp, &tmp, &utmp);
+        /* Recursive call our self to dive into the child tree. */
+        appWin = applicationWindowBelowCursor(childWin);
+    }
+
+    return appWin;
+}
+
+/*******************************************************************************
+ *
+ * DragInstance Declaration
+ *
+ ******************************************************************************/
+
+/* For now only one DragInstance will exits when the app is running. In the
+ * future the support for having more than one D&D operation supported at the
+ * time will be necessary. */
+class DragInstance
+{
+public:
+    enum State
+    {
+        Uninitialized,
+        Initialized,
+        Dragging,
+        Dropped
+    };
+
+    enum Mode
+    {
+        Unknown,
+        HG,
+        GH
+    };
+
+    DragInstance(Display *pDisplay, DragAndDropService *pParent);
+    int  init(uint32_t u32ScreenId);
+    void uninit();
+    void reset();
+
+    /* H->G */
+    int  hgEnter(const RTCList<RTCString> &formats, uint32_t actions);
+    int  hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action);
+    int  hgX11ClientMessage(const XEvent& e);
+    int  hgDrop();
+    int  hgX11SelectionRequest(const XEvent& e);
+    int  hgDataReceived(void *pvData, uint32_t cData);
+
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+    /* G->H */
+    int  ghIsDnDPending();
+    int  ghDropped(const RTCString &strFormat, uint32_t action);
+#endif
+
+    /* X11 helpers */
+    int  moveCursor(uint32_t u32xPos, uint32_t u32yPos);
+    void sendButtonEvent(Window w, int rx, int ry, int button, bool fPress) const;
+    void showProxyWin(int &rx, int &ry) const;
+    void hideProxyWin() const;
+    void registerForEvents(Window w) const;
+
+    void setActionsWindowProperty(Window win, const RTCList<Atom> &actionList) const;
+    void clearActionsWindowProperty(Window win) const;
+    void setFormatsWindowProperty(Window win, Atom property) const;
+    void clearFormatsWindowProperty(Window win) const;
+
+    RTCList<Atom>        toAtomList(const RTCList<RTCString> &formatList) const;
+    RTCList<Atom>        toAtomList(void *pvData, uint32_t cData) const;
+    static Atom          toX11Action(uint32_t uAction);
+    static RTCList<Atom> toX11Actions(uint32_t uActions);
+    static uint32_t      toHGCMAction(Atom atom);
+    static uint32_t      toHGCMActions(const RTCList<Atom> &actionsList);
+
+    /* Member vars */
+    DragAndDropService *m_pParent;
+    Display            *m_pDisplay;
+    int                 m_screenId;
+    Screen             *m_pScreen;
+    Window              m_rootWin;
+    Window              m_proxyWin;
+    Window              m_curWin;
+    long                m_curVer;
+    RTCList<Atom>       m_formats;
+    RTCList<Atom>       m_actions;
+
+    XEvent              m_selEvent;
+
+    Mode                m_mode;
+    State               m_state;
+
+    static const RTCList<RTCString> m_sstrStringMimeTypes;
+};
+
+/*******************************************************************************
+ *
+ * DragAndDropService Declaration
+ *
+ ******************************************************************************/
+
+class DragAndDropService : public VBoxClient::Service
+{
+public:
+    DragAndDropService()
+      : m_pDisplay(0)
+      , m_hHGCMThread(NIL_RTTHREAD)
+      , m_hX11Thread(NIL_RTTHREAD)
+      , m_hEventSem(NIL_RTSEMEVENT)
+      , m_pCurDnD(0)
+      , m_fSrvStopping(false)
+    {}
+
+    virtual const char *getPidFilePath() { return ".vboxclient-draganddrop.pid"; }
+
+    /** @todo Move this part in VbglR3 and just provide a callback for the platform-specific
+              notification stuff, since this is very similar to the VBoxTray code. */
+    virtual int run(bool fDaemonised = false);
+
+    virtual void cleanup()
+    {
+        /* Cleanup */
+        x11DragAndDropTerm();
+        VbglR3DnDTerm();
+    };
+
+private:
+    int x11DragAndDropInit();
+    int x11DragAndDropTerm();
+    static int hgcmEventThread(RTTHREAD hThread, void *pvUser);
+    static int x11EventThread(RTTHREAD hThread, void *pvUser);
+
+    bool waitForXMsg(XEvent &ecm, int type, uint32_t uiMaxMS = 100);
+    void clearEventQueue();
+    /* Usually XCheckMaskEvent could be used for queering selected x11 events.
+     * Unfortunately this doesn't work exactly with the events we need. So we
+     * use this predicate method below and XCheckIfEvent. */
+    static Bool isDnDRespondEvent(Display * /* pDisplay */, XEvent *pEvent, char *pUser)
+    {
+        if (!pEvent)
+            return False;
+        if (   pEvent->type == SelectionClear
+            || pEvent->type == ClientMessage
+            || pEvent->type == MotionNotify
+            || pEvent->type == SelectionRequest)
+//            || (   pEvent->type == ClientMessage
+//                && reinterpret_cast<XClientMessageEvent*>(pEvent)->window == reinterpret_cast<Window>(pUser))
+//            || (   pEvent->type == SelectionRequest
+//                && reinterpret_cast<XSelectionRequestEvent*>(pEvent)->requestor == reinterpret_cast<Window>(pUser)))
+            return True;
+        return False;
+    }
+
+    /* Private member vars */
+    Display             *m_pDisplay;
+
+    RTCMTList<DnDEvent>  m_eventQueue;
+    RTTHREAD             m_hHGCMThread;
+    RTTHREAD             m_hX11Thread;
+    RTSEMEVENT           m_hEventSem;
+    DragInstance        *m_pCurDnD;
+    bool                 m_fSrvStopping;
+
+    friend class DragInstance;
+};
+
+/*******************************************************************************
+ *
+ * DragInstanc Implementation
+ *
+ ******************************************************************************/
+
+DragInstance::DragInstance(Display *pDisplay, DragAndDropService *pParent)
+  : m_pParent(pParent)
+  , m_pDisplay(pDisplay)
+  , m_pScreen(0)
+  , m_rootWin(0)
+  , m_proxyWin(0)
+  , m_curWin(0)
+  , m_curVer(-1)
+  , m_mode(Unknown)
+  , m_state(Uninitialized)
+{
+    uninit();
+}
+
+void DragInstance::uninit()
+{
+    reset();
+    if (m_proxyWin != 0)
+        XDestroyWindow(m_pDisplay, m_proxyWin);
+    m_state    = Uninitialized;
+    m_screenId = -1;
+    m_pScreen  = 0;
+    m_rootWin  = 0;
+    m_proxyWin = 0;
+}
+
+void DragInstance::reset()
+{
+    /* Hide the proxy win. */
+    hideProxyWin();
+    /* If we are currently the Xdnd selection owner, clear that. */
+    Window w = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
+    if (w == m_proxyWin)
+        XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), None, CurrentTime);
+    /* Clear any other DnD specific data on the proxy win. */
+    clearFormatsWindowProperty(m_proxyWin);
+    clearActionsWindowProperty(m_proxyWin);
+    /* Reset the internal state. */
+    m_formats.clear();
+    m_curWin = 0;
+    m_curVer = -1;
+    m_state  = Initialized;
+}
+
+const RTCList<RTCString> DragInstance::m_sstrStringMimeTypes = RTCList<RTCString>()
+    /* Uri's */
+    << "text/uri-list"
+    /* Text */
+    << "text/plain;charset=utf-8"
+    << "UTF8_STRING"
+    << "text/plain"
+    << "COMPOUND_TEXT"
+    << "TEXT"
+    << "STRING"
+    /* OpenOffice formates */
+    << "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""
+    << "application/x-openoffice-drawing;windows_formatname=\"Drawing Format\"";
+
+int DragInstance::init(uint32_t u32ScreenId)
+{
+    int rc = VINF_SUCCESS;
+    do
+    {
+        uninit();
+        /* Enough screens configured in the x11 server? */
+        if ((int)u32ScreenId > ScreenCount(m_pDisplay))
+        {
+            rc = VERR_GENERAL_FAILURE;
+            break;
+        }
+        /* Get the screen number from the x11 server. */
+//        pDrag->screen = ScreenOfDisplay(m_pDisplay, u32ScreenId);
+//        if (!pDrag->screen)
+//        {
+//            rc = VERR_GENERAL_FAILURE;
+//            break;
+//        }
+        m_screenId = u32ScreenId;
+        /* Now query the corresponding root window of this screen. */
+        m_rootWin = RootWindow(m_pDisplay, m_screenId);
+        if (!m_rootWin)
+        {
+            rc = VERR_GENERAL_FAILURE;
+            break;
+        }
+        /* Create an invisible window which will act as proxy for the DnD
+         * operation. This window will be used for both the GH and HG
+         * direction. */
+        XSetWindowAttributes attr;
+        RT_ZERO(attr);
+        attr.do_not_propagate_mask = 0;
+        attr.override_redirect     = True;
+//        attr.background_pixel      = WhitePixel(m_pDisplay, m_screenId);
+        m_proxyWin = XCreateWindow(m_pDisplay, m_rootWin, 0, 0, 1, 1, 0,
+                                   CopyFromParent, InputOnly, CopyFromParent,
+                                   CWOverrideRedirect | CWDontPropagate,
+                                   &attr);
+
+//        m_proxyWin = XCreateSimpleWindow(m_pDisplay, m_rootWin, 0, 0, 50, 50, 0, WhitePixel(m_pDisplay, m_screenId), WhitePixel(m_pDisplay, m_screenId));
+
+        if (!m_proxyWin)
+        {
+            rc = VERR_GENERAL_FAILURE;
+            break;
+        }
+        /* Make the new window Xdnd aware. */
+        Atom ver = VBOX_XDND_VERSION;
+        XChangeProperty(m_pDisplay, m_proxyWin, xAtom(XA_XdndAware), XA_ATOM, 32, PropModeReplace,
+                        reinterpret_cast<unsigned char*>(&ver), 1);
+    }while(0);
+
+    m_state = Initialized;
+
+    return rc;
+}
+
+/*
+ * Host -> Guest
+ */
+
+int DragInstance::hgEnter(const RTCList<RTCString> &formats, uint32_t actions)
+{
+    int rc = VINF_SUCCESS;
+
+    reset();
+    DO(("DnD_ENTR: formats=%u: ", formats.size()));
+#if defined(VERBOSE) && defined(DEBUG_poetzsch)
+    for (size_t i = 0; i < formats.size(); ++i)
+        DO(("'%s' ", formats.at(i).c_str()));
+#endif /* DEBUG */
+    DO(("\n"));
+
+    m_formats = toAtomList(formats);
+
+    /* If we have more than 3 formats we have to use the type list extension. */
+    if (m_formats.size() > 3)
+        setFormatsWindowProperty(m_proxyWin, xAtom(XA_XdndTypeList));
+
+    /* Announce the possible actions */
+    setActionsWindowProperty(m_proxyWin, toX11Actions(actions));
+
+    /* Set the DnD selection owner to our window. */
+    XSetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection), m_proxyWin, CurrentTime);
+
+    m_mode  = HG;
+    m_state = Dragging;
+
+    return rc;
+}
+
+int DragInstance::hgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t action)
+{
+    DO(("DnD_MOVE: "));
+
+    if (   m_mode  != HG
+        || m_state != Dragging)
+        return VERR_INVALID_STATE;
+
+    int rc  = VINF_SUCCESS;
+    int xrc = Success;
+
+    /* Move the mouse cursor within the guest. */
+    moveCursor(u32xPos, u32yPos);
+
+    Window newWin = None; /* Default to _no_ window below the cursor. */
+    long   newVer = -1;   /* This means the current window is _not_ XdndAware. */
+
+    /* Search for the application window below the cursor. */
+    newWin = gX11->applicationWindowBelowCursor(m_rootWin);
+    if (newWin != None)
+    {
+        /* Temp stuff for the XGetWindowProperty call. */
+        Atom atmp;
+        int fmt;
+        unsigned long cItems, cbRemaining;
+        unsigned char *pcData = NULL;
+        /* Query the XdndAware property from the window. We are interested in
+         * the version and if it is XdndAware at all. */
+        xrc = XGetWindowProperty(m_pDisplay, newWin, xAtom(XA_XdndAware), 0, 2, False, AnyPropertyType, &atmp, &fmt, &cItems, &cbRemaining, &pcData);
+        if (RT_UNLIKELY(xrc != Success))
+            DO(("DnD_MOVE: error in getting the window property (%s)\n", gX11->xErrorToString(xrc).c_str()));
+        else
+        {
+            if (RT_UNLIKELY(pcData == NULL || fmt != 32 || cItems != 1))
+                DO(("Prop=error[data=%#x,fmt=%u,items=%u] ", pcData, fmt, cItems));
+            else
+            {
+                newVer = reinterpret_cast<long*>(pcData)[0];
+                DO(("XdndAware=%u ", newVer));
+            }
+            XFree(pcData);
+        }
+    }
+
+    if (newWin != m_curWin && m_curVer != -1)
+    {
+        DO(("leave=%#x ", m_curWin));
+
+        /* We left the current XdndAware window. Announce this to the window. */
+
+        XClientMessageEvent m;
+        RT_ZERO(m);
+        m.type         = ClientMessage;
+        m.display      = m_pDisplay;
+        m.window       = m_curWin;
+        m.message_type = xAtom(XA_XdndLeave);
+        m.format       = 32;
+        m.data.l[0]    = m_proxyWin;
+
+        xrc = XSendEvent(m_pDisplay, m_curWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
+        if (RT_UNLIKELY(xrc == 0))
+            DO(("DnD_MOVE: error sending xevent\n"));
+    }
+
+    if (newWin != m_curWin && newVer != -1)
+    {
+        DO(("enter=%#x ", newWin));
+
+        /* We enter a new window. Announce the XdndEnter event to the new
+         * window. The first three mime types are attached to the event (the
+         * others could be requested by the XdndTypeList property from the
+         * window itself). */
+
+        XClientMessageEvent m;
+        RT_ZERO(m);
+        m.type         = ClientMessage;
+        m.display      = m_pDisplay;
+        m.window       = newWin;
+        m.message_type = xAtom(XA_XdndEnter);
+        m.format       = 32;
+        m.data.l[0]    = m_proxyWin;
+        m.data.l[1]    = RT_MAKE_U32_FROM_U8(m_formats.size() > 3 ? 1 : 0, 0, 0, RT_MIN(VBOX_XDND_VERSION, newVer));
+        m.data.l[2]    = m_formats.value(0, None);
+        m.data.l[3]    = m_formats.value(1, None);
+        m.data.l[4]    = m_formats.value(2, None);
+
+        xrc = XSendEvent(m_pDisplay, newWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
+        if (RT_UNLIKELY(xrc == 0))
+            DO(("DnD_MOVE: error sending xevent\n"));
+    }
+
+    if (newVer != -1)
+    {
+        DO(("move=%#x pos=%ux%u ", newWin, u32xPos, u32yPos));
+
+        /* Send a XdndPosition event with the proposed action to the guest. */
+
+        Atom pa = toX11Action(action);
+        DO(("action='%s' ", xAtomToString(pa).c_str()));
+
+        XClientMessageEvent m;
+        RT_ZERO(m);
+        m.type         = ClientMessage;
+        m.display      = m_pDisplay;
+        m.window       = newWin;
+        m.message_type = xAtom(XA_XdndPosition);
+        m.format       = 32;
+        m.data.l[0]    = m_proxyWin;
+        m.data.l[2]    = RT_MAKE_U32(u32yPos, u32xPos);
+        m.data.l[3]    = CurrentTime;
+        m.data.l[4]    = pa;
+
+        xrc = XSendEvent(m_pDisplay, newWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
+        if (RT_UNLIKELY(xrc == 0))
+            DO(("DnD_MOVE: error sending xevent\n"));
+    }
+    if (newWin == None && newVer == -1)
+        /* No window to process, so send a ignore ack event to the host. */
+        rc = VbglR3DnDHGAcknowledgeOperation(DND_IGNORE_ACTION);
+
+    m_curWin = newWin;
+    m_curVer = RT_MIN(VBOX_XDND_VERSION, newVer);
+
+    DO(("\n"));
+
+    return rc;
+}
+
+int DragInstance::hgX11ClientMessage(const XEvent& e)
+{
+    if (   m_mode  != HG)
+//        || m_state != Dragging)
+        return VERR_INVALID_STATE;
+
+    /* Client messages are used to inform us about the status of a XdndAware
+     * window, in response of some events we send to them. */
+    int rc = VINF_SUCCESS;
+    if (   e.xclient.message_type == xAtom(XA_XdndStatus)
+        && m_curWin               == static_cast<Window>(e.xclient.data.l[0]))
+    {
+        /* The XdndStatus message tell us if the window will accept the DnD
+         * event and with which action. We immediately send this info down to
+         * the host as a response of a previous DnD message. */
+        DO(("DnD_STAT: win=%#x,accept=%RTbool,action='%s'\n",
+            e.xclient.data.l[0],
+            ASMBitTest(&e.xclient.data.l[1], 0),
+            xAtomToString(e.xclient.data.l[4]).c_str()));
+        uint32_t uAction = DND_IGNORE_ACTION;
+        /* Todo: compare this with the allowed actions. */
+        if (ASMBitTest(&e.xclient.data.l[1], 0))
+            uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4]));
+        rc = VbglR3DnDHGAcknowledgeOperation(uAction);
+    }
+    else if (e.xclient.message_type == xAtom(XA_XdndFinished))
+    {
+        /* This message is send on a un/successful DnD drop request. */
+        DO(("DnD_FINI: win=%#x,success=%RTbool,action='%s'\n",
+            e.xclient.data.l[0],
+            ASMBitTest(&e.xclient.data.l[1], 0),
+            xAtomToString(e.xclient.data.l[2]).c_str()));
+        reset();
+    }
+    else
+        DO(("DnD_CLI: win=%#x,msg='%s'\n", e.xclient.data.l[0], xAtomToString(e.xclient.message_type).c_str()));
+    return rc;
+}
+
+int DragInstance::hgDrop()
+{
+    DO(("DnD_DROP: win=%#x\n", m_curWin));
+
+    if (   m_mode  != HG
+        || m_state != Dragging)
+        return VERR_INVALID_STATE;
+
+    int rc = VINF_SUCCESS;
+
+    /* Send a drop event to the current window and reset our DnD status. */
+    XClientMessageEvent m;
+    RT_ZERO(m);
+    m.type         = ClientMessage;
+    m.display      = m_pDisplay;
+    m.window       = m_curWin;
+    m.message_type = xAtom(XA_XdndDrop);
+    m.format       = 32;
+    m.data.l[0]    = m_proxyWin;
+    m.data.l[2]    = CurrentTime;
+
+    int xrc = XSendEvent(m_pDisplay, m_curWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
+    if (RT_UNLIKELY(xrc == 0))
+        DO(("DnD_DROP: error sending xevent\n"));
+
+    m_curWin = None;
+    m_curVer = -1;
+
+    m_state = Dropped;
+
+    return rc;
+}
+
+int DragInstance::hgX11SelectionRequest(const XEvent& e)
+{
+    AssertReturn(e.type == SelectionRequest, VERR_INVALID_PARAMETER);
+
+    if (   m_mode  != HG)
+//        || m_state != D)
+        return VERR_INVALID_STATE;
+
+    DO(("DnD_SELR: owner=%#x,requestor=%#x,sel_atom='%s',tar_atom='%s',prop_atom='%s',time=%u\n",
+        e.xselectionrequest.owner,
+        e.xselectionrequest.requestor,
+        xAtomToString(e.xselectionrequest.selection).c_str(),
+        xAtomToString(e.xselectionrequest.target).c_str(),
+        xAtomToString(e.xselectionrequest.property).c_str(),
+        e.xselectionrequest.time));
+
+    int rc = VINF_SUCCESS;
+
+    /* A window is asking for some data. Normally here the data would be copied
+     * into the selection buffer and send to the requestor. Obviously we can't
+     * do that, cause we first need to ask the host for the data of the
+     * requested mime type. This is done and later answered with the correct
+     * data (s. dataReceived). */
+
+    /* Is the requestor asking for the possible mime types? */
+    if(e.xselectionrequest.target == xAtom(XA_TARGETS))
+    {
+        DO(("DnD_SELR: ask for target list\n"));
+        /* If so, set the window property with the formats on the requestor
+         * window. */
+        setFormatsWindowProperty(e.xselectionrequest.requestor, e.xselectionrequest.property);
+        XEvent s;
+        RT_ZERO(s);
+        s.xselection.type      = SelectionNotify;
+        s.xselection.display   = e.xselection.display;
+        s.xselection.time      = e.xselectionrequest.time;
+        s.xselection.selection = e.xselectionrequest.selection;
+        s.xselection.requestor = e.xselectionrequest.requestor;
+        s.xselection.target    = e.xselectionrequest.target;
+        s.xselection.property  = e.xselectionrequest.property;
+        int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
+        if (RT_UNLIKELY(xrc == 0))
+            DO(("DnD_SELR: error sending xevent\n"));
+    }
+    /* Is the requestor asking for a specific mime type (we support)? */
+    else if(m_formats.contains(e.xselectionrequest.target))
+    {
+        DO(("DnD_SELR: ask for data (format='%s')\n", xAtomToString(e.xselectionrequest.target).c_str()));
+        /* If so, we need to inform the host about this request. Save the
+         * selection request event for later use. */
+        if (   m_state != Dropped)
+            //        || m_curWin != e.xselectionrequest.requestor)
+        {
+            DO(("DnD_SELR: refuse\n"));
+            XEvent s;
+            RT_ZERO(s);
+            s.xselection.type      = SelectionNotify;
+            s.xselection.display   = e.xselection.display;
+            s.xselection.time      = e.xselectionrequest.time;
+            s.xselection.selection = e.xselectionrequest.selection;
+            s.xselection.requestor = e.xselectionrequest.requestor;
+            s.xselection.target    = None;
+            s.xselection.property  = e.xselectionrequest.property;
+            int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
+            if (RT_UNLIKELY(xrc == 0))
+                DO(("DnD_SELR: error sending xevent\n"));
+        }
+        else
+        {
+            memcpy(&m_selEvent, &e, sizeof(XEvent));
+            rc = VbglR3DnDHGRequestData(xAtomToString(e.xselectionrequest.target).c_str());
+        }
+    }
+    /* Anything else. */
+    else
+    {
+        DO(("DnD_SELR: refuse\n"));
+        /* We don't understand this request message and therefore answer with an
+         * refusal messages. */
+        XEvent s;
+        RT_ZERO(s);
+        s.xselection.type      = SelectionNotify;
+        s.xselection.display   = e.xselection.display;
+        s.xselection.time      = e.xselectionrequest.time;
+        s.xselection.selection = e.xselectionrequest.selection;
+        s.xselection.requestor = e.xselectionrequest.requestor;
+        s.xselection.target    = None; /* default is refusing */
+        s.xselection.property  = None; /* default is refusing */
+        int xrc = XSendEvent(e.xselection.display, e.xselectionrequest.requestor, False, 0, &s);
+        if (RT_UNLIKELY(xrc == 0))
+            DO(("DnD_SELR: error sending xevent\n"));
+    }
+
+    return rc;
+}
+
+int DragInstance::hgDataReceived(void *pvData, uint32_t cData)
+{
+    if (   m_mode  != HG
+        || m_state != Dropped)
+        return VERR_INVALID_STATE;
+
+    if (RT_UNLIKELY(   pvData == NULL
+                    || cData  == 0))
+        return VERR_INVALID_PARAMETER;
+
+    if (RT_UNLIKELY(m_state != Dropped))
+        return VERR_INVALID_STATE;
+
+    /* Make a copy of the data. The xserver will become the new owner. */
+    void *pvNewData = RTMemAlloc(cData);
+    if (RT_UNLIKELY(!pvNewData))
+        return VERR_NO_MEMORY;
+    memcpy(pvNewData, pvData, cData);
+
+    /* The host send us the DnD data in the requested mime type. This allows us
+     * to fill the XdndSelection property of the requestor window with the data
+     * and afterwards inform him about the new status. */
+    XEvent s;
+    RT_ZERO(s);
+    s.xselection.type      = SelectionNotify;
+    s.xselection.display   = m_selEvent.xselection.display;
+//    s.xselection.owner     = m_selEvent.xselectionrequest.owner;
+    s.xselection.time      = m_selEvent.xselectionrequest.time;
+    s.xselection.selection = m_selEvent.xselectionrequest.selection;
+    s.xselection.requestor = m_selEvent.xselectionrequest.requestor;
+    s.xselection.target    = m_selEvent.xselectionrequest.target;
+    s.xselection.property  = m_selEvent.xselectionrequest.property;
+
+    DO(("DnD_SEND: owner=%#x,requestor=%#x,sel_atom='%s',tar_atom='%s',prop_atom='%s',time=%u\n",
+        m_selEvent.xselectionrequest.owner,
+        s.xselection.requestor,
+        xAtomToString(s.xselection.selection).c_str(),
+        xAtomToString(s.xselection.target).c_str(),
+        xAtomToString(s.xselection.property).c_str(),
+        s.xselection.time));
+
+    /* Fill up the property with the data. */
+    XChangeProperty(s.xselection.display, s.xselection.requestor, s.xselection.property, s.xselection.target, 8, PropModeReplace,
+                    reinterpret_cast<const unsigned char*>(pvNewData), cData);
+    int xrc = XSendEvent(s.xselection.display, s.xselection.requestor, True, 0, &s);
+    if (RT_UNLIKELY(xrc == 0))
+        DO(("DnD_SEND: error sending xevent\n"));
+
+    return VINF_SUCCESS;
+}
+
+
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+/*
+ * Guest -> Host
+ */
+
+int DragInstance::ghIsDnDPending()
+{
+    int rc = VINF_SUCCESS;
+    Window w = XGetSelectionOwner(m_pDisplay, xAtom(XA_XdndSelection));
+    DO(("Checking pending %X %X\n", w, m_proxyWin));
+    /* Is there someone own the Xdnd selection which aren't we. */
+    if (   w
+        && w != m_proxyWin)
+    {
+        /* Map the window on the current cursor position, which should provoke
+         * an XdndEnter event. */
+        int rx, ry;
+        showProxyWin(rx, ry);
+        XEvent e;
+        if (m_pParent->waitForXMsg(e, ClientMessage))
+        {
+            int xrc = Success;
+            XClientMessageEvent *clme = reinterpret_cast<XClientMessageEvent*>(&e);
+            DO(("next X event %s\n", gX11->xAtomToString(clme->message_type).c_str()));
+            if (clme->message_type == xAtom(XA_XdndEnter))
+            {
+                Atom type = None;
+                int f;
+                unsigned long n, a;
+                unsigned char *ret = 0;
+                reset();
+
+                m_formats.clear();
+                m_actions.clear();
+                m_curWin = w;
+                DO(("XA_XdndEnter\n"));
+                /* Check if the mime types are in the msg itself or if we need
+                 * to fetch the XdndTypeList property from the window. */
+                if (!ASMBitTest(&clme->data.l[1], 0))
+                {
+                    for (int i = 2; i < 5; ++i)
+                    {
+                        DO(("receive list msg: %s\n", gX11->xAtomToString(clme->data.l[i]).c_str()));
+                        m_formats.append(clme->data.l[i]);
+                    }
+                }
+                else
+                {
+                    xrc = XGetWindowProperty(m_pDisplay, w, xAtom(XA_XdndTypeList), 0, VBOX_MAX_XPROPERTIES, False, XA_ATOM, &type, &f, &n, &a, &ret);
+                    if (   xrc == Success
+                        && n > 0
+                        && ret)
+                    {
+                        Atom *data = reinterpret_cast<Atom*>(ret);
+                        for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i)
+                        {
+                            DO(("receive list: %s\n", gX11->xAtomToString(data[i]).c_str()));
+                            m_formats.append(data[i]);
+                        }
+                        XFree(ret);
+                    }
+                }
+                /* Fetch the possible list of actions, if this property is set. */
+                xrc = XGetWindowProperty(m_pDisplay, w, xAtom(XA_XdndActionList), 0, VBOX_MAX_XPROPERTIES, False, XA_ATOM, &type, &f, &n, &a, &ret);
+                if (   xrc == Success
+                    && n > 0
+                    && ret)
+                {
+                    Atom *data = reinterpret_cast<Atom*>(ret);
+                    for (int i = 0; i < RT_MIN(VBOX_MAX_XPROPERTIES, n); ++i)
+                    {
+                        DO(("receive actions: %s\n", gX11->xAtomToString(data[i]).c_str()));
+                        m_actions.append(data[i]);
+                    }
+                    XFree(ret);
+                }
+
+                m_state = Dragging;
+                m_mode  = GH;
+                /* Acknowledge the event by sending a Status msg back to the
+                 * window. */
+                XClientMessageEvent m;
+                RT_ZERO(m);
+                m.type         = ClientMessage;
+                m.display      = m_pDisplay;
+                m.window       = clme->data.l[0];
+                m.message_type = xAtom(XA_XdndStatus);
+                m.format       = 32;
+                m.data.l[0]    = m_proxyWin;
+                m.data.l[1]    = 1;
+                m.data.l[4]    = xAtom(XA_XdndActionCopy);
+                xrc = XSendEvent(m_pDisplay, clme->data.l[0], False, 0, reinterpret_cast<XEvent*>(&m));
+                if (RT_UNLIKELY(xrc == 0))
+                    DO(("DnD_PNDG: error sending xevent\n"));
+            }
+            else if (clme->message_type == xAtom(XA_XdndPosition))
+            {
+                DO(("XA_XdndPosition\n"));
+                XClientMessageEvent m;
+                RT_ZERO(m);
+                m.type         = ClientMessage;
+                m.display      = m_pDisplay;
+                m.window       = clme->data.l[0];
+                m.message_type = xAtom(XA_XdndStatus);
+                m.format       = 32;
+                m.data.l[0]    = m_proxyWin;
+                m.data.l[1]    = 1;
+                m.data.l[4]    = clme->data.l[4];
+                xrc = XSendEvent(m_pDisplay, clme->data.l[0], False, 0, reinterpret_cast<XEvent*>(&m));
+                if (RT_UNLIKELY(xrc == 0))
+                    DO(("DnD_PNDG: error sending xevent\n"));
+            }
+            else if (clme->message_type == xAtom(XA_XdndLeave))
+            {
+            }
+        }
+        hideProxyWin();
+
+        rc = VbglR3DnDGHAcknowledgePending(DND_COPY_ACTION, toHGCMActions(m_actions), gX11->xAtomListToString(m_formats).c_str());
+    }
+    return rc;
+}
+
+int DragInstance::ghDropped(const RTCString &strFormat, uint32_t action)
+{
+    DO(("DND_DRO: format='%s' action=%d\n", strFormat.c_str(), action));
+    int rc = VINF_SUCCESS;
+
+    /* Show the proxy window, so that the source will find it. */
+    int rx, ry;
+    showProxyWin(rx, ry);
+    XFlush(m_pDisplay);
+    /* We send a fake release event to the current window, cause
+     * this should have the grab. */
+    sendButtonEvent(m_curWin, rx, ry, 1, false);
+    /* The fake button release event, should lead to an XdndDrop event from the
+     * source. Because of the showing of the proxy window, sometimes other Xdnd
+     * events occurs before, like a XdndPosition event. We are not interested
+     * in those, so try to get the right one. */
+    XEvent e;
+    XClientMessageEvent *clme = 0;
+    RT_ZERO(e);
+    int tries = 3;
+    do
+    {
+        if (m_pParent->waitForXMsg(e, ClientMessage))
+        {
+            if (reinterpret_cast<XClientMessageEvent*>(&e)->message_type == xAtom(XA_XdndDrop))
+            {
+                clme = reinterpret_cast<XClientMessageEvent*>(&e);
+                break;
+            }
+        }
+    }while(tries--);
+    if (clme)
+    {
+        /* Make some paranoid checks. */
+        if (clme->message_type == xAtom(XA_XdndDrop))
+        {
+            /* Request to convert the selection in the specific format and
+             * place it to our proxy window as property. */
+            Window srcWin = m_curWin;//clme->data.l[0];
+            Atom aFormat  = gX11->stringToxAtom(strFormat.c_str());
+            XConvertSelection(m_pDisplay, xAtom(XA_XdndSelection), aFormat, xAtom(XA_XdndSelection), m_proxyWin, clme->data.l[2]);
+            /* Wait for the selection notify event. */
+            RT_ZERO(e);
+            if (m_pParent->waitForXMsg(e, SelectionNotify))
+            {
+                /* Make some paranoid checks. */
+                if (   e.xselection.type      == SelectionNotify
+                    && e.xselection.display   == m_pDisplay
+                    && e.xselection.selection == xAtom(XA_XdndSelection)
+                    && e.xselection.requestor == m_proxyWin
+                    && e.xselection.target    == aFormat)
+                {
+                    DO(("DND_DRO: selection notfiy (from: %x)\n", m_curWin));
+                    Atom type;
+                    int format;
+                    unsigned long cItems, cbRemaining;
+                    unsigned char *ucData = 0;
+                    XGetWindowProperty(m_pDisplay, m_proxyWin, xAtom(XA_XdndSelection),
+                                       0, VBOX_MAX_XPROPERTIES, True, AnyPropertyType,
+                                       &type, &format, &cItems, &cbRemaining, &ucData);
+                    DO(("DND_DRO: %s %d %d %s\n", gX11->xAtomToString(type).c_str(), cItems, format, ucData));
+                    if (   type        != None
+                        && ucData      != NULL
+                        && format      >= 8
+                        && cItems      >  0
+                        && cbRemaining == 0)
+                    {
+                        size_t cbData = cItems * (format / 8);
+                        /* For whatever reason some of the string mime-types are not
+                         * zero terminated. Check that and correct it when necessary,
+                         * cause the guest side wants this always. */
+                        if (   m_sstrStringMimeTypes.contains(strFormat)
+                            && ucData[cbData - 1] != '\0')
+                        {
+                            DO(("rebuild %u\n", cbData));
+                            unsigned char *ucData1 = static_cast<unsigned char*>(RTMemAlloc(cbData + 1));
+                            if (ucData1)
+                            {
+                                memcpy(ucData1, ucData, cbData);
+                                ucData1[cbData++] = '\0';
+                                /* Got the data and its fully transfered. */
+                                rc = VbglR3DnDGHSendData(ucData1, cbData);
+                                RTMemFree(ucData1);
+                            }
+                            else
+                                rc = VERR_NO_MEMORY;
+                        }
+                        else
+                            /* Just send the data to the host. */
+                            rc = VbglR3DnDGHSendData(ucData, cbData);
+
+                        DO(("send responce\n"));
+                        /* Confirm the result of the transfer to the source window. */
+                        XClientMessageEvent m;
+                        RT_ZERO(m);
+                        m.type         = ClientMessage;
+                        m.display      = m_pDisplay;
+                        m.window       = srcWin;
+                        m.message_type = xAtom(XA_XdndFinished);
+                        m.format       = 32;
+                        m.data.l[0]    = m_proxyWin;
+                        m.data.l[1]    = RT_SUCCESS(rc) ?                   1 : 0;    /* Confirm or deny success */
+                        m.data.l[2]    = RT_SUCCESS(rc) ? toX11Action(action) : None; /* Action used on success */
+
+                        int xrc = XSendEvent(m_pDisplay, srcWin, True, NoEventMask, reinterpret_cast<XEvent*>(&m));
+                        if (RT_UNLIKELY(xrc == 0))
+                            DO(("DnD_DRO: error sending xevent\n"));
+                    }
+                    else
+                    {
+                        if (type == xAtom(XA_INCR))
+                        {
+                            /* Todo: */
+                            AssertMsgFailed(("Incrementally transfers are not supported, yet\n"));
+                            rc = VERR_NOT_IMPLEMENTED;
+                        }
+                        else
+                        {
+                            AssertMsgFailed(("Not supported data type\n"));
+                            rc = VERR_INVALID_PARAMETER;
+                        }
+                        /* Cancel this. */
+                        XClientMessageEvent m;
+                        RT_ZERO(m);
+                        m.type         = ClientMessage;
+                        m.display      = m_pDisplay;
+                        m.window       = srcWin;
+                        m.message_type = xAtom(XA_XdndFinished);
+                        m.format       = 32;
+                        m.data.l[0]    = m_proxyWin;
+                        m.data.l[1]    = 0;
+                        m.data.l[2]    = None;
+                        int xrc = XSendEvent(m_pDisplay, srcWin, False, NoEventMask, reinterpret_cast<XEvent*>(&m));
+                        if (RT_UNLIKELY(xrc == 0))
+                            DO(("DnD_DRO: error sending xevent\n"));
+                        m_curWin = 0;
+                    }
+                    /* Cleanup */
+                    if (ucData)
+                        XFree(ucData);
+                }
+                else
+                    rc = VERR_INVALID_PARAMETER;
+            }
+            else
+                rc = VERR_TIMEOUT;
+        }
+        else
+            rc = VERR_WRONG_ORDER;
+    }
+    else
+        rc = VERR_TIMEOUT;
+
+    /* Inform the host on error */
+    if (RT_FAILURE(rc))
+        VbglR3DnDGHErrorEvent(rc);
+
+    /* At this point, we have either successfully transfered any data or not.
+     * So reset our internal state, cause we are done. */
+    reset();
+
+    return rc;
+}
+
+#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
+
+/*
+ * Helpers
+ */
+
+int DragInstance::moveCursor(uint32_t u32xPos, uint32_t u32yPos)
+{
+    /* Move the guest pointer to the DnD position, so we can find the window
+     * below that position. */
+    XWarpPointer(m_pDisplay, None, m_rootWin, 0, 0, 0, 0, u32xPos, u32yPos);
+    return VINF_SUCCESS;
+}
+
+void DragInstance::sendButtonEvent(Window w, int rx, int ry, int button, bool fPress) const
+{
+//    XTestFakeMotionEvent(m_pDisplay, -1, rx, ry, CurrentTime);
+//    XTestFakeMotionEvent(m_pDisplay, -1, rx + 1, ry + 1, CurrentTime);
+//    int rc = XTestFakeButtonEvent(m_pDisplay, 1, False, CurrentTime);
+//    if (rc != 0)
+    {
+        XButtonEvent be;
+        RT_ZERO(be);
+        be.display      = m_pDisplay;
+        be.root         = m_rootWin;
+        be.window       = w;
+        be.subwindow    = None;
+        be.same_screen  = True;
+        be.time         = CurrentTime;
+        be.button       = button;
+        be.state       |= button == 1 ? Button1MotionMask :
+                          button == 2 ? Button2MotionMask :
+                          button == 3 ? Button3MotionMask :
+                          button == 4 ? Button4MotionMask :
+                          button == 5 ? Button5MotionMask : 0;
+        be.type         = fPress ? ButtonPress : ButtonRelease;
+        be.x_root       = rx;
+        be.y_root       = ry;
+        XTranslateCoordinates(m_pDisplay, be.root, be.window, be.x_root, be.y_root, &be.x, &be.y, &be.subwindow);
+        int xrc = XSendEvent(m_pDisplay, be.window, True, ButtonPressMask, reinterpret_cast<XEvent*>(&be));
+        if (RT_UNLIKELY(xrc == 0))
+            DO(("DnD_BTN: error sending xevent\n"));
+    }
+
+}
+
+void DragInstance::showProxyWin(int &rx, int &ry) const
+{
+    int cx, cy;
+    unsigned int m;
+    Window r, c;
+//    XTestGrabControl(m_pDisplay, False);
+    XQueryPointer(m_pDisplay, m_rootWin, &r, &c, &rx, &ry, &cx, &cy, &m);
+    XSynchronize(m_pDisplay, True);
+    XMapWindow(m_pDisplay, m_proxyWin);
+    XRaiseWindow(m_pDisplay, m_proxyWin);
+    XMoveResizeWindow(m_pDisplay, m_proxyWin, rx, ry, 1, 1);
+    XWarpPointer(m_pDisplay, None, m_rootWin, 0, 0, 0, 0, rx , ry);
+    XSynchronize(m_pDisplay, False);
+//    XTestGrabControl(m_pDisplay, True);
+}
+
+void DragInstance::hideProxyWin() const
+{
+    XUnmapWindow(m_pDisplay, m_proxyWin);
+}
+
+/* Currently, not used */
+void DragInstance::registerForEvents(Window w) const
+{
+//    if (w == m_proxyWin)
+//        return;
+
+    DO(("%x\n", w));
+//    XSelectInput(m_pDisplay, w, Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask);//| SubstructureNotifyMask);
+//    XSelectInput(m_pDisplay, w, ButtonMotionMask); //PointerMotionMask);
+    XSelectInput(m_pDisplay, w, PointerMotionMask); //PointerMotionMask);
+    Window hRealRoot, hParent;
+    Window *phChildrenRaw = NULL;
+    unsigned cChildren;
+    if (XQueryTree(m_pDisplay, w, &hRealRoot, &hParent, &phChildrenRaw, &cChildren))
+    {
+        for (unsigned i = 0; i < cChildren; ++i)
+            registerForEvents(phChildrenRaw[i]);
+        XFree(phChildrenRaw);
+    }
+}
+
+void DragInstance::setActionsWindowProperty(Window win, const RTCList<Atom> &actionList) const
+{
+    if (actionList.isEmpty())
+        return;
+
+    XChangeProperty(m_pDisplay, win, xAtom(XA_XdndActionList), XA_ATOM, 32, PropModeReplace,
+                    reinterpret_cast<const unsigned char*>(actionList.raw()), actionList.size());
+}
+
+void DragInstance::clearActionsWindowProperty(Window win) const
+{
+    XDeleteProperty(m_pDisplay, win, xAtom(XA_XdndActionList));
+}
+
+void DragInstance::setFormatsWindowProperty(Window win, Atom property) const
+{
+    if (m_formats.isEmpty())
+        return;
+
+    /* We support TARGETS and the data types. */
+    RTCList<Atom> targets(m_formats.size() + 1);
+    targets.append(xAtom(XA_TARGETS));
+    targets.append(m_formats);
+
+    /* Add the property with the property data to the window. */
+    XChangeProperty(m_pDisplay, win, property, XA_ATOM, 32, PropModeReplace,
+                    reinterpret_cast<const unsigned char*>(targets.raw()), targets.size());
+}
+
+void DragInstance::clearFormatsWindowProperty(Window win) const
+{
+    XDeleteProperty(m_pDisplay, win, xAtom(XA_XdndTypeList));
+}
+
+RTCList<Atom> DragInstance::toAtomList(const RTCList<RTCString> &formatList) const
+{
+    RTCList<Atom> atomList;
+    for (size_t i = 0; i < formatList.size(); ++i)
+        atomList.append(XInternAtom(m_pDisplay, formatList.at(i).c_str(), False));
+
+    return atomList;
+}
+
+RTCList<Atom> DragInstance::toAtomList(void *pvData, uint32_t cData) const
+{
+    if (   !pvData
+        || !cData)
+        return RTCList<Atom>();
+    char *pszStr = (char*)pvData;
+    uint32_t cStr = cData;
+
+    RTCList<Atom> atomList;
+    while (cStr > 0)
+    {
+        size_t cSize = RTStrNLen(pszStr, cStr);
+        /* Create a copy with max N chars, so that we are on the save side,
+         * even if the data isn't zero terminated. */
+        char *pszTmp = RTStrDupN(pszStr, cSize);
+        DO(("f: %s\n", pszTmp));
+        atomList.append(XInternAtom(m_pDisplay, pszTmp, False));
+        RTStrFree(pszTmp);
+        pszStr += cSize + 1;
+        cStr   -= cSize + 1;
+    }
+
+    return atomList;
+}
+
+/* static */
+Atom DragInstance::toX11Action(uint32_t uAction)
+{
+    /* Ignore is None */
+    return (isDnDCopyAction(uAction) ? xAtom(XA_XdndActionCopy) :
+            isDnDMoveAction(uAction) ? xAtom(XA_XdndActionMove) :
+            isDnDLinkAction(uAction) ? xAtom(XA_XdndActionLink) :
+            None);
+}
+
+/* static */
+RTCList<Atom> DragInstance::toX11Actions(uint32_t uActions)
+{
+    RTCList<Atom> actionList;
+    if (hasDnDCopyAction(uActions))
+        actionList.append(xAtom(XA_XdndActionCopy));
+    if (hasDnDMoveAction(uActions))
+        actionList.append(xAtom(XA_XdndActionMove));
+    if (hasDnDLinkAction(uActions))
+        actionList.append(xAtom(XA_XdndActionLink));
+
+    return actionList;
+}
+
+/* static */
+uint32_t DragInstance::toHGCMAction(Atom atom)
+{
+    uint32_t uAction = DND_IGNORE_ACTION;
+    if (atom == xAtom(XA_XdndActionCopy))
+        uAction = DND_COPY_ACTION;
+    else if (atom == xAtom(XA_XdndActionMove))
+        uAction = DND_MOVE_ACTION;
+    else if (atom == xAtom(XA_XdndActionLink))
+        uAction = DND_LINK_ACTION;
+    return uAction;
+}
+
+/* static */
+uint32_t DragInstance::toHGCMActions(const RTCList<Atom> &actionsList)
+{
+    uint32_t uActions = DND_IGNORE_ACTION;
+    for (size_t i = 0; i < actionsList.size(); ++i)
+        uActions |= toHGCMAction(actionsList.at(i));
+    return uActions;
+}
+
+/*******************************************************************************
+ *
+ * DragAndDropService Implementation
+ *
+ ******************************************************************************/
+
+RTCList<RTCString> toStringList(void *pvData, uint32_t cData)
+{
+    if (   !pvData
+        || !cData)
+        return RTCList<RTCString>();
+    char *pszStr = (char*)pvData;
+    uint32_t cStr = cData;
+
+    RTCList<RTCString> strList;
+    while (cStr > 0)
+    {
+        size_t cSize = RTStrNLen(pszStr, cStr);
+        /* Create a copy with max N chars, so that we are on the save side,
+         * even if the data isn't zero terminated. */
+        char *pszTmp = RTStrDupN(pszStr, cSize);
+        strList.append(pszTmp);
+        RTStrFree(pszTmp);
+        pszStr += cSize + 1;
+        cStr   -= cSize + 1;
+    }
+
+    return strList;
+}
+
+bool DragAndDropService::waitForXMsg(XEvent &ecm, int type, uint32_t uiMaxMS /* = 100 */)
+{
+    const uint64_t uiStart = RTTimeProgramMilliTS();
+    do
+    {
+        if (!m_eventQueue.isEmpty())
+        {
+            DO(("new msg size %d\n", m_eventQueue.size()));
+            /* Check if there is a client message in the queue. */
+            for (size_t i = 0; i < m_eventQueue.size(); ++i)
+            {
+                DnDEvent e = m_eventQueue.at(i);
+                if(   e.type     == DnDEvent::X11_Type)
+                    DO(("new msg\n"));
+                if(   e.type     == DnDEvent::X11_Type
+                   && e.x11.type == type)
+                {
+                    m_eventQueue.removeAt(i);
+                    ecm = e.x11;
+                    return true;
+                }
+            }
+        }
+        int rc = RTSemEventWait(m_hEventSem, 25);
+//        if (RT_FAILURE(rc))
+//            return false;
+    }
+    while(RTTimeProgramMilliTS() - uiStart < uiMaxMS);
+
+    return false;
+}
+
+void DragAndDropService::clearEventQueue()
+{
+    m_eventQueue.clear();
+}
+
+int DragAndDropService::run(bool fDaemonised /* = false */)
+{
+    int rc = VINF_SUCCESS;
+    LogRelFlowFunc(("\n"));
+
+    /* We need to initialize XLib with thread support, otherwise our
+     * simultaneously access to the display makes trouble (has to be called
+     * before any usage of XLib). */
+    if (!XInitThreads())
+        AssertMsgFailedReturn(("Failed to initialize thread-safe XLib.\n"), VERR_GENERAL_FAILURE);
+
+    do
+    {
+        /* Initialize our service */
+        rc = VbglR3DnDInit();
+        if (RT_FAILURE(rc))
+            break;
+
+        /* Initialize X11 DND */
+        rc = x11DragAndDropInit();
+        if (RT_FAILURE(rc))
+            break;
+
+        m_pCurDnD = new DragInstance(m_pDisplay, this);
+        /* Note: For multiple screen support in VBox it is not necessary to use
+         * another screen number than zero. Maybe in the future it will become
+         * necessary if VBox supports multiple X11 screens. */
+        m_pCurDnD->init(0);
+        /* Loop over new events */
+        do
+        {
+            DnDEvent e;
+            RT_ZERO(e);
+            if (m_eventQueue.isEmpty())
+                rc = RTSemEventWait(m_hEventSem, 50);
+            if (!m_eventQueue.isEmpty())
+            {
+                e = m_eventQueue.first();
+                m_eventQueue.removeFirst();
+                DO(("new msg %d\n", e.type));
+                if (e.type == DnDEvent::HGCM_Type)
+                {
+                    switch (e.hgcm.uType)
+                    {
+                        case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
+                        {
+                            RTCList<RTCString> formats = RTCString(e.hgcm.pszFormats, e.hgcm.cbFormats - 1).split("\r\n");
+                            m_pCurDnD->hgEnter(formats, e.hgcm.u.a.uAllActions);
+                            /* Enter is always followed by a move event. */
+                        }
+                        case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
+                        {
+                            m_pCurDnD->hgMove(e.hgcm.u.a.uXpos, e.hgcm.u.a.uYpos, e.hgcm.u.a.uDefAction);
+                            break;
+                        }
+                        case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
+                        {
+                            m_pCurDnD->reset();
+                            /* Not sure if this is really right! */
+                            clearEventQueue();
+                            break;
+                        }
+                        case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+                        {
+                            m_pCurDnD->hgDrop();
+                            break;
+                        }
+                        case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+                        {
+                            m_pCurDnD->hgDataReceived(e.hgcm.u.b.pvData, e.hgcm.u.b.cbData);
+                            break;
+                        }
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+                        case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
+                        {
+                            m_pCurDnD->ghIsDnDPending();
+                            break;
+                        }
+                        case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+                        {
+                            m_pCurDnD->ghDropped(e.hgcm.pszFormats, e.hgcm.u.a.uDefAction);
+                            /* Not sure if this is really right! */
+                            clearEventQueue();
+                            break;
+                        }
+#endif
+                    }
+                    /* Some messages require cleanup. */
+                    switch (e.hgcm.uType)
+                    {
+                        case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
+                        case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
+                        case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+                        case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+#endif
+                        {
+                            if (e.hgcm.pszFormats)
+                                RTMemFree(e.hgcm.pszFormats);
+                            break;
+                        }
+                        case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+                        {
+                            if (e.hgcm.pszFormats)
+                                RTMemFree(e.hgcm.pszFormats);
+                            if (e.hgcm.u.b.pvData)
+                                RTMemFree(e.hgcm.u.b.pvData);
+                            break;
+                        }
+                    }
+
+                }
+                else if(e.type == DnDEvent::X11_Type)
+                {
+                    DO(("X11 type: %u\n", e.x11.type));
+                    /* Now the X11 event stuff */
+                    switch (e.x11.type)
+                    {
+                        case SelectionRequest: m_pCurDnD->hgX11SelectionRequest(e.x11); break;
+                        case ClientMessage:    m_pCurDnD->hgX11ClientMessage(e.x11); break;
+                        case SelectionClear:   DO(("DnD_CLER\n")); break;
+//                      case MotionNotify: m_pCurDnD->hide(); break;
+                    }
+                }
+            }
+        }while(!ASMAtomicReadBool(&m_fSrvStopping));
+    }while(0);
+
+    LogRelFlowFunc(("returning %Rrc\n", rc));
+    return rc;
+}
+
+int DragAndDropService::x11DragAndDropInit()
+{
+    /* Connect to the x11 server. */
+    m_pDisplay = XOpenDisplay(NULL);
+    if (!m_pDisplay)
+        /* todo: correct errors */
+        return VERR_NOT_FOUND;
+
+    xHelpers::instance(m_pDisplay);
+
+    int rc = VINF_SUCCESS;
+    do
+    {
+        /* Signal a new event to our main loop. */
+        rc = RTSemEventCreate(&m_hEventSem);
+        if (RT_FAILURE(rc))
+            break;
+        /* Event thread for events coming from the HGCM device. */
+        rc = RTThreadCreate(&m_hHGCMThread, hgcmEventThread, this,
+                            0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
+                            "HGCM-NOTIFY");
+        if (RT_FAILURE(rc))
+            break;
+        /* Event thread for events coming from the x11 system. */
+        rc = RTThreadCreate(&m_hX11Thread, x11EventThread, this,
+                            0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
+                            "X11-NOTIFY");
+    }while(0);
+
+    /* Cleanup on failure */
+    if (RT_FAILURE(rc))
+        x11DragAndDropTerm();
+
+    return rc;
+}
+
+int DragAndDropService::x11DragAndDropTerm()
+{
+    /* Mark that we are stopping. */
+    ASMAtomicWriteBool(&m_fSrvStopping, true);
+
+    /* Send a x11 client messages to the x11 event loop. */
+    XClientMessageEvent m;
+    RT_ZERO(m);
+    m.type         = ClientMessage;
+    m.display      = m_pDisplay;
+    m.window       = None;
+    m.message_type = xAtom(XA_dndstop);
+    m.format       = 32;
+    int xrc = XSendEvent(m_pDisplay, None, True, NoEventMask, reinterpret_cast<XEvent*>(&m));
+    if (RT_UNLIKELY(xrc == 0))
+        DO(("DnD_TERM: error sending xevent\n"));
+    /* Wait for our event threads to stop. */
+//    if (m_hX11Thread)
+//        RTThreadWait(m_hX11Thread, RT_INDEFINITE_WAIT, 0);
+//    if (m_hHGCMThread)
+//        RTThreadWait(m_hHGCMThread, RT_INDEFINITE_WAIT, 0);
+    /* Cleanup */
+    /* todo: This doesn't work. The semaphore was interrupted by the user
+     * signal. It is not possible to destroy a semaphore while it is in interrupted state.
+     * According to Frank, the cleanup stuff done here is done _wrong_. We just
+     * should signal the main loop to stop and do the cleanup there. Needs
+     * adoption in all VBoxClient::Service's. */
+//    if (m_hEventSem)
+//        RTSemEventDestroy(m_hEventSem);
+    if (m_pDisplay)
+        XCloseDisplay(m_pDisplay);
+    return VINF_SUCCESS;
+}
+
+/* static */
+int DragAndDropService::hgcmEventThread(RTTHREAD hThread, void *pvUser)
+{
+    AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
+    DragAndDropService *pSrv = static_cast<DragAndDropService*>(pvUser);
+    DnDEvent e;
+    do
+    {
+        RT_ZERO(e);
+        e.type = DnDEvent::HGCM_Type;
+        /* Wait for new events */
+        int rc = VbglR3DnDProcessNextMessage(&e.hgcm);
+        if (RT_SUCCESS(rc))
+        {
+            pSrv->m_eventQueue.append(e);
+            rc = RTSemEventSignal(pSrv->m_hEventSem);
+            if (RT_FAILURE(rc))
+                return rc;
+        }
+    }while(!ASMAtomicReadBool(&pSrv->m_fSrvStopping));
+
+    return VINF_SUCCESS;
+}
+
+/* static */
+int DragAndDropService::x11EventThread(RTTHREAD hThread, void *pvUser)
+{
+    AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
+    DragAndDropService *pSrv = static_cast<DragAndDropService*>(pvUser);
+    DnDEvent e;
+    do
+    {
+        /* Wait for new events. We can't use XIfEvent here, cause this locks
+         * the window connection with a mutex and if no X11 events occurs this
+         * blocks any other calls we made to X11. So instead check for new
+         * events and if there are not any new one, sleep for a certain amount
+         * of time. */
+        if (XEventsQueued(pSrv->m_pDisplay, QueuedAfterFlush) > 0)
+        {
+            RT_ZERO(e);
+            e.type = DnDEvent::X11_Type;
+            XNextEvent(pSrv->m_pDisplay, &e.x11);
+            /* Check for a stop message. */
+//            if (   e.x11.type == ClientMessage
+//                && e.x11.xclient.message_type == xAtom(XA_dndstop))
+//            {
+//                break;
+//            }
+//            if (isDnDRespondEvent(pSrv->m_pDisplay, &e.x11, 0))
+            {
+                /* Appending makes a copy of the event structure. */
+                pSrv->m_eventQueue.append(e);
+                int rc = RTSemEventSignal(pSrv->m_hEventSem);
+                if (RT_FAILURE(rc))
+                    return rc;
+            }
+        }
+        else
+            RTThreadSleep(25);
+    } while(!ASMAtomicReadBool(&pSrv->m_fSrvStopping));
+
+    return VINF_SUCCESS;
+}
+
+/* Static factory */
+VBoxClient::Service *VBoxClient::GetDragAndDropService()
+{
+    return new(DragAndDropService);
+}
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp	(revision 42261)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -189,4 +189,32 @@
             {
                 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(ClipboardMode)(mode));
+            }
+        }
+        else if (!strcmp(a->argv[1], "draganddrop"))
+        {
+            if (a->argc <= 1 + 1)
+            {
+                errorArgument("Missing argument to '%s'. Expected drag'n'drop mode.", a->argv[1]);
+                rc = E_FAIL;
+                break;
+            }
+
+            DragAndDropMode_T mode;
+            if (!strcmp(a->argv[2], "disabled"))
+                mode = DragAndDropMode_Disabled;
+            else if (!strcmp(a->argv[2], "hosttoguest"))
+                mode = DragAndDropMode_HostToGuest;
+            else if (!strcmp(a->argv[2], "guesttohost"))
+                mode = DragAndDropMode_GuestToHost;
+            else if (!strcmp(a->argv[2], "bidirectional"))
+                mode = DragAndDropMode_Bidirectional;
+            else
+            {
+                errorArgument("Invalid '%s' argument '%s'.", a->argv[1], a->argv[2]);
+                rc = E_FAIL;
+            }
+            if (SUCCEEDED(rc))
+            {
+                CHECK_ERROR_BREAK(sessionMachine, COMSETTER(DragAndDropMode)(mode));
             }
         }
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp	(revision 42261)
@@ -305,5 +305,6 @@
                      "                            [--audiocontroller ac97|hda|sb16]\n"
                      "                            [--clipboard disabled|hosttoguest|guesttohost|\n"
-                     "                                         bidirectional]\n");
+                     "                                         bidirectional]\n"
+                     "                            [--draganddrop disabled|hosttoguest\n");
         RTStrmPrintf(pStrm,
                      "                            [--vrde on|off]\n"
@@ -429,4 +430,5 @@
                      "                            clipboard disabled|hosttoguest|guesttohost|\n"
                      "                                         bidirectional]\n"
+                     "                            draganddrop disabled|hosttoguest]\n"
                      "                            vrde on|off |\n"
                      "                            vrdeport <port> |\n"
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 42261)
@@ -1513,4 +1513,46 @@
     }
 
+    /* Drag'n'drop */
+    {
+        const char *psz = "Unknown";
+        DragAndDropMode_T enmMode;
+        rc = machine->COMGETTER(DragAndDropMode)(&enmMode);
+        switch (enmMode)
+        {
+            case DragAndDropMode_Disabled:
+                if (details == VMINFO_MACHINEREADABLE)
+                    psz = "disabled";
+                else
+                    psz = "disabled";
+                break;
+            case DragAndDropMode_HostToGuest:
+                if (details == VMINFO_MACHINEREADABLE)
+                    psz = "hosttoguest";
+                else
+                    psz = "HostToGuest";
+                break;
+            case DragAndDropMode_GuestToHost:
+                if (details == VMINFO_MACHINEREADABLE)
+                    psz = "guesttohost";
+                else
+                    psz = "GuestToHost";
+                break;
+            case DragAndDropMode_Bidirectional:
+                if (details == VMINFO_MACHINEREADABLE)
+                    psz = "bidirectional";
+                else
+                    psz = "Bidirectional";
+                break;
+            default:
+                if (details == VMINFO_MACHINEREADABLE)
+                    psz = "unknown";
+                break;
+        }
+        if (details == VMINFO_MACHINEREADABLE)
+            RTPrintf("draganddrop=\"%s\"\n", psz);
+        else
+            RTPrintf("Drag'n'drop Mode:  %s\n", psz);
+    }
+
     if (console)
     {
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp	(revision 42261)
@@ -140,4 +140,5 @@
     MODIFYVM_AUDIO,
     MODIFYVM_CLIPBOARD,
+    MODIFYVM_DRAGANDDROP,
     MODIFYVM_VRDPPORT,                /* VRDE: deprecated */
     MODIFYVM_VRDPADDRESS,             /* VRDE: deprecated */
@@ -286,4 +287,5 @@
     { "--audio",                    MODIFYVM_AUDIO,                     RTGETOPT_REQ_STRING },
     { "--clipboard",                MODIFYVM_CLIPBOARD,                 RTGETOPT_REQ_STRING },
+    { "--draganddrop",              MODIFYVM_DRAGANDDROP,               RTGETOPT_REQ_STRING },
     { "--vrdpport",                 MODIFYVM_VRDPPORT,                  RTGETOPT_REQ_STRING },     /* deprecated */
     { "--vrdpaddress",              MODIFYVM_VRDPADDRESS,               RTGETOPT_REQ_STRING },     /* deprecated */
@@ -2002,4 +2004,27 @@
             }
 
+            case MODIFYVM_DRAGANDDROP:
+            {
+                DragAndDropMode_T mode;
+                if (!strcmp(ValueUnion.psz, "disabled"))
+                    mode = DragAndDropMode_Disabled;
+                else if (!strcmp(ValueUnion.psz, "hosttoguest"))
+                    mode = DragAndDropMode_HostToGuest;
+                else if (!strcmp(ValueUnion.psz, "guesttohost"))
+                    mode = DragAndDropMode_GuestToHost;
+                else if (!strcmp(ValueUnion.psz, "bidirectional"))
+                    mode = DragAndDropMode_Bidirectional;
+                else
+                {
+                    errorArgument("Invalid --draganddrop argument '%s'", ValueUnion.psz);
+                    rc = E_FAIL;
+                }
+                if (SUCCEEDED(rc))
+                {
+                    CHECK_ERROR(machine, COMSETTER(DragAndDropMode)(mode));
+                }
+                break;
+            }
+
             case MODIFYVM_VRDE_EXTPACK:
             {
Index: /trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk	(revision 42261)
@@ -112,4 +112,5 @@
 	$(if $(VBOX_WITH_EHCI),VBOX_WITH_EHCI) \
 	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP) \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH) \
 	$(if $(VBOX_WITH_CRHGSMI),VBOX_WITH_CRHGSMI) \
 	$(if $(VBOX_WITH_VIRTIO),VBOX_WITH_VIRTIO) \
Index: /trunk/src/VBox/Frontends/VirtualBox/src/VBoxVMInformationDlg.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/VBoxVMInformationDlg.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/VBoxVMInformationDlg.cpp	(revision 42261)
@@ -476,6 +476,6 @@
             resolution += QString ("x%1").arg (bpp);
 
-        QString mode = gpConverter->toString(m.GetClipboardMode());
-
+        QString clipboardMode = gpConverter->toString(m.GetClipboardMode());
+        QString dragAndDropMode = gpConverter->toString(m.GetDragAndDropMode());
 
         CMachineDebugger debugger = console.GetDebugger();
@@ -518,5 +518,6 @@
         result += hdrRow.arg (":/state_running_16px.png").arg (tr ("Runtime Attributes"));
         result += formatValue (tr ("Screen Resolution"), resolution, maxLength);
-        result += formatValue (tr ("Clipboard Mode"), mode, maxLength);
+        result += formatValue (tr ("Clipboard Mode"), clipboardMode, maxLength);
+        result += formatValue (tr ("Drag'n'Drop Mode"), dragAndDropMode, maxLength);
         result += formatValue (VBoxGlobal::tr ("VT-x/AMD-V", "details report"), virtualization, maxLength);
         result += formatValue (VBoxGlobal::tr ("Nested Paging", "details report"), nested, maxLength);
Index: /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackend.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackend.h	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackend.h	(revision 42261)
@@ -55,4 +55,5 @@
 template<> bool canConvert<KDeviceType>();
 template<> bool canConvert<KClipboardMode>();
+template<> bool canConvert<KDragAndDropMode>();
 template<> bool canConvert<KMediumType>();
 template<> bool canConvert<KMediumVariant>();
@@ -82,4 +83,5 @@
 template<> QString toString(const KDeviceType &type);
 template<> QString toString(const KClipboardMode &mode);
+template<> QString toString(const KDragAndDropMode &mode);
 template<> QString toString(const KMediumType &type);
 template<> QString toString(const KMediumVariant &variant);
Index: /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendCOM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendCOM.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendCOM.cpp	(revision 42261)
@@ -34,4 +34,5 @@
 template<> bool canConvert<KDeviceType>() { return true; }
 template<> bool canConvert<KClipboardMode>() { return true; }
+template<> bool canConvert<KDragAndDropMode>() { return true; }
 template<> bool canConvert<KMediumType>() { return true; }
 template<> bool canConvert<KMediumVariant>() { return true; }
@@ -200,4 +201,18 @@
 }
 
+/* QString <= KDragAndDropMode: */
+template<> QString toString(const KDragAndDropMode &mode)
+{
+    switch (mode)
+    {
+        case KDragAndDropMode_Disabled:      return QApplication::translate("VBoxGlobal", "Disabled", "DragAndDropType");
+        case KDragAndDropMode_HostToGuest:   return QApplication::translate("VBoxGlobal", "Host To Guest", "DragAndDropType");
+        case KDragAndDropMode_GuestToHost:   return QApplication::translate("VBoxGlobal", "Guest To Host", "DragAndDropType");
+        case KDragAndDropMode_Bidirectional: return QApplication::translate("VBoxGlobal", "Bidirectional", "DragAndDropType");
+        default: AssertMsgFailed(("No text for %d", mode)); break;
+    }
+    return QString();
+}
+
 /* QString <= KMediumType: */
 template<> QString toString(const KMediumType &type)
Index: /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIListView.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIListView.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIListView.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -99,5 +99,6 @@
         aPainter->drawLine (r.left(), r.top() - 1, r.right(), r.top() - 1);
         aPainter->fillRect (r, linearGrad);
-    }else
+    }
+    else
     {
         /* Color for items and no focus on the application at all */
Index: /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIMessageBox.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIMessageBox.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIMessageBox.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -350,5 +350,6 @@
         int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this);
         return icon.pixmap (size, size);
-    }else
+    }
+    else
         return QPixmap();
 }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QISplitter.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QISplitter.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QISplitter.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -101,5 +101,6 @@
             linearGrad.setColorAt(1, gradientStop);
             painter.fillRect(QRect(QPoint(0,1), size() - QSize(0, 2)), QBrush(linearGrad));
-        }else
+        }
+        else
         {
             painter.setPen(topColor);
@@ -248,5 +249,6 @@
         return new QSplitterHandle(orientation(), this);
 #endif /* RT_OS_DARWIN */
-    }else
+    }
+    else
         return new QIShadeSplitterHandle(orientation(), this);
 }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIStateIndicator.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIStateIndicator.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIStateIndicator.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -137,5 +137,6 @@
         else
             QFrame::mousePressEvent (aEv);
-    }else
+    }
+    else
         QFrame::mousePressEvent (aEv);
 }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -2365,5 +2365,6 @@
                 Error,
                 tr("Failed to open appliance."));
-    }else
+    }
+    else
     {
         /* Preserve the current error info before calling the object again */
@@ -2440,5 +2441,6 @@
                 Error,
                 tr("Failed to create appliance."));
-    }else
+    }
+    else
     {
         /* Preserve the current error info before calling the object again */
@@ -2462,5 +2464,6 @@
                 Error,
                 tr("Failed to create an appliance."));
-    }else
+    }
+    else
     {
         message(pParent ? pParent : mainWindowShown(),
Index: /trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIWindowMenuManager.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIWindowMenuManager.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIWindowMenuManager.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -108,5 +108,6 @@
             if (m_regWindows.contains(pActive->windowTitle()))
                 m_regWindows[pActive->windowTitle()]->setChecked(true);
-        }else
+        }
+        else
         {
             if (QAction *pChecked = m_pGroup->checkedAction())
Index: /trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp	(revision 42261)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -531,5 +531,6 @@
                 break;
             strTarget = QString::fromUtf8(pszPath);
-        }else
+        }
+        else
             strTarget = strFile;
     }while(0);
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp	(revision 42261)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp	(revision 42261)
@@ -0,0 +1,344 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIDnDHandler class implementation
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QApplication>
+#include <QKeyEvent>
+#include <QMimeData>
+#include <QStringList>
+#include <QTimer>
+
+/* GUI includes: */
+#include "UIDnDHandler.h"
+#include "UIMessageCenter.h"
+
+/* COM includes: */
+#include "CSession.h"
+#include "CConsole.h"
+#include "CGuest.h"
+
+UIDnDHandler *UIDnDHandler::m_pInstance = 0;
+
+UIDnDHandler::UIDnDHandler()
+{
+}
+
+/*
+ * Host -> Guest
+ */
+
+Qt::DropAction UIDnDHandler::dragHGEnter(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget * /* pParent = 0 */)
+{
+    /* Ask the guest for starting a DnD event. */
+    KDragAndDropAction result = guest.DragHGEnter(screenId,
+                                                  x,
+                                                  y,
+                                                  toVBoxDnDAction(proposedAction),
+                                                  toVBoxDnDActions(possibleActions),
+                                                  pMimeData->formats().toVector());
+    /* Set the DnD action returned by the guest. */
+    return toQtDnDAction(result);
+}
+
+Qt::DropAction UIDnDHandler::dragHGMove(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget * /* pParent = 0 */)
+{
+    /* Ask the guest for starting a DnD event. */
+    KDragAndDropAction result = guest.DragHGMove(screenId,
+                                                 x,
+                                                 y,
+                                                 toVBoxDnDAction(proposedAction),
+                                                 toVBoxDnDActions(possibleActions),
+                                                 pMimeData->formats().toVector());
+    /* Set the DnD action returned by the guest. */
+    return toQtDnDAction(result);
+}
+
+Qt::DropAction UIDnDHandler::dragHGDrop(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent /* = 0 */)
+{
+    /* The format the guest requests. */
+    QString format;
+    /* Ask the guest for dropping data. */
+    KDragAndDropAction result = guest.DragHGDrop(screenId,
+                                                 x,
+                                                 y,
+                                                 toVBoxDnDAction(proposedAction),
+                                                 toVBoxDnDActions(possibleActions),
+                                                 pMimeData->formats().toVector(), format);
+    /* Has the guest accepted the drop event? */
+    if (result != KDragAndDropAction_Ignore)
+    {
+        /* Get the actually data */
+        const QByteArray &d = pMimeData->data(format);
+        if (   !d.isEmpty()
+            && !format.isEmpty())
+        {
+            /* We need the data in the vector format. */
+            QVector<uint8_t> dv(d.size());
+            memcpy(dv.data(), d.constData(), d.size());
+
+            CProgress progress = guest.DragHGPutData(screenId, format, dv);
+            if (    guest.isOk()
+                && !progress.isNull())
+            {
+                msgCenter().showModalProgressDialog(progress, tr("Dropping data ..."), ":/progress_dnd_hg_90px.png", pParent,  true);
+                if (!progress.GetCanceled() && progress.isOk() && progress.GetResultCode() != 0)
+                {
+                    msgCenter().cannotDropData(progress, pParent);
+                    result = KDragAndDropAction_Ignore;
+                }
+            }
+            else
+            {
+                msgCenter().cannotDropData(guest, pParent);
+                result = KDragAndDropAction_Ignore;
+            }
+        }
+    }
+
+    return toQtDnDAction(result);
+}
+
+void UIDnDHandler::dragHGLeave(CGuest &guest, ulong screenId, QWidget * /* pParent = 0 */)
+{
+    guest.DragHGLeave(screenId);
+}
+
+/*
+ * Guest -> Host
+ */
+
+class UIDnDMimeData: public QMimeData
+{
+    Q_OBJECT;
+
+    enum State
+    {
+        Dragging,
+        Dropped,
+        Finished,
+        Canceled
+    };
+
+public:
+    UIDnDMimeData(CSession &session, QStringList formats, Qt::DropAction defAction, Qt::DropActions actions, QWidget *pParent)
+      : m_pParent(pParent)
+      , m_session(session)
+      , m_formats(formats)
+      , m_defAction(defAction)
+      , m_actions(actions)
+      , m_fState(Dragging)
+    {
+        /* This is unbelievable hacky, but I didn't found another way. Stupid
+         * Qt QDrag interface is so less verbose, that we in principle know
+         * nothing about what happens when the user drag something around. It
+         * is possible that the target request data (s. retrieveData) while the
+         * mouse button is still pressed. This isn't something we can support,
+         * cause it would mean transferring the data from the guest while the
+         * mouse is still moving (thing of a 2GB file ...). So the idea is to
+         * detect the mouse release event and only after this happened, allow
+         * data to be retrieved. Unfortunately the QDrag object eats all events
+         * while a drag is going on (see QDragManager in the Qt src's). So what
+         * we do, is installing an event filter after the QDrag::exec is called
+         * to be last in the event filter queue and therefore called before the
+         * one installed by the QDrag object.
+         *
+         * Todo: test this on all supported platforms (X11 works) */
+        QTimer::singleShot(0, this, SLOT(sltInstallEventFilter()));
+    }
+
+    virtual QStringList formats() const { return m_formats; }
+    virtual bool hasFormat(const QString &mimeType) const { return m_formats.contains(mimeType); }
+
+public slots:
+    void sltActionChanged(Qt::DropAction action) { m_defAction = action; }
+
+protected:
+    virtual QVariant retrieveData(const QString &mimeType, QVariant::Type type) const
+    {
+        /* Mouse button released? */
+        if (m_fState != Dropped)
+            return m_data;
+
+        /* Supported types. See below in the switch statement. */
+        if (!(   type == QVariant::String
+              || type == QVariant::ByteArray))
+            return QVariant();
+
+        CGuest guest = m_session.GetConsole().GetGuest();
+        /* No, 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()
+            && !progress.isNull())
+        {
+            msgCenter().showModalProgressDialog(progress, tr("Dropping data ..."), ":/progress_dnd_gh_90px.png", m_pParent, true);
+            if (!progress.GetCanceled() && progress.isOk() && progress.GetResultCode() != 0)
+                msgCenter().cannotDropData(progress, m_pParent);
+            else if (!progress.GetCanceled())
+            {
+                /* After the data is successfully arrived from the guest, we
+                 * query it from Main. */
+                QVector<uint8_t> data = guest.DragGHGetData();
+                if (!data.isEmpty())
+                {
+//                    printf("qt data (%d, %d, '%s'): %s\n", data.size(), type, qPrintable(mimeType), data.data());
+                    /* Todo: not sure what to add here more: needs more testing. */
+                    switch (type)
+                    {
+                        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;
+                        }
+                        default: break;
+                    }
+                }
+                m_fState = Finished;
+            }
+            if (progress.GetCanceled())
+                m_fState = Canceled;
+        }
+        else
+            msgCenter().cannotDropData(guest, m_pParent);
+        return m_data;
+    }
+
+    bool eventFilter(QObject * /* pObject */, QEvent *pEvent)
+    {
+        switch (pEvent->type())
+        {
+            case QEvent::MouseButtonRelease: m_fState = Dropped; break;
+            case QEvent::KeyPress:
+            {
+                if (static_cast<QKeyEvent*>(pEvent)->key() == Qt::Key_Escape)
+                    m_fState = Canceled;
+                break;
+            }
+        }
+
+        /* Propagate the event further. */
+        return false;
+    }
+
+private slots:
+    void sltInstallEventFilter() { qApp->installEventFilter(this); }
+
+private:
+    /* Private members. */
+    QWidget          *m_pParent;
+    CSession          m_session;
+    QStringList       m_formats;
+    Qt::DropAction    m_defAction;
+    Qt::DropActions   m_actions;
+    mutable State     m_fState;
+    mutable QVariant  m_data;
+};
+
+void UIDnDHandler::dragGHPending(CSession &session, ulong screenId, QWidget *pParent /* = 0 */)
+{
+    /* How does this work: Host is asking the guest if there is any DnD
+     * operation pending, when the mouse leaves the guest window
+     * (DragGHPending). On return there is some info about a running DnD
+     * operation (or defaultAction is KDragAndDropAction_Ignore if not). With
+     * this information we create a Qt QDrag object with our own QMimeType
+     * implementation and call exec. Please note, this *blocks* until the DnD
+     * operation has finished. */
+    CGuest guest = session.GetConsole().GetGuest();
+    QVector<QString> formats;
+    QVector<KDragAndDropAction> actions;
+    KDragAndDropAction defaultAction = guest.DragGHPending(screenId, formats, actions);
+
+    if (    defaultAction != KDragAndDropAction_Ignore
+        && !formats.isEmpty())
+    {
+        QDrag *pDrag = new QDrag(pParent);
+        /* pMData is transfered to the QDrag object, so no need for deletion. */
+        UIDnDMimeData *pMData = new UIDnDMimeData(session, formats.toList(), toQtDnDAction(defaultAction), toQtDnDActions(actions), pParent);
+        /* Inform the mime data object of any changes in the current action. */
+        connect(pDrag, SIGNAL(actionChanged(Qt::DropAction)),
+                pMData, SLOT(sltActionChanged(Qt::DropAction)));
+        pDrag->setMimeData(pMData);
+        /* Fire it up. */
+        pDrag->exec(toQtDnDActions(actions), toQtDnDAction(defaultAction));
+    }
+}
+
+/*
+ * Drag and Drop helper methods
+ */
+
+KDragAndDropAction UIDnDHandler::toVBoxDnDAction(Qt::DropAction action)
+{
+    if (action == Qt::CopyAction)
+        return KDragAndDropAction_Copy;
+    if (action == Qt::MoveAction)
+        return KDragAndDropAction_Move;
+    if (action == Qt::LinkAction)
+        return KDragAndDropAction_Link;
+
+    return KDragAndDropAction_Ignore;
+}
+
+QVector<KDragAndDropAction> UIDnDHandler::toVBoxDnDActions(Qt::DropActions actions)
+{
+    QVector<KDragAndDropAction> vbActions;
+    if (actions.testFlag(Qt::IgnoreAction))
+        vbActions << KDragAndDropAction_Ignore;
+    if (actions.testFlag(Qt::CopyAction))
+        vbActions << KDragAndDropAction_Copy;
+    if (actions.testFlag(Qt::MoveAction))
+        vbActions << KDragAndDropAction_Move;
+    if (actions.testFlag(Qt::LinkAction))
+        vbActions << KDragAndDropAction_Link;
+
+    return vbActions;
+}
+
+Qt::DropAction UIDnDHandler::toQtDnDAction(KDragAndDropAction action)
+{
+    if (action == KDragAndDropAction_Copy)
+        return Qt::CopyAction;
+    if (action == KDragAndDropAction_Move)
+        return Qt::MoveAction;
+    if (action == KDragAndDropAction_Link)
+        return Qt::LinkAction;
+
+    return Qt::IgnoreAction;
+}
+
+Qt::DropActions UIDnDHandler::toQtDnDActions(const QVector<KDragAndDropAction> &actions)
+{
+    Qt::DropActions a = 0;
+    for (int i = 0; i < actions.size(); ++i)
+    {
+        switch (actions.at(i))
+        {
+            case KDragAndDropAction_Ignore: a |= Qt::IgnoreAction; break;
+            case KDragAndDropAction_Copy:   a |= Qt::CopyAction; break;
+            case KDragAndDropAction_Move:   a |= Qt::MoveAction; break;
+            case KDragAndDropAction_Link:   a |= Qt::LinkAction; break;
+        }
+    }
+    return a;
+}
+
+#include "UIDnDHandler.moc"
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp	(revision 42261)
@@ -824,4 +824,5 @@
 
 #ifdef VBOX_WITH_DRAG_AND_DROP
+# ifdef VBOX_WITH_DRAG_AND_DROP_GH
             if (   cpnt.x() < 0
                 || cpnt.x() > iCw - 1
@@ -836,4 +837,5 @@
                 }
             }
+# endif
 #endif /* VBOX_WITH_DRAG_AND_DROP */
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/UIVMListView.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/UIVMListView.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/UIVMListView.cpp	(revision 42261)
@@ -529,10 +529,12 @@
                 pEvent->accept();
             }
-        }else if (   VBoxGlobal::hasAllowedExtension(file, OVFFileExts)
+        }
+        else if (   VBoxGlobal::hasAllowedExtension(file, OVFFileExts)
                   && pEvent->possibleActions().testFlag(Qt::CopyAction))
         {
             pEvent->setDropAction(Qt::CopyAction);
             pEvent->accept();
-        }else if (   VBoxGlobal::hasAllowedExtension(file, VBoxExtPackFileExts)
+        }
+        else if (   VBoxGlobal::hasAllowedExtension(file, VBoxExtPackFileExts)
                   && pEvent->possibleActions().testFlag(Qt::CopyAction))
         {
@@ -934,5 +936,6 @@
                 QFontMetrics fm(fontMetric(aIndex, UIVMItemModel::SnapShotFontRole));
                 return QRect(QPoint(0, 0), fm.size(0, QString("(%1)").arg(text)));
-            }else
+            }
+            else
                 return QRect();
             break;
Index: /trunk/src/VBox/Frontends/VirtualBox/src/settings/VBoxSettingsSelector.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/settings/VBoxSettingsSelector.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/settings/VBoxSettingsSelector.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -438,5 +438,6 @@
         item->setTabWidget (tabWidget);
         result = tabWidget;
-    }else
+    }
+    else
     {
         SelectorActionItem *parent = findActionItem (aParentId);
Index: /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -43,4 +43,10 @@
     mCbClipboard->addItem (""); /* KClipboardMode_GuestToHost */
     mCbClipboard->addItem (""); /* KClipboardMode_Bidirectional */
+
+    /* Drag'n'drop mode */
+    mCbDragAndDrop->addItem (""); /* KDragAndDropMode_Disabled */
+    mCbDragAndDrop->addItem (""); /* KDragAndDropMode_HostToGuest */
+    mCbDragAndDrop->addItem (""); /* KDragAndDropMode_GuestToHost */
+    mCbDragAndDrop->addItem (""); /* KDragAndDropMode_Bidirectional */
 
 #ifdef Q_WS_MAC
@@ -99,4 +105,5 @@
     generalData.m_strSnapshotsHomeDir = QFileInfo(m_machine.GetSettingsFilePath()).absolutePath();
     generalData.m_clipboardMode = m_machine.GetClipboardMode();
+    generalData.m_dragAndDropMode = m_machine.GetDragAndDropMode();
     generalData.m_strDescription = m_machine.GetDescription();
 
@@ -124,4 +131,5 @@
     mPsSnapshot->setHomeDir(generalData.m_strSnapshotsHomeDir);
     mCbClipboard->setCurrentIndex(generalData.m_clipboardMode);
+    mCbDragAndDrop->setCurrentIndex(generalData.m_dragAndDropMode);
     mTeDescription->setPlainText(generalData.m_strDescription);
 
@@ -149,4 +157,5 @@
     generalData.m_strSnapshotsFolder = mPsSnapshot->path();
     generalData.m_clipboardMode = (KClipboardMode)mCbClipboard->currentIndex();
+    generalData.m_dragAndDropMode = (KDragAndDropMode)mCbDragAndDrop->currentIndex();
     generalData.m_strDescription = mTeDescription->toPlainText().isEmpty() ?
                                    QString::null : mTeDescription->toPlainText();
@@ -174,4 +183,5 @@
             /* Advanced tab: */
             m_machine.SetClipboardMode(generalData.m_clipboardMode);
+            m_machine.SetDragAndDropMode(generalData.m_dragAndDropMode);
             m_machine.SetExtraData(GUI_SaveMountedAtRuntime, generalData.m_fSaveMountedAtRuntime ? "yes" : "no");
             m_machine.SetExtraData(GUI_ShowMiniToolBar, generalData.m_fShowMiniToolBar ? "yes" : "no");
@@ -221,5 +231,6 @@
     setTabOrder (m_pNameAndSystemEditor, mPsSnapshot);
     setTabOrder (mPsSnapshot, mCbClipboard);
-    setTabOrder (mCbClipboard, mCbSaveMounted);
+    setTabOrder (mCbClipboard, mCbDragAndDrop);
+    setTabOrder (mCbDragAndDrop, mCbSaveMounted);
     setTabOrder (mCbSaveMounted, mCbShowToolBar);
     setTabOrder (mCbShowToolBar, mCbToolBarAlignment);
@@ -245,4 +256,10 @@
     mCbClipboard->setItemText (2, gpConverter->toString (KClipboardMode_GuestToHost));
     mCbClipboard->setItemText (3, gpConverter->toString (KClipboardMode_Bidirectional));
+
+    /* Drag'n'drop mode */
+    mCbDragAndDrop->setItemText (0, gpConverter->toString (KDragAndDropMode_Disabled));
+    mCbDragAndDrop->setItemText (1, gpConverter->toString (KDragAndDropMode_HostToGuest));
+    mCbDragAndDrop->setItemText (2, gpConverter->toString (KDragAndDropMode_GuestToHost));
+    mCbDragAndDrop->setItemText (3, gpConverter->toString (KDragAndDropMode_Bidirectional));
 }
 
@@ -256,4 +273,6 @@
     mLbClipboard->setEnabled(isMachineInValidMode());
     mCbClipboard->setEnabled(isMachineInValidMode());
+    mLbDragAndDrop->setEnabled(isMachineInValidMode());
+    mCbDragAndDrop->setEnabled(isMachineInValidMode());
     mLbMedia->setEnabled(isMachineInValidMode());
     mCbSaveMounted->setEnabled(isMachineInValidMode());
Index: /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.h	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.h	(revision 42261)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -37,4 +37,5 @@
         , m_strSnapshotsHomeDir(QString())
         , m_clipboardMode(KClipboardMode_Disabled)
+        , m_dragAndDropMode(KDragAndDropMode_Disabled)
         , m_strDescription(QString()) {}
     /* Functions: */
@@ -49,4 +50,5 @@
                (m_strSnapshotsHomeDir == other.m_strSnapshotsHomeDir) &&
                (m_clipboardMode == other.m_clipboardMode) &&
+               (m_dragAndDropMode == other.m_dragAndDropMode) &&
                (m_strDescription == other.m_strDescription);
     }
@@ -63,4 +65,5 @@
     QString m_strSnapshotsHomeDir;
     KClipboardMode m_clipboardMode;
+    KDragAndDropMode m_dragAndDropMode;
     QString m_strDescription;
 };
Index: /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.ui
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.ui	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.ui	(revision 42261)
@@ -3,5 +3,5 @@
  VBox frontends: Qt4 GUI ("VirtualBox"):
 
-     Copyright (C) 2008 Oracle Corporation
+     Copyright (C) 2008-2012 Oracle Corporation
 
      This file is part of VirtualBox Open Source Edition (OSE), as
@@ -132,4 +132,43 @@
           </item>
           <item row="2" column="0" >
+           <widget class="QLabel" name="mLbDragAndDrop" >
+            <property name="text" >
+             <string>&amp;Drag'n'Drop:</string>
+            </property>
+            <property name="alignment" >
+             <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+            </property>
+            <property name="buddy" >
+             <cstring>mCbDragAndDrop</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="1" >
+           <widget class="QComboBox" name="mCbDragAndDrop" >
+            <property name="sizePolicy" >
+             <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="whatsThis" >
+                <string>Selects which data will be copied between the guest and the host OS by drag'n'drop. This feature requires Guest Additions to be installed in the guest OS.</string>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="2" >
+           <spacer name="mSpHor2" >
+            <property name="orientation" >
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0" >
+             <size>
+              <width>0</width>
+              <height>0</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item row="3" column="0" >
            <widget class="QLabel" name="mLbMedia" >
             <property name="text" >
@@ -141,5 +180,5 @@
            </widget>
           </item>
-          <item row="2" column="1" >
+          <item row="3" column="1" >
            <widget class="QCheckBox" name="mCbSaveMounted" >
             <property name="sizePolicy" >
@@ -160,5 +199,5 @@
            </widget>
           </item>
-          <item row="3" column="0" >
+          <item row="4" column="0" >
            <widget class="QLabel" name="mLbToolBar" >
             <property name="text" >
@@ -170,5 +209,5 @@
            </widget>
           </item>
-          <item row="3" column="1" >
+          <item row="4" column="1" >
            <widget class="QCheckBox" name="mCbShowToolBar" >
             <property name="sizePolicy" >
@@ -189,5 +228,5 @@
            </widget>
           </item>
-          <item row="4" column="1" >
+          <item row="5" column="1" >
            <widget class="QCheckBox" name="mCbToolBarAlignment" >
             <property name="sizePolicy" >
@@ -212,5 +251,5 @@
        </item>
        <item>
-        <spacer name="mSpVer2" >
+        <spacer name="mSpVer3" >
          <property name="orientation" >
           <enum>Qt::Vertical</enum>
Index: /trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIProgressDialog.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIProgressDialog.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIProgressDialog.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -277,5 +277,6 @@
         }
         m_progressBar->setValue(m_progress.GetPercent());
-    }else
+    }
+    else
         m_pEtaLbl->setText(m_strCancel);
 }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/widgets/VBoxFilePathSelectorWidget.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/widgets/VBoxFilePathSelectorWidget.cpp	(revision 42260)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/widgets/VBoxFilePathSelectorWidget.cpp	(revision 42261)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -131,5 +131,6 @@
         /* Installing necessary event filters */
         lineEdit()->installEventFilter (this);
-    }else
+    }
+    else
     {
         if (lineEdit())
Index: /trunk/src/VBox/HostServices/DragAndDrop/Makefile.kmk
===================================================================
--- /trunk/src/VBox/HostServices/DragAndDrop/Makefile.kmk	(revision 42261)
+++ /trunk/src/VBox/HostServices/DragAndDrop/Makefile.kmk	(revision 42261)
@@ -0,0 +1,50 @@
+# $Id$
+## @file
+# Sub-Makefile for the Guest Control Host Service.
+#
+
+#
+# Copyright (C) 2011-2012 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# Include sub-makefile(s).
+# include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
+
+#
+# The drag and drop service DLL.
+#
+DLLS += VBoxDragAndDropSvc
+VBoxDragAndDropSvc_TEMPLATE  = VBOXR3
+VBoxDragAndDropSvc_NAME.os2  = VBoxDnD
+VBoxDragAndDropSvc_DEFS      = \
+	VBOX_WITH_HGCM \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
+VBoxDragAndDropSvc_INCS      = $(PATH_ROOT)/src/VBox/Main/include ./
+VBoxDragAndDropSvc_INCS.win  = \
+	$(PATH_TOOL_$(VBOX_VCC_TOOL)_ATLMFC_INC) \
+	$(VBOX_PATH_SDK)
+
+VBoxDragAndDropSvc_SOURCES = \
+	service.cpp \
+	dndmanager.cpp
+
+VBoxDragAndDropSvc_LIBS = \
+	$(LIB_VMM) \
+	$(LIB_RUNTIME) \
+	$(LIB_REM)
+
+VBoxDragAndDropSvc_LDFLAGS.darwin = \
+	-install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxDragAndDropSvc.dylib
+
+include $(FILE_KBUILD_SUB_FOOTER)
Index: /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp
===================================================================
--- /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp	(revision 42261)
+++ /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp	(revision 42261)
@@ -0,0 +1,762 @@
+/* $Id$ */
+/** @file
+ * Drag and Drop manager.
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/******************************************************************************
+ *   Header Files                                                             *
+ ******************************************************************************/
+
+#define LOG_GROUP LOG_GROUP_HGCM
+
+#include "dndmanager.h"
+
+#include <VBox/log.h>
+#include <iprt/file.h>
+#include <iprt/dir.h>
+#include <iprt/path.h>
+#include <iprt/uri.h>
+
+#define VERBOSE 1
+
+#if defined(VERBOSE) && defined(DEBUG_poetzsch)
+# include <iprt/stream.h>
+# define DO(s) RTPrintf s
+#else
+# define DO(s) do {} while(0)
+//# define DO(s) Log s
+#endif
+
+/******************************************************************************
+ *   Private declarations                                                     *
+ ******************************************************************************/
+
+typedef DECLCALLBACK(int) FNDNDPRIVATEPROGRESS(size_t cbDone, void *pvUser);
+typedef FNDNDPRIVATEPROGRESS *PFNDNDPRIVATEPROGRESS;
+
+/**
+ * Internal DnD message class for informing the guest about a new directory.
+ *
+ * @see DnDHGSendDataMessage
+ */
+class DnDHGSendDirPrivate: public DnDMessage
+{
+public:
+    DnDHGSendDirPrivate(const RTCString &strPath, uint32_t fMode, uint64_t cbSize, PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
+      : m_strPath(strPath)
+      , m_cbSize(cbSize)
+      , m_pfnProgressCallback(pfnProgressCallback)
+      , m_pvProgressUser(pvProgressUser)
+    {
+        VBOXHGCMSVCPARM paTmpParms[3];
+        paTmpParms[0].setString(m_strPath.c_str());
+        paTmpParms[1].setUInt32(m_strPath.length() + 1);
+        paTmpParms[2].setUInt32(fMode);
+        m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_DIR, 3, paTmpParms);
+    }
+
+    int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+    {
+        int rc = DnDMessage::currentMessage(uMsg, cParms, paParms);
+        /* Advance progress info */
+        if (   RT_SUCCESS(rc)
+            && m_pfnProgressCallback)
+            rc = m_pfnProgressCallback(m_cbSize, m_pvProgressUser);
+
+        return rc;
+    }
+
+protected:
+    RTCString m_strPath;
+
+    /* Progress stuff */
+    size_t                 m_cbSize;
+    PFNDNDPRIVATEPROGRESS  m_pfnProgressCallback;
+    void                  *m_pvProgressUser;
+};
+
+/**
+ * Internal DnD message class for informing the guest about a new file.
+ *
+ * @see DnDHGSendDataMessage
+ */
+class DnDHGSendFilePrivate: public DnDMessage
+{
+public:
+    DnDHGSendFilePrivate(const RTCString &strHostPath, const RTCString &strGuestPath, uint32_t fMode, uint64_t cbSize, PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
+    ~DnDHGSendFilePrivate();
+
+    int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+
+protected:
+    RTCString              m_strHostPath;
+    RTCString              m_strGuestPath;
+    uint64_t               m_cbSize;
+    uint64_t               m_cbDone;
+    RTFILE                 m_hCurFile;
+    VBOXHGCMSVCPARM        m_paSkelParms[5];
+
+    /* Progress stuff */
+    PFNDNDPRIVATEPROGRESS  m_pfnProgressCallback;
+    void                  *m_pvProgressUser;
+};
+
+/**
+ * Internal DnD message class for informing the guest about new drag & drop
+ * data.
+ *
+ * @see DnDHGSendDataMessage
+ */
+class DnDHGSendDataMessagePrivate: public DnDMessage
+{
+public:
+    DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
+    int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+
+protected:
+    size_t                 m_cbSize;
+    size_t                 m_cbDone;
+
+    /* Progress stuff */
+    PFNDNDPRIVATEPROGRESS  m_pfnProgressCallback;
+    void                  *m_pvProgressUser;
+};
+
+/******************************************************************************
+ *   Implementation                                                           *
+ ******************************************************************************/
+
+/******************************************************************************
+ *   DnDHGSendFilePrivate                                                *
+ ******************************************************************************/
+
+DnDHGSendFilePrivate::DnDHGSendFilePrivate(const RTCString &strHostPath, const RTCString &strGuestPath, uint32_t fMode, uint64_t cbSize, PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
+  : m_strHostPath(strHostPath)
+  , m_strGuestPath(strGuestPath)
+  , m_cbSize(cbSize)
+  , m_cbDone(0)
+  , m_hCurFile(0)
+  , m_pfnProgressCallback(pfnProgressCallback)
+  , m_pvProgressUser(pvProgressUser)
+{
+    m_paSkelParms[0].setString(m_strGuestPath.c_str());
+    m_paSkelParms[1].setUInt32(m_strGuestPath.length() + 1);
+    m_paSkelParms[2].setPointer(NULL, 0);
+    m_paSkelParms[3].setUInt32(0);
+    m_paSkelParms[4].setUInt32(fMode);
+    m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5, m_paSkelParms);
+}
+
+DnDHGSendFilePrivate::~DnDHGSendFilePrivate()
+{
+    if (m_hCurFile)
+        RTFileClose(m_hCurFile);
+}
+
+int DnDHGSendFilePrivate::currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    if (!m_pNextMsg)
+        return VERR_NO_DATA;
+
+    int rc = m_pNextMsg->getData(uMsg, cParms, paParms);
+    clearNextMsg();
+    if (RT_FAILURE(rc))
+        return rc;
+
+    if (!m_hCurFile)
+    {
+        rc = RTFileOpen(&m_hCurFile, m_strHostPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_ALL);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    /* How big is the pointer provided by the guest? */
+    uint32_t cbToRead = paParms[2].u.pointer.size;
+    size_t cbRead;
+    rc = RTFileRead(m_hCurFile, paParms[2].u.pointer.addr, cbToRead, &cbRead);
+    if (RT_FAILURE(rc))
+    {
+        /* On error, immediately close the file. */
+        RTFileClose(m_hCurFile);
+        m_hCurFile = 0;
+        return rc;
+    }
+    m_cbDone += cbRead;
+    /* Tell the guest the actual size. */
+    paParms[3].setUInt32(cbRead);
+    /* Check if we are done. */
+    if (m_cbSize == m_cbDone)
+    {
+        RTFileClose(m_hCurFile);
+        m_hCurFile = 0;
+    }
+    else
+    {
+        /* More data! Prepare the next message. */
+        m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5, m_paSkelParms);
+    }
+
+    /* Advance progress info */
+    if (   RT_SUCCESS(rc)
+        && m_pfnProgressCallback)
+        rc = m_pfnProgressCallback(cbRead, m_pvProgressUser);
+
+    return rc;
+}
+
+/******************************************************************************
+ *   DnDHGSendDataMessagePrivate                                                *
+ ******************************************************************************/
+
+DnDHGSendDataMessagePrivate::DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
+  : m_cbSize(paParms[4].u.uint32)
+  , m_cbDone(0)
+  , m_pfnProgressCallback(pfnProgressCallback)
+  , m_pvProgressUser(pvProgressUser)
+{
+    /* Create the initial data message. */
+    m_pNextMsg = new HGCM::Message(uMsg, cParms, paParms);
+}
+
+int DnDHGSendDataMessagePrivate::currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    /* Todo: don't copy the data parts ... just move the data pointer in
+     * the original data ptr. */
+    if (!m_pNextMsg)
+        return VERR_NO_DATA;
+
+    int rc = VINF_SUCCESS;
+
+    HGCM::Message *pCurMsg = m_pNextMsg;
+    m_pNextMsg = 0;
+    rc = pCurMsg->getData(uMsg, cParms, paParms);
+    /* Depending on the current message, the data pointer is on a
+     * different position (HOST_DND_HG_SND_DATA=3;
+     * HOST_DND_HG_SND_MORE_DATA=0). */
+    int iPos = uMsg == DragAndDropSvc::HOST_DND_HG_SND_DATA ? 3 : 0;
+    m_cbDone += paParms[iPos + 1].u.uint32;
+    /* Info & data send already? */
+    if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        paParms[iPos + 1].u.uint32 = paParms[iPos].u.pointer.size;
+        VBOXHGCMSVCPARM paTmpParms[2];
+        void     *pvOldData;
+        uint32_t  cOldData;
+        pCurMsg->getParmPtrInfo(iPos, &pvOldData, &cOldData);
+        paTmpParms[0].setPointer(static_cast<uint8_t*>(pvOldData) + paParms[iPos].u.pointer.size, cOldData - paParms[iPos].u.pointer.size);
+        paTmpParms[1].setUInt32(cOldData - paParms[iPos].u.pointer.size);
+        m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA, 2, paTmpParms);
+    }
+    delete pCurMsg;
+
+    /* Advance progress info */
+    if (   RT_SUCCESS(rc)
+        && m_pfnProgressCallback)
+        rc = m_pfnProgressCallback(m_cbDone, m_pvProgressUser);
+
+    return rc;
+}
+
+/******************************************************************************
+ *   DnDHGSendDataMessage                                                       *
+ ******************************************************************************/
+
+/*
+ * This class is a meta message class. It doesn't consist of any own message
+ * data, but handle the meta info, the data itself as well any files or
+ * directories which have to be transfered to the guest.
+ */
+DnDHGSendDataMessage::DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser)
+  : m_cbAll(0)
+  , m_cbTransfered(0)
+  , m_pfnProgressCallback(pfnProgressCallback)
+  , m_pvProgressUser(pvProgressUser)
+{
+    RTCString strNewUris;
+    /* Check the format for any uri type. */
+    if (hasFileUrls(static_cast<const char*>(paParms[1].u.pointer.addr), paParms[1].u.pointer.size))
+    {
+        DO(("old data '%s'\n", (char*)paParms[3].u.pointer.addr));
+        /* The list is separated by newline (Even if only one file is
+         * listed). */
+        RTCList<RTCString> oldUriList = RTCString(static_cast<const char*>(paParms[3].u.pointer.addr), paParms[3].u.pointer.size).split("\r\n");
+        if (!oldUriList.isEmpty())
+        {
+            RTCList<RTCString> newUriList;
+            for (size_t i = 0; i < oldUriList.size(); ++i)
+            {
+                const RTCString &strUri = oldUriList.at(i);
+                /* Query the path component of a file URI. If this hasn't a
+                 * file scheme null is returned. */
+                if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO))
+                {
+                    /* Add the path to our internal file list (recursive in
+                     * the case of a directory). */
+                    if (char *pszFilename = RTPathFilename(pszFilePath))
+                    {
+                        char *pszNewUri = RTUriFileCreate(pszFilename);
+                        if (pszNewUri)
+                        {
+                            newUriList.append(pszNewUri);
+                            RTStrFree(pszNewUri);
+                            buildFileTree(pszFilePath, pszFilename - pszFilePath);
+                        }
+                    }
+                    RTStrFree(pszFilePath);
+                }
+                else
+                    newUriList.append(strUri);
+            }
+            /* We have to change the actual DnD data. Remove any host paths and
+             * just decode the filename into the new data. The guest tools will
+             * add the correct path again, before sending the DnD drop event to
+             * some window. */
+            strNewUris = RTCString::join(newUriList, "\r\n") + "\r\n";
+            /* Remark: We don't delete the old pointer here, cause this is done
+             * by the caller. We just use the RTString data, which has the
+             * scope of this ctor. This is enough cause the data is copied in
+             * the DnDHGSendDataMessagePrivate anyway. */
+            paParms[3].u.pointer.addr = (void*)strNewUris.c_str();
+            paParms[3].u.pointer.size = strNewUris.length() + 1;
+            paParms[4].u.uint32       = strNewUris.length() + 1;
+        }
+    }
+    /* Add the size of the data to the todo list. */
+    m_cbAll += paParms[4].u.uint32;
+    /* The first message is the meta info for the data and the data itself. */
+    m_pNextPathMsg = new DnDHGSendDataMessagePrivate(uMsg, cParms, paParms, &DnDHGSendDataMessage::progressCallback, this);
+
+    DO(("new data '%s'\n", (char*)paParms[3].u.pointer.addr));
+    DO(("cbAll: %u\n", m_cbAll));
+    DO(("cbData: %u\n", paParms[4].u.uint32));
+
+    for (size_t i = 0; i < m_uriList.size(); ++i)
+        DO(("file: %s : %s - %o - %ld\n", m_uriList.at(i).m_strHostPath.c_str(), m_uriList.at(i).m_strGuestPath.c_str(), m_uriList.at(i).m_fMode, m_uriList.at(i).m_cbSize));
+}
+
+DnDHGSendDataMessage::~DnDHGSendDataMessage()
+{
+    if (m_pNextPathMsg)
+        delete m_pNextPathMsg;
+}
+
+HGCM::Message* DnDHGSendDataMessage::nextHGCMMessage()
+{
+    if (!m_pNextPathMsg)
+        return NULL;
+
+    return m_pNextPathMsg->nextHGCMMessage();
+}
+
+int DnDHGSendDataMessage::currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
+{
+    if (!m_pNextPathMsg)
+        return VERR_NO_DATA;
+
+    return m_pNextPathMsg->currentMessageInfo(puMsg, pcParms);
+}
+
+int DnDHGSendDataMessage::currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    if (!m_pNextPathMsg)
+        return VERR_NO_DATA;
+
+    /* Fill the data out of our current queued message. */
+    int rc = m_pNextPathMsg->currentMessage(uMsg, cParms, paParms);
+    /* Has this message more data to deliver? */
+    if (!m_pNextPathMsg->isMessageWaiting())
+    {
+        delete m_pNextPathMsg;
+        m_pNextPathMsg = NULL;
+    }
+
+    /* File data to send? */
+    if (!m_pNextPathMsg)
+    {
+        if (m_uriList.isEmpty())
+            return rc;
+        /* Create new messages based on our internal path list. Currently
+         * this could be directories or regular files. */
+        PathEntry nextPath = m_uriList.first();
+        if (RTFS_IS_DIRECTORY(nextPath.m_fMode))
+            m_pNextPathMsg = new DnDHGSendDirPrivate(nextPath.m_strGuestPath, nextPath.m_fMode, nextPath.m_cbSize, &DnDHGSendDataMessage::progressCallback, this);
+        else if (RTFS_IS_FILE(nextPath.m_fMode))
+            m_pNextPathMsg = new DnDHGSendFilePrivate(nextPath.m_strHostPath, nextPath.m_strGuestPath, nextPath.m_fMode, nextPath.m_cbSize, &DnDHGSendDataMessage::progressCallback, this);
+        else
+            AssertMsgFailedReturn(("type '%d' is not supported for path '%s'", nextPath.m_fMode, nextPath.m_strHostPath.c_str()), VERR_NO_DATA);
+        m_uriList.removeFirst();
+    }
+    return rc;
+}
+
+bool DnDHGSendDataMessage::hasFileUrls(const char *pcszFormat, size_t cbMax) const
+{
+    DO(("format %s\n", pcszFormat));
+    /* text/uri also an official variant? */
+    return    RTStrNICmp(pcszFormat, "text/uri-list", cbMax)             == 0
+           || RTStrNICmp(pcszFormat, "x-special/gnome-icon-list", cbMax) == 0;
+}
+
+int DnDHGSendDataMessage::buildFileTree(const char *pcszPath, size_t cbBaseLen)
+{
+    RTFSOBJINFO objInfo;
+    int rc = RTPathQueryInfo(pcszPath, &objInfo, RTFSOBJATTRADD_NOTHING);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /* These are the types we currently support. Symlinks are not directly
+     * supported. First the guest could be an OS which doesn't support it and
+     * second the symlink could point to a file which is out of the base tree.
+     * Both things are hard to support. For now we just copy the target file in
+     * this case. */
+    if (!(   RTFS_IS_DIRECTORY(objInfo.Attr.fMode)
+          || RTFS_IS_FILE(objInfo.Attr.fMode)
+          || RTFS_IS_SYMLINK(objInfo.Attr.fMode)))
+        return VINF_SUCCESS;
+
+    uint64_t cbSize = 0;
+    rc = RTFileQuerySize(pcszPath, &cbSize);
+    if (rc == VERR_IS_A_DIRECTORY)
+        rc = VINF_SUCCESS;
+    if (RT_FAILURE(rc))
+        return rc;
+    m_uriList.append(PathEntry(pcszPath, &pcszPath[cbBaseLen], objInfo.Attr.fMode, cbSize));
+    m_cbAll += cbSize;
+    DO(("cbFile: %u\n", cbSize));
+
+    PRTDIR hDir;
+    /* We have to try to open even symlinks, cause they could be symlinks
+     * to directories. */
+    rc = RTDirOpen(&hDir, pcszPath);
+    /* The following error happens when this was a symlink to an file or a
+     * regular file. */
+    if (rc == VERR_PATH_NOT_FOUND)
+        return VINF_SUCCESS;
+    if (RT_FAILURE(rc))
+        return rc;
+
+    while (RT_SUCCESS(rc))
+    {
+        RTDIRENTRY DirEntry;
+        rc = RTDirRead(hDir, &DirEntry, NULL);
+        if (RT_FAILURE(rc))
+        {
+            if (rc == VERR_NO_MORE_FILES)
+                rc = VINF_SUCCESS;
+            break;
+        }
+        switch (DirEntry.enmType)
+        {
+            case RTDIRENTRYTYPE_DIRECTORY:
+            {
+                /* Skip "." and ".." entries. */
+                if (   RTStrCmp(DirEntry.szName, ".")  == 0
+                    || RTStrCmp(DirEntry.szName, "..") == 0)
+                    break;
+                if (char *pszRecDir = RTStrAPrintf2("%s%c%s", pcszPath, RTPATH_DELIMITER, DirEntry.szName))
+                {
+                    rc = buildFileTree(pszRecDir, cbBaseLen);
+                    RTStrFree(pszRecDir);
+                }
+                else
+                    rc = VERR_NO_MEMORY;
+                break;
+            }
+            case RTDIRENTRYTYPE_SYMLINK:
+            case RTDIRENTRYTYPE_FILE:
+            {
+                if (char *pszNewFile = RTStrAPrintf2("%s%c%s", pcszPath, RTPATH_DELIMITER, DirEntry.szName))
+                {
+                    /* We need the size and the mode of the file. */
+                    RTFSOBJINFO objInfo1;
+                    rc = RTPathQueryInfo(pszNewFile, &objInfo1, RTFSOBJATTRADD_NOTHING);
+                    if (RT_FAILURE(rc))
+                        return rc;
+                    rc = RTFileQuerySize(pszNewFile, &cbSize);
+                    if (RT_FAILURE(rc))
+                        break;
+                    m_uriList.append(PathEntry(pszNewFile, &pszNewFile[cbBaseLen], objInfo1.Attr.fMode, cbSize));
+                    m_cbAll += cbSize;
+                    RTStrFree(pszNewFile);
+                }
+                else
+                    rc = VERR_NO_MEMORY;
+                break;
+            }
+            default: break;
+        }
+    }
+    RTDirClose(hDir);
+
+    return rc;
+}
+
+int DnDHGSendDataMessage::progressCallback(size_t cbDone, void *pvUser)
+{
+    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
+
+    DnDHGSendDataMessage *pSelf = static_cast<DnDHGSendDataMessage *>(pvUser);
+
+    /* How many bytes are transfered already. */
+    pSelf->m_cbTransfered += cbDone;
+
+    /* Advance progress info */
+    if (pSelf->m_pfnProgressCallback)
+        return pSelf->m_pfnProgressCallback(100.0 / pSelf->m_cbAll * pSelf->m_cbTransfered, DragAndDropSvc::DND_PROGRESS_RUNNING, pSelf->m_pvProgressUser);
+    else
+        return VINF_SUCCESS;
+}
+
+/******************************************************************************
+ *   DnDManager                                                               *
+ ******************************************************************************/
+
+int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    int rc = VINF_SUCCESS;
+    switch (uMsg)
+    {
+        case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
+        {
+            clear();
+            LogFlowFunc(("HOST_DND_HG_EVT_ENTER\n"));
+            DO(("HOST_DND_HG_EVT_ENTER\n"));
+            /* Verify parameter count and types. */
+            if (   cParms != 7
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
+                || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
+                || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
+                || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
+                || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
+                || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                m_fOpInProcess = true;
+                DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
+                m_dndMessageQueue.append(pMessage);
+            }
+            break;
+        }
+        case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
+        {
+            LogFlowFunc(("HOST_DND_HG_EVT_MOVE\n"));
+            DO(("HOST_DND_HG_EVT_MOVE\n"));
+            /* Verify parameter count and types. */
+            if (   cParms != 7
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
+                || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
+                || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
+                || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
+                || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
+                || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                m_fOpInProcess = true;
+                DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
+                m_dndMessageQueue.append(pMessage);
+            }
+            break;
+        }
+        case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
+        {
+            LogFlowFunc(("HOST_DND_HG_EVT_LEAVE\n"));
+            DO(("HOST_DND_HG_EVT_LEAVE\n"));
+
+            /* Verify parameter count and types. */
+            if (cParms != 0)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
+                m_dndMessageQueue.append(pMessage);
+            }
+            m_fOpInProcess = false;
+            break;
+        }
+        case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+        {
+            LogFlowFunc(("HOST_DND_HG_EVT_DROPPED\n"));
+            DO(("HOST_DND_HG_EVT_DROPPED\n"));
+            /* Verify parameter count and types. */
+            if (   cParms != 7
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
+                || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
+                || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
+                || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
+                || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
+                || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
+                m_dndMessageQueue.append(pMessage);
+            }
+            break;
+        }
+        case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+        {
+            LogFlowFunc(("HOST_DND_HG_SND_DATA\n"));
+            DO(("HOST_DND_HG_SND_DATA\n"));
+
+            /* Verify parameter count and types. */
+            if (   cParms != 5
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* format */
+                || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
+                || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
+                || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* data size */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DnDHGSendDataMessage *pMessage = new DnDHGSendDataMessage(uMsg, cParms, paParms, m_pfnProgressCallback, m_pvProgressUser);
+                m_dndMessageQueue.append(pMessage);
+            }
+            break;
+        }
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+        case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
+        {
+            LogFlowFunc(("HOST_DND_GH_REQ_PENDING\n"));
+            DO(("HOST_DND_GH_REQ_PENDING\n"));
+
+            /* Verify parameter count and types. */
+            if (   cParms != 1
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
+                m_dndMessageQueue.append(pMessage);
+            }
+            break;
+        }
+        case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+        {
+            LogFlowFunc(("HOST_DND_GH_EVT_DROPPED\n"));
+            DO(("HOST_DND_GH_EVT_DROPPED\n"));
+
+            /* Verify parameter count and types. */
+            if (   cParms != 3
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* format */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
+                || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
+                m_dndMessageQueue.append(pMessage);
+            }
+            break;
+        }
+#endif
+        default: rc = VERR_NOT_IMPLEMENTED; break;
+    }
+
+    return rc;
+}
+
+HGCM::Message* DnDManager::nextHGCMMessage()
+{
+    if (m_pCurMsg)
+        return m_pCurMsg->nextHGCMMessage();
+    else
+    {
+        if (m_dndMessageQueue.isEmpty())
+            return 0;
+
+        return m_dndMessageQueue.first()->nextHGCMMessage();
+    }
+}
+
+int DnDManager::nextMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
+{
+    AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
+    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
+
+    int rc = VINF_SUCCESS;
+
+    if (m_pCurMsg)
+        rc = m_pCurMsg->currentMessageInfo(puMsg, pcParms);
+    else
+    {
+        if (m_dndMessageQueue.isEmpty())
+        {
+            rc = VERR_NO_DATA;
+//            if (m_pfnProgressCallback)
+//                m_pfnProgressCallback(100.0, DragAndDropSvc::DND_OP_CANCELLED, m_pvProgressUser);
+        }
+        else
+            rc = m_dndMessageQueue.first()->currentMessageInfo(puMsg, pcParms);
+    }
+
+    DO(("next msg info: %d %d %Rrc\n", *puMsg, *pcParms, rc));
+    return rc;
+}
+
+int DnDManager::nextMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    if (!m_pCurMsg)
+    {
+        /* Check for pending messages in our queue. */
+        if (m_dndMessageQueue.isEmpty())
+            return VERR_NO_DATA;
+        m_pCurMsg = m_dndMessageQueue.first();
+        m_dndMessageQueue.removeFirst();
+    }
+
+    /* Fetch the current message info */
+    int rc = m_pCurMsg->currentMessage(uMsg, cParms, paParms);
+    /* If this message not provide any additional sub messages, clear it. */
+    if (!m_pCurMsg->isMessageWaiting())
+    {
+        delete m_pCurMsg;
+        m_pCurMsg = 0;
+    }
+
+    /* If the user has canceled the operation, we need to cleanup all pending
+     * events and inform the progress callback about our successful cleanup. */
+    if (   rc == VERR_CANCELLED
+        && m_pfnProgressCallback)
+    {
+        /* Clear any pending messages */
+        clear();
+        /* Create a new cancel message to inform the guest. */
+        m_pCurMsg = new DnDHGCancelMessage();
+        m_pfnProgressCallback(100.0, DragAndDropSvc::DND_PROGRESS_CANCELLED, m_pvProgressUser);
+    }
+
+    DO(("next msg: %d %d %Rrc\n", uMsg, cParms, rc));
+    return rc;
+}
+
+void DnDManager::clear()
+{
+    if (m_pCurMsg)
+    {
+        delete m_pCurMsg;
+        m_pCurMsg = 0;
+    }
+    while (!m_dndMessageQueue.isEmpty())
+    {
+        delete m_dndMessageQueue.last();
+        m_dndMessageQueue.removeLast();
+    }
+}
+
Index: /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.h
===================================================================
--- /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.h	(revision 42261)
+++ /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.h	(revision 42261)
@@ -0,0 +1,197 @@
+/** @file
+ * Drag and Drop manager.
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___VBox_HostService_DnD_dndmanager_h
+#define ___VBox_HostService_DnD_dndmanager_h
+
+#include <VBox/HostServices/Service.h>
+#include <VBox/HostServices/DragAndDropSvc.h>
+
+#include <iprt/cpp/ministring.h>
+#include <iprt/cpp/list.h>
+
+typedef DECLCALLBACK(int) FNDNDPROGRESS(unsigned uPercentage, uint32_t uState, void *pvUser);
+typedef FNDNDPROGRESS *PFNDNDPROGRESS;
+
+/**
+ * DnD message class. This class forms the base of all other more specialized
+ * message classes.
+ */
+class DnDMessage
+{
+public:
+    DnDMessage()
+      : m_pNextMsg(NULL)
+    {
+    }
+    virtual ~DnDMessage()
+    {
+        clearNextMsg();
+    }
+
+    virtual HGCM::Message* nextHGCMMessage()
+    {
+        return m_pNextMsg;
+    }
+    virtual int currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
+    {
+        AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
+        AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
+
+        if (!m_pNextMsg)
+            return VERR_NO_DATA;
+
+        *puMsg = m_pNextMsg->message();
+        *pcParms = m_pNextMsg->paramsCount();
+
+        return VINF_SUCCESS;
+    }
+    virtual int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+    {
+        if (!m_pNextMsg)
+            return VERR_NO_DATA;
+
+        int rc = m_pNextMsg->getData(uMsg, cParms, paParms);
+
+        clearNextMsg();
+
+        return rc;
+    }
+    virtual void clearNextMsg()
+    {
+        if (m_pNextMsg)
+        {
+            delete m_pNextMsg;
+            m_pNextMsg = NULL;
+        }
+    }
+
+    virtual bool isMessageWaiting() const { return m_pNextMsg != NULL; }
+
+protected:
+    HGCM::Message *m_pNextMsg;
+};
+
+/**
+ * DnD message class for generic messages which didn't need any special
+ * handling.
+ */
+class DnDGenericMessage: public DnDMessage
+{
+public:
+    DnDGenericMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+    {
+        m_pNextMsg = new HGCM::Message(uMsg, cParms, paParms);
+    }
+};
+
+/**
+ * DnD message class for informing the guest about a new drop data event.
+ */
+class DnDHGSendDataMessage: public DnDMessage
+{
+public:
+    DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser);
+    ~DnDHGSendDataMessage();
+
+    HGCM::Message* nextHGCMMessage();
+    int currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms);
+    int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+
+    bool isMessageWaiting() const { return m_pNextPathMsg; }
+
+protected:
+    struct PathEntry
+    {
+        PathEntry(const RTCString &strHostPath, const RTCString &strGuestPath, uint32_t fMode, uint64_t cbSize)
+          : m_strHostPath(strHostPath)
+          , m_strGuestPath(strGuestPath)
+          , m_fMode(fMode)
+          , m_cbSize(cbSize) {}
+        RTCString m_strHostPath;
+        RTCString m_strGuestPath;
+        uint32_t  m_fMode;
+        uint64_t  m_cbSize;
+    };
+
+    bool hasFileUrls(const char *pcszFormat, size_t cbMax) const;
+    int buildFileTree(const char *pcszPath, size_t cbBaseLen);
+    static DECLCALLBACK(int) progressCallback(size_t cbDone, void *pvUser);
+
+    RTCList<PathEntry>  m_uriList;
+    DnDMessage         *m_pNextPathMsg;
+
+    /* Progress stuff */
+    size_t              m_cbAll;
+    size_t              m_cbTransfered;
+    PFNDNDPROGRESS      m_pfnProgressCallback;
+    void               *m_pvProgressUser;
+};
+
+/**
+ * DnD message class for informing the guest to cancel any currently and
+ * pending activities.
+ */
+class DnDHGCancelMessage: public DnDMessage
+{
+public:
+    DnDHGCancelMessage()
+    {
+        m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL, 0, 0);
+    }
+};
+
+/**
+ * DnD manager. Manage creation and queuing of messages for the various DnD
+ * messages types.
+ */
+class DnDManager
+{
+public:
+    DnDManager(PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser)
+      : m_pCurMsg(0)
+      , m_fOpInProcess(false)
+      , m_pfnProgressCallback(pfnProgressCallback)
+      , m_pvProgressUser(pvProgressUser)
+    {}
+    ~DnDManager()
+    {
+        clear();
+    }
+
+    int addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+
+    HGCM::Message *nextHGCMMessage();
+    int nextMessageInfo(uint32_t *puMsg, uint32_t *pcParms);
+    int nextMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+
+    void clear();
+
+    bool hasActiveOperation() const { return m_fOpInProcess; }
+
+private:
+    DnDMessage           *m_pCurMsg;
+    RTCList<DnDMessage*>  m_dndMessageQueue;
+
+    bool                  m_fOpInProcess;
+
+    /* Progress stuff */
+    PFNDNDPROGRESS        m_pfnProgressCallback;
+    void                 *m_pvProgressUser;
+};
+
+#endif /* ___VBox_HostService_DnD_dndmanager_h */
+
Index: /trunk/src/VBox/HostServices/DragAndDrop/service.cpp
===================================================================
--- /trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 42261)
+++ /trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 42261)
@@ -0,0 +1,491 @@
+/* $Id$ */
+/** @file
+ * Drag and Drop Service.
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @page pg_svc_guest_control   Guest Control HGCM Service
+ *
+ * This service acts as a proxy for handling and buffering host command requests
+ * and clients on the guest. It tries to be as transparent as possible to let
+ * the guest (client) and host side do their protocol handling as desired.
+ *
+ * The following terms are used:
+ * - Host:   A host process (e.g. VBoxManage or another tool utilizing the Main API)
+ *           which wants to control something on the guest.
+ * - Client: A client (e.g. VBoxService) running inside the guest OS waiting for
+ *           new host commands to perform. There can be multiple clients connected
+ *           to a service. A client is represented by its HGCM client ID.
+ * - Context ID: An (almost) unique ID automatically generated on the host (Main API)
+ *               to not only distinguish clients but individual requests. Because
+ *               the host does not know anything about connected clients it needs
+ *               an indicator which it can refer to later. This context ID gets
+ *               internally bound by the service to a client which actually processes
+ *               the command in order to have a relationship between client<->context ID(s).
+ *
+ * The host can trigger commands which get buffered by the service (with full HGCM
+ * parameter info). As soon as a client connects (or is ready to do some new work)
+ * it gets a buffered host command to process it. This command then will be immediately
+ * removed from the command list. If there are ready clients but no new commands to be
+ * processed, these clients will be set into a deferred state (that is being blocked
+ * to return until a new command is available).
+ *
+ * If a client needs to inform the host that something happened, it can send a
+ * message to a low level HGCM callback registered in Main. This callback contains
+ * the actual data as well as the context ID to let the host do the next necessary
+ * steps for this context. This context ID makes it possible to wait for an event
+ * inside the host's Main API function (like starting a process on the guest and
+ * wait for getting its PID returned by the client) as well as cancelling blocking
+ * host calls in order the client terminated/crashed (HGCM detects disconnected
+ * clients and reports it to this service's callback).
+ */
+
+/******************************************************************************
+ *   Header Files                                                             *
+ ******************************************************************************/
+#define LOG_GROUP LOG_GROUP_HGCM
+
+#include "dndmanager.h"
+
+//# define DO(s) RTPrintf s
+#define DO(s) do {} while(0)
+//#define DO(s) Log s
+
+/******************************************************************************
+ *   Service class declaration                                                *
+ ******************************************************************************/
+
+/**
+ * Specialized drag & drop service class.
+ */
+class DragAndDropService: public HGCM::AbstractService<DragAndDropService>
+{
+public:
+    explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
+      : HGCM::AbstractService<DragAndDropService>(pHelpers)
+      , m_pManager(0)
+      , m_cClients(0)
+    {}
+
+protected:
+    /* HGCM service implementation */
+    int  init(VBOXHGCMSVCFNTABLE *pTable);
+    int  uninit();
+    int  clientConnect(uint32_t u32ClientID, void *pvClient);
+    int  clientDisconnect(uint32_t u32ClientID, void *pvClient);
+    void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+    int  hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+
+    static DECLCALLBACK(int) progressCallback(unsigned uPercentage, uint32_t uState, void *pvUser);
+    int      hostMessage(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+    void     modeSet(uint32_t u32Mode);
+    inline uint32_t modeGet() { return m_u32Mode; };
+
+    DnDManager             *m_pManager;
+
+    uint32_t                m_cClients;
+    RTCList<HGCM::Client*>  m_clientQueue;
+    uint32_t                m_u32Mode;
+};
+
+/******************************************************************************
+ *   Service class implementation                                             *
+ ******************************************************************************/
+
+int DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable)
+{
+    /* Register functions. */
+    pTable->pfnHostCall          = svcHostCall;
+    pTable->pfnSaveState         = NULL;  /* The service is stateless, so the normal */
+    pTable->pfnLoadState         = NULL;  /* construction done before restoring suffices */
+    pTable->pfnRegisterExtension = svcRegisterExtension;
+    modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
+
+    m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
+
+    return VINF_SUCCESS;
+}
+
+int DragAndDropService::uninit()
+{
+    delete m_pManager;
+
+    return VINF_SUCCESS;
+}
+
+int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
+{
+    LogFlowFunc(("New client (%ld) connected\n", u32ClientID));
+    DO(("New client (%ld) connected\n", u32ClientID));
+    if (m_cClients < UINT32_MAX)
+        m_cClients++;
+    else
+        AssertMsgFailed(("Maximum number of clients reached\n"));
+    return VINF_SUCCESS;
+}
+
+int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
+{
+    /* Remove all waiters with this clientId. */
+    while (!m_clientQueue.isEmpty())
+    {
+        HGCM::Client *pClient = m_clientQueue.first();
+        if (pClient->clientId() == u32ClientID)
+        {
+            m_pHelpers->pfnCallComplete(pClient->handle(), VERR_INTERRUPTED);
+            m_clientQueue.removeFirst();
+            delete pClient;
+        }
+    }
+
+    return VINF_SUCCESS;
+}
+
+void DragAndDropService::modeSet(uint32_t u32Mode)
+{
+    switch (u32Mode)
+    {
+        case VBOX_DRAG_AND_DROP_MODE_OFF:
+        case VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST:
+        case VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST:
+        case VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL:
+            LogRel(("drag'n'drop mode = %d\n", u32Mode));
+            m_u32Mode = u32Mode;
+            break;
+
+        default:
+            m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
+    }
+}
+
+void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    int rc = VINF_SUCCESS;
+    LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
+                 u32ClientID, u32Function, cParms, paParms));
+//    RTPrintf("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
+//                 u32ClientID, u32Function, cParms, paParms);
+
+    switch (u32Function)
+    {
+        case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
+        {
+            DO(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
+            if (   cParms != 3
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* message */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
+                || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32);
+                if (   RT_FAILURE(rc)
+                    && paParms[2].u.uint32) /* Blocking? */
+                {
+                    m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle, u32Function, cParms, paParms));
+                    rc = VINF_HGCM_ASYNC_EXECUTE;
+                }
+            }
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
+        {
+            DO(("GUEST_DND_HG_ACK_OP\n"));
+            if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
+                && modeGet() != VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
+            {
+                DO(("=> ignoring!\n"));
+                break;
+            }
+
+            if (   cParms != 1
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DragAndDropSvc::VBOXDNDCBHGACKOPDATA data;
+                data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP;
+                paParms[0].getUInt32(&data.uAction);
+                if (m_pfnHostCallback)
+                    rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
+//                m_pHelpers->pfnCallComplete(callHandle, rc);
+            }
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
+        {
+            DO(("GUEST_DND_HG_REQ_DATA\n"));
+            if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
+                && modeGet() != VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
+            {
+                DO(("=> ignoring!\n"));
+                break;
+            }
+
+            if (   cParms != 1
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DragAndDropSvc::VBOXDNDCBHGREQDATADATA data;
+                data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA;
+                uint32_t cTmp;
+                paParms[0].getPointer((void**)&data.pszFormat, &cTmp);
+                if (m_pfnHostCallback)
+                    rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
+//                m_pHelpers->pfnCallComplete(callHandle, rc);
+//                if (data.pszFormat)
+//                    RTMemFree(data.pszFormat);
+//                if (data.pszTmpPath)
+//                    RTMemFree(data.pszTmpPath);
+            }
+            break;
+        }
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
+        {
+            DO(("GUEST_DND_GH_ACK_PENDING\n"));
+            if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
+                && modeGet() != VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
+            {
+                DO(("=> ignoring!\n"));
+                break;
+            }
+
+            if (   cParms != 3
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* allactions */
+                || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* format */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA data;
+                data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING;
+                paParms[0].getUInt32(&data.uDefAction);
+                paParms[1].getUInt32(&data.uAllActions);
+                uint32_t cTmp;
+                paParms[2].getPointer((void**)&data.pszFormat, &cTmp);
+                if (m_pfnHostCallback)
+                    rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
+            }
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
+        {
+            DO(("GUEST_DND_GH_SND_DATA\n"));
+            if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
+                && modeGet() != VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
+            {
+                DO(("=> ignoring\n"));
+                break;
+            }
+
+            if (   cParms != 2
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
+                || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DragAndDropSvc::VBOXDNDCBSNDDATADATA data;
+                data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA;
+                paParms[0].getPointer((void**)&data.pvData, &data.cbData);
+                paParms[1].getUInt32(&data.cbAllSize);
+                if (m_pfnHostCallback)
+                    rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
+            }
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
+        {
+            DO(("GUEST_DND_GH_EVT_ERROR\n"));
+            if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
+                && modeGet() != VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
+            {
+                DO(("=> ignoring!\n"));
+                break;
+            }
+
+            if (   cParms != 1
+                || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
+                rc = VERR_INVALID_PARAMETER;
+            else
+            {
+                DragAndDropSvc::VBOXDNDCBEVTERRORDATA data;
+                data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR;
+                uint32_t rcOp;
+                paParms[0].getUInt32(&rcOp);
+                data.rc = rcOp;
+                if (m_pfnHostCallback)
+                    rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
+            }
+            break;
+        }
+#endif
+        default:
+        {
+            /* All other messages are handled by the DnD manager. */
+            rc = m_pManager->nextMessage(u32Function, cParms, paParms);
+            /* Check for error. Buffer overflow is allowed. It signals the
+             * guest to ask for more data in the next event. */
+            if (   RT_FAILURE(rc)
+                && rc != VERR_CANCELLED
+                && rc != VERR_BUFFER_OVERFLOW) /* Buffer overflow is allowed. */
+            {
+                m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle, u32Function, cParms, paParms));
+                rc = VINF_HGCM_ASYNC_EXECUTE;
+            }
+            break;
+        }
+    }
+    /* If async execute is requested, we didn't notify the guest about
+     * completion. The client is queued into the waiters list and will be
+     * notified as soon as a new event is available. */
+    if (rc != VINF_HGCM_ASYNC_EXECUTE)
+        m_pHelpers->pfnCallComplete(callHandle, rc);
+    DO(("guest call: %Rrc\n", rc));
+}
+
+int DragAndDropService::hostMessage(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    int rc = VINF_SUCCESS;
+#if 0
+    HGCM::Message *pMessage = new HGCM::Message(u32Function, cParms, paParms);
+    m_hostQueue.push(pMessage);
+//    bool fPush = true;
+    RTPrintf("client queue %u\n", m_clientQueue.size());
+    RTPrintf("host   queue %u\n", m_hostQueue.size());
+    if (!m_clientQueue.empty())
+    {
+        pMessage = m_hostQueue.front();
+        HGCM::Client *pClient = m_clientQueue.front();
+        /* Check if this was a request for getting the next host
+         * message. If so, return the message id and the parameter
+         * count. The message itself has to be queued. */
+        if (pClient->message() == DragAndDropSvc::GUEST_GET_NEXT_HOST_MSG)
+        {
+            RTPrintf("client is waiting for next host msg\n");
+//            rc = VERR_TOO_MUCH_DATA;
+            pClient->addMessageInfo(pMessage);
+            /* temp */
+//        m_pHelpers->pfnCallComplete(pClient->handle(), rc);
+//        m_clientQueue.pop();
+//        delete pClient;
+        }
+        else
+        {
+            RTPrintf("client is waiting for host msg (%d)\n", u32Function);
+            /* There is a request for a host message pending. Check
+             * if this is the correct message and if so deliver. If
+             * not the message will be queued. */
+            rc = pClient->addMessage(pMessage);
+            m_hostQueue.pop();
+            delete pMessage;
+//            if (RT_SUCCESS(rc))
+//                fPush = false;
+        }
+        /* In any case mark this client request as done. */
+        m_pHelpers->pfnCallComplete(pClient->handle(), rc);
+        m_clientQueue.pop_front();
+        delete pClient;
+    }
+//    if (fPush)
+//    {
+//        RTPrintf("push message\n");
+//        m_hostQueue.push(pMessage);
+//    }
+//    else
+//        delete pMessage;
+#endif
+
+    return rc;
+}
+
+int DragAndDropService::hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    int rc = VINF_SUCCESS;
+    if (u32Function == DragAndDropSvc::HOST_DND_SET_MODE)
+    {
+        if (cParms != 1)
+            rc = VERR_INVALID_PARAMETER;
+        else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
+            rc = VERR_INVALID_PARAMETER;
+        else
+            modeSet(paParms[0].u.uint32);
+    }
+    else if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
+    {
+        rc = m_pManager->addMessage(u32Function, cParms, paParms);
+        if (    RT_SUCCESS(rc)
+            && !m_clientQueue.isEmpty())
+        {
+            HGCM::Client *pClient = m_clientQueue.first();
+            /* Check if this was a request for getting the next host
+             * message. If so, return the message id and the parameter
+             * count. The message itself has to be queued. */
+            if (pClient->message() == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
+            {
+                DO(("client is waiting for next host msg\n"));
+//              rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32);
+                uint32_t uMsg1;
+                uint32_t cParms1;
+                rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1);
+                if (RT_SUCCESS(rc))
+                {
+                    pClient->addMessageInfo(uMsg1, cParms1);
+                    m_pHelpers->pfnCallComplete(pClient->handle(), rc);
+                    m_clientQueue.removeFirst();
+                    delete pClient;
+                }
+                else
+                    AssertMsgFailed(("Should not happen!"));
+            }
+            else
+                AssertMsgFailed(("Should not happen!"));
+        }
+//      else
+//          AssertMsgFailed(("Should not happen %Rrc!", rc));
+    }
+
+    LogFlowFunc(("rc=%Rrc\n", rc));
+    return rc;
+}
+
+DECLCALLBACK(int) DragAndDropService::progressCallback(unsigned uPercentage, uint32_t uState, void *pvUser)
+{
+    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
+
+    DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
+
+    if (pSelf->m_pfnHostCallback)
+    {
+        DO(("GUEST_DND_HG_EVT_PROGRESS %u\n", uPercentage));
+        DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
+        data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
+        data.uPercentage  = uPercentage;
+        data.uState       = uState;
+
+        return pSelf->m_pfnHostCallback(pSelf->m_pvHostData, DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS, &data, sizeof(data));
+    }
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * @copydoc VBOXHGCMSVCLOAD
+ */
+extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
+{
+    return DragAndDropService::svcLoad(pTable);
+}
+
Index: /trunk/src/VBox/Installer/linux/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Installer/linux/Makefile.kmk	(revision 42260)
+++ /trunk/src/VBox/Installer/linux/Makefile.kmk	(revision 42261)
@@ -125,4 +125,5 @@
 	$(if $(VBOX_WITH_GUEST_PROPS),VBoxGuestPropSvc.so,) \
 	$(if $(VBOX_WITH_GUEST_CONTROL),VBoxGuestControlSvc.so,) \
+	$(if $(VBOX_WITH_DRAG_AND_DROP),VBoxDragAndDropSvc.so,) \
 	$(if $(VBOX_WITH_MAIN), \
 		VBoxAutostart \
Index: /trunk/src/VBox/Installer/linux/debian/lintian-override.in
===================================================================
--- /trunk/src/VBox/Installer/linux/debian/lintian-override.in	(revision 42260)
+++ /trunk/src/VBox/Installer/linux/debian/lintian-override.in	(revision 42261)
@@ -13,4 +13,5 @@
 %VERPKG%: shlib-with-non-pic-code usr/lib/virtualbox/VBoxGuestPropSvc.so
 %VERPKG%: shlib-with-non-pic-code usr/lib/virtualbox/VBoxGuestControlSvc.so
+%VERPKG%: shlib-with-non-pic-code usr/lib/virtualbox/VBoxDragAndDropSvc.so
 %VERPKG%: shlib-with-non-pic-code usr/lib/virtualbox/VBoxNetDHCP.so
 %VERPKG%: shlib-with-non-pic-code usr/lib/virtualbox/VBoxVRDP.so
@@ -63,4 +64,5 @@
 %VERPKG%: no-shlibs-control-file usr/lib/virtualbox/VBoxGuestPropSvc.so
 %VERPKG%: no-shlibs-control-file usr/lib/virtualbox/VBoxGuestControlSvc.so
+%VERPKG%: no-shlibs-control-file usr/lib/virtualbox/VBoxDragAndDropSvc.so
 %VERPKG%: no-shlibs-control-file usr/lib/virtualbox/VBoxVRDP.so
 %VERPKG%: no-shlibs-control-file usr/lib/virtualbox/VBoxAuth.so
@@ -91,4 +93,5 @@
 %VERPKG%: binary-or-shlib-defines-rpath ./usr/lib/virtualbox/VBoxSharedCrOpenGL.so /usr/lib/virtualbox
 %VERPKG%: binary-or-shlib-defines-rpath ./usr/lib/virtualbox/VBoxSharedFolders.so /usr/lib/virtualbox
+%VERPKG%: binary-or-shlib-defines-rpath ./usr/lib/virtualbox/VBoxDragAndDropSvc.so /usr/lib/virtualbox
 %VERPKG%: binary-or-shlib-defines-rpath ./usr/lib/virtualbox/VBoxTestOGL /usr/lib/virtualbox
 %VERPKG%: binary-or-shlib-defines-rpath ./usr/lib/virtualbox/VBoxVMM.so /usr/lib/virtualbox
Index: /trunk/src/VBox/Installer/linux/deffiles
===================================================================
--- /trunk/src/VBox/Installer/linux/deffiles	(revision 42260)
+++ /trunk/src/VBox/Installer/linux/deffiles	(revision 42261)
@@ -5,5 +5,5 @@
 
 #
-# Copyright (C) 2007-2010 Oracle Corporation
+# Copyright (C) 2007-2012 Oracle Corporation
 #
 # This file is part of VirtualBox Open Source Edition (OSE), as
@@ -50,4 +50,5 @@
     VBoxGuestPropSvc.so \
     VBoxGuestControlSvc.so \
+    VBoxDragAndDropSvc.so \
     VBoxAuth.so \
     VBoxAuthSimple.so \
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 42260)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 42261)
@@ -59,4 +59,5 @@
 	$(if $(VBOX_WITH_COPYTOGUEST),VBOX_WITH_COPYTOGUEST,) \
 	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,) \
 	$(if $(VBOX_WITH_CROGL),VBOX_WITH_CROGL,) \
 	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
@@ -537,4 +538,5 @@
 	$(if $(VBOX_WITH_VIDEOHWACCEL),VBOX_WITH_VIDEOHWACCEL,) \
 	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,) \
 	$(if $(VBOX_WITH_USB),VBOX_WITH_USB,) \
 	$(if-expr defined(VBOX_WITH_EHCI) && defined(VBOX_WITH_USB),VBOX_WITH_EHCI,) \
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42260)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42261)
@@ -1059,4 +1059,18 @@
     <desc>
       Host-Guest clipboard interchange mode.
+    </desc>
+
+    <const name="Disabled"          value="0"/>
+    <const name="HostToGuest"       value="1"/>
+    <const name="GuestToHost"       value="2"/>
+    <const name="Bidirectional"     value="3"/>
+  </enum>
+
+  <enum
+    name="DragAndDropMode"
+    uuid="b618ea0e-b6fb-4f8d-97f7-5e237e49b547"
+    >
+    <desc>
+      Drag'n'Drop interchange mode.
     </desc>
 
@@ -3739,5 +3753,5 @@
   <interface
     name="IMachine" extends="$unknown"
-    uuid="1d03031a-ce63-4641-9d67-3a16e03778d5"
+    uuid="0e84a036-73bf-49c8-b587-c558d4daa788"
     wsmap="managed"
     >
@@ -4242,4 +4256,10 @@
         Synchronization mode between the host OS clipboard
         and the guest OS clipboard.
+      </desc>
+    </attribute>
+
+    <attribute name="dragAndDropMode" type="DragAndDropMode">
+      <desc>
+        Which mode is allowed for drag'n'drop.
       </desc>
     </attribute>
@@ -16333,5 +16353,5 @@
   <interface
     name="IInternalSessionControl" extends="$unknown"
-    uuid="9ddb5449-f463-47cb-a717-d6f22da3b3a2"
+    uuid="3e83963a-1c3b-400d-8c5f-f2d077b0a597"
     internal="yes"
     wsmap="suppress"
@@ -16533,4 +16553,13 @@
       <param name="clipboardMode" type="ClipboardMode" dir="in">
         <desc>The new shared clipboard mode.</desc>
+      </param>
+    </method>
+
+    <method name="onDragAndDropModeChange">
+      <desc>
+        Notification when the drag'n'drop mode changes.
+      </desc>
+      <param name="dragAndDropMode" type="DragAndDropMode" dir="in">
+        <desc>The new mode for drag'n'drop.</desc>
       </param>
     </method>
@@ -18285,5 +18314,5 @@
   <enum
     name="VBoxEventType"
-    uuid="100cf5c8-7dd4-4600-8d75-636d211479c9"
+    uuid="b627520a-6b1a-4a9a-914d-f31434d3d10f"
     >
 
@@ -18548,7 +18577,12 @@
       </desc>
     </const>
+    <const name="OnDragAndDropModeChanged" value="73">
+      <desc>
+        See <link to="IDragAndDropModeChangedEvent">IDragAndDropModeChangedEvent</link>.
+      </desc>
+    </const>
 
     <!-- Last event marker -->
-    <const name="Last" value="73">
+    <const name="Last" value="74">
       <desc>
         Must be last event, used for iterations and structures relying on numerical event values.
@@ -19306,4 +19340,19 @@
       <desc>
         The new clipboard mode.
+      </desc>
+    </attribute>
+  </interface>
+
+  <interface
+    name="IDragAndDropModeChangedEvent" extends="IEvent"
+    uuid="e90b8850-ac8e-4dff-8059-4100ae2c3c3d"
+    wsmap="managed" autogen="VBoxEvent" id="OnDragAndDropModeChanged"
+    >
+    <desc>
+      Notification when the drag'n'drop mode changes.
+    </desc>
+    <attribute name="dragAndDropMode" type="DragAndDropMode" readonly="yes">
+      <desc>
+        The new drag'n'drop mode.
       </desc>
     </attribute>
Index: /trunk/src/VBox/Main/include/ConsoleImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 42260)
+++ /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 42261)
@@ -198,4 +198,5 @@
     HRESULT onCPUExecutionCapChange(ULONG aExecutionCap);
     HRESULT onClipboardModeChange(ClipboardMode_T aClipboardMode);
+    HRESULT onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode);
     HRESULT onVRDEServerChange(BOOL aRestart);
     HRESULT onUSBControllerChange();
@@ -602,4 +603,5 @@
 
     void changeClipboardMode(ClipboardMode_T aClipboardMode);
+    void changeDragAndDropMode(DragAndDropMode_T aDragAndDropMode);
 
 #ifdef VBOX_WITH_USB
Index: /trunk/src/VBox/Main/include/GuestDnDImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestDnDImpl.h	(revision 42261)
+++ /trunk/src/VBox/Main/include/GuestDnDImpl.h	(revision 42261)
@@ -0,0 +1,53 @@
+/** @file
+ * Definition of GuestDnD
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ____H_GUESTDND
+#define ____H_GUESTDND
+
+/* Forward declaration of the d-pointer. */
+struct GuestDnDPrivate;
+
+class GuestDnD
+{
+public:
+    GuestDnD(const ComObjPtr<Guest>& pGuest);
+    ~GuestDnD();
+
+    /* Host -> Guest */
+    HRESULT dragHGEnter(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction);
+    HRESULT dragHGMove(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction);
+    HRESULT dragHGLeave(ULONG uScreenId);
+    HRESULT dragHGDrop(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), BSTR *pstrFormat, DragAndDropAction_T *pResultAction);
+    HRESULT dragHGPutData(ULONG uScreenId, IN_BSTR wstrFormat, ComSafeArrayIn(BYTE, data), IProgress **ppProgress);
+
+    /* Guest -> Host */
+    HRESULT dragGHPending(ULONG uScreenId, ComSafeArrayOut(BSTR, formats), ComSafeArrayOut(DragAndDropAction_T, allowedActions), DragAndDropAction_T *pDefaultAction);
+    HRESULT dragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action, IProgress **ppProgress);
+    HRESULT dragGHGetData(ComSafeArrayOut(BYTE, data));
+
+    /* Guest response */
+    static DECLCALLBACK(int) notifyGuestDragAndDropEvent(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
+
+private:
+
+    /* d-pointer */
+    GuestDnDPrivate *d_ptr;
+
+    friend struct GuestDnDPrivate;
+};
+
+#endif /* ____H_GUESTDND */
+
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 42260)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 42261)
@@ -282,4 +282,5 @@
 
         ClipboardMode_T      mClipboardMode;
+        DragAndDropMode_T    mDragAndDropMode;
 
         typedef std::list<GuestProperty> GuestPropertyList;
@@ -438,4 +439,6 @@
     STDMETHOD(COMGETTER(ClipboardMode))(ClipboardMode_T *aClipboardMode);
     STDMETHOD(COMSETTER(ClipboardMode))(ClipboardMode_T aClipboardMode);
+    STDMETHOD(COMGETTER(DragAndDropMode))(DragAndDropMode_T *aDragAndDropMode);
+    STDMETHOD(COMSETTER(DragAndDropMode))(DragAndDropMode_T aDragAndDropMode);
     STDMETHOD(COMGETTER(GuestPropertyNotificationPatterns))(BSTR *aPattern);
     STDMETHOD(COMSETTER(GuestPropertyNotificationPatterns))(IN_BSTR aPattern);
@@ -691,4 +694,5 @@
     virtual HRESULT onSharedFolderChange() { return S_OK; }
     virtual HRESULT onClipboardModeChange(ClipboardMode_T /* aClipboardMode */) { return S_OK; }
+    virtual HRESULT onDragAndDropModeChange(DragAndDropMode_T /* aDragAndDropMode */) { return S_OK; }
     virtual HRESULT onBandwidthGroupChange(IBandwidthGroup * /* aBandwidthGroup */) { return S_OK; }
     virtual HRESULT onStorageDeviceChange(IMediumAttachment * /* mediumAttachment */, BOOL /* remove */) { return S_OK; }
@@ -1077,4 +1081,5 @@
     HRESULT onSharedFolderChange();
     HRESULT onClipboardModeChange(ClipboardMode_T aClipboardMode);
+    HRESULT onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode);
     HRESULT onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup);
     HRESULT onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove);
Index: /trunk/src/VBox/Main/include/SessionImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/SessionImpl.h	(revision 42260)
+++ /trunk/src/VBox/Main/include/SessionImpl.h	(revision 42261)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -96,4 +96,5 @@
     STDMETHOD(OnSharedFolderChange)(BOOL aGlobal);
     STDMETHOD(OnClipboardModeChange)(ClipboardMode_T aClipboardMode);
+    STDMETHOD(OnDragAndDropModeChange)(DragAndDropMode_T aDragAndDropMode);
     STDMETHOD(OnUSBDeviceAttach)(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError, ULONG aMaskedIfs);
     STDMETHOD(OnUSBDeviceDetach)(IN_BSTR aId, IVirtualBoxErrorInfo *aError);
Index: /trunk/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp	(revision 42261)
@@ -57,5 +57,6 @@
         if (FAILED(rc)) return rc;
         mNext = nextEI;
-    }else
+    }
+    else
         mNext = aNext;
 
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 42261)
@@ -111,4 +111,5 @@
 
 #include <VBox/HostServices/VBoxClipboardSvc.h>
+#include <VBox/HostServices/DragAndDropSvc.h>
 #ifdef VBOX_WITH_GUEST_PROPS
 # include <VBox/HostServices/GuestPropertySvc.h>
@@ -4887,4 +4888,44 @@
         alock.release();
         fireClipboardModeChangedEvent(mEventSource, aClipboardMode);
+    }
+
+    LogFlowThisFunc(("Leaving rc=%#x\n", rc));
+    return rc;
+}
+
+/**
+ * Called by IInternalSessionControl::OnDragAndDropModeChange().
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT Console::onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode)
+{
+    LogFlowThisFunc(("\n"));
+
+    AutoCaller autoCaller(this);
+    AssertComRCReturnRC(autoCaller.rc());
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    HRESULT rc = S_OK;
+
+    /* don't trigger the Drag'n'drop mode change if the VM isn't running */
+    SafeVMPtrQuiet ptrVM(this);
+    if (ptrVM.isOk())
+    {
+        if (   mMachineState == MachineState_Running
+            || mMachineState == MachineState_Teleporting
+            || mMachineState == MachineState_LiveSnapshotting)
+            changeDragAndDropMode(aDragAndDropMode);
+        else
+            rc = setInvalidMachineStateError();
+        ptrVM.release();
+    }
+
+    /* notify console callbacks on success */
+    if (SUCCEEDED(rc))
+    {
+        alock.release();
+        fireDragAndDropModeChangedEvent(mEventSource, aDragAndDropMode);
     }
 
@@ -7686,17 +7727,17 @@
         default:
         case ClipboardMode_Disabled:
-            LogRel(("VBoxSharedClipboard mode: Off\n"));
+            LogRel(("Shared cipboard mode: Off\n"));
             parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_OFF;
             break;
         case ClipboardMode_GuestToHost:
-            LogRel(("VBoxSharedClipboard mode: Guest to Host\n"));
+            LogRel(("Shared clipboard mode: Guest to Host\n"));
             parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST;
             break;
         case ClipboardMode_HostToGuest:
-            LogRel(("VBoxSharedClipboard mode: Host to Guest\n"));
+            LogRel(("Shared clipboard mode: Host to Guest\n"));
             parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST;
             break;
         case ClipboardMode_Bidirectional:
-            LogRel(("VBoxSharedClipboard mode: Bidirectional\n"));
+            LogRel(("Shared clipboard mode: Bidirectional\n"));
             parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL;
             break;
@@ -7704,4 +7745,41 @@
 
     pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE, 1, &parm);
+}
+
+/**
+ * Changes the drag'n_drop mode.
+ *
+ * @param aDragAndDropMode  new drag'n'drop mode.
+ */
+void Console::changeDragAndDropMode(DragAndDropMode_T aDragAndDropMode)
+{
+    VMMDev *pVMMDev = m_pVMMDev;
+    Assert(pVMMDev);
+
+    VBOXHGCMSVCPARM parm;
+    parm.type = VBOX_HGCM_SVC_PARM_32BIT;
+
+    switch (aDragAndDropMode)
+    {
+        default:
+        case DragAndDropMode_Disabled:
+            LogRel(("Drag'n'drop mode: Off\n"));
+            parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_OFF;
+            break;
+        case ClipboardMode_GuestToHost:
+            LogRel(("Drag'n'drop mode: Guest to Host\n"));
+            parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST;
+            break;
+        case ClipboardMode_HostToGuest:
+            LogRel(("Drag'n'drop mode: Host to Guest\n"));
+            parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST;
+            break;
+        case ClipboardMode_Bidirectional:
+            LogRel(("Drag'n'drop mode: Bidirectional\n"));
+            parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL;
+            break;
+    }
+
+    pVMMDev->hgcmHostCall("VBoxDragAndDropSvc", DragAndDropSvc::HOST_DND_SET_MODE, 1, &parm);
 }
 
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 42261)
@@ -2469,4 +2469,7 @@
          */
         {
+            DragAndDropMode_T mode = DragAndDropMode_Disabled;
+            hrc = pMachine->COMGETTER(DragAndDropMode)(&mode);                              H();
+
             /* Load the service */
             rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
@@ -2487,5 +2490,8 @@
                     Log(("Cannot register VBoxDragAndDropSvc extension!\n"));
                 else
+                {
+                    changeDragAndDropMode(mode);
                     Log(("VBoxDragAndDropSvc loaded\n"));
+                }
             }
         }
Index: /trunk/src/VBox/Main/src-client/GuestDnDImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDImpl.cpp	(revision 42261)
+++ /trunk/src/VBox/Main/src-client/GuestDnDImpl.cpp	(revision 42261)
@@ -0,0 +1,995 @@
+/* $Id$ */
+/** @file
+ * VirtualBox COM class implementation: Guest Drag and Drop parts
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "GuestImpl.h"
+#include "AutoCaller.h"
+
+#ifdef VBOX_WITH_DRAG_AND_DROP
+# include "ConsoleImpl.h"
+# include "ProgressImpl.h"
+# include "GuestDnDImpl.h"
+
+# include <VMMDev.h>
+
+# include <VBox/com/list.h>
+# include <VBox/HostServices/DragAndDropSvc.h>
+
+# include <iprt/stream.h>
+# include <iprt/semaphore.h>
+# include <iprt/cpp/utils.h>
+
+/* How does this work:
+ *
+ * Drag and Drop is handled over the internal HGCM service for the host <->
+ * guest communication. Beside that we need to map the Drag and Drop protocols
+ * of the various OS's we support to our internal channels, this is also highly
+ * communicative in both directions. Unfortunately HGCM isn't really designed
+ * for that. Next we have to foul some of the components. This includes to
+ * trick X11 on the guest side, but also Qt needs to be tricked on the host
+ * side a little bit.
+ *
+ * The following components are involved:
+ *
+ * 1. GUI: Uses the Qt classes for Drag and Drop and mainly forward the content
+ *    of it to the Main IGuest interface (see UIDnDHandler.cpp).
+ * 2. Main: Public interface for doing Drag and Drop. Also manage the IProgress
+ *    interfaces for blocking the caller by showing a progress dialog. (see
+ *    this file)
+ * 3. HGCM service: Handle all messages from the host to the guest at once and
+ *    encapsulate the internal communication details. (see dndmanager.cpp and
+ *    friends)
+ * 4. Guest additions: Split into the platform neutral part (see
+ *    VBoxGuestR3LibDragAndDrop.cpp) and the guest OS specific parts.
+ *    Receive/send message from/to the HGCM service and does all guest specific
+ *    operations. Currently only X11 is supported. (see draganddrop.cpp within
+ *    VBoxClient)
+ *
+ * Host  -> Guest:
+ * 1. There are DnD Enter, Move, Leave events which are send exactly like this
+ *    to the guest. The info includes the pos, mimetypes and allowed actions.
+ *    The guest has to respond with an action it would accept, so the GUI could
+ *    change the cursor.
+ * 2. On drop, first a drop event is send. If this is accepted a drop data
+ *    event follows. This blocks the GUI and shows some progress indicator.
+ *
+ * Guest -> Host:
+ * 1. The GUI is asking the guest if a DnD event is pending when the user moves
+ *    the cursor out of the view window. If so, this returns the mimetypes and
+ *    allowed actions.
+ * (2. On every mouse move this is asked again, to make sure the DnD event is
+ *     still valid.)
+ * 3. On drop the host request the data from the guest. This blocks the GUI and
+ *    shows some progress indicator.
+ *
+ * Some hints:
+ * m_sstrAllowedMimeTypes here in this file defines the allowed mime-types.
+ * This is necessary because we need special handling for some of the
+ * mime-types. E.g. for URI lists we need to transfer the actual dirs and
+ * files. Text EOL may to be changed. Also unknown mime-types may need special
+ * handling as well, which may lead to undefined behavior in the host/guest, if
+ * not done.
+ *
+ * Dropping of a directory, means recursively transferring _all_ the content.
+ *
+ * Directories and files are placed into a public visible user directory on the
+ * guest (~/Documents/VirtualBox Dropped Files). We can't delete them after the
+ * DnD operation, because we didn't know what the DnD target does with it. E.g.
+ * it could just be opened in place. This could lead ofc to filling up the disk
+ * within the guest. To inform the user about this, a small app could be
+ * developed which scans this directory regularly and inform the user with a
+ * tray icon hint (and maybe the possibility to clean this up instantly). The
+ * same has to be done in the G->H direction when it is implemented.
+ *
+ * Of course only regularly files are supported. Symlinks are resolved and
+ * transfered as regularly files. First we don't know if the other side support
+ * symlinks at all and second they could point to somewhere in a directory tree
+ * which not exists on the other side.
+ *
+ * The code tries to preserve the file modes of the transfered dirs/files. This
+ * is useful (and maybe necessary) for two things:
+ * 1. If a file is executable, it should be also after the transfer, so the
+ *    user can just execute it, without manually tweaking the modes first.
+ * 2. If a dir/file is not accessible by group/others in the host, it shouldn't
+ *    be in the guest.
+ * In any case, the user mode is always set to rwx (so that we can access it
+ * ourself, in e.g. for a cleanup case after cancel).
+ *
+ * Cancel is supported in both directions and cleans up all previous steps
+ * (thats is: deleting already transfered dirs/files).
+ *
+ * There are a lot of DO (debug output) calls in the code. This could be
+ * disabled, but should be removed (or replaced by Log calls) when this is
+ * nearly finished.
+ *
+ * For Windows guests there could be different communication become necessary.
+ * So the current interface isn't set in stone and should be made public only,
+ * after someone had deeply looked into the Win guest support. See
+ * http://www.catch22.net/tuts/dragdrop for a start.
+ *
+ * How to test:
+ * First set VBOX_WITH_DRAG_AND_DROP=1 in LocalConfig.kmk. The best is if the
+ * host match the guest OS arch. Just build the tree and point a shared folder
+ * within the guest to the additions subfolder in bin. Start the guest and
+ * execute ./VBoxClient --dragandrop --nodaemon within this shared folder. You
+ * should now be able of dragging text or files to the guest. I used a 64bit
+ * Linux for both the host and the guest. If the archs don't match, you need to
+ * first setup a build environment in the guest ofc.
+ *
+ * In general I propose the following changes in the VBox HGCM infrastructure
+ * for the future:
+ * - Currently it isn't really possible to send messages to the guest from the
+ *   host. The host informs the guest just that there is something, the guest
+ *   than has to ask which message and depending on that send the appropriate
+ *   message to the host, which is filled with the right data.
+ * - There is no generic interface for sending bigger memory blocks to/from the
+ *   guest. This is now done here, but I guess was also necessary for e.g.
+ *   guest execution. So something generic which brake this up into smaller
+ *   blocks and send it would be nice (with all the error handling and such
+ *   ofc).
+ * - I developed a "protocol" for the DnD communication here. So the host and
+ *   the guest have always to match in the revision. This is ofc bad, because
+ *   the additions could be outdated easily. So some generic protocol number
+ *   support in HGCM for asking the host and the guest of the support version,
+ *   would be nice. Ofc at least the host should be able to talk to the guest,
+ *   even when the version is below the host one.
+ * All this stuff would be useful for the current services, but also for future
+ * onces.
+ *
+ * Todo:
+ * - Dragging out of the guest (partly done)
+ *   - ESC doesn't really work
+ *   - transfer of URIs (that is the files and patching of the data)
+ *   - testing in a multi monitor setup
+ *   ... in any case it seems a little bit difficult to handle from the Qt
+ *   side. Maybe also a host specific implementation becomes necessary ...
+ *   this would be really worst ofc.
+ * - Win guest support (maybe there have to be done a mapping between the
+ *   official mime-types and Win Clipboard formats (see QWindowsMime, for an
+ *   idea), for VBox internally only mime-types should be used)
+ * - EOL handling on text (should be shared with the clipboard code)
+ * - add configuration (GH, HG, Bidirectional, None), like for the clipboard
+ * - HG->GH and GH->HG-switch: Handle the case the user drags something out of
+ *   the guest and than return to the source view (or another window in the
+ *   multiple guest screen scenario).
+ * - add support for more mime-types (especially images, csv)
+ * - test unusual behavior:
+ *   - DnD service crash in the guest during a DnD op (e.g. crash of VBoxClient or X11)
+ *   - not expected order of the events between HGCM and the guest
+ * - Security considerations: We transfer a lot of memory between the guest and
+ *   the host and even allow the creation of dirs/files. Maybe there should be
+ *   limits introduced to preventing DOS attacks or filling up all the memory
+ *   (both in the host and the guest).
+ * - test, test, test ...
+ */
+
+class DnDGuestResponse
+{
+public:
+    DnDGuestResponse(const ComObjPtr<Guest>& pGuest);
+    ~DnDGuestResponse();
+
+    int notifyAboutGuestResponse();
+    int waitForGuestResponse();
+
+    void setDefAction(uint32_t a) { m_defAction = a; }
+    uint32_t defAction() const { return m_defAction; }
+
+    void setAllActions(uint32_t a) { m_allActions = a; }
+    uint32_t allActions() const { return m_allActions; }
+
+    void setFormat(const Utf8Str &strFormat) { m_strFormat = strFormat; }
+    Utf8Str format() const { return m_strFormat; }
+
+    int addData(void *pvData, uint32_t cbData, uint32_t *pcbCurSize);
+    void resetData();
+    void data(void **ppvData, uint32_t *pcbData) const { *ppvData = m_pvData; *pcbData = m_cbData; }
+    bool hasData() const { return m_pvData != NULL; }
+
+    int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS);
+    HRESULT resetProgress(const ComObjPtr<Guest>& pParent);
+    HRESULT queryProgressTo(IProgress **ppProgress);
+
+private:
+    RTSEMEVENT           m_EventSem;
+    uint32_t             m_defAction;
+    uint32_t             m_allActions;
+    Utf8Str              m_strFormat;
+    void                *m_pvData;
+    uint32_t             m_cbData;
+
+    ComObjPtr<Guest>     m_parent;
+    ComObjPtr<Progress>  m_progress;
+};
+
+class GuestDnDPrivate
+{
+private:
+    /* todo: currently we only support one response. Maybe this needs to be extended at some time. */
+    GuestDnDPrivate(GuestDnD *q, const ComObjPtr<Guest>& pGuest)
+        : q_ptr(q)
+        , p(pGuest)
+        , m_pDnDResponse(new DnDGuestResponse(pGuest))
+    {}
+    ~GuestDnDPrivate() { delete m_pDnDResponse; }
+
+    DnDGuestResponse *response() const { return m_pDnDResponse; }
+
+    void adjustCoords(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
+    void hostCall(const char* psczFunction, uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
+
+    /* Static helper */
+    static RTCString           toFormatString(ComSafeArrayIn(IN_BSTR, formats));
+    static void                toFormatSafeArray(const RTCString &strFormats, ComSafeArrayOut(BSTR, formats));
+
+    static DragAndDropAction_T toMainAction(uint32_t uAction);
+    static void                toMainActions(uint32_t uActions, ComSafeArrayOut(DragAndDropAction_T, actions));
+    static uint32_t            toHGCMAction(DragAndDropAction_T action);
+    static void                toHGCMActions(DragAndDropAction_T inDefAction, uint32_t *pOutDefAction, ComSafeArrayIn(DragAndDropAction_T, inAllowedActions), uint32_t *pOutAllowedActions);
+
+    /* Private q and parent pointer */
+    GuestDnD                        *q_ptr;
+    ComObjPtr<Guest>                 p;
+
+    /* Private helper members */
+    static const RTCList<RTCString>  m_sstrAllowedMimeTypes;
+    DnDGuestResponse                *m_pDnDResponse;
+
+    friend class GuestDnD;
+};
+
+/* What mime-types are supported by VirtualBox.
+ * Note: If you add something here, make sure you test it with all guest OS's!
+ */
+/* static */
+const RTCList<RTCString> GuestDnDPrivate::m_sstrAllowedMimeTypes = RTCList<RTCString>()
+    /* Uri's */
+    << "text/uri-list"
+    /* Text */
+    << "text/plain;charset=utf-8"
+    << "UTF8_STRING"
+    << "text/plain"
+    << "COMPOUND_TEXT"
+    << "TEXT"
+    << "STRING"
+    /* OpenOffice formates */
+    << "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""
+    << "application/x-openoffice-drawing;windows_formatname=\"Drawing Format\"";
+
+DnDGuestResponse::DnDGuestResponse(const ComObjPtr<Guest>& pGuest)
+  : m_EventSem(NIL_RTSEMEVENT)
+  , m_defAction(0)
+  , m_allActions(0)
+  , m_pvData(0)
+  , m_cbData(0)
+  , m_parent(pGuest)
+{
+    int rc = RTSemEventCreate(&m_EventSem);
+    AssertRC(rc);
+}
+
+DnDGuestResponse::~DnDGuestResponse()
+{
+    resetData();
+    int rc = RTSemEventDestroy(m_EventSem);
+    AssertRC(rc);
+}
+
+int DnDGuestResponse::notifyAboutGuestResponse()
+{
+    return RTSemEventSignal(m_EventSem);
+}
+
+int DnDGuestResponse::waitForGuestResponse()
+{
+    return RTSemEventWait(m_EventSem, 300);
+}
+
+int DnDGuestResponse::addData(void *pvData, uint32_t cbData, uint32_t *pcbCurSize)
+{
+    int rc = VINF_SUCCESS;
+    m_pvData = RTMemRealloc(m_pvData, m_cbData + cbData);
+    if (m_pvData)
+    {
+        memcpy(&static_cast<uint8_t*>(m_pvData)[m_cbData], pvData, cbData);
+        m_cbData    += cbData;
+        *pcbCurSize  = m_cbData;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+void DnDGuestResponse::resetData()
+{
+    if (m_pvData)
+    {
+        RTMemFree(m_pvData);
+        m_pvData = NULL;
+    }
+    m_cbData = 0;
+}
+
+HRESULT DnDGuestResponse::resetProgress(const ComObjPtr<Guest>& pParent)
+{
+    m_progress.setNull();
+    HRESULT rc = m_progress.createObject();
+    if (SUCCEEDED(rc))
+    {
+        rc = m_progress->init(static_cast<IGuest*>(pParent),
+                              Bstr(pParent->tr("Dropping data")).raw(),
+                              TRUE);
+    }
+    return rc;
+}
+
+int DnDGuestResponse::setProgress(unsigned uPercentage, uint32_t uState, int rcOp /* = VINF_SUCCESS */)
+{
+    int vrc = VINF_SUCCESS;
+    HRESULT rc;
+    if (!m_progress.isNull())
+    {
+        BOOL fCompleted;
+        rc = m_progress->COMGETTER(Completed)(&fCompleted);
+        if (!fCompleted)
+        {
+            if (uState == DragAndDropSvc::DND_PROGRESS_ERROR)
+                rc = m_progress->notifyComplete(E_FAIL,
+                                                COM_IIDOF(IGuest),
+                                                m_parent->getComponentName(),
+                                                m_parent->tr("Guest error (%Rrc)"), rcOp);
+            else if (uState == DragAndDropSvc::DND_PROGRESS_CANCELLED)
+                rc = m_progress->notifyComplete(S_OK);
+            else
+            {
+                rc = m_progress->SetCurrentOperationProgress(uPercentage);
+                if (   uState      == DragAndDropSvc::DND_PROGRESS_COMPLETE
+                    || uPercentage >= 100)
+                    rc = m_progress->notifyComplete(S_OK);
+            }
+        }
+        BOOL fCanceled = FALSE;
+        rc = m_progress->COMGETTER(Canceled)(&fCanceled);
+        if (fCanceled)
+            vrc = VERR_CANCELLED;
+    }
+    return vrc;
+}
+
+HRESULT DnDGuestResponse::queryProgressTo(IProgress **ppProgress)
+{
+    return m_progress.queryInterfaceTo(ppProgress);
+}
+
+void GuestDnDPrivate::adjustCoords(ULONG uScreenId, ULONG *puX, ULONG *puY) const
+{
+    /* For multi-monitor support we need to add shift values to the coordinates
+     * (depending on the screen number). */
+    ComPtr<IDisplay> pDisplay;
+    HRESULT rc = p->mParent->COMGETTER(Display)(pDisplay.asOutParam());
+    if (FAILED(rc)) throw rc;
+    ComPtr<IFramebuffer> pFramebuffer;
+    LONG xShift, yShift;
+    rc = pDisplay->COMGETTER(Framebuffer)(uScreenId, pFramebuffer.asOutParam(), &xShift, &yShift);
+    if (FAILED(rc)) throw rc;
+    *puX += xShift;
+    *puY += yShift;
+}
+
+void GuestDnDPrivate::hostCall(const char* psczFunction, uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const
+{
+    VMMDev *vmmDev = 0;
+    {
+        /* Make sure mParent is valid, so set the read lock while using.
+         * Do not keep this lock while doing the actual call, because in the meanwhile
+         * another thread could request a write lock which would be a bad idea ... */
+        AutoReadLock alock(p COMMA_LOCKVAL_SRC_POS);
+
+        /* Forward the information to the VMM device. */
+        AssertPtr(p->mParent);
+        vmmDev = p->mParent->getVMMDev();
+    }
+
+    if (!vmmDev)
+        throw p->setError(VBOX_E_VM_ERROR,
+                          p->tr("VMM device is not available (is the VM running?)"));
+
+    LogFlowFunc(("hgcmHostCall msg=%s; numParms=%u\n", psczFunction, u32Function));
+    int vrc = vmmDev->hgcmHostCall("VBoxDragAndDropSvc",
+                                   u32Function,
+                                   cParms, paParms);
+    if (RT_FAILURE(vrc))
+    {
+        LogFlowFunc(("hgcmHostCall error: %Rrc\n", vrc));
+        throw p->setError(VBOX_E_VM_ERROR,
+                          p->tr("hgcmHostCall failed (%Rrc)"), vrc);
+    }
+}
+
+/* static */
+RTCString GuestDnDPrivate::toFormatString(ComSafeArrayIn(IN_BSTR, formats))
+{
+    const RTCList<Utf8Str> formatList(ComSafeArrayInArg(formats));
+    RTCString strFormat;
+    for (size_t i = 0; i < formatList.size(); ++i)
+    {
+        const RTCString &f = formatList.at(i);
+        /* Only keep allowed format types. */
+        if (m_sstrAllowedMimeTypes.contains(f))
+            strFormat += f + "\r\n";
+    }
+    return strFormat;
+}
+
+/* static */
+void GuestDnDPrivate::toFormatSafeArray(const RTCString &strFormats, ComSafeArrayOut(BSTR, formats))
+{
+    RTCList<RTCString> list = strFormats.split("\r\n");
+    size_t i = 0;
+    while(i < list.size())
+    {
+        /* Only keep allowed format types. */
+        if (!m_sstrAllowedMimeTypes.contains(list.at(i)))
+            list.removeAt(i);
+        else
+            ++i;
+    }
+    /* Create a safe array out of the cleaned list. */
+    com::SafeArray<BSTR> sfaFormats(list.size());
+    for (i = 0; i < list.size(); ++i)
+    {
+        const RTCString &f = list.at(i);
+        if (m_sstrAllowedMimeTypes.contains(f))
+        {
+            Bstr bstr(f);
+            bstr.detachTo(&sfaFormats[i]);
+        }
+    }
+    sfaFormats.detachTo(ComSafeArrayOutArg(formats));
+}
+
+/* static */
+uint32_t GuestDnDPrivate::toHGCMAction(DragAndDropAction_T action)
+{
+    uint32_t a = DND_IGNORE_ACTION;
+    switch (action)
+    {
+        case DragAndDropAction_Copy:   a = DND_COPY_ACTION; break;
+        case DragAndDropAction_Move:   a = DND_MOVE_ACTION; break;
+        case DragAndDropAction_Link:   /* For now it doesn't seems useful to allow a link action between host & guest. Maybe later! */
+        case DragAndDropAction_Ignore: /* Ignored */ break;
+        default: AssertMsgFailed(("Action %u not recognized!\n", action)); break;
+    }
+    return a;
+}
+
+/* static */
+void GuestDnDPrivate::toHGCMActions(DragAndDropAction_T inDefAction, uint32_t *pOutDefAction, ComSafeArrayIn(DragAndDropAction_T, inAllowedActions), uint32_t *pOutAllowedActions)
+{
+    const com::SafeArray<DragAndDropAction_T> sfaInActions(ComSafeArrayInArg(inAllowedActions));
+
+    /* Defaults */
+    *pOutDefAction = toHGCMAction(inDefAction);;
+    *pOutAllowedActions = DND_IGNORE_ACTION;
+
+    /* First convert the allowed actions to a bit array. */
+    for (size_t i = 0; i < sfaInActions.size(); ++i)
+        *pOutAllowedActions |= toHGCMAction(sfaInActions[i]);
+
+    /* Second check if the default action is a valid action and if not so try
+     * to find an allowed action. */
+    if (isDnDIgnoreAction(*pOutDefAction))
+    {
+        if (hasDnDCopyAction(*pOutAllowedActions))
+            *pOutDefAction = DND_COPY_ACTION;
+        else if (hasDnDMoveAction(*pOutAllowedActions))
+            *pOutDefAction = DND_MOVE_ACTION;
+    }
+}
+
+/* static */
+DragAndDropAction_T GuestDnDPrivate::toMainAction(uint32_t uAction)
+{
+    /* For now it doesn't seems useful to allow a link action between host & guest. Maybe later! */
+    return (isDnDCopyAction(uAction) ? (DragAndDropAction_T)DragAndDropAction_Copy :
+            isDnDMoveAction(uAction) ? (DragAndDropAction_T)DragAndDropAction_Move :
+            (DragAndDropAction_T)DragAndDropAction_Ignore);
+}
+
+/* static */
+void GuestDnDPrivate::toMainActions(uint32_t uActions, ComSafeArrayOut(DragAndDropAction_T, actions))
+{
+    /* For now it doesn't seems useful to allow a link action between host & guest. Maybe later! */
+    RTCList<DragAndDropAction_T> list;
+    if (hasDnDCopyAction(uActions))
+        list.append(DragAndDropAction_Copy);
+    if (hasDnDMoveAction(uActions))
+        list.append(DragAndDropAction_Move);
+
+    com::SafeArray<DragAndDropAction_T> sfaActions(list.size());
+    for (size_t i = 0; i < list.size(); ++i)
+        sfaActions[i] = list.at(i);
+    sfaActions.detachTo(ComSafeArrayOutArg(actions));
+}
+
+GuestDnD::GuestDnD(const ComObjPtr<Guest>& pGuest)
+    : d_ptr(new GuestDnDPrivate(this, pGuest))
+{
+}
+
+GuestDnD::~GuestDnD()
+{
+    delete d_ptr;
+}
+
+HRESULT GuestDnD::dragHGEnter(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    /* Default is ignoring */
+    *pResultAction = DragAndDropAction_Ignore;
+
+    /* Check & convert the drag & drop actions */
+    uint32_t uDefAction      = 0;
+    uint32_t uAllowedActions = 0;
+    d->toHGCMActions(defaultAction, &uDefAction, ComSafeArrayInArg(allowedActions), &uAllowedActions);
+    /* If there is no usable action, ignore this request. */
+    if (isDnDIgnoreAction(uDefAction))
+        return S_OK;
+
+    /* Make a flat data string out of the mime-type list. */
+    RTCString strFormats = d->toFormatString(ComSafeArrayInArg(formats));
+    /* If there is no valid mime-type, ignore this request. */
+    if (strFormats.isEmpty())
+        return S_OK;
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        /* Adjust the coordinates in a multi-monitor setup. */
+        d->adjustCoords(uScreenId, &uX, &uY);
+
+        VBOXHGCMSVCPARM paParms[7];
+        int i = 0;
+        paParms[i++].setUInt32(uScreenId);
+        paParms[i++].setUInt32(uX);
+        paParms[i++].setUInt32(uY);
+        paParms[i++].setUInt32(uDefAction);
+        paParms[i++].setUInt32(uAllowedActions);
+        paParms[i++].setPointer((void*)strFormats.c_str(), strFormats.length() + 1);
+        paParms[i++].setUInt32(strFormats.length() + 1);
+
+        d->hostCall("HOST_DND_HG_EVT_ENTER",
+                    DragAndDropSvc::HOST_DND_HG_EVT_ENTER,
+                    i,
+                    paParms);
+
+        DnDGuestResponse *pDnD = d->response();
+        /* This blocks until the request is answered (or timeout). */
+        if (pDnD->waitForGuestResponse() == VERR_TIMEOUT)
+            return S_OK;
+
+        /* Copy the response info */
+        *pResultAction = d->toMainAction(pDnD->defAction());
+    }
+    catch (HRESULT rc2)
+    {
+        rc = rc2;
+    }
+
+    return rc;
+}
+
+HRESULT GuestDnD::dragHGMove(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    /* Default is ignoring */
+    *pResultAction = DragAndDropAction_Ignore;
+
+    /* Check & convert the drag & drop actions */
+    uint32_t uDefAction      = 0;
+    uint32_t uAllowedActions = 0;
+    d->toHGCMActions(defaultAction, &uDefAction, ComSafeArrayInArg(allowedActions), &uAllowedActions);
+    /* If there is no usable action, ignore this request. */
+    if (isDnDIgnoreAction(uDefAction))
+        return S_OK;
+
+    /* Make a flat data string out of the mime-type list. */
+    RTCString strFormats = d->toFormatString(ComSafeArrayInArg(formats));
+    /* If there is no valid mime-type, ignore this request. */
+    if (strFormats.isEmpty())
+        return S_OK;
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        /* Adjust the coordinates in a multi-monitor setup. */
+        d->adjustCoords(uScreenId, &uX, &uY);
+
+        VBOXHGCMSVCPARM paParms[7];
+        int i = 0;
+        paParms[i++].setUInt32(uScreenId);
+        paParms[i++].setUInt32(uX);
+        paParms[i++].setUInt32(uY);
+        paParms[i++].setUInt32(uDefAction);
+        paParms[i++].setUInt32(uAllowedActions);
+        paParms[i++].setPointer((void*)strFormats.c_str(), strFormats.length() + 1);
+        paParms[i++].setUInt32(strFormats.length() + 1);
+
+        d->hostCall("HOST_DND_HG_EVT_MOVE",
+                    DragAndDropSvc::HOST_DND_HG_EVT_MOVE,
+                    i,
+                    paParms);
+
+        DnDGuestResponse *pDnD = d->response();
+        /* This blocks until the request is answered (or timeout). */
+        if (pDnD->waitForGuestResponse() == VERR_TIMEOUT)
+            return S_OK;
+
+        /* Copy the response info */
+        *pResultAction = d->toMainAction(pDnD->defAction());
+    }
+    catch (HRESULT rc2)
+    {
+        rc = rc2;
+    }
+
+    return rc;
+}
+
+HRESULT GuestDnD::dragHGLeave(ULONG uScreenId)
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        d->hostCall("HOST_DND_HG_EVT_LEAVE",
+                    DragAndDropSvc::HOST_DND_HG_EVT_LEAVE,
+                    0,
+                    NULL);
+
+        DnDGuestResponse *pDnD = d->response();
+        /* This blocks until the request is answered (or timeout). */
+        pDnD->waitForGuestResponse();
+    }
+    catch (HRESULT rc2)
+    {
+        rc = rc2;
+    }
+
+    return rc;
+}
+
+HRESULT GuestDnD::dragHGDrop(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), BSTR *pstrFormat, DragAndDropAction_T *pResultAction)
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    /* Default is ignoring */
+    *pResultAction = DragAndDropAction_Ignore;
+
+    /* Check & convert the drag & drop actions */
+    uint32_t uDefAction      = 0;
+    uint32_t uAllowedActions = 0;
+    d->toHGCMActions(defaultAction, &uDefAction, ComSafeArrayInArg(allowedActions), &uAllowedActions);
+    /* If there is no usable action, ignore this request. */
+    if (isDnDIgnoreAction(uDefAction))
+        return S_OK;
+
+    /* Make a flat data string out of the mime-type list. */
+    RTCString strFormats = d->toFormatString(ComSafeArrayInArg(formats));
+    /* If there is no valid mime-type, ignore this request. */
+    if (strFormats.isEmpty())
+        return S_OK;
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        /* Adjust the coordinates in a multi-monitor setup. */
+        d->adjustCoords(uScreenId, &uX, &uY);
+
+        VBOXHGCMSVCPARM paParms[7];
+        int i = 0;
+        paParms[i++].setUInt32(uScreenId);
+        paParms[i++].setUInt32(uX);
+        paParms[i++].setUInt32(uY);
+        paParms[i++].setUInt32(uDefAction);
+        paParms[i++].setUInt32(uAllowedActions);
+        paParms[i++].setPointer((void*)strFormats.c_str(), strFormats.length() + 1);
+        paParms[i++].setUInt32(strFormats.length() + 1);
+
+        d->hostCall("HOST_DND_HG_EVT_DROPPED",
+                    DragAndDropSvc::HOST_DND_HG_EVT_DROPPED,
+                    i,
+                    paParms);
+
+        DnDGuestResponse *pDnD = d->response();
+        /* This blocks until the request is answered (or timeout). */
+        if (pDnD->waitForGuestResponse() == VERR_TIMEOUT)
+            return S_OK;
+
+        /* Copy the response info */
+        *pResultAction = d->toMainAction(pDnD->defAction());
+        Bstr(pDnD->format()).cloneTo(pstrFormat);
+    }
+    catch (HRESULT rc2)
+    {
+        rc = rc2;
+    }
+
+    return rc;
+}
+
+HRESULT GuestDnD::dragHGPutData(ULONG uScreenId, IN_BSTR bstrFormat, ComSafeArrayIn(BYTE, data), IProgress **ppProgress)
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        Utf8Str strFormat(bstrFormat);
+        com::SafeArray<BYTE> sfaData(ComSafeArrayInArg(data));
+
+        VBOXHGCMSVCPARM paParms[5];
+        int i = 0;
+        paParms[i++].setUInt32(uScreenId);
+        paParms[i++].setPointer((void*)strFormat.c_str(), (uint32_t)strFormat.length() + 1);
+        paParms[i++].setUInt32((uint32_t)strFormat.length() + 1);
+        paParms[i++].setPointer((void*)sfaData.raw(), (uint32_t)sfaData.size());
+        paParms[i++].setUInt32((uint32_t)sfaData.size());
+
+        DnDGuestResponse *pDnD = d->response();
+        /* Reset any old progress status. */
+        pDnD->resetProgress(p);
+
+        d->hostCall("HOST_DND_HG_SND_DATA",
+                    DragAndDropSvc::HOST_DND_HG_SND_DATA,
+                    i,
+                    paParms);
+
+        /* Query the progress object to the caller. */
+        pDnD->queryProgressTo(ppProgress);
+    }
+    catch (HRESULT rc2)
+    {
+        rc = rc2;
+    }
+
+    return rc;
+}
+
+# ifdef VBOX_WITH_DRAG_AND_DROP_GH
+HRESULT GuestDnD::dragGHPending(ULONG uScreenId, ComSafeArrayOut(BSTR, formats), ComSafeArrayOut(DragAndDropAction_T, allowedActions), DragAndDropAction_T *pDefaultAction)
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    /* Default is ignoring */
+    *pDefaultAction = DragAndDropAction_Ignore;
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        VBOXHGCMSVCPARM paParms[1];
+        int i = 0;
+        paParms[i++].setUInt32(uScreenId);
+
+        d->hostCall("HOST_DND_GH_REQ_PENDING",
+                    DragAndDropSvc::HOST_DND_GH_REQ_PENDING,
+                    i,
+                    paParms);
+
+        DnDGuestResponse *pDnD = d->response();
+        /* This blocks until the request is answered (or timeout). */
+        if (pDnD->waitForGuestResponse() == VERR_TIMEOUT)
+            return S_OK;
+
+        if (isDnDIgnoreAction(pDnD->defAction()))
+            return S_OK;
+
+        /* Fetch the default action to use. */
+        *pDefaultAction = d->toMainAction(pDnD->defAction());
+        /* Convert the formats strings to a vector of strings. */
+        d->toFormatSafeArray(pDnD->format(), ComSafeArrayOutArg(formats));
+        /* Convert the action bit field to a vector of actions. */
+        d->toMainActions(pDnD->allActions(), ComSafeArrayOutArg(allowedActions));
+    }
+    catch (HRESULT rc2)
+    {
+        rc = rc2;
+    }
+
+    return rc;
+}
+
+HRESULT GuestDnD::dragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action, IProgress **ppProgress)
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    Utf8Str strFormat(bstrFormat);
+    HRESULT rc = S_OK;
+
+    uint32_t uAction = d->toHGCMAction(action);
+    /* If there is no usable action, ignore this request. */
+    if (isDnDIgnoreAction(uAction))
+        return S_OK;
+
+    try
+    {
+        VBOXHGCMSVCPARM paParms[3];
+        int i = 0;
+        paParms[i++].setPointer((void*)strFormat.c_str(), (uint32_t)strFormat.length() + 1);
+        paParms[i++].setUInt32((uint32_t)strFormat.length() + 1);
+        paParms[i++].setUInt32(uAction);
+
+        DnDGuestResponse *pDnD = d->response();
+        /* Reset any old data and the progress status. */
+        pDnD->resetData();
+        pDnD->resetProgress(p);
+
+        d->hostCall("HOST_DND_GH_EVT_DROPPED",
+                    DragAndDropSvc::HOST_DND_GH_EVT_DROPPED,
+                    i,
+                    paParms);
+
+        /* Query the progress object to the caller. */
+        pDnD->queryProgressTo(ppProgress);
+    }
+    catch (HRESULT rc2)
+    {
+        rc = rc2;
+    }
+
+    return rc;
+}
+
+HRESULT GuestDnD::dragGHGetData(ComSafeArrayOut(BYTE, data))
+{
+    DPTR(GuestDnD);
+    const ComObjPtr<Guest> &p = d->p;
+
+    HRESULT rc = S_OK;
+
+    DnDGuestResponse *pDnD = d->response();
+    /* Is there data at all? */
+    if (pDnD->hasData())
+    {
+        /* Copy the data into an safe array of bytes. */
+        void     *pvData = 0;
+        uint32_t  cbData = 0;
+        pDnD->data(&pvData, &cbData);
+        com::SafeArray<BYTE> sfaData(cbData);
+        memcpy(sfaData.raw(), pvData, cbData);
+        sfaData.detachTo(ComSafeArrayOutArg(data));
+        /* Delete the data. */
+        pDnD->resetData();
+    }
+    else
+        rc = VBOX_E_INVALID_OBJECT_STATE;
+
+    return rc;
+}
+
+# endif /* VBOX_WITH_DRAG_AND_DROP_GH */
+
+DECLCALLBACK(int) GuestDnD::notifyGuestDragAndDropEvent(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms)
+{
+    ComObjPtr<Guest> pGuest = reinterpret_cast<Guest*>(pvExtension);
+    if (!pGuest->m_pGuestDnD)
+        return VINF_SUCCESS;
+
+    GuestDnDPrivate *d = static_cast<GuestDnDPrivate*>(pGuest->m_pGuestDnD->d_ptr);
+    const ComObjPtr<Guest> &p = d->p;
+
+    DnDGuestResponse *pDnD = d->response();
+    if (pDnD == NULL)
+        return VERR_INVALID_PARAMETER;
+
+    int rc = VINF_SUCCESS;
+    switch (u32Function)
+    {
+        case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
+        {
+            DragAndDropSvc::PVBOXDNDCBHGACKOPDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGACKOPDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            pDnD->setDefAction(pCBData->uAction);
+            rc = pDnD->notifyAboutGuestResponse();
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
+        {
+            DragAndDropSvc::PVBOXDNDCBHGREQDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGREQDATADATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            pDnD->setFormat(pCBData->pszFormat);
+            rc = pDnD->notifyAboutGuestResponse();
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
+        {
+            DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            rc = pDnD->setProgress(pCBData->uPercentage, pCBData->uState);
+            break;
+        }
+#ifdef VBOX_WITH_DRAG_AND_DROP_GH
+        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
+        {
+            DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            pDnD->setFormat(pCBData->pszFormat);
+            pDnD->setDefAction(pCBData->uDefAction);
+            pDnD->setAllActions(pCBData->uAllActions);
+            rc = pDnD->notifyAboutGuestResponse();
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
+        {
+            DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            uint32_t cbCurSize = 0;
+            pDnD->addData(pCBData->pvData, pCBData->cbData, &cbCurSize);
+            rc = pDnD->setProgress(100.0 / pCBData->cbAllSize * cbCurSize, (pCBData->cbAllSize == cbCurSize ? DragAndDropSvc::DND_PROGRESS_COMPLETE : DragAndDropSvc::DND_PROGRESS_RUNNING));
+            /* Todo: for now we instantly confirm the cancel. Check if the
+             * guest should first clean up stuff itself and than really confirm
+             * the cancel request by an extra message. */
+            if (rc == VERR_CANCELLED)
+                pDnD->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED);
+            break;
+        }
+        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
+        {
+            DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            /* Cleanup */
+            pDnD->resetData();
+            rc = pDnD->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc);
+            break;
+        }
+#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
+        default: AssertMsgFailedReturn(("Function %u not recognized!\n", u32Function), VERR_INVALID_PARAMETER); break;
+    }
+
+    return rc;
+}
+
+#endif /* VBOX_WITH_DRAG_AND_DROP */
+
Index: /trunk/src/VBox/Main/src-client/GuestImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 42261)
@@ -845,5 +845,5 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-#ifdef VBOX_WITH_DRAG_AND_DROP
+#if defined(VBOX_WITH_DRAG_AND_DROP) && defined(VBOX_WITH_DRAG_AND_DROP_GH)
     return m_pGuestDnD->dragGHPending(uScreenId, ComSafeArrayOutArg(formats), ComSafeArrayOutArg(allowedActions), pDefaultAction);
 #else /* VBOX_WITH_DRAG_AND_DROP */
@@ -861,5 +861,5 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-#ifdef VBOX_WITH_DRAG_AND_DROP
+#if defined(VBOX_WITH_DRAG_AND_DROP) && defined(VBOX_WITH_DRAG_AND_DROP_GH)
     return m_pGuestDnD->dragGHDropped(bstrFormat, action, ppProgress);
 #else /* VBOX_WITH_DRAG_AND_DROP */
@@ -876,5 +876,5 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-#ifdef VBOX_WITH_DRAG_AND_DROP
+#if defined(VBOX_WITH_DRAG_AND_DROP) && defined(VBOX_WITH_DRAG_AND_DROP_GH)
     return m_pGuestDnD->dragGHGetData(ComSafeArrayOutArg(data));
 #else /* VBOX_WITH_DRAG_AND_DROP */
Index: /trunk/src/VBox/Main/src-client/SessionImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/SessionImpl.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-client/SessionImpl.cpp	(revision 42261)
@@ -673,4 +673,18 @@
 
     return mConsole->onClipboardModeChange(aClipboardMode);
+}
+
+STDMETHODIMP Session::OnDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode)
+{
+    LogFlowThisFunc(("\n"));
+
+    AutoCaller autoCaller(this);
+    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+
+    return mConsole->onDragAndDropModeChange(aDragAndDropMode);
 }
 
Index: /trunk/src/VBox/Main/src-server/ApplianceImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/ApplianceImpl.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-server/ApplianceImpl.cpp	(revision 42261)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -799,5 +799,6 @@
                 if (FAILED(rc)) throw rc;
                 ++cOp;
-            }else
+            }
+            else
                 break;
         }
Index: /trunk/src/VBox/Main/src-server/ApplianceImplIO.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/ApplianceImplIO.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-server/ApplianceImplIO.cpp	(revision 42261)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -298,5 +298,5 @@
          */
         bool fFound = false;
-        for(;;)
+        for (;;)
         {
             char *pszFilename = 0;
@@ -314,5 +314,6 @@
                         break;
                 }
-            }else
+            }
+            else
                 break;
         }
@@ -500,5 +501,5 @@
                 /* First loop over all the free memory in the circular
                  * memory buffer (could be turn around at the end). */
-                for(;;)
+                for (;;)
                 {
                     if (   cbMemAllRead == cbAvail
@@ -514,5 +515,5 @@
                      * method could also split the writes up into to smaller
                      * parts. */
-                    for(;;)
+                    for (;;)
                     {
                         if (cbAllWritten == cbMemRead)
@@ -557,5 +558,5 @@
                 /* First loop over all the available memory in the circular
                  * memory buffer (could be turn around at the end). */
-                for(;;)
+                for (;;)
                 {
                     if (   cbMemAllWrite == cbAvail
@@ -571,5 +572,5 @@
                      * smaller parts. */
                     size_t cbAllRead = 0;
-                    for(;;)
+                    for (;;)
                     {
                         if (cbAllRead == cbMemWrite)
@@ -638,5 +639,5 @@
 //    RTPrintf("start\n");
     int rc = VINF_SUCCESS;
-    for(;;)
+    for (;;)
     {
 //        RTPrintf(" wait\n");
@@ -981,5 +982,5 @@
         size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
         size_t cbAllWritten = 0;
-        for(;;)
+        for (;;)
         {
             /* Finished? */
@@ -1000,5 +1001,5 @@
 
     size_t cbAllWritten = 0;
-    for(;;)
+    for (;;)
     {
         /* Finished? */
@@ -1082,5 +1083,5 @@
 
     size_t cbAllRead = 0;
-    for(;;)
+    for (;;)
     {
         /* Finished? */
@@ -1256,5 +1257,5 @@
         }
 
-        for(;;)
+        for (;;)
         {
             size_t cbRead = 0;
@@ -1286,5 +1287,6 @@
         *ppvBuf = pvBuf;
         *pcbSize = cbAllRead;
-    }else
+    }
+    else
     {
         if (pvBuf)
@@ -1310,5 +1312,5 @@
 
     size_t cbAllWritten = 0;
-    for(;;)
+    for (;;)
     {
         if (cbAllWritten >= cbSize)
Index: /trunk/src/VBox/Main/src-server/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 42261)
@@ -197,4 +197,5 @@
 
     mClipboardMode = ClipboardMode_Disabled;
+    mDragAndDropMode = DragAndDropMode_Disabled;
     mGuestPropertyNotificationPatterns = "";
 
@@ -2603,4 +2604,44 @@
     mHWData.backup();
     mHWData->mClipboardMode = aClipboardMode;
+
+    /* Save settings if online - todo why is this required?? */
+    if (Global::IsOnline(mData->mMachineState))
+        saveSettings(NULL);
+
+    return S_OK;
+}
+
+STDMETHODIMP Machine::COMGETTER(DragAndDropMode)(DragAndDropMode_T *aDragAndDropMode)
+{
+    CheckComArgOutPointerValid(aDragAndDropMode);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aDragAndDropMode = mHWData->mDragAndDropMode;
+
+    return S_OK;
+}
+
+STDMETHODIMP
+Machine::COMSETTER(DragAndDropMode)(DragAndDropMode_T aDragAndDropMode)
+{
+    HRESULT rc = S_OK;
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    alock.release();
+    rc = onDragAndDropModeChange(aDragAndDropMode);
+    alock.acquire();
+    if (FAILED(rc)) return rc;
+
+    setModified(IsModified_MachineData);
+    mHWData.backup();
+    mHWData->mDragAndDropMode = aDragAndDropMode;
 
     /* Save settings if online - todo why is this required?? */
@@ -8419,4 +8460,7 @@
         // Clipboard
         mHWData->mClipboardMode = data.clipboardMode;
+
+        // drag'n'drop
+        mHWData->mDragAndDropMode = data.dragAndDropMode;
 
         // guest settings
@@ -9593,4 +9637,7 @@
         data.clipboardMode = mHWData->mClipboardMode;
 
+        // drag'n'drop
+        data.dragAndDropMode = mHWData->mDragAndDropMode;
+
         /* Guest */
         data.ulMemoryBalloonSize = mHWData->mMemoryBalloonSize;
@@ -10442,5 +10489,6 @@
                             && find(llMedia.begin(), llMedia.end(), pParent) == llMedia.end())
                             llMedia.push_back(pParent);
-                    }else
+                    }
+                    else
                         break;
                     pParent = pParent->getParent();
@@ -12896,4 +12944,27 @@
 
 /**
+ * @note Locks this object for reading.
+ */
+HRESULT SessionMachine::onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode)
+{
+    LogFlowThisFunc(("\n"));
+
+    AutoCaller autoCaller(this);
+    AssertComRCReturnRC(autoCaller.rc());
+
+    ComPtr<IInternalSessionControl> directControl;
+    {
+        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+        directControl = mData->mSession.mDirectControl;
+    }
+
+    /* ignore notifications sent after #OnSessionEnd() is called */
+    if (!directControl)
+        return S_OK;
+
+    return directControl->OnDragAndDropModeChange(aDragAndDropMode);
+}
+
+/**
  *  @note Locks this object for reading.
  */
Index: /trunk/src/VBox/Main/testcase/tstAPI.cpp
===================================================================
--- /trunk/src/VBox/Main/testcase/tstAPI.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/testcase/tstAPI.cpp	(revision 42261)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -1417,5 +1417,6 @@
                 else
                     RTPrintf("Error: failed to import appliance. No error message available!\n");
-            }else
+            }
+            else
                 RTPrintf("Successfully imported the appliance.\n");
         }
Index: /trunk/src/VBox/Main/xml/Settings.cpp
===================================================================
--- /trunk/src/VBox/Main/xml/Settings.cpp	(revision 42260)
+++ /trunk/src/VBox/Main/xml/Settings.cpp	(revision 42261)
@@ -1615,5 +1615,6 @@
           chipsetType(ChipsetType_PIIX3),
           fEmulatedUSBCardReader(false),
-          clipboardMode(ClipboardMode_Bidirectional),
+          clipboardMode(ClipboardMode_Disabled),
+          dragAndDropMode(DragAndDropMode_Disabled),
           ulMemoryBalloonSize(0),
           fPageFusionEnabled(false)
@@ -1687,4 +1688,5 @@
                   && (llSharedFolders           == h.llSharedFolders)
                   && (clipboardMode             == h.clipboardMode)
+                  && (dragAndDropMode           == h.dragAndDropMode)
                   && (ulMemoryBalloonSize       == h.ulMemoryBalloonSize)
                   && (fPageFusionEnabled        == h.fPageFusionEnabled)
@@ -2762,4 +2764,21 @@
                 else
                     throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in Clipboard/@mode attribute"), strTemp.c_str());
+            }
+        }
+        else if (pelmHwChild->nameEquals("DragAndDrop"))
+        {
+            Utf8Str strTemp;
+            if (pelmHwChild->getAttributeValue("mode", strTemp))
+            {
+                if (strTemp == "Disabled")
+                    hw.dragAndDropMode = DragAndDropMode_Disabled;
+                else if (strTemp == "HostToGuest")
+                    hw.dragAndDropMode = DragAndDropMode_HostToGuest;
+                else if (strTemp == "GuestToHost")
+                    hw.dragAndDropMode = DragAndDropMode_GuestToHost;
+                else if (strTemp == "Bidirectional")
+                    hw.dragAndDropMode = DragAndDropMode_Bidirectional;
+                else
+                    throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in DragAndDrop/@mode attribute"), strTemp.c_str());
             }
         }
@@ -4066,10 +4085,21 @@
     switch (hw.clipboardMode)
     {
-        case ClipboardMode_Disabled: pcszClip = "Disabled"; break;
+        default: /*case ClipboardMode_Disabled:*/ pcszClip = "Disabled"; break;
         case ClipboardMode_HostToGuest: pcszClip = "HostToGuest"; break;
         case ClipboardMode_GuestToHost: pcszClip = "GuestToHost"; break;
-        default: /*case ClipboardMode_Bidirectional:*/ pcszClip = "Bidirectional"; break;
+        case ClipboardMode_Bidirectional: pcszClip = "Bidirectional"; break;
     }
     pelmClip->setAttribute("mode", pcszClip);
+
+    xml::ElementNode *pelmDragAndDrop = pelmHardware->createChild("DragAndDrop");
+    const char *pcszDragAndDrop;
+    switch (hw.dragAndDropMode)
+    {
+        default: /*case DragAndDropMode_Disabled:*/ pcszDragAndDrop = "Disabled"; break;
+        case DragAndDropMode_HostToGuest: pcszDragAndDrop = "HostToGuest"; break;
+        case DragAndDropMode_GuestToHost: pcszDragAndDrop = "GuestToHost"; break;
+        case DragAndDropMode_Bidirectional: pcszDragAndDrop = "Bidirectional"; break;
+    }
+    pelmDragAndDrop->setAttribute("mode", pcszDragAndDrop);
 
     if (m->sv >= SettingsVersion_v1_10)
Index: /trunk/src/VBox/Main/xml/VirtualBox-settings-common.xsd
===================================================================
--- /trunk/src/VBox/Main/xml/VirtualBox-settings-common.xsd	(revision 42260)
+++ /trunk/src/VBox/Main/xml/VirtualBox-settings-common.xsd	(revision 42261)
@@ -7,5 +7,5 @@
  *  Common definitions
 
-     Copyright (C) 2004-2011 Oracle Corporation
+     Copyright (C) 2004-2012 Oracle Corporation
 
      This file is part of VirtualBox Open Source Edition (OSE), as
@@ -172,4 +172,13 @@
 
 <xsd:simpleType name="TClipboardMode">
+  <xsd:restriction base="xsd:string">
+    <xsd:enumeration value="Disabled"/>
+    <xsd:enumeration value="HostToGuest"/>
+    <xsd:enumeration value="GuestToHost"/>
+    <xsd:enumeration value="Bidirectional"/>
+  </xsd:restriction>
+</xsd:simpleType>
+
+<xsd:simpleType name="TDragAndDropMode">
   <xsd:restriction base="xsd:string">
     <xsd:enumeration value="Disabled"/>
@@ -793,4 +802,8 @@
 </xsd:complexType>
 
+<xsd:complexType name="TDragAndDrop">
+  <xsd:attribute name="mode" type="TDragAndDropMode" use="required"/>
+</xsd:complexType>
+
 <xsd:complexType name="TGuest">
   <xsd:attribute name="memoryBalloonSize"        type="xsd:unsignedInt" default="0"/>
@@ -865,4 +878,5 @@
     </xsd:element>
     <xsd:element name="Clipboard" type="TClipboard"/>
+    <xsd:element name="DragAndDrop" type="TDragAndDrop"/>
     <xsd:element name="Guest" type="TGuest"/>
     <xsd:element name="GuestProperties" type="TGuestProperties" minOccurs="0">
Index: /trunk/src/VBox/Runtime/common/misc/s3.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/misc/s3.cpp	(revision 42260)
+++ /trunk/src/VBox/Runtime/common/misc/s3.cpp	(revision 42261)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -258,5 +258,6 @@
             case 404: rc = VERR_S3_NOT_FOUND; break; /* Site not found */
         }
-    }else
+    }
+    else
     {
         switch(code)
Index: /trunk/src/VBox/Runtime/testcase/tstRTUri.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTUri.cpp	(revision 42260)
+++ /trunk/src/VBox/Runtime/testcase/tstRTUri.cpp	(revision 42261)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2011 Oracle Corporation
+ * Copyright (C) 2011-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -206,5 +206,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
@@ -222,5 +223,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
@@ -238,5 +240,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
@@ -254,5 +257,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
@@ -270,5 +274,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
@@ -286,5 +291,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
@@ -303,5 +309,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
@@ -320,5 +327,6 @@
         RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
-    }else
+    }
+    else
         RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
 
