Index: /trunk/include/VBox/GuestHost/DragAndDrop.h
===================================================================
--- /trunk/include/VBox/GuestHost/DragAndDrop.h	(revision 58211)
+++ /trunk/include/VBox/GuestHost/DragAndDrop.h	(revision 58212)
@@ -59,8 +59,10 @@
     int AddFile(const char *pszFile);
     int AddDir(const char *pszDir);
+    int Close(void);
     bool IsOpen(void) const;
     int OpenEx(const char *pszPath, uint32_t fFlags);
     int OpenTemp(uint32_t fFlags);
     const char *GetDirAbs(void) const;
+    int Reopen(void);
     int Reset(bool fDeleteContent);
     int Rollback(void);
@@ -68,9 +70,12 @@
 protected:
 
+    int closeInternal(void);
+
+protected:
+
+    /** Open flags. */
+    uint32_t                     fOpen;
     /** Directory handle for drop directory. */
     PRTDIR                       hDir;
-    /** Flag indicating whether the drop directory
-     *  has been opened for processing or not. */
-    bool                         fOpen;
     /** Absolute path to drop directory. */
     RTCString                    strPathAbs;
@@ -197,5 +202,5 @@
     void RemoveFirst(void);
     int RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags);
-    RTCString RootToString(const RTCString &strPathBase = "", const RTCString &strSeparator = "\r\n");
+    RTCString RootToString(const RTCString &strPathBase = "", const RTCString &strSeparator = "\r\n") const;
     size_t RootCount(void) const { return m_lstRoot.size(); }
     uint32_t TotalCount(void) const { return m_cTotal; }
Index: /trunk/include/VBox/HostServices/DragAndDropSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/DragAndDropSvc.h	(revision 58211)
+++ /trunk/include/VBox/HostServices/DragAndDropSvc.h	(revision 58212)
@@ -22,4 +22,34 @@
  * You may elect to license modified versions of this file under the
  * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/**
+ * Protocol handling and notes:
+ *     All client/server components should be backwards compatible.
+ *
+ ******************************************************************************
+ *
+ * Protocol changelog:
+ *
+ *     Protocol v1 (VBox < 5.0):
+ *         - Initial implementation which only implemented host to guest transfers.
+ *         - For file transfers all file information such as the file name and file size were
+ *           transferred with every file data chunk being sent.
+ *
+ *     Protocol v2 (VBox 5.0):
+ *         - Added support for guest to host transfers.
+ *         - Added protocol version support through VBOXDNDCONNECTMSG. The host takes the installed
+ *           Guest Additions version as indicator which protocol to use for communicating with the guest.
+ *           The guest itself uses VBOXDNDCONNECTMSG to report its supported protocol version to the DnD service.
+ *
+ *     Protocol v3 (VBox 5.0+):
+ *         - Added VBOXDNDSNDDATAHDR and VBOXDNDCBSNDDATAHDRDATA to support (simple) accounting of objects
+ *           being transferred, along with supplying separate meta data size (which is part of the total size being sent).
+ *         - Added new HOST_DND_HG_SND_DATA_HDR + GUEST_DND_GH_SND_DATA_HDR commands which now allow specifying an optional
+ *           compression type and defining a checksum for the overall data transfer.
+ *         - Enhannced VBOXDNDGHSENDDATAMSG to support (rolling) checksums for the supplied data block.
+ *         - VBOXDNDHGSENDFILEDATAMSG and VBOXDNDGHSENDFILEDATAMSG are now sharing the same HGCM mesasge.
+ *         - VBOXDNDHGSENDDATAMSG and VBOXDNDGHSENDDATAMSG can now contain an optional checksum for the current data block.
+ *         - Removed unused HOST_DND_GH_RECV_DIR, HOST_DND_GH_RECV_FILE_DATA and HOST_DND_GH_RECV_FILE_HDR commands.
  */
 
@@ -106,11 +136,20 @@
     /** The host requested to cancel the current DnD operation. */
     HOST_DND_HG_EVT_CANCEL             = 204,
-    /** Gets the actual MIME data, based on
-     *  the format(s) specified by HOST_DND_HG_EVT_ENTER. If the guest
-     *  supplied buffer too small to send the actual data, the host
-     *  will send a HOST_DND_HG_SND_MORE_DATA message as follow-up. */
+    /** Sends the data header at the beginning of a (new)
+     *  data transfer. */
+    HOST_DND_HG_SND_DATA_HDR           = 210,
+    /**
+     * Sends the actual meta data, based on
+     * the format(s) specified by HOST_DND_HG_EVT_ENTER.
+     *
+     * Protocol v1/v2: If the guest supplied buffer too small to send
+     *                 the actual data, the host will send a HOST_DND_HG_SND_MORE_DATA
+     *                 message as follow-up.
+     * Protocol v3+:   The incoming meta data size is specified upfront in the
+     *                 HOST_DND_HG_SND_DATA_HDR message and must be handled accordingly.
+     */
     HOST_DND_HG_SND_DATA               = 205,
-    /** Sent when the actual buffer for HOST_DND_HG_SND_DATA
-     *  was too small, issued by the DnD host service. */
+    /** Sent when the actual buffer for HOST_DND_HG_SND_DATA was too small. */
+    /** @todo Deprecated function; do not use anymore. */
     HOST_DND_HG_SND_MORE_DATA          = 206,
     /** Directory entry to be sent to the guest. */
@@ -133,11 +172,4 @@
      *  a specific MIME type. */
     HOST_DND_GH_EVT_DROPPED            = 601,
-    /** Creates a directory on the guest. */
-    HOST_DND_GH_RECV_DIR               = 650,
-    /** Retrieves file data from the guest. */
-    HOST_DND_GH_RECV_FILE_DATA         = 670,
-    /** Retrieves a file header from the guest.
-     *  Note: Only for protocol version 2 and up (>= VBox 5.0). */
-    HOST_DND_GH_RECV_FILE_HDR          = 671,
     /** Blow the type up to 32-bit. */
     HOST_DND_32BIT_HACK                = 0x7fffffff
@@ -185,4 +217,7 @@
      */
     GUEST_DND_GH_ACK_PENDING           = 500,
+    /** Sends the data header at the beginning of a (new)
+     *  data transfer. */
+    GUEST_DND_GH_SND_DATA_HDR          = 503,
     /**
      * Sends data of the requested format to the host. There can
@@ -227,16 +262,18 @@
  */
 
+/**
+ * Action message for telling the guest about the currently ongoing
+ * drag and drop action when entering the guest's area, moving around in it
+ * and dropping content into it from the host.
+ *
+ * Used by:
+ * HOST_DND_HG_EVT_ENTER
+ * HOST_DND_HG_EVT_MOVE
+ * HOST_DND_HG_EVT_DROPPED
+ */
 typedef struct VBOXDNDHGACTIONMSG
 {
     VBoxGuestHGCMCallInfo hdr;
 
-    /**
-     * HG Action event.
-     *
-     * Used by:
-     * HOST_DND_HG_EVT_ENTER
-     * HOST_DND_HG_EVT_MOVE
-     * HOST_DND_HG_EVT_DROPPED
-     */
     HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
     HGCMFunctionParameter uX;           /* OUT uint32_t */
@@ -248,80 +285,152 @@
 } VBOXDNDHGACTIONMSG;
 
+/**
+ * Tells the guest that the host has left its drag and drop area on the guest.
+ *
+ * Used by:
+ * HOST_DND_HG_EVT_LEAVE
+ */
 typedef struct VBOXDNDHGLEAVEMSG
 {
     VBoxGuestHGCMCallInfo hdr;
+} VBOXDNDHGLEAVEMSG;
+
+
+/**
+ * Tells the guest that the host wants to cancel the current drag and drop operation.
+ *
+ * Used by:
+ * HOST_DND_HG_EVT_CANCEL
+ */
+typedef struct VBOXDNDHGCANCELMSG
+{
+    VBoxGuestHGCMCallInfo hdr;
+} VBOXDNDHGCANCELMSG;
+
+/**
+ * Sends the header of an incoming (meta) data block.
+ *
+ * Used by:
+ * HOST_DND_HG_SND_DATA_HDR
+ * GUEST_DND_GH_SND_DATA_HDR
+ *
+ * New since protocol v3.
+ */
+typedef struct VBOXDNDHGSENDDATAHDRMSG
+{
+    VBoxGuestHGCMCallInfo hdr;
+
+    /** Context ID. Unused at the moment. */
+    HGCMFunctionParameter uContext;        /* OUT uint32_t */
+    /** Data transfer flags. Not yet used and must be 0. */
+    HGCMFunctionParameter uFlags;          /* OUT uint32_t */
+    /** Screen ID where the data originates from. */
+    HGCMFunctionParameter uScreenId;       /* OUT uint32_t */
+    /** Total size (in bytes) to transfer. */
+    HGCMFunctionParameter cbTotal;         /* OUT uint64_t */
     /**
-     * HG Leave event.
+     * Total meta data size (in bytes) to transfer.
+     * This size also is part of cbTotal already, so:
      *
-     * Used by:
-     * HOST_DND_HG_EVT_LEAVE
+     * cbTotal = cbMeta + additional size for files etc.
      */
-} VBOXDNDHGLEAVEMSG;
-
-typedef struct VBOXDNDHGCANCELMSG
-{
-    VBoxGuestHGCMCallInfo hdr;
-
-    /**
-     * HG Cancel return event.
-     *
-     * Used by:
-     * HOST_DND_HG_EVT_CANCEL
-     */
-} VBOXDNDHGCANCELMSG;
-
+    HGCMFunctionParameter cbMeta;          /* OUT uint64_t */
+    /** Meta data format. */
+    HGCMFunctionParameter pvMetaFmt;       /* OUT ptr */
+    /** Size (in bytes) of meta data format. */
+    HGCMFunctionParameter cbMetaFmt;       /* OUT uint32_t */
+    /* Number of objects (files/directories) to transfer. */
+    HGCMFunctionParameter cObjects;        /* OUT uint64_t */
+    /** Compression type. */
+    HGCMFunctionParameter enmCompression;  /* OUT uint32_t */
+    /** Checksum type. */
+    HGCMFunctionParameter enmChecksumType; /* OUT uint32_t */
+    /** Checksum buffer for the entire data to be transferred. */
+    HGCMFunctionParameter pvChecksum;      /* OUT ptr */
+    /** Size (in bytes) of checksum. */
+    HGCMFunctionParameter cbChecksum;      /* OUT uint32_t */
+} VBOXDNDHGSENDDATAHDRMSG;
+
+/**
+ * Sends a (meta) data block to the guest.
+ *
+ * Used by:
+ * HOST_DND_HG_SND_DATA
+ */
 typedef struct VBOXDNDHGSENDDATAMSG
 {
     VBoxGuestHGCMCallInfo hdr;
 
-    /**
-     * HG Send Data event.
-     *
-     * Used by:
-     * HOST_DND_HG_SND_DATA
-     */
-    HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
-    HGCMFunctionParameter pvFormat;     /* OUT ptr */
-    HGCMFunctionParameter cFormat;      /* OUT uint32_t */
-    HGCMFunctionParameter pvData;       /* OUT ptr */
-    HGCMFunctionParameter cbData;       /* OUT uint32_t */
+    union
+    {
+        struct
+        {
+            HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
+            HGCMFunctionParameter pvFormat;     /* OUT ptr */
+            HGCMFunctionParameter cbFormat;     /* OUT uint32_t */
+            HGCMFunctionParameter pvData;       /* OUT ptr */
+            HGCMFunctionParameter cbData;       /* OUT uint32_t */
+        } v1;
+        /* No changes in v2. */
+        struct
+        {
+            /** Context ID. Unused at the moment. */
+            HGCMFunctionParameter uContext;     /* OUT uint32_t */
+            /** Data block to send. */
+            HGCMFunctionParameter pvData;       /* OUT ptr */
+            /** Size (in bytes) of data block to send. */
+            HGCMFunctionParameter cbData;       /* OUT uint32_t */
+            /** Checksum of data block, based on the checksum
+             *  type in the data header. Optional. */
+            HGCMFunctionParameter pvChecksum;   /* OUT ptr */
+            /** Size (in bytes) of checksum to send. */
+            HGCMFunctionParameter cbChecksum;   /* OUT uint32_t */
+        } v3;
+    } u;
 } VBOXDNDHGSENDDATAMSG;
 
+/**
+ * Sends more (meta) data in case the data didn't fit
+ * into the current XXX_DND_HG_SND_DATA message.
+ *
+ ** @todo Deprecated since protocol v3. Don't use! Will be removed.
+ *
+ * Used by:
+ * HOST_DND_HG_SND_MORE_DATA
+ */
 typedef struct VBOXDNDHGSENDMOREDATAMSG
 {
     VBoxGuestHGCMCallInfo hdr;
 
-    /**
-     * HG Send More Data event.
-     *
-     * Used by:
-     * HOST_DND_HG_SND_MORE_DATA
-     */
     HGCMFunctionParameter pvData;       /* OUT ptr */
     HGCMFunctionParameter cbData;       /* OUT uint32_t */
 } VBOXDNDHGSENDMOREDATAMSG;
 
+/**
+ * Directory entry event.
+ *
+ * Used by:
+ * HOST_DND_HG_SND_DIR
+ * GUEST_DND_GH_SND_DIR
+ */
 typedef struct VBOXDNDHGSENDDIRMSG
 {
     VBoxGuestHGCMCallInfo hdr;
 
-    /**
-     * HG Directory event.
-     *
-     * Used by:
-     * HOST_DND_HG_SND_DIR
-     */
+    /** Directory name. */
     HGCMFunctionParameter pvName;       /* OUT ptr */
+    /** Size (in bytes) of directory name. */
     HGCMFunctionParameter cbName;       /* OUT uint32_t */
+    /** Directory mode. */
     HGCMFunctionParameter fMode;        /* OUT uint32_t */
 } VBOXDNDHGSENDDIRMSG;
 
 /**
- * File header event.
+ * File header message, marking the start of transferring a new file.
  * Note: Only for protocol version 2 and up.
  *
  * Used by:
  * HOST_DND_HG_SND_FILE_HDR
- * HOST_DND_GH_SND_FILE_HDR
+ * GUEST_DND_GH_SND_FILE_HDR
  */
 typedef struct VBOXDNDHGSENDFILEHDRMSG
@@ -341,5 +450,4 @@
     /** Total size (in bytes). */
     HGCMFunctionParameter cbTotal;      /* OUT uint64_t */
-
 } VBOXDNDHGSENDFILEHDRMSG;
 
@@ -360,8 +468,13 @@
         struct
         {
+            /** File name. */
             HGCMFunctionParameter pvName;       /* OUT ptr */
+            /** Size (in bytes) of file name. */
             HGCMFunctionParameter cbName;       /* OUT uint32_t */
+            /** Current data chunk. */
             HGCMFunctionParameter pvData;       /* OUT ptr */
+            /** Size (in bytes) of current data chunk. */
             HGCMFunctionParameter cbData;       /* OUT uint32_t */
+            /** File mode. */
             HGCMFunctionParameter fMode;        /* OUT uint32_t */
         } v1;
@@ -372,37 +485,57 @@
             /** Context ID. Unused at the moment. */
             HGCMFunctionParameter uContext;     /* OUT uint32_t */
+            /** Current data chunk. */
             HGCMFunctionParameter pvData;       /* OUT ptr */
+            /** Size (in bytes) of current data chunk. */
             HGCMFunctionParameter cbData;       /* OUT uint32_t */
             /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
         } v2;
+        struct
+        {
+            /** Context ID. Unused at the moment. */
+            HGCMFunctionParameter uContext;     /* OUT uint32_t */
+            /** Current data chunk. */
+            HGCMFunctionParameter pvData;       /* OUT ptr */
+            /** Size (in bytes) of current data chunk. */
+            HGCMFunctionParameter cbData;       /* OUT uint32_t */
+            /** Checksum of data block, based on the checksum
+             *  type in the data header. Optional. */
+            HGCMFunctionParameter pvChecksum;   /* OUT ptr */
+            /** Size (in bytes) of curren data chunk checksum. */
+            HGCMFunctionParameter cbChecksum;   /* OUT uint32_t */
+        } v3;
     } u;
-
 } VBOXDNDHGSENDFILEDATAMSG;
 
+/**
+ * Asks the guest if a guest->host DnD operation is in progress.
+ *
+ * Used by:
+ * HOST_DND_GH_REQ_PENDING
+ */
 typedef struct VBOXDNDGHREQPENDINGMSG
 {
     VBoxGuestHGCMCallInfo hdr;
 
-    /**
-     * GH Request Pending event.
-     *
-     * Used by:
-     * HOST_DND_GH_REQ_PENDING
-     */
+    /** Screen ID. */
     HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
 } VBOXDNDGHREQPENDINGMSG;
 
+/**
+ * Tells the guest that the host has dropped the ongoing guest->host
+ * DnD operation on a valid target on the host.
+ *
+ * Used by:
+ * HOST_DND_GH_EVT_DROPPED
+ */
 typedef struct VBOXDNDGHDROPPEDMSG
 {
     VBoxGuestHGCMCallInfo hdr;
 
-    /**
-     * GH Dropped event.
-     *
-     * Used by:
-     * HOST_DND_GH_EVT_DROPPED
-     */
+    /** Requested format for sending the data. */
     HGCMFunctionParameter pvFormat;     /* OUT ptr */
-    HGCMFunctionParameter cFormat;      /* OUT uint32_t */
+    /** Size (in bytes) of requested format. */
+    HGCMFunctionParameter cbFormat;     /* OUT uint32_t */
+    /** Drop action peformed on the host. */
     HGCMFunctionParameter uAction;      /* OUT uint32_t */
 } VBOXDNDGHDROPPEDMSG;
@@ -423,15 +556,15 @@
     VBoxGuestHGCMCallInfo hdr;
 
-    HGCMFunctionParameter msg;          /* OUT uint32_t */
+    /** Message ID. */
+    HGCMFunctionParameter uMsg;      /* OUT uint32_t */
     /** Number of parameters the message needs. */
-    HGCMFunctionParameter num_parms;    /* OUT uint32_t */
+    HGCMFunctionParameter cParms;    /* OUT uint32_t */
     /** Whether or not to block (wait) for a
      *  new message to arrive. */
-    HGCMFunctionParameter block;        /* OUT uint32_t */
-
+    HGCMFunctionParameter fBlock;    /* OUT uint32_t */
 } VBOXDNDNEXTMSGMSG;
 
 /**
- * Connection request. Used to tell the DnD protocol
+ * Guest connection request. Used to tell the DnD protocol
  * version to the (host) service.
  *
@@ -447,5 +580,4 @@
     /** Connection flags. Optional. */
     HGCMFunctionParameter uFlags;        /* OUT uint32_t */
-
 } VBOXDNDCONNECTMSG;
 
@@ -486,5 +618,6 @@
 
 /**
- * GH Acknowledge Pending event.
+ * Acknowledges a pending drag and drop event
+ * to the host.
  *
  * Used by:
@@ -501,5 +634,16 @@
 
 /**
- * GH Send Data event.
+ * Sends the header of an incoming data block
+ * to the host.
+ *
+ * Used by:
+ * GUEST_DND_GH_SND_DATA_HDR
+ *
+ * New since protocol v3.
+ */
+typedef struct VBOXDNDHGSENDDATAHDRMSG VBOXDNDGHSENDDATAHDRMSG;
+
+/**
+ * Sends a (meta) data block to the host.
  *
  * Used by:
@@ -507,45 +651,4 @@
  */
 typedef struct VBOXDNDGHSENDDATAMSG
-{
-    VBoxGuestHGCMCallInfo hdr;
-
-    HGCMFunctionParameter pvData;       /* OUT ptr */
-    /** Total bytes to send. This can be more than
-     *  the data block specified in pvData above, e.g.
-     *  when sending over file objects afterwards. */
-    HGCMFunctionParameter cbTotalBytes; /* OUT uint32_t */
-} VBOXDNDGHSENDDATAMSG;
-
-/**
- * GH Directory event.
- *
- * Used by:
- * GUEST_DND_GH_SND_DIR
- */
-typedef struct VBOXDNDGHSENDDIRMSG
-{
-    VBoxGuestHGCMCallInfo hdr;
-
-    HGCMFunctionParameter pvName;       /* OUT ptr */
-    HGCMFunctionParameter cbName;       /* OUT uint32_t */
-    HGCMFunctionParameter fMode;        /* OUT uint32_t */
-} VBOXDNDGHSENDDIRMSG;
-
-/**
- * GH File header event.
- * Note: Only for protocol version 2 and up.
- *
- * Used by:
- * HOST_DND_GH_SND_FILE_HDR
- */
-typedef struct VBOXDNDHGSENDFILEHDRMSG VBOXDNDGHSENDFILEHDRMSG;
-
-/**
- * GH File data event.
- *
- * Used by:
- * GUEST_DND_HG_SND_FILE_DATA
- */
-typedef struct VBOXDNDGHSENDFILEDATAMSG
 {
     VBoxGuestHGCMCallInfo hdr;
@@ -553,30 +656,56 @@
     union
     {
-        /* Note: Protocol v1 sends the file name + file mode
-         *       every time a file data chunk is being sent. */
-        struct
-        {
-            HGCMFunctionParameter pvName;   /* OUT ptr */
-            HGCMFunctionParameter cbName;   /* OUT uint32_t */
-            HGCMFunctionParameter fMode;    /* OUT uint32_t */
-            HGCMFunctionParameter pvData;   /* OUT ptr */
-            HGCMFunctionParameter cbData;   /* OUT uint32_t */
+        struct
+        {
+            HGCMFunctionParameter pvData;       /* OUT ptr */
+            /** Total bytes to send. This can be more than
+             * the data block specified in pvData above, e.g.
+             * when sending over file objects afterwards. */
+            HGCMFunctionParameter cbTotalBytes; /* OUT uint32_t */
         } v1;
         struct
         {
-            /** Note: pvName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
-            /** Note: cbName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
             /** Context ID. Unused at the moment. */
-            HGCMFunctionParameter uContext; /* OUT uint32_t */
-            HGCMFunctionParameter pvData;   /* OUT ptr */
-            HGCMFunctionParameter cbData;   /* OUT uint32_t */
-            /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
-        } v2;
+            HGCMFunctionParameter uContext;     /* OUT uint32_t */
+            /** Data block to send. */
+            HGCMFunctionParameter pvData;       /* OUT ptr */
+            /** Size (in bytes) of data block to send. */
+            HGCMFunctionParameter cbData;       /* OUT uint32_t */
+            /** (Rolling) Checksum, based on checksum type in data header. */
+            HGCMFunctionParameter pvChecksum;   /* OUT ptr */
+            /** Size (in bytes) of checksum. */
+            HGCMFunctionParameter cbChecksum;   /* OUT uint32_t */
+        } v3;
     } u;
-
-} VBOXDNDGHSENDFILEDATAMSG;
-
-/**
- * GH Error event.
+} VBOXDNDGHSENDDATAMSG;
+
+/**
+ * Sends a directory entry to the host.
+ *
+ * Used by:
+ * GUEST_DND_GH_SND_DIR
+ */
+typedef struct VBOXDNDHGSENDDIRMSG VBOXDNDGHSENDDIRMSG;
+
+/**
+ * Sends a file header to the host.
+ *
+ * Used by:
+ * GUEST_DND_GH_SND_FILE_HDR
+ *
+ * New since protocol v2.
+ */
+typedef struct VBOXDNDHGSENDFILEHDRMSG VBOXDNDGHSENDFILEHDRMSG;
+
+/**
+ * Sends file data to the host.
+ *
+ * Used by:
+ * GUEST_DND_GH_SND_FILE_DATA
+ */
+typedef struct VBOXDNDHGSENDFILEDATAMSG VBOXDNDGHSENDFILEDATAMSG;
+
+/**
+ * Sends a guest error event to the host.
  *
  * Used by:
@@ -604,4 +733,5 @@
     CB_MAGIC_DND_GH_ACK_PENDING            = 0xbe975a14,
     CB_MAGIC_DND_GH_SND_DATA               = 0x4eb61bff,
+    CB_MAGIC_DND_GH_SND_DATA_HDR           = 0x4631ee4f,
     CB_MAGIC_DND_GH_SND_DIR                = 0x411ca754,
     CB_MAGIC_DND_GH_SND_FILE_HDR           = 0x65e35eaf,
@@ -669,13 +799,82 @@
 } VBOXDNDCBGHACKPENDINGDATA, *PVBOXDNDCBGHACKPENDINGDATA;
 
+/**
+ * Data header.
+ * New since protocol v3.
+ */
+typedef struct VBOXDNDDATAHDR
+{
+    /** Data transfer flags. Not yet used and must be 0. */
+    uint32_t                    uFlags;
+    /** Screen ID where the data originates from. */
+    uint32_t                    uScreenId;
+    /** Total size (in bytes) to transfer. */
+    uint64_t                    cbTotal;
+    /** Meta data size (in bytes) to transfer.
+     *  This size also is part of cbTotal already. */
+    uint32_t                    cbMeta;
+    /** Meta format buffer. */
+    void                       *pvMetaFmt;
+    /** Size (in bytes) of meta format buffer. */
+    uint32_t                    cbMetaFmt;
+    /** Number of objects (files/directories) to transfer. */
+    uint64_t                    cObjects;
+    /** Compression type. Currently unused, so specify 0.
+     **@todo Add IPRT compression type enumeration as soon as it's available. */
+    uint32_t                    enmCompression;
+    /** Checksum type. Currently unused, so specify RTDIGESTTYPE_INVALID. */
+    RTDIGESTTYPE                enmChecksumType;
+    /** The actual checksum buffer for the entire data to be transferred,
+     *  based on enmChksumType. If RTDIGESTTYPE_INVALID is specified,
+     *  no checksum is being used and pvChecksum will be NULL. */
+    void                       *pvChecksum;
+    /** Size (in bytes) of checksum. */
+    uint32_t                    cbChecksum;
+} VBOXDNDDATAHDR, *PVBOXDNDSNDDATAHDR;
+
+/* New since protocol v3. */
+typedef struct VBOXDNDCBSNDDATAHDRDATA
+{
+    /** Callback data header. */
+    VBOXDNDCBHEADERDATA         hdr;
+    /** Actual header data. */
+    VBOXDNDDATAHDR              data;
+} VBOXDNDCBSNDDATAHDRDATA, *PVBOXDNDCBSNDDATAHDRDATA;
+
+typedef struct VBOXDNDSNDDATA
+{
+    union
+    {
+        struct
+        {
+            /** Data block buffer. */
+            void                       *pvData;
+            /** Size (in bytes) of data block. */
+            uint32_t                    cbData;
+            /** Total metadata size (in bytes). This is transmitted
+             *  with every message because the size can change. */
+            uint32_t                    cbTotalSize;
+        } v1;
+        /* Protocol v2: No changes. */
+        struct
+        {
+            /** Data block buffer. */
+            void                       *pvData;
+            /** Size (in bytes) of data block. */
+            uint32_t                    cbData;
+            /** (Rolling) Checksum. Not yet implemented. */
+            void                       *pvChecksum;
+            /** Size (in bytes) of checksum. Not yet implemented. */
+            uint32_t                    cbChecksum;
+        } v3;
+    } u;
+} VBOXDNDSNDDATA, *PVBOXDNDSNDDATA;
+
 typedef struct VBOXDNDCBSNDDATADATA
 {
     /** Callback data header. */
     VBOXDNDCBHEADERDATA         hdr;
-    void                       *pvData;
-    uint32_t                    cbData;
-    /** Total metadata size (in bytes). This is transmitted
-     *  with every message because the size can change. */
-    uint32_t                    cbTotalSize;
+    /** Actual data. */
+    VBOXDNDSNDDATA              data;
 } VBOXDNDCBSNDDATADATA, *PVBOXDNDCBSNDDATADATA;
 
@@ -684,10 +883,13 @@
     /** Callback data header. */
     VBOXDNDCBHEADERDATA         hdr;
+    /** Directory path. */
     char                       *pszPath;
+    /** Size (in bytes) of path. */
     uint32_t                    cbPath;
+    /** Directory creation mode. */
     uint32_t                    fMode;
 } VBOXDNDCBSNDDIRDATA, *PVBOXDNDCBSNDDIRDATA;
 
-/*  Note: Only for protocol version 2 and up (>= VBox 5.0). */
+/* Note: Only for protocol version 2 and up (>= VBox 5.0). */
 typedef struct VBOXDNDCBSNDFILEHDRDATA
 {
@@ -725,6 +927,13 @@
             uint32_t            fMode;
         } v1;
-        /* Note: Protocol version 2 has the file attributes (name, size,
-                 mode, ...) in the VBOXDNDCBSNDFILEHDRDATA structure. */
+        /* Protocol v2 + v3: Have the file attributes (name, size, mode, ...)
+                             in the VBOXDNDCBSNDFILEHDRDATA structure. */
+        struct
+        {
+            /** Checksum for current file data chunk. */
+            void               *pvChecksum;
+            /** Size (in bytes) of current data chunk. */
+            uint32_t            cbChecksum;
+        } v3;
     } u;
 } VBOXDNDCBSNDFILEDATADATA, *PVBOXDNDCBSNDFILEDATADATA;
Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 58211)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 58212)
@@ -125,5 +125,5 @@
  * The library termination function.
  */
-DECLVBGL(void) VbglTerminate(void);
+DECLVBGL(void) VbglTerminate (void);
 
 
@@ -149,5 +149,5 @@
  * @return VBox status code.
  */
-DECLVBGL(int) VbglGRPerform(VMMDevRequestHeader *pReq);
+DECLVBGL(int) VbglGRPerform (VMMDevRequestHeader *pReq);
 
 /**
@@ -158,5 +158,5 @@
  * @return VBox status code.
  */
-DECLVBGL(void) VbglGRFree(VMMDevRequestHeader *pReq);
+DECLVBGL(void) VbglGRFree (VMMDevRequestHeader *pReq);
 
 /**
@@ -170,5 +170,5 @@
  * @return VBox status code.
  */
-DECLVBGL(int) VbglGRVerify(const VMMDevRequestHeader *pReq, size_t cbReq);
+DECLVBGL(int) VbglGRVerify (const VMMDevRequestHeader *pReq, size_t cbReq);
 /** @} */
 
@@ -205,6 +205,6 @@
  */
 
-DECLR0VBGL(int) VbglR0HGCMInternalConnect(VBoxGuestHGCMConnectInfo *pConnectInfo,
-                                          PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
+DECLR0VBGL(int) VbglR0HGCMInternalConnect (VBoxGuestHGCMConnectInfo *pConnectInfo,
+                                           PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
 
 
@@ -226,6 +226,6 @@
  */
 
-DECLR0VBGL(int) VbglR0HGCMInternalDisconnect(VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
-                                             PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
+DECLR0VBGL(int) VbglR0HGCMInternalDisconnect (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
+                                              PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
 
 /** Call a HGCM service.
@@ -243,6 +243,6 @@
  * @return VBox status code.
  */
-DECLR0VBGL(int) VbglR0HGCMInternalCall(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
-                                       PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
+DECLR0VBGL(int) VbglR0HGCMInternalCall (VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
+                                        PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
 
 /** Call a HGCM service. (32 bits packet structure in a 64 bits guest)
@@ -260,6 +260,6 @@
  * @return  VBox status code.
  */
-DECLR0VBGL(int) VbglR0HGCMInternalCall32(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
-                                         PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
+DECLR0VBGL(int) VbglR0HGCMInternalCall32 (VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
+                                          PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
 
 /** @name VbglR0HGCMInternalCall flags
@@ -296,5 +296,5 @@
  * @return VBox status code.
  */
-DECLVBGL(int) VbglHGCMConnect(VBGLHGCMHANDLE *pHandle, VBoxGuestHGCMConnectInfo *pData);
+DECLVBGL(int) VbglHGCMConnect (VBGLHGCMHANDLE *pHandle, VBoxGuestHGCMConnectInfo *pData);
 
 /**
@@ -306,5 +306,5 @@
  * @return VBox status code.
  */
-DECLVBGL(int) VbglHGCMDisconnect(VBGLHGCMHANDLE handle, VBoxGuestHGCMDisconnectInfo *pData);
+DECLVBGL(int) VbglHGCMDisconnect (VBGLHGCMHANDLE handle, VBoxGuestHGCMDisconnectInfo *pData);
 
 /**
@@ -317,5 +317,5 @@
  * @return VBox status code.
  */
-DECLVBGL(int) VbglHGCMCall(VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
+DECLVBGL(int) VbglHGCMCall (VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
 
 /**
@@ -329,5 +329,5 @@
  * @return VBox status code.
  */
-DECLVBGL(int) VbglHGCMCallUserData(VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
+DECLVBGL(int) VbglHGCMCallUserData (VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
 
 /**
@@ -365,10 +365,10 @@
  * @returns VBox status code.
  */
-DECLVBGL(int) VbglPhysHeapInit(void);
+DECLVBGL(int) VbglPhysHeapInit (void);
 
 /**
  * Shutdown the heap.
  */
-DECLVBGL(void) VbglPhysHeapTerminate(void);
+DECLVBGL(void) VbglPhysHeapTerminate (void);
 
 /**
@@ -376,7 +376,7 @@
  *
  * @returns Virtual address of the allocated memory block.
- * @param   cbSize    Size of block to be allocated.
- */
-DECLVBGL(void *) VbglPhysHeapAlloc(uint32_t cbSize);
+ * @param cbSize    Size of block to be allocated.
+ */
+DECLVBGL(void *) VbglPhysHeapAlloc (uint32_t cbSize);
 
 /**
@@ -401,13 +401,13 @@
 DECLVBGL(void)      VbglPhysHeapFree(void *pv);
 
-DECLVBGL(int)       VbglQueryVMMDevMemory(VMMDevMemory **ppVMMDevMemory);
-DECLR0VBGL(bool)    VbglR0CanUsePhysPageList(void);
+DECLVBGL(int) VbglQueryVMMDevMemory (VMMDevMemory **ppVMMDevMemory);
+DECLR0VBGL(bool) VbglR0CanUsePhysPageList(void);
 
 # ifndef VBOX_GUEST
 /** @name Mouse
  * @{ */
-DECLVBGL(int)       VbglSetMouseNotifyCallback(PFNVBOXGUESTMOUSENOTIFY pfnNotify, void *pvUser);
-DECLVBGL(int)       VbglGetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py);
-DECLVBGL(int)       VbglSetMouseStatus(uint32_t fFeatures);
+DECLVBGL(int)     VbglSetMouseNotifyCallback(PFNVBOXGUESTMOUSENOTIFY pfnNotify, void *pvUser);
+DECLVBGL(int)     VbglGetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py);
+DECLVBGL(int)     VbglSetMouseStatus(uint32_t fFeatures);
 /** @}  */
 # endif /* VBOX_GUEST */
@@ -492,5 +492,5 @@
 /** The folder for the video mode hint unix domain socket on Unix-like guests.
  * @note This can be safely changed as all users are rebuilt in lock-step. */
-#define VBGLR3HOSTDISPSOCKETPATH    "/tmp/.VBoxService"
+#define VBGLR3HOSTDISPSOCKETPATH "/tmp/.VBoxService"
 /** The path to the video mode hint unix domain socket on Unix-like guests. */
 #define VBGLR3HOSTDISPSOCKET        VBGLR3VIDEOMODEHINTSOCKETPATH "/VideoModeHint"
@@ -758,10 +758,12 @@
      *        Use a union for the HGCM stuff then. */
 
-    /** IN: HGCM client ID to use for communication. */
+    /** IN:  HGCM client ID to use for communication. */
     uint32_t uClientID;
-    /** IN: Protocol version to use. */
+    /** IN:  Protocol version to use. */
     uint32_t uProtocol;
     /** OUT: Number of parameters retrieved. */
     uint32_t uNumParms;
+    /** IN:  Max chunk size (in bytes) for data transfers. */
+    uint32_t cbMaxChunkSize;
 } VBGLR3GUESTDNDCMDCTX, *PVBGLR3GUESTDNDCMDCTX;
 
@@ -771,5 +773,5 @@
     uint32_t uScreenId;           /** Screen ID this request belongs to. */
     char    *pszFormats;          /** Format list (\r\n separated). */
-    uint32_t cbFormats;           /** Size of pszFormats (\0 included). */
+    uint32_t cbFormats;           /** Size (in bytes) of pszFormats (\0 included). */
     union
     {
@@ -784,5 +786,5 @@
         {
             void    *pvData;      /** Data request. */
-            size_t   cbData;      /** Size of pvData. */
+            uint32_t cbData;      /** Size (in bytes) of pvData. */
         } b; /** Values used in drop data event type. */
     } u;
@@ -793,12 +795,11 @@
 VBGLR3DECL(int)     VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx);
 
-VBGLR3DECL(int)     VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent);
-
-VBGLR3DECL(int)     VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction);
-VBGLR3DECL(int)     VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat);
-VBGLR3DECL(int)     VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
+VBGLR3DECL(int)     VbglR3DnDRecvNextMsg(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent);
+
+VBGLR3DECL(int)     VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction);
+VBGLR3DECL(int)     VbglR3DnDHGSendReqData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pcszFormat);
+VBGLR3DECL(int)     VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
 #  ifdef VBOX_WITH_DRAG_AND_DROP_GH
-VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uDefAction,
-                                                  uint32_t uAllActions, const char *pszFormats);
+VBGLR3DECL(int)     VbglR3DnDGHSendAckPending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats, uint32_t cbFormats);
 VBGLR3DECL(int)     VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData);
 VBGLR3DECL(int)     VbglR3DnDGHSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcOp);
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp	(revision 58211)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp	(revision 58212)
@@ -22,4 +22,6 @@
 #include <VBox/VBoxGuestLib.h>
 #include "VBox/HostServices/DragAndDropSvc.h"
+
+using namespace DragAndDropSvc;
 
 #include <iprt/asm.h>
@@ -520,5 +522,5 @@
             switch (pEvent->Event.uType)
             {
-                case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
+                case HOST_DND_HG_EVT_ENTER:
                 {
                     LogFlowThisFunc(("HOST_DND_HG_EVT_ENTER\n"));
@@ -540,5 +542,5 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
+                case HOST_DND_HG_EVT_MOVE:
                 {
                     LogFlowThisFunc(("HOST_DND_HG_EVT_MOVE: %d,%d\n",
@@ -550,5 +552,5 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
+                case HOST_DND_HG_EVT_LEAVE:
                 {
                     LogFlowThisFunc(("HOST_DND_HG_EVT_LEAVE\n"));
@@ -558,5 +560,5 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+                case HOST_DND_HG_EVT_DROPPED:
                 {
                     LogFlowThisFunc(("HOST_DND_HG_EVT_DROPPED\n"));
@@ -566,5 +568,8 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+                case HOST_DND_HG_SND_DATA:
+                    /* Protocol v1 + v2: Also contains the header data.
+                    /* Note: Fall through is intentional. */
+                case HOST_DND_HG_SND_DATA_HDR:
                 {
                     LogFlowThisFunc(("HOST_DND_HG_SND_DATA\n"));
@@ -575,5 +580,5 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
+                case HOST_DND_HG_EVT_CANCEL:
                 {
                     LogFlowThisFunc(("HOST_DND_HG_EVT_CANCEL\n"));
@@ -583,5 +588,5 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
+                case HOST_DND_GH_REQ_PENDING:
                 {
                     LogFlowThisFunc(("HOST_DND_GH_REQ_PENDING\n"));
@@ -595,5 +600,5 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+                case HOST_DND_GH_EVT_DROPPED:
                 {
                     LogFlowThisFunc(("HOST_DND_GH_EVT_DROPPED\n"));
@@ -616,9 +621,9 @@
             switch (pEvent->Event.uType)
             {
-                case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
-                case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
-                case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
+                case HOST_DND_HG_EVT_ENTER:
+                case HOST_DND_HG_EVT_MOVE:
+                case HOST_DND_HG_EVT_DROPPED:
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-                case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
+                case HOST_DND_GH_EVT_DROPPED:
 #endif
                 {
@@ -628,5 +633,6 @@
                 }
 
-                case DragAndDropSvc::HOST_DND_HG_SND_DATA:
+                case HOST_DND_HG_SND_DATA:
+                case HOST_DND_HG_SND_DATA_HDR:
                 {
                     if (pEvent->Event.pszFormats)
@@ -945,5 +951,5 @@
     if (RT_SUCCESS(rc))
     {
-        rc = VbglR3DnDHGAcknowledgeOperation(&mDnDCtx, uActionNotify);
+        rc = VbglR3DnDHGSendAckOp(&mDnDCtx, uActionNotify);
         if (RT_FAILURE(rc))
             LogFlowThisFunc(("Acknowledging operation failed with rc=%Rrc\n", rc));
@@ -1015,5 +1021,5 @@
             {
                 LogRel(("DnD: Requesting data as '%s' ...\n", mFormatRequested.c_str()));
-                rc = VbglR3DnDHGRequestData(&mDnDCtx, mFormatRequested.c_str());
+                rc = VbglR3DnDHGSendReqData(&mDnDCtx, mFormatRequested.c_str());
                 if (RT_FAILURE(rc))
                     LogFlowThisFunc(("Requesting data failed with rc=%Rrc\n", rc));
@@ -1215,6 +1221,7 @@
         uAllActions = uDefAction;
 
-        rc = VbglR3DnDGHAcknowledgePending(&mDnDCtx,
-                                           uDefAction, uAllActions, strFormats.c_str());
+        rc = VbglR3DnDGHSendAckPending(&mDnDCtx,
+                                       uDefAction, uAllActions,
+                                       strFormats.c_str(), strFormats.length() + 1 /* Include termination */);
         if (RT_FAILURE(rc))
         {
@@ -1761,7 +1768,6 @@
         /* Note: pEvent will be free'd by the consumer later. */
 
-        rc = VbglR3DnDProcessNextMessage(&pCtx->cmdCtx, &pEvent->Event);
-        LogFlowFunc(("VbglR3DnDProcessNextMessage returned uType=%RU32, rc=%Rrc\n",
-                     pEvent->Event.uType, rc));
+        rc = VbglR3DnDRecvNextMsg(&pCtx->cmdCtx, &pEvent->Event);
+        LogFlowFunc(("VbglR3DnDRecvNextMsg: uType=%RU32, rc=%Rrc\n", pEvent->Event.uType, rc));
 
         if (   RT_SUCCESS(rc)
Index: /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 58211)
+++ /trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp	(revision 58212)
@@ -48,22 +48,19 @@
 #include <VBox/HostServices/DragAndDropSvc.h>
 
+using namespace DragAndDropSvc;
+
 #include "VBGLR3Internal.h"
 
-/* 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)
- */
-
-
 /*********************************************************************************************************************************
-*   Private internal functions                                                                                                   *
+*    Forward declarations                                                                                                        *
 *********************************************************************************************************************************/
 
-static int vbglR3DnDQueryNextHostMessageType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
+VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
+
+/*********************************************************************************************************************************
+*    Private internal functions                                                                                                  *
+*********************************************************************************************************************************/
+
+static int vbglR3DnDGetNextMsgType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
 {
     AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
@@ -71,14 +68,14 @@
     AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
+    VBOXDNDNEXTMSGMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
+    Msg.hdr.u32Function = GUEST_DND_GET_NEXT_HOST_MSG;
     Msg.hdr.cParms      = 3;
 
-    Msg.msg.SetUInt32(0);
-    Msg.num_parms.SetUInt32(0);
-    Msg.block.SetUInt32(fWait ? 1 : 0);
+    Msg.uMsg.SetUInt32(0);
+    Msg.cParms.SetUInt32(0);
+    Msg.fBlock.SetUInt32(fWait ? 1 : 0);
 
     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
@@ -88,22 +85,23 @@
         if (RT_SUCCESS(rc))
         {
-            rc = Msg.msg.GetUInt32(puMsg);         AssertRC(rc);
-            rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
-        }
-    }
-
-    return rc;
-}
-
-static int vbglR3DnDHGProcessActionMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                           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)
+            rc = Msg.uMsg.GetUInt32(puMsg);         AssertRC(rc);
+            rc = Msg.cParms.GetUInt32(pcParms); AssertRC(rc);
+        }
+    }
+
+    return rc;
+}
+
+/** @todo r=andy Clean up the parameter list. */
+static int vbglR3DnDHGRecvAction(PVBGLR3GUESTDNDCMDCTX pCtx,
+                                 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)
 {
     AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
@@ -117,6 +115,7 @@
     AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
+    VBOXDNDHGACTIONMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
     Msg.hdr.u32Function = uMsg;
@@ -151,12 +150,12 @@
 }
 
-static int vbglR3DnDHGProcessLeaveMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
+static int vbglR3DnDHGRecvLeave(PVBGLR3GUESTDNDCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
+    VBOXDNDHGLEAVEMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
+    Msg.hdr.u32Function = HOST_DND_HG_EVT_LEAVE;
     Msg.hdr.cParms      = 0;
 
@@ -168,12 +167,13 @@
 }
 
-static int vbglR3DnDHGProcessCancelMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
+static int vbglR3DnDHGRecvCancel(PVBGLR3GUESTDNDCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
+    VBOXDNDHGCANCELMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
+    Msg.hdr.u32Function = HOST_DND_HG_EVT_CANCEL;
     Msg.hdr.cParms      = 0;
 
@@ -185,9 +185,9 @@
 }
 
-static int vbglR3DnDHGProcessSendDirMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                            char     *pszDirname,
-                                            uint32_t  cbDirname,
-                                            uint32_t *pcbDirnameRecv,
-                                            uint32_t *pfMode)
+static int vbglR3DnDHGRecvDir(PVBGLR3GUESTDNDCMDCTX pCtx,
+                              char     *pszDirname,
+                              uint32_t  cbDirname,
+                              uint32_t *pcbDirnameRecv,
+                              uint32_t *pfMode)
 {
     AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
@@ -197,12 +197,13 @@
     AssertPtrReturn(pfMode,         VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
+    VBOXDNDHGSENDDIRMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
+    Msg.hdr.u32Function = HOST_DND_HG_SND_DIR;
     Msg.hdr.cParms      = 3;
 
     Msg.pvName.SetPtr(pszDirname, cbDirname);
-    Msg.cbName.SetUInt32(0);
+    Msg.cbName.SetUInt32(cbDirname);
     Msg.fMode.SetUInt32(0);
 
@@ -223,12 +224,12 @@
 }
 
-static int vbglR3DnDHGProcessSendFileMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                             char                 *pszFilename,
-                                             uint32_t              cbFilename,
-                                             uint32_t             *pcbFilenameRecv,
-                                             void                 *pvData,
-                                             uint32_t              cbData,
-                                             uint32_t             *pcbDataRecv,
-                                             uint32_t             *pfMode)
+static int vbglR3DnDHGRecvFileData(PVBGLR3GUESTDNDCMDCTX pCtx,
+                                   char                 *pszFilename,
+                                   uint32_t              cbFilename,
+                                   uint32_t             *pcbFilenameRecv,
+                                   void                 *pvData,
+                                   uint32_t              cbData,
+                                   uint32_t             *pcbDataRecv,
+                                   uint32_t             *pfMode)
 {
     AssertPtrReturn(pCtx,            VERR_INVALID_POINTER);
@@ -241,22 +242,23 @@
     AssertPtrReturn(pfMode,          VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGSENDFILEDATAMSG Msg;
+    VBOXDNDHGSENDFILEDATAMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA;
+    Msg.hdr.u32Function = HOST_DND_HG_SND_FILE_DATA;
 
     if (pCtx->uProtocol <= 1)
     {
         Msg.u.v1.pvName.SetPtr(pszFilename, cbFilename);
-        Msg.u.v1.cbName.SetUInt32(cbFilename);
+        Msg.u.v1.cbName.SetUInt32(0);
         Msg.u.v1.pvData.SetPtr(pvData, cbData);
-        Msg.u.v1.cbData.SetUInt32(cbData);
+        Msg.u.v1.cbData.SetUInt32(0);
         Msg.u.v1.fMode.SetUInt32(0);
 
         Msg.hdr.cParms = 5;
     }
-    else
-    {
-        Msg.u.v2.uContext.SetUInt32(0); /** @todo Not used yet. */
+    else if (pCtx->uProtocol == 2)
+    {
+        Msg.u.v2.uContext.SetUInt32(0);
         Msg.u.v2.pvData.SetPtr(pvData, cbData);
         Msg.u.v2.cbData.SetUInt32(cbData);
@@ -264,4 +266,16 @@
         Msg.hdr.cParms = 3;
     }
+    else if (pCtx->uProtocol >= 3)
+    {
+        Msg.u.v3.uContext.SetUInt32(0);
+        Msg.u.v3.pvData.SetPtr(pvData, cbData);
+        Msg.u.v3.cbData.SetUInt32(0);
+        Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
+        Msg.u.v3.cbChecksum.SetUInt32(0);
+
+        Msg.hdr.cParms = 5;
+    }
+    else
+        AssertMsgFailed(("Protocol %RU32 not implemented\n", pCtx->uProtocol));
 
     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
@@ -280,22 +294,31 @@
                 AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
             }
-            else
-            {
+            else if (pCtx->uProtocol == 2)
+            {
+                /** @todo Context ID not used yet. */
                 rc = Msg.u.v2.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
                 AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
             }
-        }
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-static int vbglR3DnDHGProcessSendFileHdrMessage(PVBGLR3GUESTDNDCMDCTX  pCtx,
-                                                char                  *pszFilename,
-                                                uint32_t               cbFilename,
-                                                uint32_t              *puFlags,
-                                                uint32_t              *pfMode,
-                                                uint64_t              *pcbTotal)
+            else if (pCtx->uProtocol >= 3)
+            {
+                /** @todo Context ID not used yet. */
+                rc = Msg.u.v3.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
+                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
+                /** @todo Add checksum support. */
+            }
+            else
+                AssertMsgFailed(("Protocol %RU32 not implemented\n", pCtx->uProtocol));
+        }
+    }
+
+    return rc;
+}
+
+static int vbglR3DnDHGRecvFileHdr(PVBGLR3GUESTDNDCMDCTX  pCtx,
+                                  char                  *pszFilename,
+                                  uint32_t               cbFilename,
+                                  uint32_t              *puFlags,
+                                  uint32_t              *pfMode,
+                                  uint64_t              *pcbTotal)
 {
     AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
@@ -306,8 +329,9 @@
     AssertReturn(pcbTotal,       VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGSENDFILEHDRMSG Msg;
+    VBOXDNDHGSENDFILEHDRMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR;
+    Msg.hdr.u32Function = HOST_DND_HG_SND_FILE_HDR;
 
     int rc;
@@ -348,22 +372,17 @@
 }
 
-static int vbglR3DnDHGProcessURIMessages(PVBGLR3GUESTDNDCMDCTX   pCtx,
-                                         void                  **ppvData,
-                                         uint32_t                cbData,
-                                         size_t                 *pcbDataRecv)
-{
-    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
-    AssertPtrReturn(ppvData,     VERR_INVALID_POINTER);
-    AssertReturn(cbData,         VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
+static int vbglR3DnDHGRecvURIData(PVBGLR3GUESTDNDCMDCTX pCtx, DnDDroppedFiles *pDroppedFiles)
+{
+    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
+    AssertPtrReturn(pDroppedFiles, VERR_INVALID_POINTER);
 
     /*
-     * Allocate chunk buffer.
+     * Allocate temporary chunk buffer.
      */
-    uint32_t cbChunkMax = _64K; /** @todo Make this configurable? */
+    uint32_t cbChunkMax = pCtx->cbMaxChunkSize;
     void *pvChunk = RTMemAlloc(cbChunkMax);
     if (!pvChunk)
         return VERR_NO_MEMORY;
-    uint32_t cbChunkRead = 0;
+    uint32_t cbChunkRead   = 0;
 
     uint64_t cbFileSize    = 0; /* Total file size (in bytes). */
@@ -373,6 +392,5 @@
      * Create and query the (unique) drop target directory in the user's temporary directory.
      */
-    DnDDroppedFiles droppedFiles;
-    int rc = droppedFiles.OpenTemp(0 /* fFlags */);
+    int rc = pDroppedFiles->OpenTemp(0 /* fFlags */);
     if (RT_FAILURE(rc))
     {
@@ -381,5 +399,5 @@
     }
 
-    const char *pszDropDir = droppedFiles.GetDirAbs();
+    const char *pszDropDir = pDroppedFiles->GetDirAbs();
     AssertPtr(pszDropDir);
 
@@ -387,5 +405,4 @@
      * Enter the main loop of retieving files + directories.
      */
-    DnDURIList lstURI;
     DnDURIObject objFile(DnDURIObject::File);
 
@@ -399,5 +416,5 @@
         uint32_t uNextMsg;
         uint32_t cNextParms;
-        rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
+        rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
         if (RT_SUCCESS(rc))
         {
@@ -406,11 +423,11 @@
             switch (uNextMsg)
             {
-                case DragAndDropSvc::HOST_DND_HG_SND_DIR:
+                case HOST_DND_HG_SND_DIR:
                 {
-                    rc = vbglR3DnDHGProcessSendDirMessage(pCtx,
-                                                          szPathName,
-                                                          sizeof(szPathName),
-                                                          &cbPathName,
-                                                          &fMode);
+                    rc = vbglR3DnDHGRecvDir(pCtx,
+                                            szPathName,
+                                            sizeof(szPathName),
+                                            &cbPathName,
+                                            &fMode);
                     LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
                                  szPathName, cbPathName, fMode, rc));
@@ -426,5 +443,5 @@
                         rc = RTDirCreate(pszPathAbs, fCreationMode, 0);
                         if (RT_SUCCESS(rc))
-                            rc = droppedFiles.AddDir(pszPathAbs);
+                            rc = pDroppedFiles->AddDir(pszPathAbs);
 
                         RTStrFree(pszPathAbs);
@@ -434,29 +451,31 @@
                     break;
                 }
-                case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
-                case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
+                case HOST_DND_HG_SND_FILE_HDR:
+                case HOST_DND_HG_SND_FILE_DATA:
                 {
-                    if (uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR)
+                    if (uNextMsg == HOST_DND_HG_SND_FILE_HDR)
                     {
-                        rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
-                                                                  szPathName,
-                                                                  sizeof(szPathName),
-                                                                  &fFlags,
-                                                                  &fMode,
-                                                                  &cbFileSize);
-                        LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
+                        rc = vbglR3DnDHGRecvFileHdr(pCtx,
+                                                    szPathName,
+                                                    sizeof(szPathName),
+                                                    &fFlags,
+                                                    &fMode,
+                                                    &cbFileSize);
+                        LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR: "
+                                     "szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
                                      szPathName, fFlags, fMode, cbFileSize, rc));
                     }
                     else
                     {
-                        rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
-                                                               szPathName,
-                                                               sizeof(szPathName),
-                                                               &cbPathName,
-                                                               pvChunk,
-                                                               cbChunkMax,
-                                                               &cbChunkRead,
-                                                               &fMode);
-                        LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
+                        rc = vbglR3DnDHGRecvFileData(pCtx,
+                                                     szPathName,
+                                                     sizeof(szPathName),
+                                                     &cbPathName,
+                                                     pvChunk,
+                                                     cbChunkMax,
+                                                     &cbChunkRead,
+                                                     &fMode);
+
+                        LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA: "
                                      "szPathName=%s, cbPathName=%RU32, cbChunkRead=%RU32, fMode=0x%x, rc=%Rrc\n",
                                      szPathName, cbPathName, cbChunkRead, fMode, rc));
@@ -464,6 +483,6 @@
 
                     if (   RT_SUCCESS(rc)
-                        && (   uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR
-                             /* Protocol v1 always sends the file name, so opening the file every time. */
+                        && (   uNextMsg == HOST_DND_HG_SND_FILE_HDR
+                            /* Protocol v1 always sends the file name, so opening the file every time. */
                             || pCtx->uProtocol <= 1)
                        )
@@ -493,5 +512,5 @@
                                 if (RT_SUCCESS(rc))
                                 {
-                                    rc = droppedFiles.AddFile(strPathAbs.c_str());
+                                    rc = pDroppedFiles->AddFile(strPathAbs.c_str());
                                     if (RT_SUCCESS(rc))
                                     {
@@ -513,5 +532,5 @@
 
                     if (   RT_SUCCESS(rc)
-                        && uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA)
+                        && uNextMsg == HOST_DND_HG_SND_FILE_DATA)
                     {
                         bool fClose = false;
@@ -521,8 +540,15 @@
                         if (RT_SUCCESS(rc))
                         {
+                            LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
+                                         "cbChunkRead=%RU32, cbChunkWritten=%RU32, cbFileWritten=%RU64 cbFileSize=%RU64\n",
+                                         cbChunkRead, cbChunkWritten, cbFileWritten + cbChunkWritten, cbFileSize));
+
                             if (pCtx->uProtocol >= 2)
                             {
                                 /* Data transfer complete? Close the file. */
                                 fClose = objFile.IsComplete();
+
+                                /* Only since protocol v2 we know the file size upfront. */
+                                Assert(cbFileWritten <= cbFileSize);
                             }
                             else
@@ -530,5 +556,4 @@
 
                             cbFileWritten += cbChunkWritten;
-                            Assert(cbFileWritten <= cbFileSize);
                         }
 
@@ -541,7 +566,7 @@
                     break;
                 }
-                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
+                case HOST_DND_HG_EVT_CANCEL:
                 {
-                    rc = vbglR3DnDHGProcessCancelMessage(pCtx);
+                    rc = vbglR3DnDHGRecvCancel(pCtx);
                     if (RT_SUCCESS(rc))
                         rc = VERR_CANCELLED;
@@ -568,5 +593,5 @@
         rc = VINF_SUCCESS;
 
-    /* Delete chunk buffer again. */
+    /* Delete temp buffer again. */
     if (pvChunk)
         RTMemFree(pvChunk);
@@ -576,46 +601,13 @@
     if (RT_FAILURE(rc))
     {
-        int rc2 = droppedFiles.Rollback();
+        objFile.Close();
+
+        int rc2 = pDroppedFiles->Rollback();
         AssertRC(rc2); /* Not fatal, don't report back to host. */
     }
     else
     {
-        /*
-         * Now we need to transform the URI list which came from the host into
-         * an URI list which also has the final "Dropped Files" directory as a prefix
-         * for each URI entry.
-         *
-         * So patch the old drop data with the new drop directory to let the drop
-         * target on the guest can find the files later.
-         */
-        void  *pvURIData = *ppvData;
-        size_t cbURIData = *pcbDataRecv;
-
-        rc = lstURI.RootFromURIData(pvURIData, cbURIData, 0 /* fFlags */);
-        if (RT_SUCCESS(rc))
-        {
-            /* Cleanup the old data and write the new data back to the event. */
-            RTMemFree(pvURIData);
-
-            RTCString strData = lstURI.RootToString(pszDropDir);
-            Assert(!strData.isEmpty());
-            LogFlowFunc(("New URI list now has %zu bytes (formerly %RU32 bytes)\n", strData.length() + 1, cbURIData));
-
-            pvURIData = RTStrDupN(strData.c_str(), strData.length());
-            if (pvURIData)
-            {
-                cbURIData = strData.length() + 1;
-            }
-            else
-                rc = VERR_NO_MEMORY;
-        }
-
-        if (RT_SUCCESS(rc))
-        {
-            *ppvData     = pvURIData;
-            *pcbDataRecv = cbURIData;
-        }
-
         /** @todo Compare the URI list with the dirs/files we really transferred. */
+        /** @todo Implement checksum verification, if any. */
     }
 
@@ -625,5 +617,5 @@
      * by the client's drag'n drop operation lateron.
      */
-    int rc2 = droppedFiles.Reset(false /* fRemoveDropDir */);
+    int rc2 = pDroppedFiles->Reset(false /* fRemoveDropDir */);
     if (RT_FAILURE(rc2)) /* Not fatal, don't report back to host. */
         LogFlowFunc(("Closing dropped files directory failed with %Rrc\n", rc2));
@@ -633,31 +625,177 @@
 }
 
-static int vbglR3DnDHGProcessDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                                 uint32_t *puScreenId,
-                                                 char     *pszFormat,
-                                                 uint32_t  cbFormat,
-                                                 uint32_t *pcbFormatRecv,
-                                                 void     *pvData,
-                                                 uint32_t  cbData,
-                                                 uint32_t *pcbDataTotal)
-{
-    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
-    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(pcbDataTotal,  VERR_INVALID_POINTER);
-
-    DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
+static int vbglR3DnDHGRecvDataRaw(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr,
+                                  void *pvData, uint32_t cbData, uint32_t *pcbDataRecv)
+{
+    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
+    AssertReturn(cbData,      VERR_INVALID_PARAMETER);
+    /* pcbDataRecv is optional. */
+
+    int rc;
+
+    LogFlowFunc(("pvDate=%p, cbData=%RU32\n", pvData, cbData));
+
+    VBOXDNDHGSENDDATAMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
-    Msg.hdr.cParms      = 5;
-
+    Msg.hdr.u32Function = HOST_DND_HG_SND_DATA;
+
+    do
+    {
+        uint32_t cbDataRecv;
+
+        if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
+        {
+            Msg.hdr.cParms  = 5;
+
+            Msg.u.v1.uScreenId.SetUInt32(0);
+            Msg.u.v1.pvFormat.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
+            Msg.u.v1.cbFormat.SetUInt32(0);
+            Msg.u.v1.pvData.SetPtr(pvData, cbData);
+            Msg.u.v1.cbData.SetUInt32(0);
+
+            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)
+                {
+                    rc = Msg.u.v1.uScreenId.GetUInt32(&pDataHdr->uScreenId);
+                    AssertRC(rc);
+
+                    /*
+                     * In case of VERR_BUFFER_OVERFLOW get the data sizes required
+                     * for the format + data blocks.
+                     */
+                    uint32_t cbFormatRecv;
+                    rc = Msg.u.v1.cbFormat.GetUInt32(&cbFormatRecv);
+                    AssertRC(rc);
+                    if (cbFormatRecv >= pDataHdr->cbMetaFmt)
+                    {
+                        rc = VERR_TOO_MUCH_DATA;
+                        break;
+                    }
+
+                    rc = Msg.u.v1.cbData.GetUInt32(&cbDataRecv);
+                    AssertRC(rc);
+                    if (cbDataRecv >= pDataHdr->cbMeta)
+                    {
+                        rc = VERR_TOO_MUCH_DATA;
+                        break;
+                    }
+
+                    pDataHdr->cbMetaFmt = cbFormatRecv;
+                }
+            }
+
+            if (RT_FAILURE(rc))
+                break;
+        }
+        else /* Protocol v3 and up. */
+        {
+            Msg.hdr.cParms = 5;
+
+            Msg.u.v3.uContext.SetUInt32(0);
+            Msg.u.v3.pvData.SetPtr(pvData, cbData);
+            Msg.u.v3.cbData.SetUInt32(0);
+            Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
+            Msg.u.v3.cbChecksum.SetUInt32(0);
+
+            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+            if (RT_SUCCESS(rc))
+            {
+                rc = Msg.hdr.result;
+                if (RT_SUCCESS(rc))
+                {
+                    rc = Msg.u.v3.cbData.GetUInt32(&cbDataRecv);
+                    AssertRC(rc);
+                }
+
+                /** @todo Use checksum for validating the received data. */
+            }
+
+            if (RT_FAILURE(rc))
+                break;
+        }
+
+        if (pcbDataRecv)
+            *pcbDataRecv = cbDataRecv;
+
+    } while (0);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static int vbglR3DnDHGRecvDataHdr(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr)
+{
+    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
+
+    Assert(pCtx->uProtocol >= 3); /* Only for protocol v3 and up. */
+
+    VBOXDNDHGSENDDATAHDRMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = pCtx->uClientID;
+    Msg.hdr.u32Function = HOST_DND_HG_SND_DATA_HDR;
+    Msg.hdr.cParms      = 12;
+
+    Msg.uContext.SetUInt32(0);
+    Msg.uFlags.SetUInt32(0);
     Msg.uScreenId.SetUInt32(0);
-    Msg.pvFormat.SetPtr(pszFormat, cbFormat);
-    Msg.cFormat.SetUInt32(0);
+    Msg.cbTotal.SetUInt64(0);
+    Msg.cbMeta.SetUInt32(0);
+    Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
+    Msg.cbMetaFmt.SetUInt32(0);
+    Msg.cObjects.SetUInt64(0);
+    Msg.enmCompression.SetUInt32(0);
+    Msg.enmChecksumType.SetUInt32(0);
+    Msg.pvChecksum.SetPtr(pDataHdr->pvChecksum, pDataHdr->cbChecksum);
+    Msg.cbChecksum.SetUInt32(0);
+
+    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+    if (RT_SUCCESS(rc))
+    {
+        rc = Msg.hdr.result;
+        if (RT_SUCCESS(rc))
+        {
+            /* Msg.uContext not needed here. */
+            Msg.uFlags.GetUInt32(&pDataHdr->uFlags);
+            Msg.uScreenId.GetUInt32(&pDataHdr->uScreenId);
+            Msg.cbTotal.GetUInt64(&pDataHdr->cbTotal);
+            Msg.cbMeta.GetUInt32(&pDataHdr->cbMeta);
+            Msg.cbMetaFmt.GetUInt32(&pDataHdr->cbMetaFmt);
+            Msg.cObjects.GetUInt64(&pDataHdr->cObjects);
+            Msg.enmCompression.GetUInt32(&pDataHdr->enmCompression);
+            Msg.enmChecksumType.GetUInt32((uint32_t *)&pDataHdr->enmChecksumType);
+            Msg.cbChecksum.GetUInt32(&pDataHdr->cbChecksum);
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/** @todo Deprecated function; will be removed. */
+static int vbglR3DnDHGRecvMoreData(PVBGLR3GUESTDNDCMDCTX pCtx,
+                                   void *pvData, uint32_t cbData, uint32_t *pcbDataRecv)
+{
+    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
+    AssertPtrReturn(pvData,      VERR_INVALID_POINTER);
+    AssertReturn(cbData,         VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
+
+    VBOXDNDHGSENDMOREDATAMSG Msg;
+    RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
+    Msg.hdr.u32ClientID = pCtx->uClientID;
+    Msg.hdr.u32Function = HOST_DND_HG_SND_MORE_DATA;
+    Msg.hdr.cParms      = 2;
+
     Msg.pvData.SetPtr(pvData, cbData);
     Msg.cbData.SetUInt32(0);
@@ -670,129 +808,151 @@
             || rc == VERR_BUFFER_OVERFLOW)
         {
-            rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
-
-            /*
-             * In case of VERR_BUFFER_OVERFLOW get the data sizes required
-             * for the format + data blocks.
-             */
-            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
-            rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
-
-            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
-            AssertReturn(cbData   >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
-        }
-    }
-
-    return rc;
-}
-
-static int vbglR3DnDHGProcessMoreDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                                     void     *pvData,
-                                                     uint32_t  cbData,
-                                                     uint32_t *pcbDataTotal)
-{
-    AssertPtrReturn(pCtx,         VERR_INVALID_POINTER);
-    AssertPtrReturn(pvData,       VERR_INVALID_POINTER);
-    AssertReturn(cbData,          VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pcbDataTotal, VERR_INVALID_POINTER);
-
-    DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
-    RT_ZERO(Msg);
-    Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
-    Msg.hdr.cParms      = 2;
-
-    Msg.pvData.SetPtr(pvData, cbData);
-    Msg.cbData.SetUInt32(0);
-
-    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)
-        {
-            rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
-            AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
-        }
-    }
-    return rc;
-}
-
-static int vbglR3DnDHGProcessSendDataMessageLoop(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                                 uint32_t *puScreenId,
-                                                 char     *pszFormat,
-                                                 uint32_t  cbFormat,
-                                                 uint32_t *pcbFormatRecv,
-                                                 void    **ppvData,
-                                                 uint32_t  cbData,
-                                                 size_t   *pcbDataRecv)
-{
-    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
-    AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
-    AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
-    AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
-    /* pcbDataRecv is optional. */
-
-    uint32_t cbDataReq = 0;
-    int rc = vbglR3DnDHGProcessDataMessageInternal(pCtx,
-                                                   puScreenId,
-                                                   pszFormat,
-                                                   cbFormat,
-                                                   pcbFormatRecv,
-                                                   *ppvData,
-                                                   cbData,
-                                                   &cbDataReq);
-    uint32_t cbDataTotal = cbDataReq;
-    void *pvData = *ppvData;
-
-    LogFlowFunc(("HOST_DND_HG_SND_DATA cbDataReq=%RU32, rc=%Rrc\n", cbDataTotal, rc));
-
-    while (rc == VERR_BUFFER_OVERFLOW)
-    {
-        uint32_t uNextMsg;
-        uint32_t cNextParms;
-        rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false);
-        if (RT_SUCCESS(rc))
-        {
-            switch(uNextMsg)
-            {
-                case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
+            rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
+            AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
+        }
+    }
+    return rc;
+}
+
+static int vbglR3DnDHGRecvDataLoop(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr,
+                                   void **ppvData, uint64_t *pcbData)
+{
+    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
+    AssertPtrReturn(ppvData,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pcbData,  VERR_INVALID_POINTER);
+
+    int rc;
+    uint32_t cbDataRecv;
+
+    if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
+    {
+        uint64_t cbDataTmp = pCtx->cbMaxChunkSize;
+        void    *pvDataTmp = RTMemAlloc(cbDataTmp);
+
+        if (!cbDataTmp)
+            return VERR_NO_MEMORY;
+
+        /**
+         * Protocols < v3 contain the header information in every HOST_DND_HG_SND_DATA
+         * message, so do the actual retrieving immediately.
+         *
+         * Also, the initial implementation used VERR_BUFFER_OVERFLOW as a return code to
+         * indicate that there will be more data coming in after the initial data chunk. There
+         * was no way of telling the total data size upfront (in form of a header or some such),
+         * so also handle this case to not break backwards compatibility.
+         */
+        rc = vbglR3DnDHGRecvDataRaw(pCtx, pDataHdr, pvDataTmp, pCtx->cbMaxChunkSize, &cbDataRecv);
+
+        /* See comment above. */
+        while (rc == VERR_BUFFER_OVERFLOW)
+        {
+            uint32_t uNextMsg;
+            uint32_t cNextParms;
+            rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, false /* fBlock */);
+            if (RT_SUCCESS(rc))
+            {
+                switch(uNextMsg)
                 {
-                    /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists.
-                     *               Instead send as many URI entries as possible per chunk and add those entries
-                     *               to our to-process list for immediata processing. Repeat the step after processing then. */
-                    LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU32 -> %RU32\n", cbDataReq, cbDataReq + cbData));
-                    pvData = RTMemRealloc(*ppvData, cbDataTotal + cbData);
-                    if (!pvData)
+                    case HOST_DND_HG_SND_MORE_DATA:
                     {
-                        rc = VERR_NO_MEMORY;
+                        /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists.
+                         *               Instead send as many URI entries as possible per chunk and add those entries
+                         *               to our to-process list for immediata processing. Repeat the step after processing then. */
+                        LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU64 -> %RU64\n",
+                                     cbDataTmp, cbDataTmp + pCtx->cbMaxChunkSize));
+                        void *pvDataNew = RTMemRealloc(pvDataTmp, cbDataTmp + pCtx->cbMaxChunkSize);
+                        if (!pvDataNew)
+                        {
+                            rc = VERR_NO_MEMORY;
+                            break;
+                        }
+
+                        pvDataTmp = pvDataNew;
+
+                        uint8_t *pvDataOff = (uint8_t *)pvDataTmp + cbDataTmp;
+                        rc = vbglR3DnDHGRecvMoreData(pCtx, pvDataOff, pCtx->cbMaxChunkSize, &cbDataRecv);
+                        if (   RT_SUCCESS(rc)
+                            || rc == VERR_BUFFER_OVERFLOW) /* Still can return VERR_BUFFER_OVERFLOW. */
+                        {
+                            cbDataTmp += cbDataRecv;
+                        }
                         break;
                     }
-                    rc = vbglR3DnDHGProcessMoreDataMessageInternal(pCtx,
-                                                                   &((char *)pvData)[cbDataTotal],
-                                                                   cbData,
-                                                                   &cbDataReq);
-                    cbDataTotal += cbDataReq;
-                    break;
+                    case HOST_DND_HG_EVT_CANCEL:
+                    default:
+                    {
+                        rc = vbglR3DnDHGRecvCancel(pCtx);
+                        if (RT_SUCCESS(rc))
+                            rc = VERR_CANCELLED;
+                        break;
+                    }
                 }
-                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
-                default:
+            }
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            /* There was no way of telling the total data size upfront
+             * (in form of a header or some such), so set the total data size here. */
+            pDataHdr->cbTotal = cbDataTmp;
+
+            *ppvData = pvDataTmp;
+            *pcbData = cbDataTmp;
+        }
+        else
+            RTMemFree(pvDataTmp);
+    }
+    else /* Protocol v3 and up. Since VBox 5.0.8. */
+    {
+        rc = vbglR3DnDHGRecvDataHdr(pCtx, pDataHdr);
+        if (RT_SUCCESS(rc))
+        {
+            LogFlowFunc(("cbMeta=%RU32\n", pDataHdr->cbMeta));
+            if (pDataHdr->cbMeta)
+            {
+                uint64_t cbDataTmp = 0;
+                void    *pvDataTmp = RTMemAlloc(pDataHdr->cbMeta);
+                if (!pvDataTmp)
+                    rc = VERR_NO_MEMORY;
+
+                if (RT_SUCCESS(rc))
                 {
-                    rc = vbglR3DnDHGProcessCancelMessage(pCtx);
+                    uint8_t *pvDataOff = (uint8_t *)pvDataTmp;
+                    while (cbDataTmp < pDataHdr->cbMeta)
+                    {
+                        rc = vbglR3DnDHGRecvDataRaw(pCtx, pDataHdr,
+                                                    pvDataOff, RT_MIN(pDataHdr->cbMeta - cbDataTmp, pCtx->cbMaxChunkSize),
+                                                    &cbDataRecv);
+                        if (RT_SUCCESS(rc))
+                        {
+                            LogFlowFunc(("cbDataRecv=%RU32, cbDataTmp=%RU64\n", cbDataRecv, cbDataTmp));
+                            Assert(cbDataTmp + cbDataRecv <= pDataHdr->cbMeta);
+                            cbDataTmp += cbDataRecv;
+                            pvDataOff += cbDataRecv;
+                        }
+                        else
+                            break;
+                    }
+
                     if (RT_SUCCESS(rc))
-                        rc = VERR_CANCELLED;
-                    break;
+                    {
+                        Assert(cbDataTmp == pDataHdr->cbMeta);
+
+                        LogFlowFunc(("Received %RU64 bytes of data\n", cbDataTmp));
+
+                        *ppvData = pvDataTmp;
+                        *pcbData = cbDataTmp;
+                    }
+                    else
+                        RTMemFree(pvDataTmp);
                 }
             }
-        }
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        *ppvData         = pvData;
-        if (pcbDataRecv)
-            *pcbDataRecv = cbDataTotal;
+            else
+            {
+                *ppvData = NULL;
+                *pcbData = 0;
+            }
+        }
     }
 
@@ -801,46 +961,111 @@
 }
 
-static int vbglR3DnDHGProcessSendDataMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                             uint32_t  *puScreenId,
-                                             char      *pszFormat,
-                                             uint32_t   cbFormat,
-                                             uint32_t  *pcbFormatRecv,
-                                             void     **ppvData,
-                                             uint32_t   cbData,
-                                             size_t    *pcbDataRecv)
-{
-    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
-    AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
-    AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
-    AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
-
-    int rc = vbglR3DnDHGProcessSendDataMessageLoop(pCtx,
-                                                   puScreenId,
-                                                   pszFormat,
-                                                   cbFormat,
-                                                   pcbFormatRecv,
-                                                   ppvData,
-                                                   cbData,
-                                                   pcbDataRecv);
-    if (RT_SUCCESS(rc))
-    {
-        /* Check if this is an URI event. If so, let VbglR3 do all the actual
+/** @todo Replace the parameters (except pCtx) with PVBOXDNDSNDDATAHDR. Later. */
+/** @todo Hand in the DnDURIList + DnDDroppedFiles objects so that this function
+ *        can fill it directly instead of passing huge blobs of data around. */
+static int vbglR3DnDHGRecvDataMain(PVBGLR3GUESTDNDCMDCTX  pCtx,
+                                   uint32_t              *puScreenId,
+                                   char                 **ppszFormat,
+                                   uint32_t              *pcbFormat,
+                                   void                 **ppvData,
+                                   uint32_t              *pcbData)
+{
+    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
+    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
+    AssertPtrReturn(ppszFormat, VERR_INVALID_POINTER);
+    AssertPtrReturn(pcbFormat,  VERR_INVALID_POINTER);
+    AssertPtrReturn(ppvData,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pcbData,    VERR_INVALID_POINTER);
+
+    VBOXDNDDATAHDR dataHdr; /** @todo See todo above. */
+    RT_ZERO(dataHdr);
+
+    dataHdr.cbMetaFmt = _64K;  /** @todo Make this configurable? */
+    dataHdr.pvMetaFmt = RTMemAlloc(dataHdr.cbMetaFmt);
+    if (!dataHdr.pvMetaFmt)
+        return VERR_NO_MEMORY;
+
+    DnDURIList lstURI;
+    DnDDroppedFiles droppedFiles;
+
+    void *pvData;    /** @todo See todo above. */
+    uint64_t cbData; /** @todo See todo above. */
+
+    int rc = vbglR3DnDHGRecvDataLoop(pCtx, &dataHdr, &pvData, &cbData);
+    if (RT_SUCCESS(rc))
+    {
+        /**
+         * Check if this is an URI event. If so, let VbglR3 do all the actual
          * data transfer + file/directory creation internally without letting
          * the caller know.
          *
          * This keeps the actual (guest OS-)dependent client (like VBoxClient /
-         * VBoxTray) small by not having too much redundant code. */
-        AssertPtr(pcbFormatRecv);
-        if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
-            rc = vbglR3DnDHGProcessURIMessages(pCtx,
-                                               ppvData,
-                                               cbData,
-                                               pcbDataRecv);
-        if (RT_FAILURE(rc))
-        {
-            int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
-            AssertRC(rc2);
-        }
+         * VBoxTray) small by not having too much redundant code.
+         */
+        Assert(dataHdr.cbMetaFmt);
+        AssertPtr(dataHdr.pvMetaFmt);
+        if (DnDMIMEHasFileURLs((char *)dataHdr.pvMetaFmt, dataHdr.cbMetaFmt))
+        {
+            AssertPtr(pvData);
+            Assert(cbData);
+            rc = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
+            if (RT_SUCCESS(rc))
+                rc = vbglR3DnDHGRecvURIData(pCtx, &droppedFiles);
+
+            if (RT_SUCCESS(rc)) /** @todo Remove this block as soon as we hand in DnDURIList. */
+            {
+                if (pvData)
+                {
+                    /* Reuse data buffer to fill in the transformed URI file list. */
+                    RTMemFree(pvData);
+                    pvData = NULL;
+                }
+
+                RTCString strData = lstURI.RootToString(droppedFiles.GetDirAbs());
+                Assert(!strData.isEmpty());
+
+                cbData = strData.length() + 1;
+                LogFlowFunc(("URI list has %zu bytes\n", cbData));
+
+                pvData = RTMemAlloc(cbData);
+                if (pvData)
+                {
+                    memcpy(pvData, strData.c_str(), cbData);
+                }
+                else
+                    rc =  VERR_NO_MEMORY;
+            }
+        }
+        else /* Raw data. */
+        {
+            const uint32_t cbDataRaw = dataHdr.cbMetaFmt;
+            if (cbData >= cbDataRaw)
+            {
+                if (cbDataRaw)
+                    memcpy(pvData, dataHdr.pvMetaFmt, cbDataRaw);
+                cbData = cbDataRaw;
+            }
+            else
+                rc = VERR_BUFFER_OVERFLOW;
+        }
+    }
+
+    if (   RT_FAILURE(rc)
+        && rc != VERR_CANCELLED)
+    {
+        if (dataHdr.pvMetaFmt)
+            RTMemFree(dataHdr.pvMetaFmt);
+        if (pvData)
+            RTMemFree(pvData);
+
+        int rc2 = VbglR3DnDHGSendProgress(pCtx, DND_PROGRESS_ERROR, 100 /* Percent */, rc);
+        AssertRC(rc2);
+    }
+    else if (RT_SUCCESS(rc))
+    {
+        *ppszFormat = (char *)dataHdr.pvMetaFmt;
+        *pcbFormat  =         dataHdr.cbMetaFmt;
+        *ppvData    = pvData;
+        *pcbData    = cbData;
     }
 
@@ -849,14 +1074,14 @@
 }
 
-static int vbglR3DnDGHProcessRequestPendingMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                                   uint32_t *puScreenId)
+static int vbglR3DnDGHRecvPending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puScreenId)
 {
     AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
     AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
+    VBOXDNDGHREQPENDINGMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
+    Msg.hdr.u32Function = HOST_DND_GH_REQ_PENDING;
     Msg.hdr.cParms      = 1;
 
@@ -876,9 +1101,9 @@
 }
 
-static int vbglR3DnDGHProcessDroppedMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                            char     *pszFormat,
-                                            uint32_t  cbFormat,
-                                            uint32_t *pcbFormatRecv,
-                                            uint32_t *puAction)
+static int vbglR3DnDGHRecvDropped(PVBGLR3GUESTDNDCMDCTX pCtx,
+                                  char     *pszFormat,
+                                  uint32_t  cbFormat,
+                                  uint32_t *pcbFormatRecv,
+                                  uint32_t *puAction)
 {
     AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
@@ -888,12 +1113,13 @@
     AssertPtrReturn(puAction,      VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
+    VBOXDNDGHDROPPEDMSG Msg;
     RT_ZERO(Msg);
+    Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
+    Msg.hdr.u32Function = HOST_DND_GH_EVT_DROPPED;
     Msg.hdr.cParms      = 3;
 
     Msg.pvFormat.SetPtr(pszFormat, cbFormat);
-    Msg.cFormat.SetUInt32(0);
+    Msg.cbFormat.SetUInt32(0);
     Msg.uAction.SetUInt32(0);
 
@@ -904,6 +1130,6 @@
         if (RT_SUCCESS(rc))
         {
-            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
-            rc = Msg.uAction.GetUInt32(puAction);      AssertRC(rc);
+            rc = Msg.cbFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
+            rc = Msg.uAction.GetUInt32(puAction);       AssertRC(rc);
 
             AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
@@ -944,5 +1170,5 @@
         {
             /* Set the default protocol version to use. */
-            pCtx->uProtocol = 2;
+            pCtx->uProtocol = 3;
 
             Assert(Info.u32ClientID);
@@ -967,4 +1193,5 @@
             {
                 fSupportsConnectReq = RTStrVersionCompare(pszHostVersion, "5.0") >= 0;
+                LogFlowFunc(("pszHostVersion=%s, fSupportsConnectReq=%RTbool\n", pszHostVersion, fSupportsConnectReq));
                 VbglR3GuestPropReadValueFree(pszHostVersion);
             }
@@ -972,4 +1199,7 @@
             VbglR3GuestPropDisconnect(uGuestPropSvcClientID);
         }
+
+        if (RT_FAILURE(rc2))
+            LogFlowFunc(("Retrieving host version failed with rc=%Rrc\n", rc2));
     }
 
@@ -981,9 +1211,9 @@
          *       does not implement this command.
          */
-        DragAndDropSvc::VBOXDNDCONNECTMSG Msg;
+        VBOXDNDCONNECTMSG Msg;
         RT_ZERO(Msg);
         Msg.hdr.result      = VERR_WRONG_ORDER;
         Msg.hdr.u32ClientID = pCtx->uClientID;
-        Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_CONNECT;
+        Msg.hdr.u32Function = GUEST_DND_CONNECT;
         Msg.hdr.cParms      = 2;
 
@@ -1005,4 +1235,6 @@
         pCtx->uProtocol = 1; /* Fall back to protocol version 1 (< VBox 5.0). */
 
+    pCtx->cbMaxChunkSize = _64K; /** @todo Use a scratch buffer on the heap? */
+
     LogFlowFunc(("uClient=%RU32, uProtocol=%RU32, rc=%Rrc\n", pCtx->uClientID, pCtx->uProtocol, rc));
     return rc;
@@ -1024,15 +1256,16 @@
 }
 
-VBGLR3DECL(int) VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent)
+VBGLR3DECL(int) VbglR3DnDRecvNextMsg(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent)
 {
     AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
     AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
 
-    uint32_t       uMsg       = 0;
-    uint32_t       uNumParms  = 0;
-    const uint32_t ccbFormats = _64K;
-    const uint32_t ccbData    = _64K;
-    int rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uMsg, &uNumParms,
-                                               true /* fWait */);
+    uint32_t       uMsg      = 0;
+    uint32_t       uNumParms = 0;
+
+    const uint32_t cbDataMax   = pCtx->cbMaxChunkSize;
+    const uint32_t cbFormatMax = pCtx->cbMaxChunkSize;
+
+    int rc = vbglR3DnDGetNextMsgType(pCtx, &uMsg, &uNumParms, true /* fWait */);
     if (RT_SUCCESS(rc))
     {
@@ -1041,94 +1274,82 @@
         switch(uMsg)
         {
-            case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
-            case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
-            case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
-            {
-                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
+            case HOST_DND_HG_EVT_ENTER:
+            case HOST_DND_HG_EVT_MOVE:
+            case HOST_DND_HG_EVT_DROPPED:
+            {
+                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(cbFormatMax));
                 if (!pEvent->pszFormats)
                     rc = VERR_NO_MEMORY;
 
                 if (RT_SUCCESS(rc))
-                    rc = vbglR3DnDHGProcessActionMessage(pCtx,
-                                                         uMsg,
-                                                         &pEvent->uScreenId,
-                                                         &pEvent->u.a.uXpos,
-                                                         &pEvent->u.a.uYpos,
-                                                         &pEvent->u.a.uDefAction,
-                                                         &pEvent->u.a.uAllActions,
-                                                         pEvent->pszFormats,
-                                                         ccbFormats,
-                                                         &pEvent->cbFormats);
+                    rc = vbglR3DnDHGRecvAction(pCtx,
+                                               uMsg,
+                                               &pEvent->uScreenId,
+                                               &pEvent->u.a.uXpos,
+                                               &pEvent->u.a.uYpos,
+                                               &pEvent->u.a.uDefAction,
+                                               &pEvent->u.a.uAllActions,
+                                               pEvent->pszFormats,
+                                               cbFormatMax,
+                                               &pEvent->cbFormats);
                 break;
             }
-            case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
-            {
-                rc = vbglR3DnDHGProcessLeaveMessage(pCtx);
+            case HOST_DND_HG_EVT_LEAVE:
+            {
+                rc = vbglR3DnDHGRecvLeave(pCtx);
                 break;
             }
-            case DragAndDropSvc::HOST_DND_HG_SND_DATA:
-            {
-                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
-                if (!pEvent->pszFormats)
-                    rc = VERR_NO_MEMORY;
-
-                if (RT_SUCCESS(rc))
-                {
-                    pEvent->u.b.pvData = RTMemAlloc(ccbData);
-                    if (!pEvent->u.b.pvData)
-                    {
-                        RTMemFree(pEvent->pszFormats);
-                        pEvent->pszFormats = NULL;
-
-                        rc = VERR_NO_MEMORY;
-                    }
-                }
-
-                if (RT_SUCCESS(rc))
-                    rc = vbglR3DnDHGProcessSendDataMessage(pCtx,
-                                                           &pEvent->uScreenId,
-                                                           pEvent->pszFormats,
-                                                           ccbFormats,
-                                                           &pEvent->cbFormats,
-                                                           &pEvent->u.b.pvData,
-                                                           ccbData,
-                                                           &pEvent->u.b.cbData);
+            case HOST_DND_HG_SND_DATA:
+                /* Protocol v1 + v2: Also contains the header data.
+                /* Note: Fall through is intentional. */
+            case HOST_DND_HG_SND_DATA_HDR:
+            {
+                rc = vbglR3DnDHGRecvDataMain(pCtx,
+                                             /* Screen ID */
+                                             &pEvent->uScreenId,
+                                             /* Format */
+                                             &pEvent->pszFormats,
+                                             &pEvent->cbFormats,
+                                             /* Data */
+                                             &pEvent->u.b.pvData,
+                                             &pEvent->u.b.cbData);
                 break;
             }
-            case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
-            case DragAndDropSvc::HOST_DND_HG_SND_DIR:
-            case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
+            case HOST_DND_HG_SND_MORE_DATA:
+            case HOST_DND_HG_SND_DIR:
+            case HOST_DND_HG_SND_FILE_DATA:
             {
                 /*
                  * All messages in this case are handled internally
-                 * by vbglR3DnDHGProcessSendDataMessage() and must
-                 * be specified by a preceding HOST_DND_HG_SND_DATA call.
+                 * by vbglR3DnDHGRecvDataMain() and must be specified
+                 * by a preceding HOST_DND_HG_SND_DATA or HOST_DND_HG_SND_DATA_HDR
+                 * calls.
                  */
                 rc = VERR_WRONG_ORDER;
                 break;
             }
-            case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
-            {
-                rc = vbglR3DnDHGProcessCancelMessage(pCtx);
+            case HOST_DND_HG_EVT_CANCEL:
+            {
+                rc = vbglR3DnDHGRecvCancel(pCtx);
                 break;
             }
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-            case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
-            {
-                rc = vbglR3DnDGHProcessRequestPendingMessage(pCtx, &pEvent->uScreenId);
+            case HOST_DND_GH_REQ_PENDING:
+            {
+                rc = vbglR3DnDGHRecvPending(pCtx, &pEvent->uScreenId);
                 break;
             }
-            case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
-            {
-                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
+            case HOST_DND_GH_EVT_DROPPED:
+            {
+                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(cbFormatMax));
                 if (!pEvent->pszFormats)
                     rc = VERR_NO_MEMORY;
 
                 if (RT_SUCCESS(rc))
-                    rc = vbglR3DnDGHProcessDroppedMessage(pCtx,
-                                                          pEvent->pszFormats,
-                                                          ccbFormats,
-                                                          &pEvent->cbFormats,
-                                                          &pEvent->u.a.uDefAction);
+                    rc = vbglR3DnDGHRecvDropped(pCtx,
+                                                pEvent->pszFormats,
+                                                cbFormatMax,
+                                                &pEvent->cbFormats,
+                                                &pEvent->u.a.uDefAction);
                 break;
             }
@@ -1145,13 +1366,13 @@
 }
 
-VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction)
+VBGLR3DECL(int) VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction)
 {
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
+    VBOXDNDHGACKOPMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
+    Msg.hdr.u32Function = GUEST_DND_HG_ACK_OP;
     Msg.hdr.cParms      = 1;
 
@@ -1165,17 +1386,17 @@
 }
 
-VBGLR3DECL(int) VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat)
+VBGLR3DECL(int) VbglR3DnDHGSendReqData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat)
 {
     AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
     AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
+    VBOXDNDHGREQDATAMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
+    Msg.hdr.u32Function = GUEST_DND_HG_REQ_DATA;
     Msg.hdr.cParms      = 1;
 
-    Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
+    Msg.pFormat.SetPtr((void*)pcszFormat, strlen(pcszFormat) + 1 /* Include termination */);
 
     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
@@ -1186,10 +1407,10 @@
 }
 
-VBGLR3DECL(int) VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr)
+VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr)
 {
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
-    AssertReturn(uStatus > DragAndDropSvc::DND_PROGRESS_UNKNOWN, VERR_INVALID_PARAMETER);
-
-    DragAndDropSvc::VBOXDNDHGEVTPROGRESSMSG Msg;
+    AssertReturn(uStatus > DND_PROGRESS_UNKNOWN, VERR_INVALID_PARAMETER);
+
+    VBOXDNDHGEVTPROGRESSMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.result      = VERR_WRONG_ORDER;
@@ -1210,20 +1431,21 @@
 
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                              uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats)
+VBGLR3DECL(int) VbglR3DnDGHSendAckPending(PVBGLR3GUESTDNDCMDCTX pCtx,
+                                          uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats, uint32_t cbFormats)
 {
     AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
     AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
-
-    DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
+    AssertReturn(cbFormats,      VERR_INVALID_PARAMETER);
+
+    VBOXDNDGHACKPENDINGMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
+    Msg.hdr.u32Function = GUEST_DND_GH_ACK_PENDING;
     Msg.hdr.cParms      = 3;
 
     Msg.uDefAction.SetUInt32(uDefAction);
     Msg.uAllActions.SetUInt32(uAllActions);
-    Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
+    Msg.pFormat.SetPtr((void*)pcszFormats, cbFormats);
 
     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
@@ -1235,5 +1457,5 @@
 
 static int vbglR3DnDGHSendDataInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                       void *pvData, uint32_t cbData, uint32_t cbAdditionalData)
+                                       void *pvData, uint64_t cbData, PVBOXDNDSNDDATAHDR pDataHdr)
 {
     AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
@@ -1241,55 +1463,109 @@
     AssertReturn(cbData,    VERR_INVALID_PARAMETER);
     /* cbAdditionalData is optional. */
-
-    DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
+    /* pDataHdr is optional in protocols < v3. */
+
+    int rc = VINF_SUCCESS;
+
+    /* For protocol v3 and up we need to send the data header first. */
+    if (pCtx->uProtocol > 2)
+    {
+        AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
+
+        VBOXDNDGHSENDDATAHDRMSG Msg;
+        RT_ZERO(Msg);
+        Msg.hdr.result      = VERR_WRONG_ORDER;
+        Msg.hdr.u32ClientID = pCtx->uClientID;
+        Msg.hdr.u32Function = GUEST_DND_GH_SND_DATA_HDR;
+        Msg.hdr.cParms      = 12;
+
+        Msg.uContext.SetUInt32(0);                           /** @todo Not used yet. */
+        Msg.uFlags.SetUInt32(0);                             /** @todo Not used yet. */
+        Msg.uScreenId.SetUInt32(0);                          /** @todo Not used for guest->host (yet). */
+        Msg.cbTotal.SetUInt64(pDataHdr->cbTotal);
+        Msg.cbMeta.SetUInt64(pDataHdr->cbMeta);
+        Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
+        Msg.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
+        Msg.cObjects.SetUInt64(pDataHdr->cObjects);
+        Msg.enmCompression.SetUInt32(0);                     /** @todo Not used yet. */
+        Msg.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */
+        Msg.pvChecksum.SetPtr(NULL, 0);                      /** @todo Not used yet. */
+        Msg.cbChecksum.SetUInt32(0);                         /** @todo Not used yet. */
+
+        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+        if (RT_SUCCESS(rc))
+            rc = Msg.hdr.result;
+
+        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU64, cObjects=%RU64, rc=%Rrc\n",
+                     pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc));
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        VBOXDNDGHSENDDATAMSG Msg;
+        RT_ZERO(Msg);
+        Msg.hdr.result      = VERR_WRONG_ORDER;
+        Msg.hdr.u32ClientID = pCtx->uClientID;
+        Msg.hdr.u32Function = GUEST_DND_GH_SND_DATA;
+
+        if (pCtx->uProtocol > 2)
+        {
+            Msg.hdr.cParms = 5;
+
+            Msg.u.v3.uContext.SetUInt32(0);      /** @todo Not used yet. */
+            Msg.u.v3.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
+            Msg.u.v3.cbChecksum.SetUInt32(0);    /** @todo Not used yet. */
+        }
+        else
+        {
+            Msg.hdr.cParms = 2;
+
+            /* Total amount of bytes to send (meta data + all directory/file objects). */
+            /* Note: Only supports uint32_t, so this is *not* a typo. */
+            Msg.u.v1.cbTotalBytes.SetUInt32((uint32_t)pDataHdr->cbTotal);
+        }
+
+        uint32_t       cbCurChunk;
+        const uint32_t cbMaxChunk = pCtx->cbMaxChunkSize;
+        uint32_t       cbSent     = 0;
+
+        HGCMFunctionParameter *pParm = (pCtx->uProtocol > 2)
+                                     ? &Msg.u.v3.pvData
+                                     : &Msg.u.v1.pvData;
+        while (cbSent < cbData)
+        {
+            cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
+            pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
+            if (pCtx->uProtocol > 2)
+                Msg.u.v3.cbData.SetUInt32(cbCurChunk);
+
+            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
+            if (RT_SUCCESS(rc))
+                rc = Msg.hdr.result;
+
+            if (RT_FAILURE(rc))
+                break;
+
+            cbSent += cbCurChunk;
+        }
+
+        if (RT_SUCCESS(rc))
+            Assert(cbSent == cbData);
+    }
+
+    LogFlowFunc(("Returning rc=%Rrc, cbData=%RU64\n", rc, cbData));
+    return rc;
+}
+
+static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)
+{
+    AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
+    AssertPtrReturn(pCtx,                                    VERR_INVALID_POINTER);
+    AssertReturn(pObj->GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
+
+    VBOXDNDGHSENDDIRMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
-    Msg.hdr.cParms      = 2;
-
-    /* Total amount of bytes to send (including this data block). */
-    Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbCurChunk;
-    uint32_t cbMaxChunk = _64K; /** @todo Transfer max. 64K chunks per message. Configurable? */
-    uint32_t cbSent     = 0;
-
-    while (cbSent < cbData)
-    {
-        cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
-        Msg.pvData.SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
-
-        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
-        if (RT_SUCCESS(rc))
-            rc = Msg.hdr.result;
-
-        if (RT_FAILURE(rc))
-            break;
-
-        cbSent += cbCurChunk;
-    }
-
-    if (RT_SUCCESS(rc))
-        Assert(cbSent == cbData);
-
-    LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32, cbSent=%RU32\n",
-                 rc, cbData, cbAdditionalData, cbSent));
-    return rc;
-}
-
-static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)
-{
-    AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
-    AssertPtrReturn(pCtx,                                    VERR_INVALID_POINTER);
-    AssertReturn(pObj->GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
-
-    DragAndDropSvc::VBOXDNDGHSENDDIRMSG Msg;
-    RT_ZERO(Msg);
-    Msg.hdr.result      = VERR_WRONG_ORDER;
-    Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
+    Msg.hdr.u32Function = GUEST_DND_GH_SND_DIR;
     Msg.hdr.cParms      = 3;
 
@@ -1332,9 +1608,9 @@
     if (pCtx->uProtocol >= 2) /* Protocol version 2 and up sends a file header first. */
     {
-        DragAndDropSvc::VBOXDNDGHSENDFILEHDRMSG MsgHdr;
+        VBOXDNDGHSENDFILEHDRMSG MsgHdr;
         RT_ZERO(MsgHdr);
         MsgHdr.hdr.result      = VERR_WRONG_ORDER;
         MsgHdr.hdr.u32ClientID = pCtx->uClientID;
-        MsgHdr.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR;
+        MsgHdr.hdr.u32Function = GUEST_DND_GH_SND_FILE_HDR;
         MsgHdr.hdr.cParms      = 6;
 
@@ -1360,24 +1636,39 @@
          * Send the actual file data, chunk by chunk.
          */
-        DragAndDropSvc::VBOXDNDGHSENDFILEDATAMSG Msg;
+        VBOXDNDGHSENDFILEDATAMSG Msg;
         RT_ZERO(Msg);
         Msg.hdr.result      = VERR_WRONG_ORDER;
         Msg.hdr.u32ClientID = pCtx->uClientID;
-        Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA;
-
-        if (pCtx->uProtocol <= 1)
-        {
-            Msg.hdr.cParms  = 5;
-
-            Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
-            Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
-            Msg.u.v1.fMode.SetUInt32(pObj->GetMode());
-        }
-        else
-        {
-            /* Only send context ID, file chunk + chunk size. */
-            Msg.hdr.cParms  = 3;
-
-            Msg.u.v2.uContext.SetUInt32(0); /** @todo Set context ID. */
+        Msg.hdr.u32Function = GUEST_DND_GH_SND_FILE_DATA;
+
+        switch (pCtx->uProtocol)
+        {
+            case 3:
+            {
+                Msg.hdr.cParms = 5;
+
+                Msg.u.v3.uContext.SetUInt32(0);
+                Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
+                Msg.u.v3.cbChecksum.SetUInt32(0);
+                break;
+            }
+
+            case 2:
+            {
+                Msg.hdr.cParms  = 3;
+
+                Msg.u.v2.uContext.SetUInt32(0);
+                break;
+            }
+
+            default: /* Protocol v1 */
+            {
+                Msg.hdr.cParms  = 5;
+
+                Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
+                Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
+                Msg.u.v1.fMode.SetUInt32(pObj->GetMode());
+                break;
+            }
         }
 
@@ -1397,13 +1688,27 @@
                 && cbRead)
             {
-                if (pCtx->uProtocol <= 1)
+                switch (pCtx->uProtocol)
                 {
-                    Msg.u.v1.pvData.SetPtr(pvBuf, cbRead);
-                    Msg.u.v1.cbData.SetUInt32(cbRead);
-                }
-                else
-                {
-                    Msg.u.v2.pvData.SetPtr(pvBuf, cbRead);
-                    Msg.u.v2.cbData.SetUInt32(cbRead);
+                    case 3:
+                    {
+                        Msg.u.v3.pvData.SetPtr(pvBuf, cbRead);
+                        Msg.u.v3.cbData.SetUInt32(cbRead);
+                        /** @todo Calculate + set checksums. */
+                        break;
+                    }
+
+                    case 2:
+                    {
+                        Msg.u.v2.pvData.SetPtr(pvBuf, cbRead);
+                        Msg.u.v2.cbData.SetUInt32(cbRead);
+                        break;
+                    }
+
+                    default:
+                    {
+                        Msg.u.v1.pvData.SetPtr(pvBuf, cbRead);
+                        Msg.u.v1.cbData.SetUInt32(cbRead);
+                        break;
+                    }
                 }
 
@@ -1459,6 +1764,6 @@
 }
 
-static int vbglR3DnDGHProcessURIMessages(PVBGLR3GUESTDNDCMDCTX pCtx,
-                                         const void *pvData, uint32_t cbData)
+static int vbglR3DnDGHSendURIData(PVBGLR3GUESTDNDCMDCTX pCtx,
+                                  const void *pvData, uint32_t cbData)
 {
     AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
@@ -1477,16 +1782,34 @@
     if (RT_SUCCESS(rc))
     {
-        /* Send metadata; in this case it's the (non-recursive) file/directory
-         * URI list the host needs to know to initialize the drag'n drop operation. */
+        /*
+         * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory
+         * URI list the host needs to know upfront to set up the drag'n drop operation.
+         */
         RTCString strRootDest = lstURI.RootToString();
-        Assert(strRootDest.isNotEmpty());
-
-        void *pvToSend = (void *)strRootDest.c_str();
-        uint32_t cbToSend = (uint32_t)strRootDest.length() + 1; /* Include string termination. */
-
-        rc = vbglR3DnDGHSendDataInternal(pCtx, pvToSend, cbToSend,
-                                         /* Include total bytes of all file paths,
-                                          * file sizes etc. */
-                                         (uint32_t)lstURI.TotalBytes());
+        if (strRootDest.isNotEmpty())
+        {
+            void *pvURIList  = (void *)strRootDest.c_str(); /* URI root list. */
+            size_t cbURLIist = strRootDest.length() + 1;    /* Include string termination. */
+
+            /* The total size also contains the size of the meta data. */
+            uint64_t cbTotal  = cbURLIist;
+                     cbTotal += lstURI.TotalBytes();
+
+            /* We're going to send an URI list in text format. */
+            char szMetaFmt[] = "text/uri-list";
+
+            VBOXDNDDATAHDR dataHeader;
+            dataHeader.uFlags    = 0; /* Flags not used yet. */
+            dataHeader.cbTotal   = cbTotal;
+            dataHeader.cbMeta    = cbURLIist;
+            dataHeader.pvMetaFmt = (void *)szMetaFmt;
+            dataHeader.cbMetaFmt = strlen(szMetaFmt) + 1; /* Include termination. */
+            dataHeader.cObjects  = lstURI.TotalCount();
+
+            rc = vbglR3DnDGHSendDataInternal(pCtx,
+                                             pvURIList, cbURLIist, &dataHeader);
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
     }
 
@@ -1520,9 +1843,9 @@
     if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
     {
-        rc = vbglR3DnDGHProcessURIMessages(pCtx, pvData, cbData);
-    }
-    else
-    {
-        rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, 0 /* cbAdditionalData */);
+        rc = vbglR3DnDGHSendURIData(pCtx, pvData, cbData);
+    }
+    else /* Send raw data. */
+    {
+        rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, NULL /* pDataHdr */);
     }
 
@@ -1541,9 +1864,9 @@
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
 
-    DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
+    VBOXDNDGHEVTERRORMSG Msg;
     RT_ZERO(Msg);
     Msg.hdr.result      = VERR_WRONG_ORDER;
     Msg.hdr.u32ClientID = pCtx->uClientID;
-    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
+    Msg.hdr.u32Function = GUEST_DND_GH_EVT_ERROR;
     Msg.hdr.cParms      = 1;
 
Index: /trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
===================================================================
--- /trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp	(revision 58211)
+++ /trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp	(revision 58212)
@@ -939,5 +939,5 @@
                     uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[XdndStatusAction]));
 
-                rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, uAction);
+                rc = VbglR3DnDHGSendAckOp(&m_dndCtx, uAction);
             }
             else if (e.xclient.message_type == xAtom(XA_XdndFinished))
@@ -1821,5 +1821,5 @@
     {
         /* No window to process, so send a ignore ack event to the host. */
-        rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, DND_IGNORE_ACTION);
+        rc = VbglR3DnDHGSendAckOp(&m_dndCtx, DND_IGNORE_ACTION);
     }
     else
@@ -1866,5 +1866,5 @@
     char szFormat[] = { "text/uri-list" };
 
-    int rc = VbglR3DnDHGRequestData(&m_dndCtx, szFormat);
+    int rc = VbglR3DnDHGSendReqData(&m_dndCtx, szFormat);
     logInfo("Drop event from host resuled in: %Rrc\n", rc);
 
@@ -2074,5 +2074,6 @@
     }
 
-    rc2 = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str());
+    rc2 = VbglR3DnDGHSendAckPending(&m_dndCtx, uDefAction, uAllActions,
+                                    strFormats.c_str(), strFormats.length() + 1 /* Include termination */);
     LogFlowThisFunc(("uClientID=%RU32, uDefAction=0x%x, allActions=0x%x, strFormats=%s, rc=%Rrc\n",
                      m_dndCtx.uClientID, uDefAction, uAllActions, strFormats.c_str(), rc2));
@@ -3196,5 +3197,5 @@
 
         /* Wait for new events. */
-        rc = VbglR3DnDProcessNextMessage(&dndCtx, &e.hgcm);
+        rc = VbglR3DnDRecvNextMsg(&dndCtx, &e.hgcm);
         if (   RT_SUCCESS(rc)
             || rc == VERR_CANCELLED)
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp	(revision 58211)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp	(revision 58212)
@@ -250,5 +250,5 @@
     {
         com::Utf8Str strTmp(strSettings);
-        strSettings = "release: ";
+        strSettings = "release:";
         strSettings.append(strTmp);
     }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.cpp	(revision 58211)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.cpp	(revision 58212)
@@ -42,12 +42,13 @@
 UIDnDDataObject::UIDnDDataObject(UIDnDHandler *pDnDHandler, const QStringList &lstFormats)
     : m_pDnDHandler(pDnDHandler)
-    , mStatus(Uninitialized)
-    , mRefCount(1)
-    , mcFormats(0)
-    , mpFormatEtc(NULL)
-    , mpStgMedium(NULL)
-    , mSemEvent(NIL_RTSEMEVENT)
-    , mpvData(NULL)
-    , mcbData(0)
+    , m_enmStatus(DnDDataObjectStatus_Uninitialized)
+    , m_cRefs(1)
+    , m_cFormats(0)
+    , m_pFormatEtc(NULL)
+    , m_pStgMedium(NULL)
+    , m_SemEvent(NIL_RTSEMEVENT)
+    , m_fDataRetrieved(false)
+    , m_pvData(NULL)
+    , m_cbData(0)
 {
     HRESULT hr;
@@ -58,8 +59,8 @@
     try
     {
-        mpFormatEtc = new FORMATETC[cMaxFormats];
-        RT_BZERO(mpFormatEtc, sizeof(FORMATETC) * cMaxFormats);
-        mpStgMedium = new STGMEDIUM[cMaxFormats];
-        RT_BZERO(mpStgMedium, sizeof(STGMEDIUM) * cMaxFormats);
+        m_pFormatEtc = new FORMATETC[cMaxFormats];
+        RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cMaxFormats);
+        m_pStgMedium = new STGMEDIUM[cMaxFormats];
+        RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cMaxFormats);
 
         for (int i = 0;
@@ -68,5 +69,5 @@
         {
             const QString &strFormat = lstFormats.at(i);
-            if (mlstFormats.contains(strFormat))
+            if (m_lstFormats.contains(strFormat))
                 continue;
 
@@ -74,22 +75,22 @@
             if (strFormat.contains("text/uri-list", Qt::CaseInsensitive))
             {
-                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_TEXT);
-                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
-                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
-                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
-                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_HDROP);
-                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
-
-                mlstFormats << strFormat;
+                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_TEXT);
+                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
+                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
+                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
+                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_HDROP);
+                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
+
+                m_lstFormats << strFormat;
             }
             /* Plain text ("text/plain"). */
             if (strFormat.contains("text/plain", Qt::CaseInsensitive))
             {
-                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_TEXT);
-                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
-                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
-                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
-
-                mlstFormats << strFormat;
+                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_TEXT);
+                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
+                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
+                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
+
+                m_lstFormats << strFormat;
             }
         }
@@ -106,5 +107,5 @@
     if (SUCCEEDED(hr))
     {
-        int rc2 = RTSemEventCreate(&mSemEvent);
+        int rc2 = RTSemEventCreate(&m_SemEvent);
         AssertRC(rc2);
 
@@ -130,6 +131,6 @@
                        RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET));
 #endif
-        mcFormats = cRegisteredFormats;
-        mStatus   = Dropped;
+        m_cFormats  = cRegisteredFormats;
+        m_enmStatus = DnDDataObjectStatus_Dropping;
     }
 
@@ -139,17 +140,17 @@
 UIDnDDataObject::~UIDnDDataObject(void)
 {
-    if (mpFormatEtc)
-        delete[] mpFormatEtc;
-
-    if (mpStgMedium)
-        delete[] mpStgMedium;
-
-    if (mpvData)
-        RTMemFree(mpvData);
-
-    if (mSemEvent != NIL_RTSEMEVENT)
-        RTSemEventDestroy(mSemEvent);
-
-    LogFlowFunc(("mRefCount=%RI32\n", mRefCount));
+    if (m_pFormatEtc)
+        delete[] m_pFormatEtc;
+
+    if (m_pStgMedium)
+        delete[] m_pStgMedium;
+
+    if (m_pvData)
+        RTMemFree(m_pvData);
+
+    if (m_SemEvent != NIL_RTSEMEVENT)
+        RTSemEventDestroy(m_SemEvent);
+
+    LogFlowFunc(("mRefCount=%RI32\n", m_cRefs));
 }
 
@@ -160,10 +161,10 @@
 STDMETHODIMP_(ULONG) UIDnDDataObject::AddRef(void)
 {
-    return InterlockedIncrement(&mRefCount);
+    return InterlockedIncrement(&m_cRefs);
 }
 
 STDMETHODIMP_(ULONG) UIDnDDataObject::Release(void)
 {
-    LONG lCount = InterlockedDecrement(&mRefCount);
+    LONG lCount = InterlockedDecrement(&m_cRefs);
     if (lCount == 0)
     {
@@ -210,27 +211,32 @@
     LPSTGMEDIUM pThisMedium = NULL;
 
+    LogFlowThisFunc(("\n"));
+
     /* Format supported? */
     ULONG lIndex;
     if (   LookupFormatEtc(pFormatEtc, &lIndex)
-        && lIndex < mcFormats) /* Paranoia. */
-    {
-        pThisMedium = &mpStgMedium[lIndex];
+        && lIndex < m_cFormats) /* Paranoia. */
+    {
+        pThisMedium = &m_pStgMedium[lIndex];
         AssertPtr(pThisMedium);
-        pThisFormat = &mpFormatEtc[lIndex];
+        pThisFormat = &m_pFormatEtc[lIndex];
         AssertPtr(pThisFormat);
 
-        LogFlowFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat));
-        LogFlowFunc(("mStatus=%ld\n", mStatus));
-        switch (mStatus)
+        LogFlowThisFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat));
+        LogFlowThisFunc(("mStatus=%RU32\n", m_enmStatus));
+        switch (m_enmStatus)
         {
-            case Dropping:
+            case DnDDataObjectStatus_Dropping:
             {
-                    LogRel3(("DnD: Dropping\n"));
-                    LogFlowFunc(("Waiting for event ...\n"));
-                    int rc2 = RTSemEventWait(mSemEvent, RT_INDEFINITE_WAIT);
-                    LogFlowFunc(("rc=%Rrc, mStatus=%ld\n", rc2, mStatus));
+#if 0
+                LogRel3(("DnD: Dropping\n"));
+                LogFlowFunc(("Waiting for event ...\n"));
+                int rc2 = RTSemEventWait(m_SemEvent, RT_INDEFINITE_WAIT);
+                LogFlowFunc(("rc=%Rrc, mStatus=%RU32\n", rc2, m_enmStatus));
+#endif
+                break;
             }
 
-            case Dropped:
+            case DnDDataObjectStatus_Dropped:
             {
                 LogRel3(("DnD: Dropped\n"));
@@ -239,5 +245,5 @@
                          pThisFormat->tymed, pThisFormat->dwAspect));
                 LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n",
-                         mstrFormat.toAscii().constData(), mpvData, mcbData));
+                         m_strFormat.toAscii().constData(), m_pvData, m_cbData));
 
                 QVariant::Type vaType;
@@ -288,29 +294,32 @@
 
                 int rc;
-                if (!mVaData.isValid())
+
+                if (!m_fDataRetrieved)
                 {
-                    /* Note:  We're usig Qt::MoveAction because this speeds up the whole operation
-                     *        significantly: Instead of copying the data from the temporary location to
-                     *        the final destination we just move it.
-                     *
-                     * Note2: The Qt::MoveAction *only* affects the behavior on the host! The desired
-                     *        action for the guest (e.g. moving a file from guest to host) is not affected
-                     *        by this setting. */
-                    rc = m_pDnDHandler->retrieveData(Qt::MoveAction,
-                                                     strMIMEType, vaType, mVaData);
+                    if (m_pDnDHandler)
+                    {
+                        rc = m_pDnDHandler->retrieveData(Qt::CopyAction,
+                                                         strMIMEType, vaType, m_vaData);
+                    }
+                    else
+                        rc = VERR_NOT_FOUND;
+
+                    m_fDataRetrieved = true;
+                    LogFlowFunc(("Retrieving data ended with %Rrc\n", rc));
                 }
-                else
-                    rc = VINF_SUCCESS; /* Data already retrieved. */
-
-                if (RT_SUCCESS(rc))
+                else /* Data already been retrieved. */
+                    rc = VINF_SUCCESS;
+
+                if (   RT_SUCCESS(rc)
+                    && m_vaData.isValid())
                 {
                     if (   strMIMEType.startsWith("text/uri-list")
                                /* One item. */
-                        && (   mVaData.canConvert(QVariant::String)
+                        && (   m_vaData.canConvert(QVariant::String)
                                /* Multiple items. */
-                            || mVaData.canConvert(QVariant::StringList))
+                            || m_vaData.canConvert(QVariant::StringList))
                        )
                     {
-                        QStringList lstFilesURI = mVaData.toStringList();
+                        QStringList lstFilesURI = m_vaData.toStringList();
                         QStringList lstFiles;
                         for (size_t i = 0; i < lstFilesURI.size(); i++)
@@ -331,34 +340,40 @@
 
                         size_t cFiles = lstFiles.size();
+                        LogFlowThisFunc(("Files (%zu)\n", cFiles));
                         if (   RT_SUCCESS(rc)
                             && cFiles)
                         {
-#ifdef DEBUG
-                            LogFlowFunc(("Files (%zu)\n", cFiles));
-                            for (size_t i = 0; i < cFiles; i++)
-                                LogFlowFunc(("\tFile: %s\n", lstFiles.at(i).toAscii().constData()));
-#endif
-                            size_t cchFiles = 0; /* Number of ASCII characters. */
+                            size_t cchFiles = 0; /* Number of characters. */
                             for (size_t i = 0; i < cFiles; i++)
                             {
-                                cchFiles += strlen(lstFiles.at(i).toAscii().constData());
+                                const char *pszFile = lstFiles.at(i).toAscii().constData();
+                                cchFiles += strlen(pszFile);
                                 cchFiles += 1; /* Terminating '\0'. */
+                                LogFlowThisFunc(("\tFile: %s (cchFiles=%zu)\n", pszFile, cchFiles));
                             }
 
-                            size_t cbBuf = sizeof(DROPFILES) + ((cchFiles + 1) * sizeof(RTUTF16));
+                            /* List termination with '\0'. */
+                            cchFiles++;
+
+                            size_t cbBuf = sizeof(DROPFILES) + (cchFiles * sizeof(RTUTF16));
                             DROPFILES *pDropFiles = (DROPFILES *)RTMemAllocZ(cbBuf);
                             if (pDropFiles)
                             {
-                                pDropFiles->pFiles = sizeof(DROPFILES);
-                                pDropFiles->fWide = 1; /* We use unicode. Always. */
+                                /* Put the files list right after our DROPFILES structure. */
+                                pDropFiles->pFiles = sizeof(DROPFILES); /* Offset to file list. */
+                                pDropFiles->fWide  = 1;                 /* We use Unicode. Always. */
 
                                 uint8_t *pCurFile = (uint8_t *)pDropFiles + pDropFiles->pFiles;
                                 AssertPtr(pCurFile);
 
+                                LogFlowThisFunc(("Encoded:\n"));
                                 for (size_t i = 0; i < cFiles; i++)
                                 {
+                                    const char *pszFile = lstFiles.at(i).toUtf8().constData();
+                                    Assert(strlen(pszFile));
+
                                     size_t cchCurFile;
                                     PRTUTF16 pwszFile;
-                                    rc = RTStrToUtf16(lstFiles.at(i).toAscii().constData(), &pwszFile);
+                                    rc = RTStrToUtf16(pszFile, &pwszFile);
                                     if (RT_SUCCESS(rc))
                                     {
@@ -376,4 +391,6 @@
                                     *pCurFile = L'\0';
                                     pCurFile += sizeof(RTUTF16);
+
+                                    LogFlowThisFunc(("\t#%zu: cchCurFile=%zu\n", i, cchCurFile));
                                 }
 
@@ -382,9 +399,12 @@
                                     *pCurFile = L'\0'; /* Final list terminator. */
 
-                                    pMedium->tymed = TYMED_HGLOBAL;
+                                    /*
+                                     * Fill out the medium structure we're going to report back.
+                                     */
+                                    pMedium->tymed          = TYMED_HGLOBAL;
                                     pMedium->pUnkForRelease = NULL;
-                                    pMedium->hGlobal = GlobalAlloc(  GMEM_ZEROINIT
-                                                                   | GMEM_MOVEABLE
-                                                                   | GMEM_DDESHARE, cbBuf);
+                                    pMedium->hGlobal        = GlobalAlloc(  GMEM_ZEROINIT
+                                                                          | GMEM_MOVEABLE
+                                                                          | GMEM_DDESHARE, cbBuf);
                                     if (pMedium->hGlobal)
                                     {
@@ -402,18 +422,25 @@
                                     else
                                         rc = VERR_NO_MEMORY;
+
+                                    LogFlowThisFunc(("Copying to TYMED_HGLOBAL (%zu bytes): %Rrc\n", cbBuf, rc));
                                 }
 
                                 RTMemFree(pDropFiles);
                             }
+                            else
+                                rc = VERR_NO_MEMORY;
+
+                            if (RT_FAILURE(rc))
+                                LogFlowThisFunc(("Failed with %Rrc\n", rc));
                         }
                     }
                     else if (   strMIMEType.startsWith("text/plain")
-                             && mVaData.canConvert(QVariant::String))
+                             && m_vaData.canConvert(QVariant::String))
                     {
-                        bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT;
-                        int cbCh = fUnicode
-                                 ? sizeof(WCHAR) : sizeof(char);
-
-                        QString strText = mVaData.toString();
+                        const bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT;
+                        const size_t cbCh   = fUnicode
+                                            ? sizeof(WCHAR) : sizeof(char);
+
+                        QString strText = m_vaData.toString();
                         size_t cbSrc = strText.length() * cbCh;
                         Assert(cbSrc);
@@ -423,13 +450,10 @@
                         AssertPtr(pvSrc);
 
-                        LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbch=%d, fUnicode=%RTbool\n",
+                        LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbCh=%zu, fUnicode=%RTbool\n",
                                      pvSrc, cbSrc, cbCh, fUnicode));
 
-                        pMedium->tymed = TYMED_HGLOBAL;
+                        pMedium->tymed          = TYMED_HGLOBAL;
                         pMedium->pUnkForRelease = NULL;
-                        pMedium->hGlobal = GlobalAlloc(  GMEM_ZEROINIT
-                                                       | GMEM_MOVEABLE
-                                                       | GMEM_DDESHARE,
-                                                       cbSrc);
+                        pMedium->hGlobal        = GlobalAlloc(GHND | GMEM_SHARE, cbSrc);
                         if (pMedium->hGlobal)
                         {
@@ -449,9 +473,10 @@
                     }
                     else
-                        LogFlowFunc(("MIME type=%s not supported\n",
-                                     strMIMEType.toAscii().constData()));
-
-                    LogFlowFunc(("Handling formats ended with rc=%Rrc\n", rc));
+                        LogRel2(("DnD: MIME type '%s' not supported\n", strMIMEType.toAscii().constData()));
+
+                    LogFlowThisFunc(("Handling formats ended with rc=%Rrc\n", rc));
                 }
+
+                break;
             }
 
@@ -488,5 +513,5 @@
     }
 
-    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
+    LogFlowThisFunc(("Returning hr=%Rhrc\n", hr));
     return hr;
 }
@@ -535,10 +560,10 @@
 {
     LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n",
-                 dwDirection, mcFormats, mpFormatEtc));
+                 dwDirection, m_cFormats, m_pFormatEtc));
 
     HRESULT hr;
     if (dwDirection == DATADIR_GET)
     {
-        hr = UIDnDEnumFormatEtc::CreateEnumFormatEtc(mcFormats, mpFormatEtc, ppEnumFormatEtc);
+        hr = UIDnDEnumFormatEtc::CreateEnumFormatEtc(m_cFormats, m_pFormatEtc, ppEnumFormatEtc);
     }
     else
@@ -571,6 +596,6 @@
 {
     LogFlowFunc(("Aborting ...\n"));
-    mStatus = Aborted;
-    return RTSemEventSignal(mSemEvent);
+    m_enmStatus = DnDDataObjectStatus_Aborted;
+    return RTSemEventSignal(m_SemEvent);
 }
 
@@ -661,12 +686,12 @@
     /* puIndex is optional. */
 
-    for (ULONG i = 0; i < mcFormats; i++)
-    {
-        if(    (pFormatEtc->tymed & mpFormatEtc[i].tymed)
-            && pFormatEtc->cfFormat == mpFormatEtc[i].cfFormat
-            && pFormatEtc->dwAspect == mpFormatEtc[i].dwAspect)
+    for (ULONG i = 0; i < m_cFormats; i++)
+    {
+        if(    (pFormatEtc->tymed & m_pFormatEtc[i].tymed)
+            && pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat
+            && pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
         {
             LogRel3(("DnD: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
-                     pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(mpFormatEtc[i].cfFormat),
+                     pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(m_pFormatEtc[i].cfFormat),
                      pFormatEtc->dwAspect, i));
 
@@ -677,28 +702,11 @@
     }
 
+#if 0
     LogRel3(("DnD: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
              pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
              pFormatEtc->dwAspect));
+#endif
 
     return false;
-}
-
-/* static */
-HGLOBAL UIDnDDataObject::MemDup(HGLOBAL hMemSource)
-{
-    DWORD dwLen    = GlobalSize(hMemSource);
-    AssertReturn(dwLen, NULL);
-    PVOID pvSource = GlobalLock(hMemSource);
-    if (pvSource)
-    {
-        PVOID pvDest = GlobalAlloc(GMEM_FIXED, dwLen);
-        if (pvDest)
-            memcpy(pvDest, pvSource, dwLen);
-
-        GlobalUnlock(hMemSource);
-        return pvDest;
-    }
-
-    return NULL;
 }
 
@@ -719,8 +727,13 @@
 }
 
-void UIDnDDataObject::SetStatus(Status status)
-{
-    LogFlowFunc(("Setting status to %ld\n", status));
-    mStatus = status;
+void UIDnDDataObject::SetStatus(DnDDataObjectStatus enmStatus)
+{
+    LogFlowFunc(("Setting status to %RU32\n", enmStatus));
+    m_enmStatus = enmStatus;
+}
+
+void UIDnDDataObject::Signal(void)
+{
+    SetStatus(DnDDataObjectStatus_Dropped);
 }
 
@@ -732,14 +745,11 @@
     int rc;
 
-    SetStatus(Dropped);
-
-    mstrFormat = strFormat;
     if (cbData)
     {
-        mpvData = RTMemAlloc(cbData);
-        if (mpvData)
+        m_pvData = RTMemAlloc(cbData);
+        if (m_pvData)
         {
-            memcpy(mpvData, pvData, cbData);
-            mcbData = cbData;
+            memcpy(m_pvData, pvData, cbData);
+            m_cbData = cbData;
             rc = VINF_SUCCESS;
         }
@@ -750,9 +760,14 @@
         rc = VINF_SUCCESS;
 
-    if (RT_FAILURE(rc))
-        mStatus = Aborted;
+    if (RT_SUCCESS(rc))
+    {
+        m_strFormat = strFormat;
+        SetStatus(DnDDataObjectStatus_Dropped);
+    }
+    else
+        SetStatus(DnDDataObjectStatus_Aborted);
 
     /* Signal in any case. */
-    int rc2 = RTSemEventSignal(mSemEvent);
+    int rc2 = RTSemEventSignal(m_SemEvent);
     if (RT_SUCCESS(rc))
         rc = rc2;
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.h	(revision 58211)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.h	(revision 58212)
@@ -37,11 +37,12 @@
 public:
 
-    enum Status
+    enum DnDDataObjectStatus
     {
-        Uninitialized = 0,
-        Initialized,
-        Dropping,
-        Dropped,
-        Aborted
+        DnDDataObjectStatus_Uninitialized = 0,
+        DnDDataObjectStatus_Initialized,
+        DnDDataObjectStatus_Dropping,
+        DnDDataObjectStatus_Dropped,
+        DnDDataObjectStatus_Aborted,
+        DnDDataObjectStatus_32Bit_Hack = 0x7fffffff
     };
 
@@ -71,35 +72,40 @@
 public:
 
-    static const char* ClipboardFormatToString(CLIPFORMAT fmt);
+    static const char *ClipboardFormatToString(CLIPFORMAT fmt);
 
     int Abort(void);
-    void SetStatus(Status status);
+    void Signal(void);
     int Signal(const QString &strFormat, const void *pvData, uint32_t cbData);
 
 protected:
 
+    void SetStatus(DnDDataObjectStatus enmStatus);
+
     bool LookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex);
-    static HGLOBAL MemDup(HGLOBAL hMemSource);
     void RegisterFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
                         LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
 
-    UIDnDHandler   *m_pDnDHandler;
-
-    Status          mStatus;
-    LONG            mRefCount;
+    /** Pointe rto drag and drop handler. */
+    UIDnDHandler           *m_pDnDHandler;
+    /** Current drag and drop status. */
+    DnDDataObjectStatus     m_enmStatus;
+    /** Internal reference count of this object. */
+    LONG                    m_cRefs;
     /** Number of native formats registered. This can be a different number than supplied with mlstFormats. */
-    ULONG           mcFormats;
-    FORMATETC      *mpFormatEtc;
-    STGMEDIUM      *mpStgMedium;
-    RTSEMEVENT      mSemEvent;
-    QStringList     mlstFormats;
-    QString         mstrFormat;
+    ULONG                   m_cFormats;
+    FORMATETC              *m_pFormatEtc;
+    STGMEDIUM              *m_pStgMedium;
+    RTSEMEVENT              m_SemEvent;
+    QStringList             m_lstFormats;
+    QString                 m_strFormat;
     /** The retrieved data as a QVariant. Needed for buffering in case a second format needs the same data,
      *  e.g. CF_TEXT and CF_UNICODETEXT. */
-    QVariant        mVaData;
+    QVariant                m_vaData;
+    /** Whether the data already was retrieved or not. */
+    bool                    m_fDataRetrieved;
     /** The retrieved data as a raw buffer. */
-    void           *mpvData;
+    void                   *m_pvData;
     /** Raw buffer size (in bytes). */
-    uint32_t        mcbData;
+    uint32_t                m_cbData;
 };
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.cpp	(revision 58211)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.cpp	(revision 58212)
@@ -24,23 +24,28 @@
 #include <iprt/thread.h>
 
+/* Qt includes: */
+#include <QApplication>
+
+/* Windows includes: */
+#include <QApplication>
 #include <windows.h>
 #include <new> /* For bad_alloc. */
 
 #include "UIDnDDropSource_win.h"
+#include "UIDnDDataObject_win.h"
 
-
-
-UIDnDDropSource::UIDnDDropSource(QWidget *pParent)
-    : mRefCount(1),
-      mpParent(pParent),
-      mdwCurEffect(0),
-      muCurAction(Qt::IgnoreAction)
+UIDnDDropSource::UIDnDDropSource(QWidget *pParent, UIDnDDataObject *pDataObject)
+    : m_cRefCount(1)
+    , m_pParent(pParent)
+    , m_pDataObject(pDataObject)
+    , m_dwCurEffect(DROPEFFECT_NONE)
+    , m_uCurAction(Qt::IgnoreAction)
 {
-    LogFlowFunc(("pParent=0x%p\n", mpParent));
+    LogFlowFunc(("pParent=0x%p\n", m_pParent));
 }
 
 UIDnDDropSource::~UIDnDDropSource(void)
 {
-    LogFlowFunc(("mRefCount=%RI32\n", mRefCount));
+    LogFlowFunc(("mRefCount=%RU32\n", m_cRefCount));
 }
 
@@ -51,11 +56,14 @@
 STDMETHODIMP_(ULONG) UIDnDDropSource::AddRef(void)
 {
-    return InterlockedIncrement(&mRefCount);
+    LogFlowFunc(("mRefCount=%RU32\n", m_cRefCount + 1));
+    return (ULONG)InterlockedIncrement(&m_cRefCount);
 }
 
 STDMETHODIMP_(ULONG) UIDnDDropSource::Release(void)
 {
-    LONG lCount = InterlockedDecrement(&mRefCount);
-    if (lCount == 0)
+    Assert(m_cRefCount > 0);
+    LogFlowFunc(("mRefCount=%RU32\n", m_cRefCount - 1));
+    LONG lCount = InterlockedDecrement(&m_cRefCount);
+    if (lCount <= 0)
     {
         delete this;
@@ -63,5 +71,5 @@
     }
 
-    return lCount;
+    return (ULONG)lCount;
 }
 
@@ -94,14 +102,12 @@
 STDMETHODIMP UIDnDDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD dwKeyState)
 {
-#ifndef DEBUG_andy
-    LogFlowFunc(("fEscapePressed=%RTbool, dwKeyState=0x%x, mdwCurEffect=%RI32, muCurAction=%RU32\n",
-                 fEscapePressed, dwKeyState, mdwCurEffect, muCurAction));
-#endif
+    LogFlowFunc(("fEscapePressed=%RTbool, dwKeyState=0x%x, m_dwCurEffect=%RI32, m_uCurAction=%RU32\n",
+                 RT_BOOL(fEscapePressed), dwKeyState, m_dwCurEffect, m_uCurAction));
 
     /* ESC pressed? Bail out. */
     if (fEscapePressed)
     {
-        mdwCurEffect = 0;
-        muCurAction = Qt::IgnoreAction;
+        m_dwCurEffect = DROPEFFECT_NONE;
+        m_uCurAction  = Qt::IgnoreAction;
 
         LogRel2(("DnD: User cancelled dropping data to the host\n"));
@@ -118,7 +124,12 @@
     if (fDropContent)
     {
+        if (m_pDataObject)
+            m_pDataObject->Signal();
+
         LogRel2(("DnD: User dropped data to the host\n"));
         return DRAGDROP_S_DROP;
     }
+
+    QApplication::processEvents();
 
     /* No change, just continue. */
@@ -134,9 +145,7 @@
 STDMETHODIMP UIDnDDropSource::GiveFeedback(DWORD dwEffect)
 {
-     Qt::DropActions dropActions = Qt::IgnoreAction;
+    Qt::DropActions dropActions = Qt::IgnoreAction;
 
-#ifndef DEBUG_andy
     LogFlowFunc(("dwEffect=0x%x\n", dwEffect));
-#endif
     if (dwEffect)
     {
@@ -147,8 +156,9 @@
         if (dwEffect & DROPEFFECT_LINK)
             dropActions |= Qt::LinkAction;
+
+        m_dwCurEffect = dwEffect;
     }
 
-    mdwCurEffect = dwEffect;
-    muCurAction = dropActions;
+    m_uCurAction  = dropActions;
 
     return DRAGDROP_S_USEDEFAULTCURSORS;
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.h	(revision 58211)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.h	(revision 58212)
@@ -22,14 +22,19 @@
 #include "COMEnums.h"
 
+class UIDnDDataObject;
+
+/**
+ * Implementation of IDropSource for drag and drop on the host.
+ */
 class UIDnDDropSource : public IDropSource
 {
 public:
 
-    UIDnDDropSource(QWidget *pParent);
+    UIDnDDropSource(QWidget *pParent, UIDnDDataObject *pDataObject);
     virtual ~UIDnDDropSource(void);
 
 public:
 
-    uint32_t GetCurrentAction(void) { return muCurAction; }
+    uint32_t GetCurrentAction(void) const { return m_uCurAction; }
 
 public: /* IUnknown methods. */
@@ -46,8 +51,13 @@
 protected:
 
-    LONG             mRefCount;
-    QWidget         *mpParent;
-    DWORD            mdwCurEffect;
-    Qt::DropActions  muCurAction;
+    /** Pointer to parent widget. */
+    QWidget         *m_pParent;
+    UIDnDDataObject *m_pDataObject;
+    /** The current reference count. */
+    LONG             m_cRefCount;
+    /** Current (last) drop effect issued. */
+    DWORD            m_dwCurEffect;
+    /** Current drop action to perform in case of a successful drop. */
+    Qt::DropActions  m_uCurAction;
 };
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp	(revision 58211)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp	(revision 58212)
@@ -335,10 +335,9 @@
 
 # ifdef RT_OS_WINDOWS
-
-    UIDnDDropSource *pDropSource = new UIDnDDropSource(m_pParent);
-    if (!pDropSource)
-        return VERR_NO_MEMORY;
     UIDnDDataObject *pDataObject = new UIDnDDataObject(this, lstFormats);
     if (!pDataObject)
+        return VERR_NO_MEMORY;
+    UIDnDDropSource *pDropSource = new UIDnDDropSource(m_pParent, pDataObject);
+    if (!pDropSource)
         return VERR_NO_MEMORY;
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp	(revision 58211)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp	(revision 58212)
@@ -109,5 +109,5 @@
 
     /* Let the user know. */
-    LogRel(("Drag and drop support for OS X is disabled in this version."));
+    LogRel(("DnD: Drag and drop support for OS X is not available in this version\n"));
 # endif /* VBOX_WITH_DRAG_AND_DROP_PROMISES */
 #else /* !RT_OS_DARWIN */
@@ -120,5 +120,5 @@
     {
         LogFlowFunc(("Current drop action is 0x%x, so can't drop yet\n", m_curAction));
-        rc = VERR_WRONG_ORDER;
+        rc = VERR_NOT_FOUND;
     }
 #endif
@@ -172,5 +172,5 @@
 
     if (RT_FAILURE(rc))
-        LogRel(("DnD: Retrieving data failed with %Rrc\n", rc));
+        LogRel2(("DnD: Retrieving data failed with %Rrc\n", rc));
 
     return QVariant(QVariant::Invalid);
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp	(revision 58211)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp	(revision 58212)
@@ -101,10 +101,12 @@
 
 
-#ifdef DEBUG_andy
+#ifdef DEBUG
+# ifdef DEBUG_andy
 /* Macro for debugging drag and drop actions which usually would
  * go to Main's logging group. */
-# define DNDDEBUG(x) LogRel(x)
-#else
-# define DNDDEBUG(x)
+#  define DNDDEBUG(x) LogFlowFunc(x)
+# else
+#  define DNDDEBUG(x)
+# endif
 #endif
 
Index: /trunk/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp	(revision 58211)
+++ /trunk/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp	(revision 58212)
@@ -28,18 +28,26 @@
 #include <VBox/GuestHost/DragAndDrop.h>
 
+#ifdef LOG_GROUP
+ #undef LOG_GROUP
+#endif
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/log.h>
+
 DnDDroppedFiles::DnDDroppedFiles(void)
     : hDir(NULL)
-    , fOpen(false) { }
-
-DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, uint32_t fFlags)
+    , fOpen(0) { }
+
+DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, uint32_t fOpen)
     : hDir(NULL)
-    , fOpen(false)
-{
-    OpenEx(pszPath, fFlags);
+    , fOpen(0)
+{
+    OpenEx(pszPath, fOpen);
 }
 
 DnDDroppedFiles::~DnDDroppedFiles(void)
 {
-    Reset(true /* fRemoveDropDir */);
+    /* Only make sure to not leak any handles and stuff, don't delete any
+     * directories / files here. */
+    closeInternal();
 }
 
@@ -62,4 +70,25 @@
 }
 
+int DnDDroppedFiles::closeInternal(void)
+{
+    int rc;
+    if (this->hDir != NULL)
+    {
+        rc = RTDirClose(this->hDir);
+        if (RT_SUCCESS(rc))
+            this->hDir = NULL;
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDDroppedFiles::Close(void)
+{
+    return closeInternal();
+}
+
 const char *DnDDroppedFiles::GetDirAbs(void) const
 {
@@ -69,5 +98,5 @@
 bool DnDDroppedFiles::IsOpen(void) const
 {
-    return this->fOpen;
+    return (this->hDir != NULL);
 }
 
@@ -129,5 +158,5 @@
                 this->hDir       = phDir;
                 this->strPathAbs = pszDropDir;
-                this->fOpen      = true;
+                this->fOpen      = fFlags;
             }
         }
@@ -135,4 +164,5 @@
     } while (0);
 
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -157,30 +187,28 @@
 int DnDDroppedFiles::Reset(bool fRemoveDropDir)
 {
-    int rc = VINF_SUCCESS;
-    if (this->fOpen)
-    {
-        rc = RTDirClose(this->hDir);
-        if (RT_SUCCESS(rc))
-        {
-            this->fOpen = false;
-            this->hDir  = NULL;
-        }
-    }
-    if (RT_SUCCESS(rc))
-    {
-        this->lstDirs.clear();
-        this->lstFiles.clear();
-
-        if (   fRemoveDropDir
-            && this->strPathAbs.isNotEmpty())
-        {
-            /* Try removing the (empty) drop directory in any case. */
-            rc = RTDirRemove(this->strPathAbs.c_str());
-            if (RT_SUCCESS(rc)) /* Only clear if successfully removed. */
-                this->strPathAbs = "";
-        }
-    }
-
-    return rc;
+    int rc = closeInternal();
+    if (RT_SUCCESS(rc))
+    {
+        if (fRemoveDropDir)
+        {
+            rc = Rollback();
+        }
+        else
+        {
+            this->lstDirs.clear();
+            this->lstFiles.clear();
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDDroppedFiles::Reopen(void)
+{
+    if (this->strPathAbs.isEmpty())
+        return VERR_NOT_FOUND;
+
+    return OpenEx(this->strPathAbs.c_str(), this->fOpen);
 }
 
@@ -190,33 +218,51 @@
         return VINF_SUCCESS;
 
-    Assert(this->fOpen);
-    Assert(this->hDir != NULL);
-
     int rc = VINF_SUCCESS;
-    int rc2;
 
     /* Rollback by removing any stuff created.
      * Note: Only remove empty directories, never ever delete
      *       anything recursive here! Steam (tm) knows best ... :-) */
+    int rc2;
     for (size_t i = 0; i < this->lstFiles.size(); i++)
     {
         rc2 = RTFileDelete(this->lstFiles.at(i).c_str());
+        if (RT_SUCCESS(rc2))
+            this->lstFiles.removeAt(i);
+
+        if (RT_SUCCESS(rc))
+           rc = rc2;
+        /* Keep going. */
+    }
+
+    for (size_t i = 0; i < this->lstDirs.size(); i++)
+    {
+        rc2 = RTDirRemove(this->lstDirs.at(i).c_str());
+        if (RT_SUCCESS(rc2))
+            this->lstDirs.removeAt(i);
+
         if (RT_SUCCESS(rc))
             rc = rc2;
-    }
-
-    for (size_t i = 0; i < this->lstDirs.size(); i++)
-    {
-        rc2 = RTDirRemove(this->lstDirs.at(i).c_str());
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-    }
-
-    /* Try to remove the empty root dropped files directory as well. */
-    rc2 = RTDirRemove(this->strPathAbs.c_str());
+        /* Keep going. */
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        Assert(this->lstFiles.isEmpty());
+        Assert(this->lstDirs.isEmpty());
+
+        rc2 = closeInternal();
+        if (RT_SUCCESS(rc2))
+        {
+            /* Try to remove the empty root dropped files directory as well.
+             * Might return VERR_DIR_NOT_EMPTY or similar. */
+            rc2 = RTDirRemove(this->strPathAbs.c_str());
+        }
+    }
+
     if (RT_SUCCESS(rc))
         rc = rc2;
 
-    return rc;
-}
-
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
Index: /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp	(revision 58211)
+++ /trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp	(revision 58212)
@@ -284,5 +284,5 @@
         RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */);
 
-        char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
+        char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */,
                                        pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */);
         if (pszPathURI)
@@ -486,5 +486,5 @@
 
 RTCString DnDURIList::RootToString(const RTCString &strPathBase /* = "" */,
-                                   const RTCString &strSeparator /* = "\r\n" */)
+                                   const RTCString &strSeparator /* = "\r\n" */) const
 {
     RTCString strRet;
@@ -504,5 +504,5 @@
                 {
                     strRet += RTCString(pszPathURI) + strSeparator;
-                    LogFlowFunc(("URI: %s\n", strRet.c_str()));
+                    LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));
                     RTStrFree(pszPathURI);
                 }
Index: /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp
===================================================================
--- /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp	(revision 58211)
+++ /trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp	(revision 58212)
@@ -84,4 +84,10 @@
             }
 
+            case DragAndDropSvc::HOST_DND_HG_SND_DATA_HDR:
+            {
+                LogFlowFunc(("HOST_DND_HG_SND_DATA_HDR\n"));
+                break;
+            }
+
             case DragAndDropSvc::HOST_DND_HG_SND_DATA:
             {
@@ -116,11 +122,4 @@
             {
                 LogFlowFunc(("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;
-                }
                 break;
             }
@@ -129,13 +128,4 @@
             {
                 LogFlowFunc(("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;
-                }
                 break;
             }
@@ -147,11 +137,14 @@
         }
 
-        if (!pMessage) /* Generic message needed? */
-            pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
-
-        if (fAppend)
-            m_dndMessageQueue.append(pMessage);
-        else
-            m_dndMessageQueue.prepend(pMessage);
+        if (RT_SUCCESS(rc))
+        {
+            if (!pMessage) /* Generic message needed? */
+                pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
+
+            if (fAppend)
+                m_dndMessageQueue.append(pMessage);
+            else
+                m_dndMessageQueue.prepend(pMessage);
+        }
     }
     catch(std::bad_alloc &)
Index: /trunk/src/VBox/HostServices/DragAndDrop/service.cpp
===================================================================
--- /trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 58211)
+++ /trunk/src/VBox/HostServices/DragAndDrop/service.cpp	(revision 58212)
@@ -16,38 +16,7 @@
  */
 
-/** @page pg_svc_guest_control   Guest Control HGCM Service
+/** @page pg_svc_guest_control   Drag and drop 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).
+ * TODO
  */
 
@@ -63,6 +32,11 @@
 #include <map>
 
+#include <VBox/GuestHost/DragAndDrop.h>
+#include <VBox/HostServices/Service.h>
+#include <VBox/HostServices/DragAndDropSvc.h>
+
 #include "dndmanager.h"
 
+using namespace DragAndDropSvc;
 
 /*********************************************************************************************************************************
@@ -158,5 +132,5 @@
     {
         AssertMsgFailed(("Maximum number of clients reached\n"));
-        return VERR_BUFFER_OVERFLOW;
+        return VERR_MAX_PROCS_REACHED;
     }
 
@@ -263,5 +237,5 @@
     switch (u32Function)
     {
-        case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
+        case GUEST_DND_GET_NEXT_HOST_MSG:
         {
             if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
@@ -277,6 +251,6 @@
         }
 
-        /* Note: New since protocol version 2. */
-        case DragAndDropSvc::GUEST_DND_CONNECT:
+        /* New since protocol v2. */
+        case GUEST_DND_CONNECT:
         {
             /*
@@ -288,9 +262,9 @@
             break;
         }
-        case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
+        case GUEST_DND_HG_ACK_OP:
             /* Fall through is intentional. */
-        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
+        case GUEST_DND_HG_REQ_DATA:
             /* Fall through is intentional. */
-        case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
+        case GUEST_DND_HG_EVT_PROGRESS:
         {
             if (   modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
@@ -304,10 +278,11 @@
         }
 
-        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
-        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
-        case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
-        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
-        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
-        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
+        case GUEST_DND_GH_ACK_PENDING:
+        case GUEST_DND_GH_SND_DATA_HDR:
+        case GUEST_DND_GH_SND_DATA:
+        case GUEST_DND_GH_SND_DIR:
+        case GUEST_DND_GH_SND_FILE_HDR:
+        case GUEST_DND_GH_SND_FILE_DATA:
+        case GUEST_DND_GH_EVT_ERROR:
         {
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
@@ -347,4 +322,8 @@
         HGCM::Client *pClient = itClient->second;
         AssertPtr(pClient);
+
+        LogFlowFunc(("Client %RU32: Protocol v%RU32\n", pClient->clientId(), pClient->protocol()));
+
+        rc = VERR_INVALID_PARAMETER; /* Play safe. */
 
         switch (u32Function)
@@ -357,15 +336,8 @@
              *       handle HOST_DND_GH_REQ_PENDING.
              */
-            case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
+            case GUEST_DND_GET_NEXT_HOST_MSG:
             {
                 LogFlowFunc(("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
+                if (cParms == 3)
                 {
                     rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
@@ -374,6 +346,6 @@
                         if (m_pfnHostCallback) /* Try asking the host. */
                         {
-                            DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG data;
-                            data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
+                            VBOXDNDCBHGGETNEXTHOSTMSG data;
+                            data.hdr.u32Magic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
                             rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
                             if (RT_SUCCESS(rc))
@@ -405,12 +377,8 @@
                 break;
             }
-            case DragAndDropSvc::GUEST_DND_CONNECT:
+            case GUEST_DND_CONNECT:
             {
                 LogFlowFunc(("GUEST_DND_CONNECT\n"));
-                if (   cParms != 2
-                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* protocol version */
-                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* additional connection flags */)
-                    rc = VERR_INVALID_PARAMETER;
-                else
+                if (cParms == 2)
                 {
                     uint32_t uProtocol;
@@ -420,4 +388,5 @@
                     if (RT_SUCCESS(rc))
                     {
+                        LogFlowFunc(("Client %RU32 is now using protocol v%RU32\n", pClient->clientId(), pClient->protocol()));
                         /** @todo Handle connection flags (paParms[1]). */
                     }
@@ -428,14 +397,11 @@
                 break;
             }
-            case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
+            case GUEST_DND_HG_ACK_OP:
             {
                 LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
-                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;
+                if (cParms == 1)
+                {
+                    VBOXDNDCBHGACKOPDATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_HG_ACK_OP;
                     rc = paParms[0].getUInt32(&data.uAction); /* Get drop action. */
                     DO_HOST_CALLBACK();
@@ -443,14 +409,11 @@
                 break;
             }
-            case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
+            case GUEST_DND_HG_REQ_DATA:
             {
                 LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
-                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;
+                if (cParms == 1)
+                {
+                    VBOXDNDCBHGREQDATADATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_HG_REQ_DATA;
                     rc = paParms[0].getPointer((void**)&data.pszFormat, &data.cbFormat);
                     DO_HOST_CALLBACK();
@@ -458,16 +421,11 @@
                 break;
             }
-            case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
+            case GUEST_DND_HG_EVT_PROGRESS:
             {
                 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n"));
-                if (   cParms != 3
-                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* status */
-                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* percent */
-                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
-                    rc = VERR_INVALID_PARAMETER;
-                else
-                {
-                    DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
-                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
+                if (cParms == 3)
+                {
+                    VBOXDNDCBHGEVTPROGRESSDATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_HG_EVT_PROGRESS;
                     rc = paParms[0].getUInt32(&data.uStatus);
                     if (RT_SUCCESS(rc))
@@ -480,16 +438,11 @@
             }
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-            case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
+            case GUEST_DND_GH_ACK_PENDING:
             {
                 LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
-                if (   cParms != 3
-                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
-                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* alloctions */
-                    || 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;
+                if (cParms == 3)
+                {
+                    VBOXDNDCBGHACKPENDINGDATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_GH_ACK_PENDING;
                     rc = paParms[0].getUInt32(&data.uDefAction);
                     if (RT_SUCCESS(rc))
@@ -501,34 +454,91 @@
                 break;
             }
-            case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
+            /* New since protocol v3. */
+            case GUEST_DND_GH_SND_DATA_HDR:
+            {
+                LogFlowFunc(("GUEST_DND_GH_SND_DATA_HDR\n"));
+                if (cParms == 12)
+                {
+                    VBOXDNDCBSNDDATAHDRDATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DATA_HDR;
+                    rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[1].getUInt32(&data.data.uFlags);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[2].getUInt32(&data.data.uScreenId);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[3].getUInt64(&data.data.cbTotal);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[4].getUInt32(&data.data.cbMeta);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[5].getPointer(&data.data.pvMetaFmt, &data.data.cbMetaFmt);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[6].getUInt32(&data.data.cbMetaFmt);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[7].getUInt64(&data.data.cObjects);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[8].getUInt32(&data.data.enmCompression);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[9].getUInt32((uint32_t *)&data.data.enmChecksumType);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[10].getPointer(&data.data.pvChecksum, &data.data.cbChecksum);
+                    if (RT_SUCCESS(rc))
+                        rc = paParms[11].getUInt32(&data.data.cbChecksum);
+
+                    LogFlowFunc(("fFlags=0x%x, cbTotalSize=%RU64, cObj=%RU64\n",
+                                 data.data.uFlags, data.data.cbTotal, data.data.cObjects));
+                    DO_HOST_CALLBACK();
+                }
+                break;
+            }
+            case GUEST_DND_GH_SND_DATA:
             {
                 LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
-                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;
-                    rc = paParms[0].getPointer((void**)&data.pvData, &data.cbData);
-                    if (RT_SUCCESS(rc))
-                        rc = paParms[1].getUInt32(&data.cbTotalSize);
-                    DO_HOST_CALLBACK();
-                }
-                break;
-            }
-            case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
+                switch (pClient->protocol())
+                {
+                    case 3:
+                    {
+                        if (cParms == 5)
+                        {
+                            VBOXDNDCBSNDDATADATA data;
+                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DATA;
+                            rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[1].getPointer((void**)&data.data.u.v3.pvData, &data.data.u.v3.cbData);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[2].getUInt32(&data.data.u.v3.cbData);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[3].getPointer((void**)&data.data.u.v3.pvChecksum, &data.data.u.v3.cbChecksum);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[4].getUInt32(&data.data.u.v3.cbChecksum);
+                            DO_HOST_CALLBACK();
+                        }
+                        break;
+                    }
+
+                    case 2:
+                    default:
+                    {
+                        if (cParms == 2)
+                        {
+                            VBOXDNDCBSNDDATADATA data;
+                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DATA;
+                            rc = paParms[0].getPointer((void**)&data.data.u.v1.pvData, &data.data.u.v1.cbData);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[1].getUInt32(&data.data.u.v1.cbTotalSize);
+                            DO_HOST_CALLBACK();
+                        }
+                        break;
+                    }
+                }
+                break;
+            }
+            case GUEST_DND_GH_SND_DIR:
             {
                 LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
-                if (   cParms != 3
-                    || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* path */
-                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* path length */
-                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
-                    rc = VERR_INVALID_PARAMETER;
-                else
-                {
-                    DragAndDropSvc::VBOXDNDCBSNDDIRDATA data;
-                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR;
+                if (cParms == 3)
+                {
+                    VBOXDNDCBSNDDIRDATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DIR;
                     uint32_t cTmp;
                     rc = paParms[0].getPointer((void**)&data.pszPath, &cTmp);
@@ -543,20 +553,12 @@
                 break;
             }
-            /* Note: Since protocol v2 (>= VBox 5.0). */
-            case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
+            /* New since protocol v2 (>= VBox 5.0). */
+            case GUEST_DND_GH_SND_FILE_HDR:
             {
                 LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n"));
-                if (   cParms != 6
-                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* context ID */
-                    || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
-                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length  */
-                    || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */
-                    || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* file mode */
-                    || paParms[5].type != VBOX_HGCM_SVC_PARM_64BIT /* file size */)
-                    rc = VERR_INVALID_PARAMETER;
-                else
-                {
-                    DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA data;
-                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR;
+                if (cParms == 6)
+                {
+                    VBOXDNDCBSNDFILEHDRDATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_HDR;
                     uint32_t cTmp;
                     /* paParms[0] is context ID; unused yet. */
@@ -577,5 +579,5 @@
                 break;
             }
-            case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
+            case GUEST_DND_GH_SND_FILE_DATA:
             {
                 LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n"));
@@ -583,19 +585,36 @@
                 switch (pClient->protocol())
                 {
-                    case 2: /* Protocol version 2 only sends the next data chunks to reduce traffic. */
+                    /* Protocol v3 adds (optional) checksums. */
+                    case 3:
                     {
-                        if (   cParms != 3
-                            /* paParms[0] is context ID; unused yet. */
-                            || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
-                            || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */)
+                        if (cParms == 5)
                         {
-                            rc = VERR_INVALID_PARAMETER;
+                            VBOXDNDCBSNDFILEDATADATA data;
+                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_DATA;
+                            rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[2].getUInt32(&data.cbData);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[3].getPointer((void**)&data.u.v3.pvChecksum, &data.u.v3.cbChecksum);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[4].getUInt32(&data.u.v3.cbChecksum);
+
+                            LogFlowFunc(("pvData=0x%p, cbData=%RU32\n", data.pvData, data.cbData));
+                            DO_HOST_CALLBACK();
                         }
-                        else
+                        break;
+                    }
+                    /* Protocol v2 only sends the next data chunks to reduce traffic. */
+                    case 2:
+                    {
+                        if (cParms == 3)
                         {
-                            DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
-                            data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
-                            /* paParms[0] is context ID; unused yet. */
-                            rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
+                            VBOXDNDCBSNDFILEDATADATA data;
+                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_DATA;
+                            rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
+                            if (RT_SUCCESS(rc))
+                                rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
                             if (RT_SUCCESS(rc))
                                 rc = paParms[2].getUInt32(&data.cbData);
@@ -606,19 +625,11 @@
                         break;
                     }
+                    /* Protocol v1 sends the file path and attributes for every file chunk (!). */
                     default:
                     {
-                        if (   cParms != 5
-                            || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
-                            || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
-                            || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
-                            || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
-                            || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
+                        if (cParms == 5)
                         {
-                            rc = VERR_INVALID_PARAMETER;
-                        }
-                        else
-                        {
-                            DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
-                            data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
+                            VBOXDNDCBSNDFILEDATADATA data;
+                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_DATA;
                             uint32_t cTmp;
                             rc = paParms[0].getPointer((void**)&data.u.v1.pszFilePath, &cTmp);
@@ -641,14 +652,11 @@
                 break;
             }
-            case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
+            case GUEST_DND_GH_EVT_ERROR:
             {
                 LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
-                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;
+                if (cParms == 1)
+                {
+                    VBOXDNDCBEVTERRORDATA data;
+                    data.hdr.u32Magic = CB_MAGIC_DND_GH_EVT_ERROR;
 
                     uint32_t rcOp;
@@ -670,6 +678,6 @@
                     if (m_pfnHostCallback)
                     {
-                        DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
-                        data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA;
+                        VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
+                        data.hdr.u32Magic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA;
                         data.uMsg    = u32Function;
                         data.cParms  = cParms;
@@ -728,5 +736,5 @@
 
     int rc;
-    if (u32Function == DragAndDropSvc::HOST_DND_SET_MODE)
+    if (u32Function == HOST_DND_SET_MODE)
     {
         if (cParms != 1)
@@ -755,5 +763,5 @@
                      */
                     uint32_t uMsg = pClient->message();
-                    if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
+                    if (uMsg == GUEST_DND_GET_NEXT_HOST_MSG)
                     {
                         LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
@@ -822,6 +830,6 @@
                      uStatus, uPercentage, rc));
 
-        DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
-        data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
+        VBOXDNDCBHGEVTPROGRESSDATA data;
+        data.hdr.u32Magic = CB_MAGIC_DND_HG_EVT_PROGRESS;
         data.uPercentage  = RT_MIN(uPercentage, 100);
         data.uStatus      = uStatus;
@@ -829,5 +837,5 @@
 
         return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
-                                        DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS,
+                                        GUEST_DND_HG_EVT_PROGRESS,
                                         &data, sizeof(data));
     }
Index: /trunk/src/VBox/Main/include/GuestDnDPrivate.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestDnDPrivate.h	(revision 58211)
+++ /trunk/src/VBox/Main/include/GuestDnDPrivate.h	(revision 58212)
@@ -22,7 +22,15 @@
 #include <iprt/dir.h>
 #include <iprt/file.h>
-
-#include "VBox/hgcmsvc.h" /* For PVBOXHGCMSVCPARM. */
-#include "VBox/GuestHost/DragAndDrop.h"
+#include <iprt/path.h>
+
+#include <VBox/hgcmsvc.h> /* For PVBOXHGCMSVCPARM. */
+#include <VBox/GuestHost/DragAndDrop.h>
+#include <VBox/HostServices/DragAndDropSvc.h>
+
+#ifdef LOG_GROUP
+ #undef LOG_GROUP
+#endif
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/log.h>
 
 /**
@@ -36,4 +44,11 @@
 class Progress;
 
+/**
+ * Type definitions.
+ */
+
+/** List (vector) of MIME types. */
+typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
+
 class GuestDnDCallbackEvent
 {
@@ -65,88 +80,400 @@
 
 /**
- * Structure for keeping the (URI) data to be sent/received.
- */
-typedef struct GuestDnDData
+ * Class for handling the (raw) meta data.
+ */
+class GuestDnDMetaData
 {
+public:
+
+    GuestDnDMetaData(void)
+        : pvData(NULL)
+        , cbData(0)
+        , cbDataUsed(0) { }
+
+    virtual ~GuestDnDMetaData(void)
+    {
+        reset();
+    }
+
+public:
+
+    size_t add(const void *pvDataAdd, size_t cbDataAdd)
+    {
+        if (!cbDataAdd)
+            return 0;
+        AssertPtrReturn(pvDataAdd, 0);
+
+        int rc = resize(cbData + cbDataAdd);
+        if (RT_FAILURE(rc))
+            return 0;
+
+        Assert(cbData >= cbDataUsed + cbDataAdd);
+        memcpy((uint8_t *)pvData + cbDataUsed, pvDataAdd, cbDataAdd);
+
+        cbDataUsed += cbDataAdd;
+
+        return cbDataAdd;
+    }
+
+    size_t add(const std::vector<BYTE> &vecAdd)
+    {
+        if (!vecAdd.size())
+            return 0;
+
+        return add(&vecAdd.front(), vecAdd.size());
+    }
+
+    void reset(void)
+    {
+        if (pvData)
+        {
+            Assert(cbData);
+            RTMemFree(pvData);
+            pvData = NULL;
+        }
+
+        cbData     = 0;
+        cbDataUsed = 0;
+    }
+
+    const void *getData(void) const { return pvData; }
+
+    void *getDataMutable(void) { return pvData; }
+
+    size_t getSize(void) const { return cbDataUsed; }
+
+public:
+
+    int fromString(const RTCString &strData)
+    {
+        int rc = VINF_SUCCESS;
+
+        if (strData.isNotEmpty())
+        {
+            const size_t cbData = strData.length() + 1; /* Include terminating zero. */
+            rc = resize(cbData);
+            if (RT_SUCCESS(rc))
+                memcpy(pvData, strData.c_str(), cbData);
+        }
+
+        return rc;
+    }
+
+    int fromURIList(const DnDURIList &lstURI)
+    {
+        return fromString(lstURI.RootToString());
+    }
+
+protected:
+
+    int resize(size_t cbSize)
+    {
+        if (!cbSize)
+        {
+            reset();
+            return VINF_SUCCESS;
+        }
+
+        if (cbSize == cbData)
+            return VINF_SUCCESS;
+
+        void *pvTmp = NULL;
+        if (!cbData)
+        {
+            Assert(cbDataUsed == 0);
+            pvTmp = RTMemAllocZ(cbSize);
+        }
+        else
+        {
+            AssertPtr(pvData);
+            pvTmp = RTMemRealloc(pvData, cbSize);
+            RT_BZERO(pvTmp, cbSize);
+        }
+
+        if (pvTmp)
+        {
+            pvData = pvTmp;
+            cbData = cbSize;
+            return VINF_SUCCESS;
+        }
+
+        return VERR_NO_MEMORY;
+    }
+
+protected:
+
+    void   *pvData;
+    size_t  cbData;
+    size_t  cbDataUsed;
+};
+
+/**
+ * Class for keeping drag and drop (meta) data
+ * to be sent/received.
+ */
+class GuestDnDData
+{
+public:
+
     GuestDnDData(void)
-        : cbToProcess(0)
-        , cbProcessed(0) { }
-
-    void Reset(void)
-    {
-        vecData.clear();
-        cbToProcess = 0;
+        : cbProcessed(0)
+        , cbAddData(0) { }
+
+    virtual ~GuestDnDData(void)
+    {
+        reset();
+    }
+
+public:
+
+    uint64_t addProcessed(uint32_t cbDataAdd)
+    {
+        const uint64_t cbTotal = getTotal();
+        Assert(cbProcessed + cbDataAdd <= cbTotal);
+        cbProcessed += cbDataAdd;
+        return cbProcessed;
+    }
+
+    bool isComplete(void) const
+    {
+        const uint64_t cbTotal = getTotal();
+        Assert(cbProcessed <= cbTotal);
+        return (cbProcessed == cbTotal);
+    }
+
+    void *getChkSumMutable(void) { return dataHdr.pvChecksum; }
+
+    uint32_t getChkSumSize(void) const { return dataHdr.cbChecksum; }
+
+    void *getFmtMutable(void) { return dataHdr.pvMetaFmt; }
+
+    uint32_t getFmtSize(void) const { return dataHdr.cbMetaFmt; }
+
+    GuestDnDMetaData &getMeta(void) { return dataMeta; }
+
+    uint8_t getPercentComplete(void) const
+    {
+        int64_t cbTotal  = RT_MAX(getTotal(), 1);
+        return (uint8_t)(cbProcessed * 100 / cbTotal);
+    }
+
+    uint64_t getProcessed(void) const { return cbProcessed; }
+
+    uint64_t getRemaining(void) const
+    {
+        const uint64_t cbTotal = getTotal();
+        Assert(cbProcessed <= cbTotal);
+        return cbTotal - cbProcessed;
+    }
+
+    uint64_t getTotal(void) const { return dataMeta.getSize() + cbAddData; }
+
+    void reset(void)
+    {
+        clearFmt();
+        clearChkSum();
+
+        RT_ZERO(dataHdr);
+
+        dataMeta.reset();
         cbProcessed = 0;
-    }
-
-    /** Array (vector) of guest DnD data. This might be an URI list, according
-     *  to the format being set. */
-    std::vector<BYTE>         vecData;
-    /** Overall size (in bytes) of data to send. */
-    uint64_t                  cbToProcess;
-    /** Overall size (in bytes) of processed file data. */
-    uint64_t                  cbProcessed;
-
-} GuestDnDData;
+        cbAddData   = 0;
+    }
+
+    int setFmt(const void *pvFmt, uint32_t cbFmt)
+    {
+        if (cbFmt)
+        {
+            AssertPtrReturn(pvFmt, VERR_INVALID_POINTER);
+            void *pvFmtTmp = RTMemAlloc(cbFmt);
+            if (!pvFmtTmp)
+                return VERR_NO_MEMORY;
+
+            clearFmt();
+
+            memcpy(pvFmtTmp, pvFmt, cbFmt);
+
+            dataHdr.pvMetaFmt = pvFmtTmp;
+            dataHdr.cbMetaFmt = cbFmt;
+        }
+        else
+            clearFmt();
+
+        return VINF_SUCCESS;
+    }
+
+    void setAdditionalSize(uint64_t cbAdd)
+    {
+        LogFlowFunc(("cbAdd=%RU64\n", cbAdd));
+
+        cbAddData = cbAdd;
+
+        invalidate();
+    }
+
+    void setEstimatedSize(uint64_t cbTotal, uint32_t cbMeta)
+    {
+        Assert(cbMeta <= cbTotal);
+
+        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU64\n", cbTotal, cbMeta));
+
+        dataMeta.reset();
+
+        dataHdr.cbMeta = cbMeta;
+        setAdditionalSize(cbTotal - cbMeta);
+    }
+
+protected:
+
+    void clearChkSum(void)
+    {
+        if (dataHdr.pvChecksum)
+        {
+            Assert(dataHdr.cbChecksum);
+            RTMemFree(dataHdr.pvChecksum);
+            dataHdr.pvChecksum = NULL;
+        }
+
+        dataHdr.cbChecksum = 0;
+    }
+
+    void clearFmt(void)
+    {
+        if (dataHdr.pvMetaFmt)
+        {
+            Assert(dataHdr.cbMetaFmt);
+            RTMemFree(dataHdr.pvMetaFmt);
+            dataHdr.pvMetaFmt = NULL;
+        }
+
+        dataHdr.cbMetaFmt = 0;
+    }
+
+    void invalidate(void)
+    {
+        /* Update data header. */
+        dataHdr.cbMeta  = dataMeta.getSize();
+        dataHdr.cbTotal = dataHdr.cbMeta + cbAddData;
+
+        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", dataHdr.cbTotal, dataHdr.cbMeta));
+    }
+
+protected:
+
+    /** The data header. */
+    VBOXDNDDATAHDR    dataHdr;
+    /** For storing the actual meta data.
+     *  This might be an URI list or just plain raw data,
+     *  according to the format being sent. */
+    GuestDnDMetaData  dataMeta;
+    /** Overall size (in bytes) of processed data. */
+    uint64_t          cbProcessed;
+    /** Additional data to process which does not count
+     *  as meta data. Just in here for accounting reasons. */
+    uint64_t          cbAddData;
+};
 
 /**
- * Structure for keeping an URI object's context around.
- */
-typedef struct GuestDnDURIObjCtx
+ * Structure for keeping a DnDURIObject context around.
+ */
+class GuestDnDURIObjCtx
 {
+public:
+
     GuestDnDURIObjCtx(void)
         : pObjURI(NULL)
-        , fAllocated(false)
+        , fIntermediate(false)
         , fHeaderSent(false) { }
 
     virtual ~GuestDnDURIObjCtx(void)
     {
-        Reset();
-    }
-
-public:
-
-    void Reset(void)
+        destroy();
+    }
+
+public:
+
+    DnDURIObject *createIntermediate(void)
+    {
+        reset();
+
+        try
+        {
+            pObjURI       = new DnDURIObject();
+            fIntermediate = true;
+        }
+        catch (std::bad_alloc &)
+        {
+        }
+
+        return pObjURI;
+    }
+
+    void destroy(void)
     {
         if (   pObjURI
-            && fAllocated)
+            && fIntermediate)
         {
             delete pObjURI;
-        }
-
-        pObjURI     = NULL;
-
-        fAllocated  = false;
-        fHeaderSent = false;
-    }
-
+            fIntermediate = false;
+        }
+
+        pObjURI = NULL;
+    }
+
+    bool isIntermediate(void) { return fIntermediate; }
+
+    bool isValid(void) const { return (pObjURI != NULL); }
+
+    void reset(void)
+    {
+        destroy();
+
+        fIntermediate = false;
+        fHeaderSent   = false;
+    }
 
     /** Pointer to current object being handled. */
     DnDURIObject             *pObjURI;
     /** Flag whether pObjURI needs deletion after use. */
-    bool                      fAllocated;
+    bool                      fIntermediate;
     /** Flag whether the object's file header has been sent already. */
     bool                      fHeaderSent;
     /** @todo Add more statistics / information here. */
-
-} GuestDnDURIObjCtx;
+};
 
 /**
- * Structure for keeping around URI (list) data.
- */
-typedef struct GuestDnDURIData
+ * Structure for keeping around an URI (data) transfer.
+ */
+class GuestDnDURIData
 {
+
+public:
+
     GuestDnDURIData(void)
-        : pvScratchBuf(NULL)
+        : cObjToProcess(0)
+        , cObjProcessed(0)
+        , pvScratchBuf(NULL)
         , cbScratchBuf(0) { }
 
     virtual ~GuestDnDURIData(void)
     {
-        Reset();
-    }
-
-    int Init(size_t cbBuf = _64K)
-    {
-        Reset();
+        reset();
+
+        if (pvScratchBuf)
+        {
+            Assert(cbScratchBuf);
+            RTMemFree(pvScratchBuf);
+            pvScratchBuf = NULL;
+        }
+        cbScratchBuf = 0;
+    }
+
+    DnDDroppedFiles &getDroppedFiles(void) { return droppedFiles; }
+
+    DnDURIList &getURIList(void) { return lstURI; }
+
+    int init(size_t cbBuf = _64K)
+    {
+        reset();
 
         pvScratchBuf = RTMemAlloc(cbBuf);
@@ -158,29 +485,180 @@
     }
 
-    const void *GetBuffer(void) const { return pvScratchBuf; }
-
-    void *GetBufferMutable(void) { return pvScratchBuf; }
-
-    size_t GetBufferSize(void) const { return cbScratchBuf; }
-
-    void Reset(void)
-    {
+    bool isComplete(void) const
+    {
+        LogFlowFunc(("cObjToProcess=%RU64, cObjProcessed=%RU64\n", cObjToProcess, cObjProcessed));
+        Assert(cObjProcessed <= cObjToProcess);
+        return (cObjProcessed == cObjToProcess);
+    }
+
+    const void *getBuffer(void) const { return pvScratchBuf; }
+
+    void *getBufferMutable(void) { return pvScratchBuf; }
+
+    size_t getBufferSize(void) const { return cbScratchBuf; }
+
+    GuestDnDURIObjCtx &getObj(uint64_t uID = 0)
+    {
+        AssertMsg(uID == 0, ("Other objects than object 0 is not supported yet\n"));
+        return objCtx;
+    }
+
+    GuestDnDURIObjCtx &getObjCurrent(void)
+    {
+        DnDURIObject *pCurObj = lstURI.First();
+        if (   !lstURI.IsEmpty()
+            && pCurObj)
+        {
+            /* Point the context object to the current DnDURIObject to process. */
+            objCtx.pObjURI = pCurObj;
+        }
+        else
+            objCtx.reset();
+
+        return objCtx;
+    }
+
+    uint64_t getObjToProcess(void) const { return cObjToProcess; }
+
+    uint64_t getObjProcessed(void) const { return cObjProcessed; }
+
+    int processObject(const DnDURIObject &Obj)
+    {
+        int rc;
+
+        /** @todo Find objct in lstURI first! */
+        switch (Obj.GetType())
+        {
+            case DnDURIObject::Directory:
+                rc = processDirectory(Obj.GetDestPath().c_str(), Obj.GetMode());
+                break;
+
+            case DnDURIObject::File:
+                rc = VINF_SUCCESS;
+                break;
+
+            default:
+                rc = VERR_NOT_IMPLEMENTED;
+                break;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            if (cObjToProcess)
+            {
+                cObjProcessed++;
+                Assert(cObjProcessed <= cObjToProcess);
+            }
+        }
+
+        return rc;
+    }
+
+    void removeObjCurrent(void)
+    {
+        if (cObjToProcess)
+        {
+            cObjProcessed++;
+            Assert(cObjProcessed <= cObjToProcess);
+        }
+
+        lstURI.RemoveFirst();
+        objCtx.reset();
+    }
+
+    void reset(uint64_t cObjs = 0)
+    {
+        cObjToProcess = cObjs;
+        cObjProcessed = 0;
+
+        LogFlowFunc(("cObjToProcess=%RU64\n", cObjToProcess));
+
+        droppedFiles.Close();
+
         lstURI.Clear();
-        objCtx.Reset();
-
-        int rc2 = droppedFiles.Rollback();
-        AssertRC(rc2);
-        rc2 = droppedFiles.Reset(true /* fRemoveDropDir */);
-        AssertRC(rc2);
-
-        if (pvScratchBuf)
-        {
-            Assert(cbScratchBuf);
-            RTMemFree(pvScratchBuf);
-            pvScratchBuf = NULL;
-        }
-        cbScratchBuf = 0;
-    }
-
+        objCtx.reset();
+    }
+
+public:
+
+    int fromMetaData(const GuestDnDMetaData &Data)
+    {
+        reset();
+
+        size_t      cbList  = Data.getSize();
+        const char *pszList = (const char *)Data.getData();
+        if (   !pszList
+            || !cbList)
+        {
+            return VINF_SUCCESS;
+        }
+
+        RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
+        if (lstURIOrg.isEmpty())
+            return VINF_SUCCESS;
+
+        /* Note: All files to be transferred will be kept open during the entire DnD
+         *       operation, also to keep the accounting right. */
+        return lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
+    }
+
+    int toMetaData(std::vector<BYTE> &vecData)
+    {
+        const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
+
+        Utf8Str strURIs = lstURI.RootToString(RTCString(pszDroppedFilesDir));
+        size_t cbData = strURIs.length();
+
+        LogFlowFunc(("%zu root URIs (%zu bytes)\n", lstURI.RootCount(), cbData));
+
+        int rc;
+
+        try
+        {
+            vecData.resize(cbData + 1 /* Include termination */);
+            memcpy(&vecData.front(), strURIs.c_str(), cbData);
+
+            rc = VINF_SUCCESS;
+        }
+        catch (std::bad_alloc &)
+        {
+            rc = VERR_NO_MEMORY;
+        }
+
+        return rc;
+    }
+
+protected:
+
+    int processDirectory(const char *pszPath, uint32_t fMode)
+    {
+        /** @todo Find directory in lstURI first! */
+        int rc;
+
+        const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
+        char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath);
+        if (pszDir)
+        {
+            rc = RTDirCreateFullPath(pszDir, fMode);
+            if (cObjToProcess)
+            {
+                cObjProcessed++;
+                Assert(cObjProcessed <= cObjToProcess);
+            }
+
+            RTStrFree(pszDir);
+        }
+        else
+             rc = VERR_NO_MEMORY;
+
+        return rc;
+    }
+
+protected:
+
+    /** Number of objects to process. */
+    uint64_t                        cObjToProcess;
+    /** Number of objects already processed. */
+    uint64_t                        cObjProcessed;
     /** Handles all drop files for this operation. */
     DnDDroppedFiles                 droppedFiles;
@@ -191,7 +669,4 @@
      *  only have one context at a time. */
     GuestDnDURIObjCtx               objCtx;
-
-protected:
-
     /** Pointer to an optional scratch buffer to use for
      *  doing the actual chunk transfers. */
@@ -199,9 +674,5 @@
     /** Size (in bytes) of scratch buffer. */
     size_t                          cbScratchBuf;
-
-} GuestDnDURIData;
-
-/** List (vector) of MIME types. */
-typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
+};
 
 /**
@@ -227,5 +698,5 @@
     GuestDnDURIData                     mURI;
     /** Callback event to use. */
-    GuestDnDCallbackEvent               mCallback;
+    GuestDnDCallbackEvent               mCBEvent;
 
 } SENDDATACTX, *PSENDDATACTX;
@@ -247,5 +718,5 @@
     /** Original drop format requested to receive from the guest. */
     com::Utf8Str                        mFmtReq;
-    /** Intermediate drop format to be received from the host.
+    /** Intermediate drop format to be received from the guest.
      *  Some original drop formats require a different intermediate
      *  drop format:
@@ -253,6 +724,6 @@
      *  Receiving a file link as "text/plain"  requires still to
      *  receive the file from the guest as "text/uri-list" first,
-     *  then pointing to the file path on the host in the "text/plain"
-     *  data returned. */
+     *  then pointing to the file path on the host with the data
+     *  in "text/plain" format returned. */
     com::Utf8Str                        mFmtRecv;
     /** Desired drop action to perform on the host.
@@ -266,5 +737,5 @@
     GuestDnDURIData                     mURI;
     /** Callback event to use. */
-    GuestDnDCallbackEvent               mCallback;
+    GuestDnDCallbackEvent               mCBEvent;
 
 } RECVDATACTX, *PRECVDATACTX;
@@ -284,4 +755,32 @@
 
     virtual ~GuestDnDMsg(void)
+    {
+        reset();
+    }
+
+public:
+
+    PVBOXHGCMSVCPARM getNextParam(void)
+    {
+        if (cParms >= cParmsAlloc)
+        {
+            if (!paParms)
+                paParms = (PVBOXHGCMSVCPARM)RTMemAlloc(4 * sizeof(VBOXHGCMSVCPARM));
+            else
+                paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
+            if (!paParms)
+                throw VERR_NO_MEMORY;
+            RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
+            cParmsAlloc += 4;
+        }
+
+        return &paParms[cParms++];
+    }
+
+    uint32_t getCount(void) const { return cParms; }
+    PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
+    uint32_t getType(void) const { return uMsg; }
+
+    void reset(void)
     {
         if (paParms)
@@ -299,41 +798,23 @@
 
             RTMemFree(paParms);
-        }
-    }
-
-public:
-
-    PVBOXHGCMSVCPARM getNextParam(void)
-    {
-        if (cParms >= cParmsAlloc)
-        {
-            paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
-            if (!paParms)
-                throw VERR_NO_MEMORY;
-            RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
-            cParmsAlloc += 4;
-        }
-
-        return &paParms[cParms++];
-    }
-
-    uint32_t getCount(void) const { return cParms; }
-    PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
-    uint32_t getType(void) const { return uMsg; }
+            paParms = NULL;
+        }
+
+        uMsg = cParms = cParmsAlloc = 0;
+    }
 
     int setNextPointer(void *pvBuf, uint32_t cbBuf)
     {
-        AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
-        AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
-
         PVBOXHGCMSVCPARM pParm = getNextParam();
         if (!pParm)
             return VERR_NO_MEMORY;
 
-        void *pvTmp = RTMemDup(pvBuf, cbBuf);
-        if (!pvTmp)
-        {
-            RTMemFree(pParm);
-            return VERR_NO_MEMORY;
+        void *pvTmp = NULL;
+        if (pvBuf)
+        {
+            Assert(cbBuf);
+            pvTmp = RTMemDup(pvBuf, cbBuf);
+            if (!pvTmp)
+                return VERR_NO_MEMORY;
         }
 
@@ -350,8 +831,5 @@
         char *pszTemp = RTStrDup(pszString);
         if (!pszTemp)
-        {
-            RTMemFree(pParm);
             return VERR_NO_MEMORY;
-        }
 
         pParm->setString(pszTemp);
@@ -477,7 +955,7 @@
     GuestDnDMIMEList      m_lstFormats;
     /** Pointer to IGuest parent object. */
-    ComObjPtr<Guest>      m_parent;
+    ComObjPtr<Guest>      m_pParent;
     /** Pointer to associated progress object. Optional. */
-    ComObjPtr<Progress>   m_progress;
+    ComObjPtr<Progress>   m_pProgress;
     /** Callback map. */
     GuestDnDCallbackMap   m_mapCallbacks;
@@ -488,4 +966,6 @@
  * implementation. Can't be instanciated directly, only via
  * the factory pattern.
+ *
+ ** @todo Move this into GuestDnDBase.
  */
 class GuestDnD
@@ -524,8 +1004,8 @@
     /** @name Public helper functions.
      * @{ */
-    HRESULT                    adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
-    int                        hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
-    GuestDnDResponse          *response(void) { return m_pResponse; }
-    std::vector<com::Utf8Str>  defaultFormats(void) const { return m_strDefaultFormats; }
+    HRESULT           adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
+    int               hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
+    GuestDnDResponse *response(void) { return m_pResponse; }
+    GuestDnDMIMEList  defaultFormats(void) const { return m_strDefaultFormats; }
     /** @}  */
 
@@ -555,5 +1035,5 @@
      * @{ */
     /** List of supported default MIME/Content-type formats. */
-    std::vector<com::Utf8Str>  m_strDefaultFormats;
+    GuestDnDMIMEList           m_strDefaultFormats;
     /** Pointer to guest implementation. */
     const ComObjPtr<Guest>     m_pGuest;
@@ -610,5 +1090,6 @@
 
     int sendCancel(void);
-    int waitForEvent(RTMSINTERVAL msTimeout, GuestDnDCallbackEvent &Event, GuestDnDResponse *pResp);
+    int updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp, uint32_t cbDataAdd = 0);
+    int waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout);
 
 protected:
@@ -624,14 +1105,17 @@
     /** @}  */
 
+    /**
+     * Internal stuff.
+     */
     struct
     {
-        /** Flag indicating whether a drop operation currently
-         *  is in progress or not. */
-        bool                        mfTransferIsPending;
+        /** Number of active transfers (guest->host or host->guest). */
+        uint32_t                    m_cTransfersPending;
         /** The DnD protocol version to use, depending on the
-         *  installed Guest Additions. */
-        uint32_t                    mProtocolVersion;
-        /** Outgoing message queue. */
-        GuestDnDMsgList             mListOutgoing;
+         *  installed Guest Additions. See DragAndDropSvc.h for
+         *  a protocol changelog. */
+        uint32_t                    m_uProtocolVersion;
+        /** Outgoing message queue (FIFO). */
+        GuestDnDMsgList             m_lstMsgOut;
     } mDataBase;
 };
Index: /trunk/src/VBox/Main/include/GuestDnDSourceImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestDnDSourceImpl.h	(revision 58211)
+++ /trunk/src/VBox/Main/include/GuestDnDSourceImpl.h	(revision 58212)
@@ -18,4 +18,9 @@
 #ifndef ____H_GUESTDNDSOURCEIMPL
 #define ____H_GUESTDNDSOURCEIMPL
+
+#include <VBox/GuestHost/DragAndDrop.h>
+#include <VBox/HostServices/DragAndDropSvc.h>
+
+using namespace DragAndDropSvc;
 
 #include "GuestDnDSourceWrap.h"
@@ -65,8 +70,9 @@
     /** @name Dispatch handlers for the HGCM callbacks.
      * @{ */
-    int i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize);
+    int i_onReceiveDataHdr(PRECVDATACTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr);
+    int i_onReceiveData(PRECVDATACTX pCtx, PVBOXDNDSNDDATA pSndData);
     int i_onReceiveDir(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint32_t fMode);
-    int i_onReceiveFileHdr(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const char *pszPath, uint32_t cbPath, uint64_t cbSize, uint32_t fMode, uint32_t fFlags);
-    int i_onReceiveFileData(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const void *pvData, uint32_t cbData);
+    int i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint64_t cbSize, uint32_t fMode, uint32_t fFlags);
+    int i_onReceiveFileData(PRECVDATACTX pCtx,const void *pvData, uint32_t cbData);
     /** @}  */
 #endif
@@ -93,5 +99,4 @@
     int i_receiveRawData(PRECVDATACTX pCtx, RTMSINTERVAL msTimeout);
     int i_receiveURIData(PRECVDATACTX pCtx, RTMSINTERVAL msTimeout);
-    int i_updateProcess(PRECVDATACTX pCtx, uint64_t cbDataAdd);
 
 protected:
@@ -101,5 +106,6 @@
         /** Maximum data block size (in bytes) the source can handle. */
         uint32_t    mcbBlockSize;
-        /** The context for receiving data from the guest. */
+        /** The context for receiving data from the guest.
+         *  At the moment only one transfer at a time is supported. */
         RECVDATACTX mRecvCtx;
     } mData;
Index: /trunk/src/VBox/Main/include/GuestDnDTargetImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestDnDTargetImpl.h	(revision 58211)
+++ /trunk/src/VBox/Main/include/GuestDnDTargetImpl.h	(revision 58212)
@@ -85,9 +85,11 @@
     int i_cancelOperation(void);
     int i_sendData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
+    int i_sendDataBody(PSENDDATACTX pCtx, GuestDnDData *pData);
+    int i_sendDataHeader(PSENDDATACTX pCtx, GuestDnDData *pData, GuestDnDURIData *pURIData /* = NULL */);
     int i_sendDirectory(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg);
     int i_sendFile(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg);
     int i_sendFileData(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg);
+    int i_sendRawData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
     int i_sendURIData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
-    int i_sendRawData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
     int i_sendURIDataLoop(PSENDDATACTX pCtx, GuestDnDMsg *pMsg);
 
Index: /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 58211)
+++ /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 58212)
@@ -194,5 +194,5 @@
     , m_defAction(0)
     , m_allActions(0)
-    , m_parent(pGuest)
+    , m_pParent(pGuest)
 {
     int rc = RTSemEventCreate(&m_EventSem);
@@ -226,12 +226,12 @@
 HRESULT GuestDnDResponse::resetProgress(const ComObjPtr<Guest>& pParent)
 {
-    m_progress.setNull();
-
-    HRESULT hr = m_progress.createObject();
+    m_pProgress.setNull();
+
+    HRESULT hr = m_pProgress.createObject();
     if (SUCCEEDED(hr))
     {
-        hr = m_progress->init(static_cast<IGuest *>(pParent),
-                              Bstr(pParent->tr("Dropping data")).raw(),
-                              TRUE /* aCancelable */);
+        hr = m_pProgress->init(static_cast<IGuest *>(pParent),
+                               Bstr(pParent->tr("Dropping data")).raw(),
+                               TRUE /* aCancelable */);
     }
 
@@ -242,7 +242,7 @@
 {
     BOOL fCanceled;
-    if (!m_progress.isNull())
-    {
-        HRESULT hr = m_progress->COMGETTER(Canceled)(&fCanceled);
+    if (!m_pProgress.isNull())
+    {
+        HRESULT hr = m_pProgress->COMGETTER(Canceled)(&fCanceled);
         AssertComRC(hr);
     }
@@ -285,12 +285,12 @@
 
     int rc = VINF_SUCCESS;
-    if (!m_progress.isNull())
+    if (!m_pProgress.isNull())
     {
         BOOL fCompleted;
-        HRESULT hr = m_progress->COMGETTER(Completed)(&fCompleted);
+        HRESULT hr = m_pProgress->COMGETTER(Completed)(&fCompleted);
         AssertComRC(hr);
 
         BOOL fCanceled;
-        hr = m_progress->COMGETTER(Canceled)(&fCanceled);
+        hr = m_pProgress->COMGETTER(Canceled)(&fCanceled);
         AssertComRC(hr);
 
@@ -303,7 +303,7 @@
                 case DragAndDropSvc::DND_PROGRESS_ERROR:
                 {
-                    hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR,
-                                                      COM_IIDOF(IGuest),
-                                                      m_parent->getComponentName(), strMsg.c_str());
+                    hr = m_pProgress->i_notifyComplete(VBOX_E_IPRT_ERROR,
+                                                       COM_IIDOF(IGuest),
+                                                       m_pParent->getComponentName(), strMsg.c_str());
                     reset();
                     break;
@@ -312,5 +312,5 @@
                 case DragAndDropSvc::DND_PROGRESS_CANCELLED:
                 {
-                    hr = m_progress->i_notifyComplete(S_OK);
+                    hr = m_pProgress->i_notifyComplete(S_OK);
                     AssertComRC(hr);
 
@@ -324,10 +324,10 @@
                     if (!fCanceled)
                     {
-                        hr = m_progress->SetCurrentOperationProgress(uPercentage);
+                        hr = m_pProgress->SetCurrentOperationProgress(uPercentage);
                         AssertComRC(hr);
                         if (   uStatus     == DragAndDropSvc::DND_PROGRESS_COMPLETE
                             || uPercentage >= 100)
                         {
-                            hr = m_progress->i_notifyComplete(S_OK);
+                            hr = m_pProgress->i_notifyComplete(S_OK);
                             AssertComRC(hr);
                         }
@@ -341,7 +341,7 @@
         }
 
-        hr = m_progress->COMGETTER(Completed)(&fCompleted);
+        hr = m_pProgress->COMGETTER(Completed)(&fCompleted);
         AssertComRC(hr);
-        hr = m_progress->COMGETTER(Canceled)(&fCanceled);
+        hr = m_pProgress->COMGETTER(Canceled)(&fCanceled);
         AssertComRC(hr);
 
@@ -382,5 +382,5 @@
 
             if (   pCBData->cbFormat == 0
-                || pCBData->cbFormat > _64K)
+                || pCBData->cbFormat > _64K) /** @todo Make this configurable? */
             {
                 rc = VERR_INVALID_PARAMETER;
@@ -470,5 +470,5 @@
 HRESULT GuestDnDResponse::queryProgressTo(IProgress **ppProgress)
 {
-    return m_progress.queryInterfaceTo(ppProgress);
+    return m_pProgress.queryInterfaceTo(ppProgress);
 }
 
@@ -738,10 +738,9 @@
 GuestDnDBase::GuestDnDBase(void)
 {
-    mDataBase.mfTransferIsPending = false;
-
-    /*
-     * Initialize public attributes.
-     */
+    /* Initialize public attributes. */
     m_lstFmtSupported = GuestDnDInst()->defaultFormats();
+
+    /* Initialzie private stuff. */
+    mDataBase.m_cTransfersPending = 0;
 }
 
@@ -796,39 +795,43 @@
 }
 
-int GuestDnDBase::getProtocolVersion(uint32_t *puVersion)
-{
-    AssertPtrReturn(puVersion, VERR_INVALID_POINTER);
+int GuestDnDBase::getProtocolVersion(uint32_t *puProto)
+{
+    AssertPtrReturn(puProto, VERR_INVALID_POINTER);
 
     int rc;
 
-    uint32_t uVer, uVerAdditions = 0;
+    uint32_t uProto        = 1; /* Use protocol v1 as a fallback. */
+    uint32_t uVerAdditions = 0;
     if (   m_pGuest
         && (uVerAdditions = m_pGuest->i_getAdditionsVersion()) > 0)
     {
-        uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions);
-        uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions);
-
-#if 0 /*def DEBUG_andy*/
+#if 1
         /* Hardcode the to-used protocol version; nice for testing side effects. */
-        uVer = 2;
+        uProto = 3;
 #else
-        uVer = (  uVBoxMajor  >= 5)
-             ? 2  /* VBox 5.0 and up: Protocol version 2. */
-             : 1; /* VBox <= 4.3:     Protocol version 1. */
-        /* Build revision is ignored. */
+        if (uVerAdditions >= VBOX_FULL_VERSION_MAKE(5, 0, 0))
+        {
+            if (uVerAdditions >= VBOX_FULL_VERSION_MAKE(5, 0, 8))
+            {
+                uProto = 3; /* Since VBox 5.0.8: Protocol v3. */
+            }
+            else
+                uProto = 2; /* VBox 5.0.0 - 5.0.6: Protocol v2. */
+        }
 #endif
-
-        LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32)\n", uVerAdditions, uVBoxMajor, uVBoxMinor));
+        LogRel3(("DnD: uVerAdditions=%RU32 (%RU32.%RU32.%RU32)\n",
+                 uVerAdditions, VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions),
+                                VBOX_FULL_VERSION_GET_BUILD(uVerAdditions)));
         rc = VINF_SUCCESS;
     }
     else
     {
-        uVer = 1; /* Fallback. */
+        uProto = 1; /* Fallback. */
         rc = VERR_NOT_FOUND;
     }
 
-    LogFlowThisFunc(("uVer=%RU32, uVerAdditions=%RU32, rc=%Rrc\n", uVer, uVerAdditions, rc));
-
-    *puVersion = uVer;
+    LogRel3(("DnD: uProto=%RU32, rc=%Rrc\n", uProto, rc));
+
+    *puProto = uProto;
     return rc;
 }
@@ -836,5 +839,5 @@
 int GuestDnDBase::msgQueueAdd(GuestDnDMsg *pMsg)
 {
-    mDataBase.mListOutgoing.push_back(pMsg);
+    mDataBase.m_lstMsgOut.push_back(pMsg);
     return VINF_SUCCESS;
 }
@@ -842,17 +845,17 @@
 GuestDnDMsg *GuestDnDBase::msgQueueGetNext(void)
 {
-    if (mDataBase.mListOutgoing.empty())
+    if (mDataBase.m_lstMsgOut.empty())
         return NULL;
-    return mDataBase.mListOutgoing.front();
+    return mDataBase.m_lstMsgOut.front();
 }
 
 void GuestDnDBase::msgQueueRemoveNext(void)
 {
-    if (!mDataBase.mListOutgoing.empty())
-    {
-        GuestDnDMsg *pMsg = mDataBase.mListOutgoing.front();
+    if (!mDataBase.m_lstMsgOut.empty())
+    {
+        GuestDnDMsg *pMsg = mDataBase.m_lstMsgOut.front();
         if (pMsg)
             delete pMsg;
-        mDataBase.mListOutgoing.pop_front();
+        mDataBase.m_lstMsgOut.pop_front();
     }
 }
@@ -860,11 +863,17 @@
 void GuestDnDBase::msgQueueClear(void)
 {
-    GuestDnDMsgList::iterator itMsg = mDataBase.mListOutgoing.begin();
-    while (itMsg != mDataBase.mListOutgoing.end())
-    {
-        delete *itMsg;
-    }
-
-    mDataBase.mListOutgoing.clear();
+    LogFlowFunc(("cMsg=%zu\n", mDataBase.m_lstMsgOut.size()));
+
+    GuestDnDMsgList::iterator itMsg = mDataBase.m_lstMsgOut.begin();
+    while (itMsg != mDataBase.m_lstMsgOut.end())
+    {
+        GuestDnDMsg *pMsg = *itMsg;
+        if (pMsg)
+            delete pMsg;
+
+        itMsg++;
+    }
+
+    mDataBase.m_lstMsgOut.clear();
 }
 
@@ -888,7 +897,34 @@
 }
 
+int GuestDnDBase::updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp,
+                                 uint32_t cbDataAdd /* = 0 */)
+{
+    AssertPtrReturn(pData, VERR_INVALID_POINTER);
+    AssertPtrReturn(pResp, VERR_INVALID_POINTER);
+    /* cbDataAdd is optional. */
+
+    LogFlowFunc(("cbTotal=%RU64, cbProcessed=%RU64, cbRemaining=%RU64, cbDataAdd=%RU32\n",
+                 pData->getProcessed(), pData->getProcessed(), pData->getRemaining(), cbDataAdd));
+
+    if (!pResp)
+        return VINF_SUCCESS;
+
+    if (cbDataAdd)
+        pData->addProcessed(cbDataAdd);
+
+    int rc = pResp->setProgress(pData->getPercentComplete(),
+                                  pData->isComplete()
+                                ? DND_PROGRESS_COMPLETE
+                                : DND_PROGRESS_RUNNING);
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
 /** @todo GuestDnDResponse *pResp needs to go. */
-int GuestDnDBase::waitForEvent(RTMSINTERVAL msTimeout, GuestDnDCallbackEvent &Event, GuestDnDResponse *pResp)
-{
+int GuestDnDBase::waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout)
+{
+    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+    AssertPtrReturn(pResp, VERR_INVALID_POINTER);
+
     int rc;
 
@@ -901,8 +937,8 @@
          * respond, do busy waiting here.
          */
-        rc = Event.Wait(500 /* ms */);
+        rc = pEvent->Wait(500 /* ms */);
         if (RT_SUCCESS(rc))
         {
-            rc = Event.Result();
+            rc = pEvent->Result();
             LogFlowFunc(("Callback done, result is %Rrc\n", rc));
             break;
Index: /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 58211)
+++ /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 58212)
@@ -37,6 +37,4 @@
 
 #include <VBox/com/array.h>
-#include <VBox/GuestHost/DragAndDrop.h>
-#include <VBox/HostServices/DragAndDropSvc.h>
 
 #ifdef LOG_GROUP
@@ -246,5 +244,5 @@
 
     /* Determine guest DnD protocol to use. */
-    GuestDnDBase::getProtocolVersion(&mDataBase.mProtocolVersion);
+    GuestDnDBase::getProtocolVersion(&mDataBase.m_uProtocolVersion);
 
     /* Default is ignoring the action. */
@@ -254,5 +252,5 @@
 
     GuestDnDMsg Msg;
-    Msg.setType(DragAndDropSvc::HOST_DND_GH_REQ_PENDING);
+    Msg.setType(HOST_DND_GH_REQ_PENDING);
     Msg.setNextUInt32(uScreenId);
 
@@ -333,10 +331,9 @@
         return S_OK;
 
-    /* Note: At the moment we only support one transfer at a time. */
-    if (ASMAtomicReadBool(&mDataBase.mfTransferIsPending))
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /* At the moment we only support one transfer at a time. */
+    if (mDataBase.m_cTransfersPending)
         return setError(E_INVALIDARG, tr("Another drop operation already is in progress"));
-
-    /* Gets reset when the thread is finished. */
-    ASMAtomicWriteBool(&mDataBase.mfTransferIsPending, true);
 
     /* Dito. */
@@ -363,15 +360,27 @@
         LogFlowFunc(("Starting thread ...\n"));
 
-        int rc = RTThreadCreate(NULL, GuestDnDSource::i_receiveDataThread,
+        RTTHREAD threadRcv;
+        int rc = RTThreadCreate(&threadRcv, GuestDnDSource::i_receiveDataThread,
                                 (void *)pTask, 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndSrcRcvData");
         if (RT_SUCCESS(rc))
         {
-            hr = pResp->queryProgressTo(aProgress.asOutParam());
-            ComAssertComRC(hr);
-
-            /* Note: pTask is now owned by the worker thread. */
+            rc = RTThreadUserWait(threadRcv, 30 * 1000 /* 30s timeout */);
+            if (RT_SUCCESS(rc))
+            {
+                mDataBase.m_cTransfersPending++;
+
+                hr = pResp->queryProgressTo(aProgress.asOutParam());
+                ComAssertComRC(hr);
+
+                /* Note: pTask is now owned by the worker thread. */
+            }
+            else
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Waiting for receiving thread failed (%Rrc)"), rc);
         }
         else
             hr = setError(VBOX_E_IPRT_ERROR, tr("Starting thread failed (%Rrc)"), rc);
+
+        if (FAILED(hr))
+            delete pTask;
     }
     catch(std::bad_alloc &)
@@ -379,6 +388,4 @@
         hr = setError(E_OUTOFMEMORY);
     }
-
-    /* Note: mDataBase.mfTransferIsPending will be set to false again by i_receiveDataThread. */
 
     LogFlowFunc(("Returning hr=%Rhrc\n", hr));
@@ -393,18 +400,18 @@
 #else /* VBOX_WITH_DRAG_AND_DROP */
 
-    /* Input validation. */
-
     AutoCaller autoCaller(this);
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    /* Don't allow receiving the actual data until our transfer
-     * actually is complete. */
-    if (ASMAtomicReadBool(&mDataBase.mfTransferIsPending))
-        return setError(E_INVALIDARG, tr("Current drop operation still in progress"));
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /* Don't allow receiving the actual data until our transfer actually is complete. */
+    if (mDataBase.m_cTransfersPending)
+        return setError(E_FAIL, tr("Current drop operation still in progress"));
 
     PRECVDATACTX pCtx = &mData.mRecvCtx;
 
-    if (pCtx->mData.vecData.empty())
-    {
+    if (pCtx->mData.getMeta().getSize() == 0)
+    {
+        LogFlowFunc(("No data available, returning 0\n"));
         aData.resize(0);
         return S_OK;
@@ -419,20 +426,16 @@
         if (fHasURIList)
         {
-            const char *pszDroppedFilesDir = pCtx->mURI.droppedFiles.GetDirAbs();
-            Utf8Str strURIs = pCtx->mURI.lstURI.RootToString(RTCString(pszDroppedFilesDir));
-            cbData = strURIs.length();
-
-            LogFlowFunc(("Found %zu root URIs (%zu bytes)\n", pCtx->mURI.lstURI.RootCount(), cbData));
-
-            aData.resize(cbData + 1 /* Include termination */);
-            memcpy(&aData.front(), strURIs.c_str(), cbData);
+            LogRel2(("DnD: Drop directory is: %s\n", pCtx->mURI.getDroppedFiles().GetDirAbs()));
+            int rc2 = pCtx->mURI.toMetaData(aData);
+            if (RT_FAILURE(rc2))
+                hr = E_OUTOFMEMORY;
         }
         else
         {
-            cbData = pCtx->mData.vecData.size();
+            cbData = pCtx->mData.getMeta().getSize();
 
             /* Copy the data into a safe array of bytes. */
             aData.resize(cbData);
-            memcpy(&aData.front(), &pCtx->mData.vecData[0], cbData);
+            memcpy(&aData.front(), pCtx->mData.getMeta().getData(), cbData);
         }
     }
@@ -523,12 +526,25 @@
 
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-int GuestDnDSource::i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize)
+int GuestDnDSource::i_onReceiveDataHdr(PRECVDATACTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr)
+{
+    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
+    AssertReturn(pDataHdr, VERR_INVALID_POINTER);
+
+    pCtx->mData.setEstimatedSize(pDataHdr->cbTotal, pDataHdr->cbMeta);
+
+    Assert(pCtx->mURI.getObjToProcess() == 0);
+    pCtx->mURI.reset(pDataHdr->cObjects);
+
+    /** @todo Handle compression type. */
+    /** @todo Handle checksum type. */
+
+    LogFlowFuncLeave();
+    return VINF_SUCCESS;
+}
+
+int GuestDnDSource::i_onReceiveData(PRECVDATACTX pCtx, PVBOXDNDSNDDATA pSndData)
 {
     AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
-    AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
-    AssertReturn(cbData,      VERR_INVALID_PARAMETER);
-    AssertReturn(cbTotalSize, VERR_INVALID_PARAMETER);
-
-    LogFlowFunc(("cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize));
+    AssertPtrReturn(pSndData, VERR_INVALID_POINTER);
 
     int rc = VINF_SUCCESS;
@@ -536,13 +552,44 @@
     try
     {
-        if (   cbData > cbTotalSize
-            || cbData > mData.mcbBlockSize)
-        {
-            LogFlowFunc(("Data sizes invalid: cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize));
+        GuestDnDData     *pData = &pCtx->mData;
+        GuestDnDURIData  *pURI  = &pCtx->mURI;
+
+        uint32_t cbData;
+        void    *pvData;
+        uint64_t cbToProcess;
+        uint32_t cbMeta;
+
+        if (mDataBase.m_uProtocolVersion < 3)
+        {
+            cbData = pSndData->u.v1.cbData;
+            pvData = pSndData->u.v1.pvData;
+
+            /* Sends the total data size to receive for every data chunk. */
+            cbToProcess = pSndData->u.v1.cbTotalSize;
+
+            /* Meta data size always is cbData, meaning there cannot be an
+             * extended data chunk transfer by sending further data. */
+            cbMeta      = cbData;
+        }
+        else
+        {
+            cbData = pSndData->u.v3.cbData;
+            pvData = pSndData->u.v3.pvData;
+
+            /* Note: Data sizes get updated in i_onReceiveDataHdr(). */
+            cbToProcess = pData->getTotal();
+            cbMeta      = pData->getMeta().getSize();
+        }
+        Assert(cbToProcess);
+
+        if (   cbData == 0
+            || cbData >  cbToProcess /* Paranoia */)
+        {
+            LogFlowFunc(("Incoming data size invalid: cbData=%RU32, cbToProcess=%RU64\n", cbData, pData->getTotal()));
             rc = VERR_INVALID_PARAMETER;
         }
-        else if (cbData < pCtx->mData.vecData.size())
-        {
-            AssertMsgFailed(("New size (%RU64) is smaller than current size (%zu)\n", cbTotalSize, pCtx->mData.vecData.size()));
+        else if (cbToProcess < cbMeta)
+        {
+            AssertMsgFailed(("cbToProcess (%RU64) is smaller than meta size (%zu)\n", cbToProcess, cbMeta));
             rc = VERR_INVALID_PARAMETER;
         }
@@ -550,36 +597,32 @@
         if (RT_SUCCESS(rc))
         {
-            pCtx->mData.vecData.insert(pCtx->mData.vecData.begin(), (BYTE *)pvData, (BYTE *)pvData + cbData);
-
-            LogFlowFunc(("vecDataSize=%zu, cbData=%RU32, cbTotalSize=%RU64\n", pCtx->mData.vecData.size(), cbData, cbTotalSize));
-
-            /* Data transfer complete? */
-            Assert(cbData <= pCtx->mData.vecData.size());
-            if (cbData == pCtx->mData.vecData.size())
+            pData->getMeta().add(pvData, cbData);
+            LogFlowThisFunc(("cbMetaSize=%zu, cbData=%RU32, cbMeta=%RU32, cbToProcess=%RU64\n",
+                             pData->getMeta().getSize(), cbData, cbMeta, cbToProcess));
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            /* (Meta) Data transfer complete? */
+            Assert(cbMeta <= pData->getMeta().getSize());
+            if (cbMeta == pData->getMeta().getSize())
             {
                 bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length());
-                LogFlowFunc(("fHasURIList=%RTbool, cbTotalSize=%RU32\n", fHasURIList, cbTotalSize));
+                LogFlowThisFunc(("fHasURIList=%RTbool\n", fHasURIList));
                 if (fHasURIList)
                 {
                     /* Try parsing the data as URI list. */
-                    rc = pCtx->mURI.lstURI.RootFromURIData(&pCtx->mData.vecData[0], pCtx->mData.vecData.size(), 0 /* uFlags */);
+                    rc = pURI->fromMetaData(pData->getMeta());
                     if (RT_SUCCESS(rc))
                     {
-                        /* Reset processed bytes. */
-                        pCtx->mData.cbProcessed = 0;
+                        if (mDataBase.m_uProtocolVersion < 3)
+                            pData->setEstimatedSize(cbToProcess, cbMeta);
 
                         /*
-                         * Assign new total size which also includes all file data to receive
-                         * from the guest.
+                         * Update our process with the data we already received.
+                         * Note: The total size will consist of the meta data (in pVecData) and
+                         *       the actual accumulated file/directory data from the guest.
                          */
-                        pCtx->mData.cbToProcess = cbTotalSize;
-
-                        /* Update our process with the data we already received.
-                         * Note: The total size will consist of the meta data (in vecData) and
-                         *       the actual accumulated file/directory data from the guest. */
-                        rc = i_updateProcess(pCtx, (uint64_t)pCtx->mData.vecData.size());
-
-                        LogFlowFunc(("URI data => cbProcessed=%RU64, cbToProcess=%RU64, rc=%Rrc\n",
-                                     pCtx->mData.cbProcessed, pCtx->mData.cbToProcess, rc));
+                        rc = updateProgress(pData, pCtx->mpResp, (uint32_t)pData->getMeta().getSize());
                     }
                 }
@@ -604,13 +647,42 @@
     LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", pszPath, cbPath, fMode));
 
+    /*
+     * Sanity checking.
+     */
+    if (   !cbPath
+        || cbPath > RTPATH_MAX)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (!RTStrIsValidEncoding(pszPath))
+        return VERR_INVALID_PARAMETER;
+
+    if (pCtx->mURI.isComplete())
+        return VERR_INVALID_PARAMETER;
+
+    GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
+    DnDURIObject *pObj       = objCtx.createIntermediate();
+    if (!pObj)
+        return VERR_NO_MEMORY;
+
     int rc;
 
-    const char *pszDroppedFilesDir = pCtx->mURI.droppedFiles.GetDirAbs();
+    const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
     char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath);
     if (pszDir)
     {
+#ifdef RT_OS_WINDOWS
+        RTPathChangeToDosSlashes(pszDir, true /* fForce */);
+#else
+        RTPathChangeToDosSlashes(pszDir, true /* fForce */);
+#endif
         rc = RTDirCreateFullPath(pszDir, fMode);
-        if (RT_FAILURE(rc))
-            LogRel2(("DnD: Error creating guest directory '%s' on the host, rc=%Rrc\n", pszDir, rc));
+        if (RT_SUCCESS(rc))
+            LogRel2(("DnD: Created guest directory on host: %s\n", pszDir));
+        else
+            LogRel(("DnD: Error creating guest directory '%s' on host, rc=%Rrc\n", pszDir, rc));
+
+        pCtx->mURI.removeObjCurrent();
 
         RTStrFree(pszDir);
@@ -623,9 +695,8 @@
 }
 
-int GuestDnDSource::i_onReceiveFileHdr(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const char *pszPath, uint32_t cbPath,
+int GuestDnDSource::i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath,
                                        uint64_t cbSize, uint32_t fMode, uint32_t fFlags)
 {
     AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     AssertReturn(cbPath,     VERR_INVALID_PARAMETER);
@@ -635,74 +706,81 @@
     LogFlowFunc(("pszPath=%s, cbPath=%RU32, cbSize=%RU64, fMode=0x%x, fFlags=0x%x\n", pszPath, cbPath, cbSize, fMode, fFlags));
 
+    /*
+     * Sanity checking.
+     */
+    if (   !cbPath
+        || cbPath > RTPATH_MAX)
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (!RTStrIsValidEncoding(pszPath))
+        return VERR_INVALID_PARAMETER;
+
+    if (cbSize > pCtx->mData.getTotal())
+    {
+        AssertMsgFailed(("File size (%RU64) exceeds total size to transfer (%RU64)\n", cbSize, pCtx->mData.getTotal()));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (pCtx->mURI.isComplete())
+        return VERR_INVALID_PARAMETER;
+
     int rc = VINF_SUCCESS;
 
     do
     {
-        DnDURIObject *pObj = pObjCtx->pObjURI;
-
-        if (    pObj
-            &&  pObj->IsOpen()
-            && !pObj->IsComplete())
-        {
-            AssertMsgFailed(("Object '%s' not complete yet\n", pObj->GetDestPath().c_str()));
-            rc = VERR_WRONG_ORDER;
-            break;
-        }
-
-        if (   pObj
-            && pObj->IsOpen()) /* File already opened? */
-        {
-            AssertMsgFailed(("Current opened object is '%s', close this first\n", pObj->GetDestPath().c_str()));
-            rc = VERR_WRONG_ORDER;
-            break;
-        }
-
-        if (cbSize > pCtx->mData.cbToProcess)
-        {
-            AssertMsgFailed(("File size (%RU64) exceeds total size to transfer (%RU64)\n", cbSize, pCtx->mData.cbToProcess));
-            rc = VERR_INVALID_PARAMETER;
-            break;
-        }
-
-        const char *pszDroppedFilesDir = pCtx->mURI.droppedFiles.GetDirAbs();
-
-        char pszPathAbs[RTPATH_MAX];
-        rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszDroppedFilesDir, pszPath);
-        if (RT_FAILURE(rc))
-        {
-            LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
-            break;
-        }
-
-        rc = DnDPathSanitize(pszPathAbs, sizeof(pszPathAbs));
-        if (RT_FAILURE(rc))
-        {
-            LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
-            break;
-        }
-
-        LogFunc(("Rebased to: %s\n", pszPathAbs));
-
-        if (   pObj
-            && pObjCtx->fAllocated)
-        {
-            delete pObj;
-            pObj = NULL;
-        }
-
-        try
-        {
-            pObj = new DnDURIObject();
-
-            pObjCtx->pObjURI    = pObj;
-            pObjCtx->fAllocated = true;
-        }
-        catch (std::bad_alloc &)
-        {
+        GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
+        DnDURIObject *pObj       = objCtx.pObjURI;
+
+        /*
+         * Sanity checking.
+         */
+        if (pObj)
+        {
+            if (    pObj->IsOpen()
+                && !pObj->IsComplete())
+            {
+                AssertMsgFailed(("Object '%s' not complete yet\n", pObj->GetDestPath().c_str()));
+                rc = VERR_WRONG_ORDER;
+                break;
+            }
+
+            if (pObj->IsOpen()) /* File already opened? */
+            {
+                AssertMsgFailed(("Current opened object is '%s', close this first\n", pObj->GetDestPath().c_str()));
+                rc = VERR_WRONG_ORDER;
+                break;
+            }
+        }
+
+        /*
+         * Create new intermediate object to work with.
+         */
+        pObj = objCtx.createIntermediate();
+        if (!pObj)
             rc = VERR_NO_MEMORY;
-        }
 
         if (RT_SUCCESS(rc))
         {
+            const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
+
+            char pszPathAbs[RTPATH_MAX];
+            rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszDroppedFilesDir, pszPath);
+            if (RT_FAILURE(rc))
+            {
+                LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
+                break;
+            }
+
+            rc = DnDPathSanitize(pszPathAbs, sizeof(pszPathAbs));
+            if (RT_FAILURE(rc))
+            {
+                LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
+                break;
+            }
+
+            LogFunc(("Rebased to: %s\n", pszPathAbs));
+
             /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
             rc = pObj->OpenEx(pszPathAbs, DnDURIObject::File, DnDURIObject::Target,
@@ -714,5 +792,5 @@
         {
             /* Note: Protocol v1 does not send any file sizes, so always 0. */
-            if (mDataBase.mProtocolVersion >= 2)
+            if (mDataBase.m_uProtocolVersion >= 2)
                 rc = pObj->SetSize(cbSize);
 
@@ -740,8 +818,7 @@
 }
 
-int GuestDnDSource::i_onReceiveFileData(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const void *pvData, uint32_t cbData)
+int GuestDnDSource::i_onReceiveFileData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData)
 {
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
-    AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
     AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     AssertReturn(cbData, VERR_INVALID_PARAMETER);
@@ -749,7 +826,15 @@
     int rc = VINF_SUCCESS;
 
+    /*
+     * Sanity checking.
+     */
+    if (cbData > mData.mcbBlockSize)
+        return VERR_INVALID_PARAMETER;
+
     do
     {
-        DnDURIObject *pObj = pObjCtx->pObjURI;
+        GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
+        DnDURIObject *pObj       = objCtx.pObjURI;
+
         if (!pObj)
         {
@@ -784,5 +869,5 @@
 
             if (RT_SUCCESS(rc))
-                rc = i_updateProcess(pCtx, cbWritten);
+                rc = updateProgress(&pCtx->mData, pCtx->mpResp, cbWritten);
         }
 
@@ -793,14 +878,7 @@
                 /** @todo Sanitize path. */
                 LogRel2(("DnD: File transfer to host complete: %s\n", pObj->GetDestPath().c_str()));
+                objCtx.reset();
+
                 rc = VINF_EOF;
-
-                /* Deletion needed? */
-                if (pObjCtx->fAllocated)
-                {
-                    delete pObj;
-                    pObj = NULL;
-
-                    pObjCtx->fAllocated = false;
-                }
             }
         }
@@ -821,4 +899,9 @@
 {
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+    /* Is this context already in receiving state? */
+    if (ASMAtomicReadBool(&pCtx->mIsActive))
+        return VERR_WRONG_ORDER;
+    ASMAtomicWriteBool(&pCtx->mIsActive, true);
 
     GuestDnD *pInst = GuestDnDInst();
@@ -829,11 +912,5 @@
     AssertPtr(pCtx->mpResp);
 
-    /* Is this context already in receiving state? */
-    if (ASMAtomicReadBool(&pCtx->mIsActive))
-        return VERR_WRONG_ORDER;
-
-    ASMAtomicWriteBool(&pCtx->mIsActive, true);
-
-    int rc = pCtx->mCallback.Reset();
+    int rc = pCtx->mCBEvent.Reset();
     if (RT_FAILURE(rc))
         return rc;
@@ -842,6 +919,6 @@
      * Reset any old data.
      */
-    pCtx->mData.Reset();
-    pCtx->mURI.Reset();
+    pCtx->mData.reset();
+    pCtx->mURI.reset();
     pResp->reset();
 
@@ -901,23 +978,24 @@
     AssertPtrReturn(pTask, VERR_INVALID_POINTER);
 
-    const ComObjPtr<GuestDnDSource> pSource(pTask->getSource());
-    Assert(!pSource.isNull());
-
-    int rc;
-
-    AutoCaller autoCaller(pSource);
-    if (SUCCEEDED(autoCaller.rc()))
-    {
-        rc = pSource->i_receiveData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
-    }
-    else
-        rc = VERR_COM_INVALID_OBJECT_STATE;
-
-    ASMAtomicWriteBool(&pSource->mDataBase.mfTransferIsPending, false);
+    const ComObjPtr<GuestDnDSource> pThis(pTask->getSource());
+    Assert(!pThis.isNull());
+
+    AutoCaller autoCaller(pThis);
+    if (FAILED(autoCaller.rc())) return VERR_COM_INVALID_OBJECT_STATE;
+
+    int rc = RTThreadUserSignal(Thread);
+    AssertRC(rc);
+
+    rc = pThis->i_receiveData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
 
     if (pTask)
         delete pTask;
 
-    LogFlowFunc(("pSource=%p returning rc=%Rrc\n", (GuestDnDSource *)pSource, rc));
+    AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
+
+    Assert(pThis->mDataBase.m_cTransfersPending);
+    pThis->mDataBase.m_cTransfersPending--;
+
+    LogFlowFunc(("pSource=%p returning rc=%Rrc\n", (GuestDnDSource *)pThis, rc));
     return rc;
 }
@@ -948,6 +1026,6 @@
      * Register callbacks.
      */
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
+    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
+    REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
 
     do
@@ -957,5 +1035,5 @@
          */
         GuestDnDMsg Msg;
-        Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED);
+        Msg.setType(HOST_DND_GH_EVT_DROPPED);
         Msg.setNextPointer((void*)pCtx->mFmtRecv.c_str(), (uint32_t)pCtx->mFmtRecv.length() + 1);
         Msg.setNextUInt32((uint32_t)pCtx->mFmtRecv.length() + 1);
@@ -967,7 +1045,7 @@
         if (RT_SUCCESS(rc))
         {
-            rc = waitForEvent(msTimeout, pCtx->mCallback, pCtx->mpResp);
+            rc = waitForEvent(&pCtx->mCBEvent, pCtx->mpResp, msTimeout);
             if (RT_SUCCESS(rc))
-                rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, VINF_SUCCESS);
+                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
         }
 
@@ -977,6 +1055,6 @@
      * Unregister callbacks.
      */
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
 
 #undef REGISTER_CALLBACK
@@ -987,5 +1065,5 @@
         if (rc == VERR_CANCELLED)
         {
-            int rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED, VINF_SUCCESS);
+            int rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
             AssertRC(rc2);
 
@@ -995,5 +1073,5 @@
         else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
         {
-            rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR,
+            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR,
                                            rc, GuestDnDSource::i_hostErrorToString(rc));
         }
@@ -1032,12 +1110,14 @@
      */
     /* Guest callbacks. */
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR);
-    if (mDataBase.mProtocolVersion >= 2)
-        REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR);
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA);
-
-    DnDDroppedFiles &droppedFiles = pCtx->mURI.droppedFiles;
+    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
+    if (mDataBase.m_uProtocolVersion >= 3)
+        REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
+    REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
+    REGISTER_CALLBACK(GUEST_DND_GH_SND_DIR);
+    if (mDataBase.m_uProtocolVersion >= 2)
+        REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_HDR);
+    REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_DATA);
+
+    DnDDroppedFiles &droppedFiles = pCtx->mURI.getDroppedFiles();
 
     do
@@ -1054,5 +1134,5 @@
          */
         GuestDnDMsg Msg;
-        Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED);
+        Msg.setType(HOST_DND_GH_EVT_DROPPED);
         Msg.setNextPointer((void*)pCtx->mFmtRecv.c_str(), (uint32_t)pCtx->mFmtRecv.length() + 1);
         Msg.setNextUInt32((uint32_t)pCtx->mFmtRecv.length() + 1);
@@ -1066,7 +1146,7 @@
             LogFlowFunc(("Waiting ...\n"));
 
-            rc = waitForEvent(msTimeout, pCtx->mCallback, pCtx->mpResp);
+            rc = waitForEvent(&pCtx->mCBEvent, pCtx->mpResp, msTimeout);
             if (RT_SUCCESS(rc))
-                rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, VINF_SUCCESS);
+                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
 
             LogFlowFunc(("Waiting ended with rc=%Rrc\n", rc));
@@ -1078,10 +1158,10 @@
      * Unregister callbacks.
      */
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR);
-    if (mDataBase.mProtocolVersion >= 2)
-        UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR);
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DIR);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_HDR);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_DATA);
 
 #undef REGISTER_CALLBACK
@@ -1094,5 +1174,5 @@
         if (rc == VERR_CANCELLED)
         {
-            rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED, VINF_SUCCESS);
+            rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
             AssertRC(rc2);
 
@@ -1102,5 +1182,5 @@
         else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
         {
-            rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR,
+            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR,
                                            rc, GuestDnDSource::i_hostErrorToString(rc));
         }
@@ -1109,11 +1189,10 @@
     if (RT_FAILURE(rc))
     {
-        rc2 = droppedFiles.Rollback(); /** @todo Inform user on rollback failure? */
-        LogFlowFunc(("Rolling back ended with rc=%Rrc\n", rc2));
-    }
-
-    rc2 = droppedFiles.Reset(RT_FAILURE(rc) ? true : false /* fRemoveDropDir */);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
+        rc2 = droppedFiles.Rollback();
+        if (RT_FAILURE(rc2))
+            LogRel2(("DnD: Rollback failed with %Rrc\n", rc2));
+    }
+
+    droppedFiles.Close();
 
     LogFlowFuncLeaveRC(rc);
@@ -1140,20 +1219,30 @@
     {
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
-        {
-            DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
+        case GUEST_DND_GH_SND_DATA_HDR:
+        {
+            PVBOXDNDCBSNDDATAHDRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATAHDRDATA>(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);
-
-            rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize);
-            break;
-        }
-        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
-        {
-            DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
+            AssertReturn(sizeof(VBOXDNDCBSNDDATAHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_SND_DATA_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+            rc = pThis->i_onReceiveDataHdr(pCtx, &pCBData->data);
+            break;
+        }
+        case GUEST_DND_GH_SND_DATA:
+        {
+            PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATADATA>(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);
+            AssertReturn(sizeof(VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+            rc = pThis->i_onReceiveData(pCtx, &pCBData->data);
+            break;
+        }
+        case GUEST_DND_GH_EVT_ERROR:
+        {
+            PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<PVBOXDNDCBEVTERRORDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
             pCtx->mpResp->reset();
@@ -1162,5 +1251,5 @@
                 pCBData->rc = VERR_GENERAL_FAILURE; /* Make sure some error is set. */
 
-            rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc,
+            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
                                            GuestDnDSource::i_guestErrorToString(pCBData->rc));
             if (RT_SUCCESS(rc))
@@ -1176,5 +1265,5 @@
     if (RT_FAILURE(rc))
     {
-        int rc2 = pCtx->mCallback.Notify(rc);
+        int rc2 = pCtx->mCBEvent.Notify(rc);
         AssertRC(rc2);
     }
@@ -1203,43 +1292,53 @@
     {
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
-        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
-        {
-            DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
+        case GUEST_DND_GH_SND_DATA_HDR:
+        {
+            PVBOXDNDCBSNDDATAHDRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATAHDRDATA>(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);
-
-            rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize);
-            break;
-        }
-        case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
-        {
-            DragAndDropSvc::PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDIRDATA>(pvParms);
+            AssertReturn(sizeof(VBOXDNDCBSNDDATAHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_SND_DATA_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+            rc = pThis->i_onReceiveDataHdr(pCtx, &pCBData->data);
+            break;
+        }
+        case GUEST_DND_GH_SND_DATA:
+        {
+            PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATADATA>(pvParms);
             AssertPtr(pCBData);
-            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);
-            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            AssertReturn(sizeof(VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+            rc = pThis->i_onReceiveData(pCtx, &pCBData->data);
+            break;
+        }
+        case GUEST_DND_GH_SND_DIR:
+        {
+            PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDIRDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
             rc = pThis->i_onReceiveDir(pCtx, pCBData->pszPath, pCBData->cbPath, pCBData->fMode);
             break;
         }
-        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
-        {
-            DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA>(pvParms);
+        case GUEST_DND_GH_SND_FILE_HDR:
+        {
+            PVBOXDNDCBSNDFILEHDRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDFILEHDRDATA>(pvParms);
             AssertPtr(pCBData);
-            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
-            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
-
-            rc = pThis->i_onReceiveFileHdr(pCtx, &pCtx->mURI.objCtx, pCBData->pszFilePath, pCBData->cbFilePath,
+            AssertReturn(sizeof(VBOXDNDCBSNDFILEHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_SND_FILE_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+            rc = pThis->i_onReceiveFileHdr(pCtx, pCBData->pszFilePath, pCBData->cbFilePath,
                                            pCBData->cbSize, pCBData->fMode, pCBData->fFlags);
             break;
         }
-        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
-        {
-            DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA>(pvParms);
+        case GUEST_DND_GH_SND_FILE_DATA:
+        {
+            PVBOXDNDCBSNDFILEDATADATA pCBData = reinterpret_cast<PVBOXDNDCBSNDFILEDATADATA>(pvParms);
             AssertPtr(pCBData);
-            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA) == cbParms, VERR_INVALID_PARAMETER);
-            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
-
-            if (pThis->mDataBase.mProtocolVersion <= 1)
+            AssertReturn(sizeof(VBOXDNDCBSNDFILEDATADATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_SND_FILE_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+
+            if (pThis->mDataBase.m_uProtocolVersion <= 1)
             {
                 /**
@@ -1250,20 +1349,19 @@
                  *   appended data to the desired file. So just pass 0 as cbSize.
                  */
-                rc = pThis->i_onReceiveFileHdr(pCtx, &pCtx->mURI.objCtx,
-                                               pCBData->u.v1.pszFilePath, pCBData->u.v1.cbFilePath,
+                rc = pThis->i_onReceiveFileHdr(pCtx, pCBData->u.v1.pszFilePath, pCBData->u.v1.cbFilePath,
                                                0 /* cbSize */, pCBData->u.v1.fMode, 0 /* fFlags */);
                 if (RT_SUCCESS(rc))
-                    rc = pThis->i_onReceiveFileData(pCtx, &pCtx->mURI.objCtx, pCBData->pvData, pCBData->cbData);
+                    rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData);
             }
             else /* Protocol v2 and up. */
-                rc = pThis->i_onReceiveFileData(pCtx, &pCtx->mURI.objCtx, pCBData->pvData, pCBData->cbData);
-            break;
-        }
-        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
-        {
-            DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
+                rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData);
+            break;
+        }
+        case GUEST_DND_GH_EVT_ERROR:
+        {
+            PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<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);
+            AssertReturn(sizeof(VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
             pCtx->mpResp->reset();
@@ -1272,5 +1370,5 @@
                 pCBData->rc = VERR_GENERAL_FAILURE; /* Make sure some error is set. */
 
-            rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc,
+            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
                                            GuestDnDSource::i_guestErrorToString(pCBData->rc));
             if (RT_SUCCESS(rc))
@@ -1315,17 +1413,17 @@
     }
 
-    /* All URI data processed? */
-    if (pCtx->mData.cbProcessed >= pCtx->mData.cbToProcess)
-    {
-        Assert(pCtx->mData.cbProcessed == pCtx->mData.cbToProcess);
+    /* All data processed? */
+    if (   pCtx->mURI.isComplete()
+        && pCtx->mData.isComplete())
+    {
         fNotify = true;
     }
 
     LogFlowFunc(("cbProcessed=%RU64, cbToProcess=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",
-                 pCtx->mData.cbProcessed, pCtx->mData.cbToProcess, fNotify, rcCallback, rc));
+                 pCtx->mData.getProcessed(), pCtx->mData.getTotal(), fNotify, rcCallback, rc));
 
     if (fNotify)
     {
-        int rc2 = pCtx->mCallback.Notify(rcCallback);
+        int rc2 = pCtx->mCBEvent.Notify(rcCallback);
         AssertRC(rc2);
     }
@@ -1335,21 +1433,2 @@
 }
 
-int GuestDnDSource::i_updateProcess(PRECVDATACTX pCtx, uint64_t cbDataAdd)
-{
-    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
-
-    LogFlowFunc(("cbProcessed=%RU64 (+ %RU64 = %RU64), cbToProcess=%RU64\n",
-                 pCtx->mData.cbProcessed, cbDataAdd, pCtx->mData.cbProcessed + cbDataAdd, pCtx->mData.cbToProcess));
-
-    pCtx->mData.cbProcessed += cbDataAdd;
-    Assert(pCtx->mData.cbProcessed <= pCtx->mData.cbToProcess);
-
-    int64_t cbTotal  = pCtx->mData.cbToProcess;
-    uint8_t uPercent = pCtx->mData.cbProcessed * 100 / (cbTotal ? cbTotal : 1);
-
-    int rc = pCtx->mpResp->setProgress(uPercent,
-                                         uPercent >= 100
-                                       ? DragAndDropSvc::DND_PROGRESS_COMPLETE
-                                       : DragAndDropSvc::DND_PROGRESS_RUNNING);
-    return rc;
-}
Index: /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp	(revision 58211)
+++ /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp	(revision 58212)
@@ -262,5 +262,5 @@
 
     /* Determine guest DnD protocol to use. */
-    GuestDnDBase::getProtocolVersion(&mDataBase.mProtocolVersion);
+    GuestDnDBase::getProtocolVersion(&mDataBase.m_uProtocolVersion);
 
     /* Default action is ignoring. */
@@ -302,5 +302,5 @@
     {
         GuestDnDMsg Msg;
-        Msg.setType(DragAndDropSvc::HOST_DND_HG_EVT_ENTER);
+        Msg.setType(HOST_DND_HG_EVT_ENTER);
         Msg.setNextUInt32(aScreenId);
         Msg.setNextUInt32(aX);
@@ -376,5 +376,5 @@
     {
         GuestDnDMsg Msg;
-        Msg.setType(DragAndDropSvc::HOST_DND_HG_EVT_MOVE);
+        Msg.setType(HOST_DND_HG_EVT_MOVE);
         Msg.setNextUInt32(aScreenId);
         Msg.setNextUInt32(aX);
@@ -418,5 +418,5 @@
 
     HRESULT hr = S_OK;
-    int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_LEAVE,
+    int rc = GuestDnDInst()->hostCall(HOST_DND_HG_EVT_LEAVE,
                                       0 /* cParms */, NULL /* paParms */);
     if (RT_SUCCESS(rc))
@@ -488,5 +488,5 @@
     {
         GuestDnDMsg Msg;
-        Msg.setType(DragAndDropSvc::HOST_DND_HG_EVT_DROPPED);
+        Msg.setType(HOST_DND_HG_EVT_DROPPED);
         Msg.setNextUInt32(aScreenId);
         Msg.setNextUInt32(aX);
@@ -545,24 +545,24 @@
     AssertPtrReturn(pTask, VERR_INVALID_POINTER);
 
-    const ComObjPtr<GuestDnDTarget> pTarget(pTask->getTarget());
-    Assert(!pTarget.isNull());
-
-    int rc;
-
-    AutoCaller autoCaller(pTarget);
-    if (SUCCEEDED(autoCaller.rc()))
-    {
-        rc = pTarget->i_sendData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
-        /* Nothing to do here anymore. */
-    }
-    else
-        rc = VERR_COM_INVALID_OBJECT_STATE;
-
-    ASMAtomicWriteBool(&pTarget->mDataBase.mfTransferIsPending, false);
+    const ComObjPtr<GuestDnDTarget> pThis(pTask->getTarget());
+    Assert(!pThis.isNull());
+
+    AutoCaller autoCaller(pThis);
+    if (FAILED(autoCaller.rc())) return VERR_COM_INVALID_OBJECT_STATE;
+
+    int rc = RTThreadUserSignal(Thread);
+    AssertRC(rc);
+
+    rc = pThis->i_sendData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
 
     if (pTask)
         delete pTask;
 
-    LogFlowFunc(("pTarget=%p returning rc=%Rrc\n", (GuestDnDTarget *)pTarget, rc));
+    AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
+
+    Assert(pThis->mDataBase.m_cTransfersPending);
+    pThis->mDataBase.m_cTransfersPending--;
+
+    LogFlowFunc(("pTarget=%p returning rc=%Rrc\n", (GuestDnDTarget *)pThis, rc));
     return rc;
 }
@@ -594,9 +594,9 @@
         return setError(E_INVALIDARG, tr("No data to send specified"));
 
-    /* Note: At the moment we only support one transfer at a time. */
-    if (ASMAtomicReadBool(&mDataBase.mfTransferIsPending))
-        return setError(E_INVALIDARG, tr("Another send operation already is in progress"));
-
-    ASMAtomicWriteBool(&mDataBase.mfTransferIsPending, true);
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /* At the moment we only support one transfer at a time. */
+    if (mDataBase.m_cTransfersPending)
+        return setError(E_INVALIDARG, tr("Another drop operation already is in progress"));
 
     /* Dito. */
@@ -617,5 +617,6 @@
         pSendCtx->mScreenID     = aScreenId;
         pSendCtx->mFmtReq       = aFormat;
-        pSendCtx->mData.vecData = aData;
+
+        pSendCtx->mData.getMeta().add(aData);
 
         SendDataTask *pTask = new SendDataTask(this, pSendCtx);
@@ -624,17 +625,26 @@
         LogFlowFunc(("Starting thread ...\n"));
 
-        int rc = RTThreadCreate(NULL, GuestDnDTarget::i_sendDataThread,
+        RTTHREAD threadSnd;
+        int rc = RTThreadCreate(&threadSnd, GuestDnDTarget::i_sendDataThread,
                                 (void *)pTask, 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndTgtSndData");
         if (RT_SUCCESS(rc))
         {
-            hr = pResp->queryProgressTo(aProgress.asOutParam());
-            ComAssertComRC(hr);
-
-            /* Note: pTask is now owned by the worker thread. */
+            rc = RTThreadUserWait(threadSnd, 30 * 1000 /* 30s timeout */);
+            if (RT_SUCCESS(rc))
+            {
+                mDataBase.m_cTransfersPending++;
+
+                hr = pResp->queryProgressTo(aProgress.asOutParam());
+                ComAssertComRC(hr);
+
+                /* Note: pTask is now owned by the worker thread. */
+            }
+            else
+                hr = setError(VBOX_E_IPRT_ERROR, tr("Waiting for sending thread failed (%Rrc)"), rc);
         }
         else
             hr = setError(VBOX_E_IPRT_ERROR, tr("Starting thread failed (%Rrc)"), rc);
 
-        if (RT_FAILURE(rc))
+        if (FAILED(hr))
             delete pSendCtx;
     }
@@ -643,6 +653,4 @@
         hr = setError(E_OUTOFMEMORY);
     }
-
-    /* Note: mDataBase.mfTransferIsPending will be set to false again by i_sendDataThread. */
 
     LogFlowFunc(("Returning hr=%Rhrc\n", hr));
@@ -662,5 +670,5 @@
 
     LogFlowFunc(("Cancelling operation, telling guest ...\n"));
-    return GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL, 0 /* cParms */, NULL /*paParms*/);
+    return GuestDnDInst()->hostCall(HOST_DND_HG_EVT_CANCEL, 0 /* cParms */, NULL /*paParms*/);
 }
 
@@ -746,5 +754,5 @@
 
     /* Clear all remaining outgoing messages. */
-    mDataBase.mListOutgoing.clear();
+    mDataBase.m_lstMsgOut.clear();
 
     /**
@@ -775,4 +783,75 @@
 }
 
+int GuestDnDTarget::i_sendDataBody(PSENDDATACTX pCtx, GuestDnDData *pData)
+{
+    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pData, VERR_INVALID_POINTER);
+
+    /** @todo Add support for multiple HOST_DND_HG_SND_DATA messages in case of more than 64K data! */
+    if (pData->getMeta().getSize() > _64K)
+        return VERR_NOT_IMPLEMENTED;
+
+    GuestDnDMsg Msg;
+
+    LogFlowFunc(("cbFmt=%RU32, cbMeta=%RU32, cbChksum=%RU32\n",
+                 pData->getFmtSize(), pData->getMeta().getSize(), pData->getChkSumSize()));
+
+    Msg.setType(HOST_DND_HG_SND_DATA);
+    if (mDataBase.m_uProtocolVersion < 3)
+    {
+        Msg.setNextUInt32(pCtx->mScreenID);                                                /* uScreenId */
+        Msg.setNextPointer(pData->getFmtMutable(), pData->getFmtSize());                   /* pvFormat */
+        Msg.setNextUInt32(pData->getFmtSize());                                            /* cbFormat */
+        Msg.setNextPointer(pData->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */
+        /* Note1: Fill in the total data to send.
+         * Note2: Only supports uint32_t. */
+        Msg.setNextUInt32((uint32_t)pData->getTotal());                                    /* cbData */
+    }
+    else
+    {
+        Msg.setNextUInt32(0);                                                              /** @todo uContext; not used yet. */
+        Msg.setNextPointer(pData->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */
+        Msg.setNextUInt32(pData->getMeta().getSize());                                     /* cbData */
+        Msg.setNextPointer(pData->getChkSumMutable(), pData->getChkSumSize());             /** @todo pvChecksum; not used yet. */
+        Msg.setNextUInt32(pData->getChkSumSize());                                         /** @todo cbChecksum; not used yet. */
+    }
+
+    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
+    if (RT_SUCCESS(rc))
+        rc = updateProgress(pData, pCtx->mpResp, pData->getMeta().getSize());
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int GuestDnDTarget::i_sendDataHeader(PSENDDATACTX pCtx, GuestDnDData *pData, GuestDnDURIData *pURIData /* = NULL */)
+{
+    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pData, VERR_INVALID_POINTER);
+    /* pURIData is optional. */
+
+    GuestDnDMsg Msg;
+
+    Msg.setType(HOST_DND_HG_SND_DATA_HDR);
+
+    Msg.setNextUInt32(0);                                                /** @todo uContext; not used yet. */
+    Msg.setNextUInt32(0);                                                /** @todo uFlags; not used yet. */
+    Msg.setNextUInt32(pCtx->mScreenID);                                  /* uScreen */
+    Msg.setNextUInt64(pData->getTotal());                                /* cbTotal */
+    Msg.setNextUInt32(pData->getMeta().getSize());                       /* cbMeta*/
+    Msg.setNextPointer(pData->getFmtMutable(), pData->getFmtSize());     /* pvMetaFmt */
+    Msg.setNextUInt32(pData->getFmtSize());                              /* cbMetaFmt */
+    Msg.setNextUInt64(pURIData ? pURIData->getObjToProcess() : 0);       /* cObjects */
+    Msg.setNextUInt32(0);                                                /** @todo enmCompression; not used yet. */
+    Msg.setNextUInt32(0);                                                /** @todo enmChecksumType; not used yet. */
+    Msg.setNextPointer(NULL, 0);                                         /** @todo pvChecksum; not used yet. */
+    Msg.setNextUInt32(0);                                                /** @todo cbChecksum; not used yet. */
+
+    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
 int GuestDnDTarget::i_sendDirectory(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg)
 {
@@ -790,9 +869,9 @@
         return VERR_BUFFER_OVERFLOW;
 
-    LogFlowFunc(("Sending directory \"%s\" using protocol v%RU32 ...\n", strPath.c_str(), mDataBase.mProtocolVersion));
-
-    pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_DIR);
+    LogRel2(("DnD: Transferring host directory to guest: %s\n", strPath.c_str()));
+
+    pMsg->setType(HOST_DND_HG_SND_DIR);
     pMsg->setNextString(strPath.c_str());                  /* path */
-    pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* path length - note: Maximum is RTPATH_MAX on guest side. */
+    pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* path length (maximum is RTPATH_MAX on guest side). */
     pMsg->setNextUInt32(pObj->GetMode());                  /* mode */
 
@@ -816,5 +895,5 @@
 
     LogFlowFunc(("Sending file with %RU32 bytes buffer, using protocol v%RU32 ...\n",
-                  mData.mcbBlockSize, mDataBase.mProtocolVersion));
+                  mData.mcbBlockSize, mDataBase.m_uProtocolVersion));
     LogFlowFunc(("strPathSrc=%s, fIsOpen=%RTbool, cbSize=%RU64\n", strPathSrc.c_str(), pObj->IsOpen(), pObj->GetSize()));
 
@@ -831,5 +910,5 @@
     if (RT_SUCCESS(rc))
     {
-        if (mDataBase.mProtocolVersion >= 2)
+        if (mDataBase.m_uProtocolVersion >= 2)
         {
             if (!pObjCtx->fHeaderSent)
@@ -840,5 +919,5 @@
                  * The just registered callback will be called by the guest afterwards.
                  */
-                pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
+                pMsg->setType(HOST_DND_HG_SND_FILE_HDR);
                 pMsg->setNextUInt32(0);                                            /* uContextID */
                 rc = pMsg->setNextString(pObj->GetDestPath().c_str());             /* pvName */
@@ -899,38 +978,44 @@
 
     /* Set the message type. */
-    pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
+    pMsg->setType(HOST_DND_HG_SND_FILE_DATA);
 
     /* Protocol version 1 sends the file path *every* time with a new file chunk.
      * In protocol version 2 we only do this once with HOST_DND_HG_SND_FILE_HDR. */
-    if (mDataBase.mProtocolVersion <= 1)
+    if (mDataBase.m_uProtocolVersion <= 1)
     {
         pMsg->setNextString(pObj->GetDestPath().c_str());                  /* pvName */
         pMsg->setNextUInt32((uint32_t)(pObj->GetDestPath().length() + 1)); /* cbName */
     }
-    else
-    {
-        /* Protocol version 2 also sends the context ID. Currently unused. */
-        pMsg->setNextUInt32(0);                                            /* context ID */
+    else if (mDataBase.m_uProtocolVersion >= 2)
+    {
+        /* Since protocol v2 we also send the context ID. Currently unused. */
+        pMsg->setNextUInt32(0);                                            /* uContext */
     }
 
     uint32_t cbRead = 0;
 
-    int rc = pObj->Read(pCtx->mURI.GetBufferMutable(), pCtx->mURI.GetBufferSize(), &cbRead);
+    int rc = pObj->Read(pCtx->mURI.getBufferMutable(), pCtx->mURI.getBufferSize(), &cbRead);
     if (RT_SUCCESS(rc))
     {
-        pCtx->mData.cbProcessed += cbRead;
-        LogFlowFunc(("cbBufSize=%zu, cbRead=%RU32, cbProcessed=%RU64, rc=%Rrc\n",
-                     pCtx->mURI.GetBufferSize(), cbRead, pCtx->mData.cbProcessed, rc));
-
-        if (mDataBase.mProtocolVersion <= 1)
-        {
-            pMsg->setNextPointer(pCtx->mURI.GetBufferMutable(), cbRead);   /* pvData */
-            pMsg->setNextUInt32(cbRead);                                   /* cbData */
-            pMsg->setNextUInt32(pObj->GetMode());                          /* fMode */
-        }
-        else
-        {
-            pMsg->setNextPointer(pCtx->mURI.GetBufferMutable(), cbRead);   /* pvData */
-            pMsg->setNextUInt32(cbRead);                                   /* cbData */
+        pCtx->mData.addProcessed(cbRead);
+        LogFlowFunc(("cbBufSize=%zu, cbRead=%RU32\n", pCtx->mURI.getBufferSize(), cbRead));
+
+        if (mDataBase.m_uProtocolVersion <= 1)
+        {
+            pMsg->setNextPointer(pCtx->mURI.getBufferMutable(), cbRead);    /* pvData */
+            pMsg->setNextUInt32(cbRead);                                    /* cbData */
+            pMsg->setNextUInt32(pObj->GetMode());                           /* fMode */
+        }
+        else /* Protocol v2 and up. */
+        {
+            pMsg->setNextPointer(pCtx->mURI.getBufferMutable(), cbRead);    /* pvData */
+            pMsg->setNextUInt32(cbRead);                                    /* cbData */
+
+            if (mDataBase.m_uProtocolVersion >= 3)
+            {
+                /** @todo Calculate checksum. */
+                pMsg->setNextPointer(NULL, 0);                              /* pvChecksum */
+                pMsg->setNextUInt32(0);                                     /* cbChecksum */
+            }
         }
 
@@ -961,16 +1046,16 @@
     LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg));
 
-    int rc      = VINF_SUCCESS; /* Will be reported back to guest. */
-    int rcGuest = VINF_SUCCESS; /* Contains error code from guest in case of VERR_GSTDND_GUEST_ERROR. */
+    int  rc      = VINF_SUCCESS;
+    int  rcGuest = VINF_SUCCESS; /* Contains error code from guest in case of VERR_GSTDND_GUEST_ERROR. */
     bool fNotify = false;
 
     switch (uMsg)
     {
-        case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
-        {
-            DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG>(pvParms);
+        case GUEST_DND_GET_NEXT_HOST_MSG:
+        {
+            PVBOXDNDCBHGGETNEXTHOSTMSG pCBData = reinterpret_cast<PVBOXDNDCBHGGETNEXTHOSTMSG>(pvParms);
             AssertPtr(pCBData);
-            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG) == cbParms, VERR_INVALID_PARAMETER);
-            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            AssertReturn(sizeof(VBOXDNDCBHGGETNEXTHOSTMSG) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
             try
@@ -1007,10 +1092,10 @@
             break;
         }
-        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
-        {
-            DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
+        case GUEST_DND_GH_EVT_ERROR:
+        {
+            PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<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);
+            AssertReturn(sizeof(VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
             pCtx->mpResp->reset();
@@ -1022,5 +1107,5 @@
             }
 
-            rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc,
+            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
                                            GuestDnDTarget::i_guestErrorToString(pCBData->rc));
             if (RT_SUCCESS(rc))
@@ -1031,13 +1116,13 @@
             break;
         }
-        case DragAndDropSvc::HOST_DND_HG_SND_DIR:
-        case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
-        case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
-        {
-            DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA pCBData
-                = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA>(pvParms);
+        case HOST_DND_HG_SND_DIR:
+        case HOST_DND_HG_SND_FILE_HDR:
+        case HOST_DND_HG_SND_FILE_DATA:
+        {
+            PVBOXDNDCBHGGETNEXTHOSTMSGDATA pCBData
+                = reinterpret_cast<PVBOXDNDCBHGGETNEXTHOSTMSGDATA>(pvParms);
             AssertPtr(pCBData);
-            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA) == cbParms, VERR_INVALID_PARAMETER);
-            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
+            AssertReturn(sizeof(VBOXDNDCBHGGETNEXTHOSTMSGDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
 
             LogFlowFunc(("pCBData->uMsg=%RU32, paParms=%p, cParms=%RU32\n", pCBData->uMsg, pCBData->paParms, pCBData->cParms));
@@ -1053,4 +1138,9 @@
                     || pCBData->cParms  != pMsg->getCount())
                 {
+                    LogFlowFunc(("Current message does not match:\n"));
+                    LogFlowFunc(("\tCallback: uMsg=%RU32, cParms=%RU32, paParms=%p\n",
+                                 pCBData->uMsg, pCBData->cParms, pCBData->paParms));
+                    LogFlowFunc(("\t    Next: uMsg=%RU32, cParms=%RU32\n", pMsg->getType(), pMsg->getCount()));
+
                     /* Start over. */
                     pThis->msgQueueClear();
@@ -1141,5 +1231,5 @@
     if (fNotify)
     {
-        int rc2 = pCtx->mCallback.Notify(rc); /** @todo Also pass guest error back? */
+        int rc2 = pCtx->mCBEvent.Notify(rc); /** @todo Also pass guest error back? */
         AssertRC(rc2);
     }
@@ -1173,9 +1263,9 @@
     }
 
-    int rc = pCtx->mURI.Init(mData.mcbBlockSize);
+    int rc = pCtx->mURI.init(mData.mcbBlockSize);
     if (RT_FAILURE(rc))
         return rc;
 
-    rc = pCtx->mCallback.Reset();
+    rc = pCtx->mCBEvent.Reset();
     if (RT_FAILURE(rc))
         return rc;
@@ -1185,72 +1275,81 @@
      */
     /* Guest callbacks. */
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG);
-    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
+    REGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
+    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     /* Host callbacks. */
-    REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR);
-    if (mDataBase.mProtocolVersion >= 2)
-        REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
-    REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
+    REGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
+    if (mDataBase.m_uProtocolVersion >= 2)
+        REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
+    REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
 
     do
     {
         /*
-         * Extract URI list from byte data.
+         * Extract URI list from current meta data.
          */
-        DnDURIList &lstURI = pCtx->mURI.lstURI; /* Use the URI list from the context. */
-
-        const char *pszList = (const char *)&pCtx->mData.vecData.front();
-        URI_DATA_IS_VALID_BREAK(pszList);
-
-        uint32_t cbList = pCtx->mData.vecData.size();
-        URI_DATA_IS_VALID_BREAK(cbList);
-
-        RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
-        URI_DATA_IS_VALID_BREAK(!lstURIOrg.isEmpty());
-
-        /* Note: All files to be transferred will be kept open during the entire DnD
-         *       operation, also to keep the accounting right. */
-        rc = lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
+        GuestDnDData    *pData = &pCtx->mData;
+        GuestDnDURIData *pURI  = &pCtx->mURI;
+
+        rc = pURI->fromMetaData(pData->getMeta());
+        if (RT_FAILURE(rc))
+            break;
+
+        LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n",
+                     pURI->getURIList().RootCount(), pURI->getURIList().TotalBytes()));
+
+        /*
+         * Set the new meta data with the URI list in it.
+         */
+        rc = pData->getMeta().fromURIList(pURI->getURIList());
+        if (RT_FAILURE(rc))
+            break;
+
+        /*
+         * Set the additional size we are going to send after the meta data header + meta data.
+         * This additional data will contain the actual file data we want to transfer.
+         */
+        pData->setAdditionalSize(pURI->getURIList().TotalBytes());
+
+        void    *pvFmt = (void *)pCtx->mFmtReq.c_str();
+        uint32_t cbFmt = pCtx->mFmtReq.length() + 1;        /* Include terminating zero. */
+
+        pData->setFmt(pvFmt, cbFmt);
+
+        /*
+         * The first message always is the data header. The meta data itself then follows
+         * and *only* contains the root elements of an URI list.
+         *
+         * After the meta data we generate the messages required to send the
+         * file/directory data itself.
+         *
+         * Note: Protocol < v3 use the first data message to tell what's being sent.
+         */
+        GuestDnDMsg Msg;
+
+        /*
+         * Send the data header first.
+         */
+        if (mDataBase.m_uProtocolVersion >= 3)
+            rc = i_sendDataHeader(pCtx, pData, &pCtx->mURI);
+
+        /*
+         * Send the (meta) data body.
+         */
         if (RT_SUCCESS(rc))
-            LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n",
-                         lstURI.RootCount(), lstURI.TotalBytes()));
-        else
-            break;
-
-        pCtx->mData.cbProcessed = 0;
-        pCtx->mData.cbToProcess = lstURI.TotalBytes();
-
-        /*
-         * The first message always is the meta info for the data. The meta
-         * info *only* contains the root elements of an URI list.
-         *
-         * After the meta data we generate the messages required to send the data itself.
-         */
-        Assert(!lstURI.IsEmpty());
-        RTCString strData = lstURI.RootToString().c_str();
-        size_t    cbData  = strData.length() + 1; /* Include terminating zero. */
-
-        GuestDnDMsg MsgSndData;
-        MsgSndData.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA);
-        MsgSndData.setNextUInt32(pCtx->mScreenID);
-        MsgSndData.setNextPointer((void *)pCtx->mFmtReq.c_str(), (uint32_t)pCtx->mFmtReq.length() + 1);
-        MsgSndData.setNextUInt32((uint32_t)pCtx->mFmtReq.length() + 1);
-        MsgSndData.setNextPointer((void*)strData.c_str(), (uint32_t)cbData);
-        MsgSndData.setNextUInt32((uint32_t)cbData);
-
-        rc = GuestDnDInst()->hostCall(MsgSndData.getType(), MsgSndData.getCount(), MsgSndData.getParms());
+            rc = i_sendDataBody(pCtx, pData);
+
         if (RT_SUCCESS(rc))
         {
-            rc = waitForEvent(msTimeout, pCtx->mCallback, pCtx->mpResp);
+            rc = waitForEvent(&pCtx->mCBEvent, pCtx->mpResp, msTimeout);
             if (RT_FAILURE(rc))
             {
                 if (rc == VERR_CANCELLED)
-                    rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED, VINF_SUCCESS);
+                    rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
                 else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
-                    rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, rc,
+                    rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
                                                    GuestDnDTarget::i_hostErrorToString(rc));
             }
             else
-                rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, VINF_SUCCESS);
+                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
         }
 
@@ -1261,11 +1360,11 @@
      */
     /* Guest callbacks. */
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG);
-    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
+    UNREGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
+    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     /* Host callbacks. */
-    UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR);
-    if (mDataBase.mProtocolVersion >= 2)
-        UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
-    UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
+    UNREGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
+    if (mDataBase.m_uProtocolVersion >= 2)
+        UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
+    UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
 
 #undef REGISTER_CALLBACK
@@ -1292,49 +1391,35 @@
 {
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
-
-    DnDURIList &lstURI = pCtx->mURI.lstURI;
-
-    uint64_t cbTotal = pCtx->mData.cbToProcess;
-    uint8_t uPercent = pCtx->mData.cbProcessed * 100 / (cbTotal ? cbTotal : 1);
-
-    LogFlowFunc(("%RU64 / %RU64 -- %RU8%%\n", pCtx->mData.cbProcessed, cbTotal, uPercent));
-
-    bool fComplete = (uPercent >= 100) || lstURI.IsEmpty();
-
-    if (pCtx->mpResp)
-    {
-        int rc2 = pCtx->mpResp->setProgress(uPercent,
-                                              fComplete
-                                            ? DragAndDropSvc::DND_PROGRESS_COMPLETE
-                                            : DragAndDropSvc::DND_PROGRESS_RUNNING);
-        AssertRC(rc2);
-    }
-
-    if (fComplete)
+    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
+
+    int rc = updateProgress(&pCtx->mData, pCtx->mpResp);
+    AssertRC(rc);
+
+    if (   pCtx->mData.isComplete()
+        && pCtx->mURI.isComplete())
+    {
         return VINF_EOF;
-
-    Assert(!lstURI.IsEmpty());
-    DnDURIObject *pCurObj = lstURI.First();
-
-    /* As we transfer all objects one after another at a time at the moment,
-     * we only need one object context at the moment. */
-    GuestDnDURIObjCtx *pObjCtx = &pCtx->mURI.objCtx;
-
-    /* Assign the pointer of the current object to our context. */
-    pObjCtx->pObjURI = pCurObj;
+    }
+
+    GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObjCurrent();
+    if (!objCtx.isValid())
+        return VERR_WRONG_ORDER;
+
+    DnDURIObject *pCurObj = objCtx.pObjURI;
+    AssertPtr(pCurObj);
 
     uint32_t fMode = pCurObj->GetMode();
-    LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
-                 pCurObj->GetSourcePath().c_str(), pCurObj->GetDestPath().c_str(),
-                 fMode, pCurObj->GetSize(),
-                 RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
-    int rc;
+    LogRel3(("DnD: Processing: srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
+             pCurObj->GetSourcePath().c_str(), pCurObj->GetDestPath().c_str(),
+             fMode, pCurObj->GetSize(),
+             RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
+
     if (RTFS_IS_DIRECTORY(fMode))
     {
-        rc = i_sendDirectory(pCtx, pObjCtx, pMsg);
+        rc = i_sendDirectory(pCtx, &objCtx, pMsg);
     }
     else if (RTFS_IS_FILE(fMode))
     {
-        rc = i_sendFile(pCtx, pObjCtx, pMsg);
+        rc = i_sendFile(pCtx, &objCtx, pMsg);
     }
     else
@@ -1355,5 +1440,5 @@
     {
         LogFlowFunc(("Removing \"%s\" from list, rc=%Rrc\n", pCurObj->GetSourcePath().c_str(), rc));
-        lstURI.RemoveFirst();
+        pCtx->mURI.removeObjCurrent();
     }
 
@@ -1370,32 +1455,32 @@
     AssertPtr(pInst);
 
-    /** @todo At the moment we only allow sending up to 64K raw data. Fix this by
-     *        using HOST_DND_HG_SND_MORE_DATA. */
-    size_t cbDataTotal = pCtx->mData.vecData.size();
-    if (   !cbDataTotal
-        || cbDataTotal > _64K)
-    {
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /* Just copy over the raw data. */
-    GuestDnDMsg Msg;
-    Msg.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA);
-    Msg.setNextUInt32(pCtx->mScreenID);
-    Msg.setNextPointer((void *)pCtx->mFmtReq.c_str(), (uint32_t)pCtx->mFmtReq.length() + 1);
-    Msg.setNextUInt32((uint32_t)pCtx->mFmtReq.length() + 1);
-    Msg.setNextPointer((void*)&pCtx->mData.vecData.front(), (uint32_t)cbDataTotal);
-    Msg.setNextUInt32(cbDataTotal);
-
-    LogFlowFunc(("Transferring %zu total bytes of raw data ('%s')\n", cbDataTotal, pCtx->mFmtReq.c_str()));
+    GuestDnDData *pData = &pCtx->mData;
+
+    /** @todo At the moment we only allow sending up to 64K raw data.
+     *        For protocol v1+v2: Fix this by using HOST_DND_HG_SND_MORE_DATA.
+     *        For protocol v3   : Send another HOST_DND_HG_SND_DATA message. */
+    if (!pData->getMeta().getSize())
+        return VINF_SUCCESS;
+
+    int rc = VINF_SUCCESS;
+
+    /*
+     * Send the data header first.
+     */
+    if (mDataBase.m_uProtocolVersion >= 3)
+        rc = i_sendDataHeader(pCtx, pData, NULL /* URI list */);
+
+    /*
+     * Send the (meta) data body.
+     */
+    if (RT_SUCCESS(rc))
+        rc = i_sendDataBody(pCtx, pData);
 
     int rc2;
-
-    int rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     if (RT_FAILURE(rc))
-        rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, rc,
+        rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
                                         GuestDnDTarget::i_hostErrorToString(rc));
     else
-        rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, rc);
+        rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, rc);
     AssertRC(rc2);
 
