Index: /trunk/Config.kmk
===================================================================
--- /trunk/Config.kmk	(revision 78306)
+++ /trunk/Config.kmk	(revision 78307)
@@ -4118,4 +4118,11 @@
  SDK_VBOX_OPUS_INCS ?= $(SDK_VBOX_OPUS_DEFAULT_INCS)
  SDK_VBOX_OPUS_LIBS ?= $(PATH_STAGE_LIB)/VBox-libopus$(VBOX_SUFF_LIB)
+endif
+
+ifdef VBOX_WITH_LIBFUSE
+ SDK_VBOX_FUSE               = .
+ SDK_VBOX_FUSE_DEFAULT_INCS := $(PATH_ROOT)/src/libs/libfuse-2.9.8/include
+ SDK_VBOX_FUSE_INCS         ?= $(SDK_VBOX_FUSE_DEFAULT_INCS)
+ SDK_VBOX_FUSE_LIBS         ?= $(PATH_STAGE_LIB)/VBox-libfuse$(VBOX_SUFF_LIB)
 endif
 
Index: /trunk/include/VBox/GuestHost/SharedClipboard-uri.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-uri.h	(revision 78307)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-uri.h	(revision 78307)
@@ -0,0 +1,319 @@
+/* $Id$ */
+/** @file
+ * Shared Clipboard - Shared URI functions between host and guest.
+ */
+
+/*
+ * Copyright (C) 2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_URI_h
+#define VBOX_INCLUDED_GuestHost_SharedClipboard_URI_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/assert.h>
+#include <iprt/fs.h>
+
+#include <iprt/cpp/list.h>
+#include <iprt/cpp/ministring.h>
+
+/** SharedClipboardDroppedFiles flags. */
+typedef uint32_t SHAREDCLIPBOARDDROPPEDFILEFLAGS;
+
+/** No flags specified. */
+#define SHAREDCLIPBOARDDROPPEDFILE_FLAGS_NONE                   0
+
+/**
+ * Class for maintaining a "dropped files" directory
+ * on the host or guest. This will contain all received files & directories
+ * for a single Shared Clipboard "paste" operation.
+ *
+ * In case of a failed Shared Clipboard operation this class can also
+ * perform a gentle rollback if required.
+ */
+class SharedClipboardDroppedFiles
+{
+
+public:
+
+    SharedClipboardDroppedFiles(void);
+    SharedClipboardDroppedFiles(const char *pszPath, SHAREDCLIPBOARDDROPPEDFILEFLAGS fFlags = SHAREDCLIPBOARDDROPPEDFILE_FLAGS_NONE);
+    virtual ~SharedClipboardDroppedFiles(void);
+
+public:
+
+    int AddFile(const char *pszFile);
+    int AddDir(const char *pszDir);
+    int Close(void);
+    bool IsOpen(void) const;
+    int OpenEx(const char *pszPath, SHAREDCLIPBOARDDROPPEDFILEFLAGS fFlags = SHAREDCLIPBOARDDROPPEDFILE_FLAGS_NONE);
+    int OpenTemp(SHAREDCLIPBOARDDROPPEDFILEFLAGS fFlags = SHAREDCLIPBOARDDROPPEDFILE_FLAGS_NONE);
+    const char *GetDirAbs(void) const;
+    int Reopen(void);
+    int Reset(bool fDeleteContent);
+    int Rollback(void);
+
+protected:
+
+    int closeInternal(void);
+
+protected:
+
+    /** Open flags. */
+    uint32_t                     m_fOpen;
+    /** Directory handle for drop directory. */
+    RTDIR                        m_hDir;
+    /** Absolute path to drop directory. */
+    RTCString                    m_strPathAbs;
+    /** List for holding created directories in the case of a rollback. */
+    RTCList<RTCString>           m_lstDirs;
+    /** List for holding created files in the case of a rollback. */
+    RTCList<RTCString>           m_lstFiles;
+};
+
+int SharedClipboardSanitizeFilename(char *pszPath, size_t cbPath);
+int SharedClipboardPathSanitize(char *pszPath, size_t cbPath);
+
+/** SharedClipboardURIObject flags. */
+typedef uint32_t SHAREDCLIPBOARDURIOBJECTFLAGS;
+
+/** No flags specified. */
+#define SHAREDCLIPBOARDURIOBJECT_FLAGS_NONE                   0
+
+/** Mask of all valid Shared Clipboard URI object flags. */
+#define SHAREDCLIPBOARDURIOBJECT_FLAGS_VALID_MASK             UINT32_C(0x0)
+
+/**
+ * Class for handling Shared Clipboard URI objects.
+ * This class abstracts the access and handling objects when performing Shared Clipboard actions.
+ */
+class SharedClipboardURIObject
+{
+public:
+
+    /**
+     * Enumeration for specifying an URI object type.
+     */
+    enum Type
+    {
+        /** Unknown type, do not use. */
+        Type_Unknown = 0,
+        /** Object is a file. */
+        Type_File,
+        /** Object is a directory. */
+        Type_Directory,
+        /** The usual 32-bit hack. */
+        Type_32Bit_Hack = 0x7fffffff
+    };
+
+    /**
+     * Enumeration for specifying an URI object view
+     * for representing its data accordingly.
+     */
+    enum View
+    {
+        /** Unknown view, do not use. */
+        View_Unknown = 0,
+        /** Handle data from the source point of view. */
+        View_Source,
+        /** Handle data from the destination point of view. */
+        View_Target,
+        /** The usual 32-bit hack. */
+        View_Dest_32Bit_Hack = 0x7fffffff
+    };
+
+    SharedClipboardURIObject(void);
+    SharedClipboardURIObject(Type type,
+                 const RTCString &strSrcPathAbs = "",
+                 const RTCString &strDstPathAbs = "");
+    virtual ~SharedClipboardURIObject(void);
+
+public:
+
+    /**
+     * Returns the given absolute source path of the object.
+     *
+     * @return  Absolute source path of the object.
+     */
+    const RTCString &GetSourcePathAbs(void) const { return m_strSrcPathAbs; }
+
+    /**
+     * Returns the given, absolute destination path of the object.
+     *
+     * @return  Absolute destination path of the object.
+     */
+    const RTCString &GetDestPathAbs(void) const { return m_strTgtPathAbs; }
+
+    RTFMODE GetMode(void) const;
+
+    uint64_t GetProcessed(void) const;
+
+    uint64_t GetSize(void) const;
+
+    /**
+     * Returns the object's type.
+     *
+     * @return  The object's type.
+     */
+    Type GetType(void) const { return m_enmType; }
+
+    /**
+     * Returns the object's view.
+     *
+     * @return  The object's view.
+     */
+    View GetView(void) const { return m_enmView; }
+
+public:
+
+    int SetSize(uint64_t cbSize);
+
+public:
+
+    void Close(void);
+    bool IsComplete(void) const;
+    bool IsOpen(void) const;
+    int Open(View enmView, uint64_t fOpen, RTFMODE fMode = 0);
+    int OpenEx(const RTCString &strPath, View enmView, uint64_t fOpen = 0, RTFMODE fMode = 0, SHAREDCLIPBOARDURIOBJECTFLAGS = SHAREDCLIPBOARDURIOBJECT_FLAGS_NONE);
+    int QueryInfo(View enmView);
+    int Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead);
+    void Reset(void);
+    int Write(const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten);
+
+public:
+
+    static int RebaseURIPath(RTCString &strPath, const RTCString &strBaseOld = "", const RTCString &strBaseNew = "");
+
+protected:
+
+    void closeInternal(void);
+    int queryInfoInternal(View enmView);
+
+protected:
+
+    /** The object's type. */
+    Type      m_enmType;
+    /** The object's view. */
+    View      m_enmView;
+    /** Absolute path (base) for the source. */
+    RTCString m_strSrcPathAbs;
+    /** Absolute path (base) for the target. */
+    RTCString m_strTgtPathAbs;
+
+    /** Union containing data depending on the object's type. */
+    union
+    {
+        /** Structure containing members for objects that
+         *  are files. */
+        struct
+        {
+            /** File handle. */
+            RTFILE      hFile;
+            /** File system object information of this file. */
+            RTFSOBJINFO objInfo;
+            /** Bytes to proces for reading/writing. */
+            uint64_t    cbToProcess;
+            /** Bytes processed reading/writing. */
+            uint64_t    cbProcessed;
+        } File;
+        struct
+        {
+            /** Directory handle. */
+            RTDIR       hDir;
+            /** File system object information of this directory. */
+            RTFSOBJINFO objInfo;
+        } Dir;
+    } u;
+};
+
+/** SharedClipboardURIList flags. */
+typedef uint32_t SHAREDCLIPBOARDURILISTFLAGS;
+
+/** No flags specified. */
+#define SHAREDCLIPBOARDURILIST_FLAGS_NONE                   0
+/** Keep the original paths, don't convert paths to relative ones. */
+#define SHAREDCLIPBOARDURILIST_FLAGS_ABSOLUTE_PATHS         RT_BIT(0)
+/** Resolve all symlinks. */
+#define SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS       RT_BIT(1)
+/** Keep the files + directory entries open while
+ *  being in this list. */
+#define SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN              RT_BIT(2)
+/** Lazy loading: Only enumerate sub directories when needed.
+ ** @todo Implement lazy loading.  */
+#define SHAREDCLIPBOARDURILIST_FLAGS_LAZY                   RT_BIT(3)
+
+/** Mask of all valid Shared Clipboard URI list flags. */
+#define SHAREDCLIPBOARDURILIST_FLAGS_VALID_MASK             UINT32_C(0xF)
+
+class SharedClipboardURIList
+{
+public:
+
+    SharedClipboardURIList(void);
+    virtual ~SharedClipboardURIList(void);
+
+public:
+
+    int AppendNativePath(const char *pszPath, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+    int AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+    int AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+    int AppendURIPath(const char *pszURI, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+    int AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+    int AppendURIPathsFromList(const RTCList<RTCString> &lstURI, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+
+    void Clear(void);
+    SharedClipboardURIObject *First(void) { return m_lstTree.first(); }
+    bool IsEmpty(void) const { return m_lstTree.isEmpty(); }
+    void RemoveFirst(void);
+    int SetFromURIData(const void *pvData, size_t cbData, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+
+    RTCString GetRootEntries(const RTCString &strPathBase = "", const RTCString &strSeparator = "\r\n") const;
+    uint64_t GetRootCount(void) const { return m_lstRoot.size(); }
+    uint64_t GetTotalCount(void) const { return m_cTotal; }
+    uint64_t GetTotalBytes(void) const { return m_cbTotal; }
+
+protected:
+
+    int addEntry(const char *pcszSource, const char *pcszTarget, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+    int appendPathRecursive(const char *pcszSrcPath, const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase, SHAREDCLIPBOARDURILISTFLAGS fFlags);
+
+protected:
+
+    /** List of all top-level file/directory entries.
+     *  Note: All paths are kept internally as UNIX paths for
+     *        easier conversion/handling!  */
+    RTCList<RTCString>      m_lstRoot;
+    /** List of all URI objects added. The list's content
+     *  might vary depending on how the objects are being
+     *  added (lazy or not). */
+    RTCList<SharedClipboardURIObject *> m_lstTree;
+    /** Total number of all URI objects. */
+    uint64_t                m_cTotal;
+    /** Total size of all URI objects, that is, the file
+     *  size of all objects (in bytes).
+     *  Note: Do *not* size_t here, as we also want to support large files
+     *        on 32-bit guests. */
+    uint64_t                m_cbTotal;
+};
+
+#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_URI_h */
+
Index: /trunk/include/VBox/GuestHost/SharedClipboard-win.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 78306)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 78307)
@@ -38,4 +38,7 @@
 
 #define VBOX_CLIPBOARD_WNDCLASS_NAME        "VBoxSharedClipboardClass"
+
+#define VBOX_CLIPBOARD_WIN_REGFMT_HTML      "VBox HTML Format"
+#define VBOX_CLIPBOARD_WIN_REGFMT_URI_LIST  "VBox URI List"
 
 /** Default timeout (in ms) for passing down messages down the clipboard chain. */
Index: /trunk/include/VBox/GuestHost/SharedClipboard.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard.h	(revision 78306)
+++ /trunk/include/VBox/GuestHost/SharedClipboard.h	(revision 78307)
@@ -42,4 +42,8 @@
 /** Shared Clipboard format is HTML. */
 #define VBOX_SHARED_CLIPBOARD_FMT_HTML          UINT32_C(0x04)
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+/** Shared Clipboard format is an URI list. */
+#define VBOX_SHARED_CLIPBOARD_FMT_URI_LIST      UINT32_C(0x08)
+#endif
 
 /**
Index: /trunk/include/VBox/HostServices/VBoxClipboardSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/VBoxClipboardSvc.h	(revision 78306)
+++ /trunk/include/VBox/HostServices/VBoxClipboardSvc.h	(revision 78307)
@@ -52,12 +52,26 @@
  * The service functions which are called by guest.
  */
-/* Call host and wait blocking for an host event VBOX_SHARED_CLIPBOARD_HOST_MSG_* */
+/** Calls the host and waits (blocking) for an host event VBOX_SHARED_CLIPBOARD_HOST_MSG_*. */
 #define VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG      1
-/* Send list of available formats to host. */
-#define VBOX_SHARED_CLIPBOARD_FN_FORMATS           2
-/* Obtain data in specified format from host. */
+/** Sends a list of available formats to host. */
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_FORMATS     2
+/** Reads data in specified format from host. */
 #define VBOX_SHARED_CLIPBOARD_FN_READ_DATA         3
-/* Send data in requested format to host. */
+/** Writes data in requested format to host. */
 #define VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA        4
+#define VBOX_SHARED_CLIPBOARD_FN_READ_DATA_CHUNK   5
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_CHUNK  6
+#define VBOX_SHARED_CLIPBOARD_FN_READ_DATA_HDR     7
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_HDR    8
+#define VBOX_SHARED_CLIPBOARD_FN_READ_DIR          9
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_DIR         10
+#define VBOX_SHARED_CLIPBOARD_FN_READ_FILE_HDR     11
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_HDR    12
+#define VBOX_SHARED_CLIPBOARD_FN_READ_FILE_DATA    13
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_DATA   14
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_CANCEL      15
+#define VBOX_SHARED_CLIPBOARD_FN_WRITE_ERROR       16
+
+#define VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE       _64K
 
 /*
@@ -78,5 +92,5 @@
 #define VBOX_SHARED_CLIPBOARD_CPARMS_GET_HOST_MSG 2
 
-typedef struct _VBoxClipboardFormats
+typedef struct _VBoxClipboardWriteFormats
 {
     VBGLIOCHGCMCALL hdr;
@@ -84,5 +98,5 @@
     /* VBOX_SHARED_CLIPBOARD_FMT_* */
     HGCMFunctionParameter formats; /* OUT uint32_t */
-} VBoxClipboardFormats;
+} VBoxClipboardWriteFormats;
 
 #define VBOX_SHARED_CLIPBOARD_CPARMS_FORMATS 1
@@ -120,4 +134,197 @@
 #define VBOX_SHARED_CLIPBOARD_CPARMS_WRITE_DATA 2
 
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+/**
+ * Data header.
+ */
+typedef struct _VBOXCLIPBOARDDATAHDR
+{
+    /** 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;
+} VBOXCLIPBOARDDATAHDR, *PVBOXCLIPBOARDDATAHDR;
+
+/**
+ * Sends the header of an incoming (meta) data block.
+ *
+ * Used by:
+ * XXX
+ */
+typedef struct _VBoxClipboardWriteDataHdrMsg
+{
+    VBGLIOCHGCMCALL 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 */
+    /**
+     * Total meta data size (in bytes) to transfer.
+     * This size also is part of cbTotal already, so:
+     *
+     * cbTotal = cbMeta + additional size for files etc.
+     */
+    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 */
+} VBoxClipboardWriteDataHdrMsg;
+
+typedef struct _VBOXCLIPBOARDWRITEDATACHUNK
+{
+    /** 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;
+} VBOXCLIPBOARDWRITEDATACHUNK, *PVBOXCLIPBOARDWRITEDATACHUNK;
+
+/**
+ * Sends a (meta) data block to the host.
+ *
+ * Used by:
+ * GUEST_DND_GH_SND_DATA
+ */
+typedef struct _VBoxClipboardWriteDataChunkMsg
+{
+    VBGLIOCHGCMCALL hdr;
+
+    /** 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 */
+    /** (Rolling) Checksum, based on checksum type in data header. */
+    HGCMFunctionParameter pvChecksum;   /* OUT ptr */
+    /** Size (in bytes) of checksum. */
+    HGCMFunctionParameter cbChecksum;   /* OUT uint32_t */
+} VBoxClipboardWriteDataChunkMsg;
+
+/**
+ * Sends a directory entry.
+ *
+ * Used by:
+ * XXX
+ */
+typedef struct _VBoxClipboardWriteDirMsg
+{
+    VBGLIOCHGCMCALL hdr;
+
+    /** Context ID. Unused at the moment. */
+    HGCMFunctionParameter uContext;     /* OUT uint32_t */
+    /** Directory name. */
+    HGCMFunctionParameter pvName;       /* OUT ptr */
+    /** Size (in bytes) of directory name. */
+    HGCMFunctionParameter cbName;       /* OUT uint32_t */
+    /** Directory mode. */
+    HGCMFunctionParameter fMode;        /* OUT uint32_t */
+} VBoxClipboardWriteDirMsg;
+
+/**
+ * File header message, marking the start of transferring a new file.
+ *
+ * Used by:
+ * XXX
+ */
+typedef struct _VBoxClipboardWriteFileHdrMsg
+{
+    VBGLIOCHGCMCALL hdr;
+
+    /** Context ID. Unused at the moment. */
+    HGCMFunctionParameter uContext;     /* OUT uint32_t */
+    /** File path. */
+    HGCMFunctionParameter pvName;       /* OUT ptr */
+    /** Size (in bytes) of file path. */
+    HGCMFunctionParameter cbName;       /* OUT uint32_t */
+    /** Optional flags; unused at the moment. */
+    HGCMFunctionParameter uFlags;       /* OUT uint32_t */
+    /** File creation mode. */
+    HGCMFunctionParameter fMode;        /* OUT uint32_t */
+    /** Total size (in bytes). */
+    HGCMFunctionParameter cbTotal;      /* OUT uint64_t */
+} VBoxClipboardWriteFileHdrMsg;
+
+/**
+ * Sends data of a file entry.
+ *
+ * Used by:
+ * XXX
+ */
+typedef struct _VBoxClipboardWriteFileDataMsg
+{
+    VBGLIOCHGCMCALL hdr;
+
+    /** 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 */
+} VBoxClipboardWriteFileDataMsg;
+
+/**
+ * Sends an error event.
+ *
+ * Used by:
+ * XXX
+ */
+typedef struct _VBoxClipboardWriteErrorMsg
+{
+    VBGLIOCHGCMCALL hdr;
+
+    /** Context ID. Unused at the moment. */
+    HGCMFunctionParameter uContext;     /* OUT uint32_t */
+    /** The error code (IPRT-style). */
+    HGCMFunctionParameter rc;           /* OUT uint32_t */
+} VBoxClipboardWriteErrorMsg;
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
+
 #pragma pack()
 
Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 78306)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 78307)
@@ -572,6 +572,9 @@
 VBGLR3DECL(int)     VbglR3ClipboardGetHostMsg(HGCMCLIENTID idClient, uint32_t *pMsg, uint32_t *pfFormats);
 VBGLR3DECL(int)     VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcb);
-VBGLR3DECL(int)     VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats);
+VBGLR3DECL(int)     VbglR3ClipboardWriteFormats(HGCMCLIENTID idClient, uint32_t fFormats);
 VBGLR3DECL(int)     VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb);
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+VBGLR3DECL(int)     VbglR3ClipboardSendError(HGCMCLIENTID idClient, int rcErr);
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
 /** @} */
 
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 78306)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 78307)
@@ -47,5 +47,6 @@
 ifdef VBOX_WITH_SHARED_CLIPBOARD
  VBoxTray_DEFS     += \
-	VBOX_WITH_SHARED_CLIPBOARD
+	VBOX_WITH_SHARED_CLIPBOARD \
+	$(if $(VBOX_WITH_SHARED_CLIPBOARD_URI_LIST),VBOX_WITH_SHARED_CLIPBOARD_URI_LIST,)
  VBoxTray_SOURCES  += \
 	VBoxClipboard.cpp \
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 78306)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 78307)
@@ -78,5 +78,5 @@
                int vboxrc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
                if (RT_SUCCESS(vboxrc))
-                   vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats);
+                   vboxrc = VbglR3ClipboardWriteFormats(pCtx->u32ClientID, uFormats);
            }
         }
@@ -128,5 +128,5 @@
                int vboxrc = VBoxClipboardWinGetFormats(pWinCtx, &uFormats);
                if (RT_SUCCESS(vboxrc))
-                   vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats);
+                   vboxrc = VbglR3ClipboardWriteFormats(pCtx->u32ClientID, uFormats);
            }
 
@@ -386,4 +386,8 @@
                }
 
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+               if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+                   hClip = SetClipboardData(CF_HDROP, NULL);
+#endif
                VBoxClipboardWinClose();
 
@@ -466,5 +470,24 @@
                    }
                }
-
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+               else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+               {
+                   hClip = GetClipboardData(CF_HDROP);
+                   if (hClip)
+                   {
+                       HDROP hDrop = (HDROP)GlobalLock(hClip);
+                       if (hDrop)
+                       {
+                           vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_URI_LIST,
+                                                             );
+                           GlobalUnlock(hClip);
+                       }
+                       else
+                       {
+                           hClip = NULL;
+                       }
+                   }
+               }
+#endif
                VBoxClipboardWinClose();
            }
Index: /trunk/src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk	(revision 78306)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk	(revision 78307)
@@ -110,4 +110,5 @@
 	VBOX_WITH_HGCM \
 	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
+	$(if $(VBOX_WITH_SHARED_CLIPBOARD),VBOX_WITH_SHARED_CLIPBOARD,) \
 	$(if $(VBOX_WITH_SHARED_FOLDERS),VBOX_WITH_SHARED_FOLDERS,) \
 	$(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL,)
@@ -160,4 +161,8 @@
  	VBoxGuestR3LibDragAndDrop.cpp
 endif
+ifdef VBOX_WITH_SHARED_CLIPBOARD
+ VBoxGuestR3Lib_DEFS      += \
+	$(if $(VBOX_WITH_SHARED_CLIPBOARD_URI_LIST),VBOX_WITH_SHARED_CLIPBOARD_URI_LIST,)
+endif
 
 VBoxGuestR3LibAdditions.cpp_DEFS = VBOX_SVN_REV=$(VBOX_SVN_REV)
@@ -202,5 +207,6 @@
 	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
 	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \
-	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,) \
+	$(if $(VBOX_WITH_SHARED_CLIPBOARD_URI_LIST),VBOX_WITH_SHARED_CLIPBOARD_URI_LIST,)
 VBoxGuestR3LibXFree86_SOURCES  = \
 	VBoxGuestR3Lib.cpp \
@@ -229,5 +235,6 @@
 	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
 	$(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP,) \
-	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
+	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,) \
+	$(if $(VBOX_WITH_SHARED_CLIPBOARD_URI_LIST),VBOX_WITH_SHARED_CLIPBOARD_URI_LIST,)
 VBoxGuestR3LibXOrg_SOURCES  = $(VBoxGuestR3LibXFree86_SOURCES)
 
Index: /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 78306)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 78307)
@@ -29,9 +29,23 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
+#include <VBox/GuestHost/SharedClipboard.h>
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+# include <VBox/GuestHost/SharedClipboard-uri.h>
+#endif
 #include <VBox/HostServices/VBoxClipboardSvc.h>
 #include <VBox/err.h>
 #include <iprt/assert.h>
 #include <iprt/string.h>
+#include <iprt/cpp/ministring.h>
 #include "VBoxGuestR3LibInternal.h"
+
+
+/*********************************************************************************************************************************
+*   Prototypes                                                                                                                   *
+*********************************************************************************************************************************/
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+static int vbglR3ClipboardSendErrorInternal(HGCMCLIENTID idClient, int rcErr);
+static int vbglR3ClipboardSendURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData);
+#endif
 
 
@@ -140,5 +154,5 @@
 
 /**
- * Advertises guest clipboard formats to the host.
+ * Writes (advertises) guest clipboard formats to the host.
  *
  * @returns VBox status code.
@@ -146,9 +160,9 @@
  * @param   fFormats        The formats to advertise.
  */
-VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
-{
-    VBoxClipboardFormats Msg;
-
-    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_FORMATS, 1);
+VBGLR3DECL(int) VbglR3ClipboardWriteFormats(HGCMCLIENTID idClient, uint32_t fFormats)
+{
+    VBoxClipboardWriteFormats Msg;
+
+    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FORMATS, 1);
     VbglHGCMParmUInt32Set(&Msg.formats, fFormats);
 
@@ -156,7 +170,6 @@
 }
 
-
-/**
- * Send guest clipboard data to the host.
+/**
+ * Sends guest clipboard data to the host.
  *
  * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
@@ -169,5 +182,5 @@
  * @param   cb              The size of the data.
  */
-VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
+static int vbglR3ClipboardWriteDataRaw(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
 {
     VBoxClipboardWriteData Msg;
@@ -179,2 +192,406 @@
 }
 
+/**
+ * Send guest clipboard data to the host.
+ *
+ * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
+ * from the host.
+ *
+ * @returns VBox status code.
+ * @param   idClient        The client id returned by VbglR3ClipboardConnect().
+ * @param   fFormat         The format of the data.
+ * @param   pv              The data.
+ * @param   cb              The size of the data.
+ */
+VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
+{
+    int rc;
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+    if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+    {
+        rc = vbglR3ClipboardSendURIData(idClient, pv, cb);
+    }
+    else
+#else
+        RT_NOREF(fFormat);
+#endif
+        rc = vbglR3ClipboardWriteDataRaw(idClient, fFormat, pv, cb);
+
+    if (RT_FAILURE(rc))
+    {
+        int rc2 = vbglR3ClipboardSendErrorInternal(idClient, rc);
+        if (RT_FAILURE(rc2))
+            LogFlowFunc(("Unable to send error (%Rrc) to host, rc=%Rrc\n", rc, rc2));
+    }
+
+    return rc;
+}
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+/**
+ * Guest -> Host
+ * Utility function to send clipboard data from guest to the host.
+ *
+ * @returns IPRT status code.
+ * @param   idClient            The client id returned by VbglR3ClipboardConnect().
+ * @param   pvData              Data block to send.
+ * @param   cbData              Size (in bytes) of data block to send.
+ * @param   pDataHdr            Data header to use -- needed for accounting.
+ */
+static int vbglR3ClipboardSendDataInternal(HGCMCLIENTID idClient,
+                                           void *pvData, uint64_t cbData, PVBOXCLIPBOARDDATAHDR pDataHdr)
+{
+    AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
+    AssertReturn(cbData,      VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
+
+    VBoxClipboardWriteDataHdrMsg MsgHdr;
+    RT_ZERO(MsgHdr);
+
+    VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_HDR, 12);
+    MsgHdr.uContext.SetUInt32(0);                           /** @todo Not used yet. */
+    MsgHdr.uFlags.SetUInt32(0);                             /** @todo Not used yet. */
+    MsgHdr.uScreenId.SetUInt32(0);                          /** @todo Not used for guest->host (yet). */
+    MsgHdr.cbTotal.SetUInt64(pDataHdr->cbTotal);
+    MsgHdr.cbMeta.SetUInt32(pDataHdr->cbMeta);
+    MsgHdr.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
+    MsgHdr.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
+    MsgHdr.cObjects.SetUInt64(pDataHdr->cObjects);
+    MsgHdr.enmCompression.SetUInt32(0);                     /** @todo Not used yet. */
+    MsgHdr.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */
+    MsgHdr.pvChecksum.SetPtr(NULL, 0);                      /** @todo Not used yet. */
+    MsgHdr.cbChecksum.SetUInt32(0);                         /** @todo Not used yet. */
+
+    int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
+
+    LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32, cObjects=%RU64, rc=%Rrc\n",
+                 pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc));
+
+    if (RT_SUCCESS(rc))
+    {
+        VBoxClipboardWriteDataChunkMsg MsgData;
+        RT_ZERO(MsgData);
+
+        VBGL_HGCM_HDR_INIT(&MsgData.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_CHUNK, 5);
+        MsgData.uContext.SetUInt32(0);      /** @todo Not used yet. */
+        MsgData.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
+        MsgData.cbChecksum.SetUInt32(0);    /** @todo Not used yet. */
+
+        uint32_t       cbCurChunk;
+        const uint32_t cbMaxChunk = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
+        uint32_t       cbSent     = 0;
+
+        HGCMFunctionParameter *pParm = &MsgData.pvData;
+
+        while (cbSent < cbData)
+        {
+            cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
+            pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
+
+            MsgData.cbData.SetUInt32(cbCurChunk);
+
+            rc = VbglR3HGCMCall(&MsgData.hdr, sizeof(MsgData));
+            if (RT_FAILURE(rc))
+                break;
+
+            cbSent += cbCurChunk;
+        }
+
+        LogFlowFunc(("cbMaxChunk=%RU32, cbData=%RU64, cbSent=%RU32, rc=%Rrc\n",
+                     cbMaxChunk, cbData, cbSent, rc));
+
+        if (RT_SUCCESS(rc))
+            Assert(cbSent == cbData);
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Guest -> Host
+ * Utility function to send a guest directory to the host.
+ *
+ * @returns IPRT status code.
+ * @param   idClient        The client id returned by VbglR3ClipboardConnect().
+ * @param   pObj            URI object containing the directory to send.
+ */
+static int vbglR3ClipboardSendDir(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
+{
+    AssertPtrReturn(pObj,                                         VERR_INVALID_POINTER);
+    AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_Directory, VERR_INVALID_PARAMETER);
+
+    RTCString strPath = pObj->GetDestPathAbs();
+    LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
+                 strPath.c_str(), strPath.length(), pObj->GetMode()));
+
+    if (strPath.length() > RTPATH_MAX)
+        return VERR_INVALID_PARAMETER;
+
+    const uint32_t cbPath = (uint32_t)strPath.length() + 1; /* Include termination. */
+
+    VBoxClipboardWriteDirMsg Msg;
+    RT_ZERO(Msg);
+
+    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DIR, 4);
+    /** @todo Context ID not used yet. */
+    Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)cbPath);
+    Msg.cbName.SetUInt32((uint32_t)cbPath);
+    Msg.fMode.SetUInt32(pObj->GetMode());
+
+    return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+}
+
+/**
+ * Guest -> Host
+ * Utility function to send a file from the guest to the host.
+ *
+ * @returns IPRT status code.
+ * @param   idClient            The client id returned by VbglR3ClipboardConnect().
+ * @param   pObj                URI object containing the file to send.
+ */
+static int vbglR3ClipboardSendFile(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
+{
+    AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
+    AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_File, VERR_INVALID_PARAMETER);
+    AssertReturn(pObj->IsOpen(),                             VERR_INVALID_STATE);
+
+    uint32_t cbBuf = _64K;           /** @todo Make this configurable? */
+    void *pvBuf = RTMemAlloc(cbBuf);
+    if (!pvBuf)
+        return VERR_NO_MEMORY;
+
+    RTCString strPath = pObj->GetDestPathAbs();
+
+    LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(),
+                 pObj->GetSize(), pObj->GetMode()));
+
+    VBoxClipboardWriteFileHdrMsg MsgHdr;
+    RT_ZERO(MsgHdr);
+
+    VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_HDR, 6);
+    MsgHdr.uContext.SetUInt32(0);                                                    /* Context ID; unused at the moment. */
+    MsgHdr.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
+    MsgHdr.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
+    MsgHdr.uFlags.SetUInt32(0);                                                      /* Flags; unused at the moment. */
+    MsgHdr.fMode.SetUInt32(pObj->GetMode());                                         /* File mode */
+    MsgHdr.cbTotal.SetUInt64(pObj->GetSize());                                       /* File size (in bytes). */
+
+    int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
+
+    LogFlowFunc(("Sending file header resulted in %Rrc\n", rc));
+
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Send the actual file data, chunk by chunk.
+         */
+        VBoxClipboardWriteFileDataMsg Msg;
+        RT_ZERO(Msg);
+
+        VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_DATA, 5);
+        Msg.uContext.SetUInt32(0);
+        Msg.pvChecksum.SetPtr(NULL, 0);
+        Msg.cbChecksum.SetUInt32(0);
+
+        uint64_t cbToReadTotal  = pObj->GetSize();
+        uint64_t cbWrittenTotal = 0;
+        while (cbToReadTotal)
+        {
+            uint32_t cbToRead = RT_MIN(cbToReadTotal, cbBuf);
+            uint32_t cbRead   = 0;
+            if (cbToRead)
+                rc = pObj->Read(pvBuf, cbToRead, &cbRead);
+
+            LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n",
+                         cbToReadTotal, cbToRead, cbRead, rc));
+
+            if (   RT_SUCCESS(rc)
+                && cbRead)
+            {
+                Msg.pvData.SetPtr(pvBuf, cbRead);
+                Msg.cbData.SetUInt32(cbRead);
+                /** @todo Calculate + set checksums. */
+
+                rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+            }
+
+            if (RT_FAILURE(rc))
+            {
+                LogFlowFunc(("Reading failed with rc=%Rrc\n", rc));
+                break;
+            }
+
+            Assert(cbRead  <= cbToReadTotal);
+            cbToReadTotal  -= cbRead;
+            cbWrittenTotal += cbRead;
+
+            LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, pObj->GetSize(), cbWrittenTotal * 100 / pObj->GetSize()));
+        };
+    }
+
+    RTMemFree(pvBuf);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Guest -> Host
+ * Utility function to send an URI object from guest to the host.
+ *
+ * @returns IPRT status code.
+ * @param   idClient            The client id returned by VbglR3ClipboardConnect().
+ * @param   pObj                URI object to send from guest to the host.
+ */
+static int vbglR3ClipboardSendURIObject(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
+{
+    AssertPtrReturn(pObj, VERR_INVALID_POINTER);
+
+    int rc;
+
+    switch (pObj->GetType())
+    {
+        case SharedClipboardURIObject::Type_Directory:
+            rc = vbglR3ClipboardSendDir(idClient, pObj);
+            break;
+
+        case SharedClipboardURIObject::Type_File:
+            rc = vbglR3ClipboardSendFile(idClient, pObj);
+            break;
+
+        default:
+            AssertMsgFailed(("Object type %ld not implemented\n", pObj->GetType()));
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    return rc;
+}
+
+/**
+ * Guest -> Host
+ * Utility function to send URI data from guest to the host.
+ *
+ * @returns IPRT status code.
+ * @param   idClient            The client id returned by VbglR3ClipboardConnect().
+ * @param   pvData              Block to URI data to send.
+ * @param   cbData              Size (in bytes) of URI data to send.
+ */
+static int vbglR3ClipboardSendURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData)
+{
+    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
+
+    RTCList<RTCString> lstPaths =
+        RTCString((const char *)pvData, cbData).split("\r\n");
+
+    /** @todo Add symlink support (SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS) here. */
+    /** @todo Add lazy loading (SHAREDCLIPBOARDURILIST_FLAGS_LAZY) here. */
+    uint32_t fFlags = SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN;
+
+    SharedClipboardURIList lstURI;
+    int rc = lstURI.AppendURIPathsFromList(lstPaths, fFlags);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * 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.GetRootEntries();
+        if (strRootDest.isNotEmpty())
+        {
+            void *pvURIList  = (void *)strRootDest.c_str(); /* URI root list. */
+            uint32_t cbURLIist = (uint32_t)strRootDest.length() + 1; /* Include string termination. */
+
+            /* The total size also contains the size of the meta data. */
+            uint64_t cbTotal  = cbURLIist;
+                     cbTotal += lstURI.GetTotalBytes();
+
+            /* We're going to send an URI list in text format. */
+            const char     szMetaFmt[] = "text/uri-list";
+            const uint32_t cbMetaFmt   = (uint32_t)strlen(szMetaFmt) + 1; /* Include termination. */
+
+            VBOXCLIPBOARDDATAHDR dataHdr;
+            dataHdr.uFlags    = 0; /* Flags not used yet. */
+            dataHdr.cbTotal   = cbTotal;
+            dataHdr.cbMeta    = cbURLIist;
+            dataHdr.pvMetaFmt = (void *)szMetaFmt;
+            dataHdr.cbMetaFmt = cbMetaFmt;
+            dataHdr.cObjects  = lstURI.GetTotalCount();
+
+            rc = vbglR3ClipboardSendDataInternal(idClient,
+                                                 pvURIList, cbURLIist, &dataHdr);
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        while (!lstURI.IsEmpty())
+        {
+            SharedClipboardURIObject *pNextObj = lstURI.First();
+
+            rc = vbglR3ClipboardSendURIObject(idClient, pNextObj);
+            if (RT_FAILURE(rc))
+                break;
+
+            lstURI.RemoveFirst();
+        }
+    }
+
+    return rc;
+}
+
+/**
+ * Guest -> Host
+ * Sends an error back to the host.
+ *
+ * @returns IPRT status code.
+ * @param   idClient            The client id returned by VbglR3ClipboardConnect().
+ * @param   rcErr               Error (IPRT-style) to send.
+ */
+static int vbglR3ClipboardSendErrorInternal(HGCMCLIENTID idClient, int rcErr)
+{
+    VBoxClipboardWriteErrorMsg Msg;
+    RT_ZERO(Msg);
+
+    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_ERROR, 2);
+    /** @todo Context ID not used yet. */
+    Msg.uContext.SetUInt32(0);
+    Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
+
+    int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+    /*
+     * Never return an error if the host did not accept the error at the current
+     * time.  This can be due to the host not having any appropriate callbacks
+     * set which would handle that error.
+     *
+     * bird: Looks like VERR_NOT_SUPPORTED is what the host will return if it
+     *       doesn't an appropriate callback.  The code used to ignore ALL errors
+     *       the host would return, also relevant ones.
+     */
+    if (RT_FAILURE(rc))
+        LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
+    if (rc == VERR_NOT_SUPPORTED)
+        rc = VINF_SUCCESS;
+
+    return rc;
+}
+
+/**
+ * Guest -> Host
+ * Send an error back to the host.
+ *
+ * @returns IPRT status code.
+ * @param   idClient            The client id returned by VbglR3ClipboardConnect().
+ * @param   rcErr               Error (IPRT-style) to send.
+ */
+VBGLR3DECL(int) VbglR3ClipboardSendError(HGCMCLIENTID idClient, int rcErr)
+{
+    return vbglR3ClipboardSendErrorInternal(idClient, rcErr);
+}
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
+
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp	(revision 78306)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceClipboard-os2.cpp	(revision 78307)
@@ -611,5 +611,5 @@
     }
     VGSvcVerbose(4, "clipboard: reporting fFormats=%#x\n", fFormats);
-    VbglR3ClipboardReportFormats(g_u32ClientId, fFormats);
+    VbglR3ClipboardWriteFormats(g_u32ClientId, fFormats);
 }
 
@@ -658,5 +658,5 @@
                 g_fEmptyClipboard = true;
                 VGSvcVerbose(3, "Reporting empty clipboard\n");
-                VbglR3ClipboardReportFormats(g_u32ClientId, 0);
+                VbglR3ClipboardWriteFormats(g_u32ClientId, 0);
             }
         }
@@ -681,5 +681,5 @@
     g_fEmptyClipboard = true;
     VGSvcVerbose(3, "Reporting empty clipboard\n");
-    VbglR3ClipboardReportFormats(g_u32ClientId, 0);
+    VbglR3ClipboardWriteFormats(g_u32ClientId, 0);
 
     vgsvcClipboardOs2PollViewer();
Index: /trunk/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp	(revision 78306)
+++ /trunk/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp	(revision 78307)
@@ -345,5 +345,5 @@
             be_clipboard->Unlock();
 
-            VbglR3ClipboardReportFormats(fClientId, formats);
+            VbglR3ClipboardWriteFormats(fClientId, formats);
             break;
         }
Index: /trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk	(revision 78306)
+++ /trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk	(revision 78307)
@@ -41,13 +41,4 @@
 	check3d.cpp
 
-ifdef VBOX_WITH_SHARED_CLIPBOARD
- VBoxClient_DEFS += \
-	VBOX_WITH_SHARED_CLIPBOARD
- VBoxClient_SOURCES += \
-	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \
-	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp \
-	clipboard.cpp
-endif
-
 VBoxClient_SOURCES.linux = \
 	chk_stubs.c
@@ -91,4 +82,5 @@
 VBoxClient_DEFS += VBOX_WITH_GUEST_PROPS
 endif
+
 ifdef VBOX_WITH_DRAG_AND_DROP
 VBoxClient_DEFS += \
@@ -100,4 +92,36 @@
 	$(VBOX_LIB_VBGL_R3) \
 	$(PATH_STAGE_LIB)/additions/VBoxDnDGuestR3Lib$(VBOX_SUFF_LIB)
+endif
+
+ifdef VBOX_WITH_SHARED_CLIPBOARD
+ VBoxClient_DEFS += \
+	VBOX_WITH_SHARED_CLIPBOARD \
+	$(if $(VBOX_WITH_SHARED_CLIPBOARD_URI_LIST),VBOX_WITH_SHARED_CLIPBOARD_URI_LIST,)
+ VBoxClient_SOURCES += \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp \
+	clipboard.cpp
+ ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+  ifdef VBOX_WITH_LIBFUSE
+   VBoxClient_SOURCES += \
+	clipboard-fuse.cpp
+   VBoxClient_LIBS += \
+	libfuse
+  endif
+  ifdef VBOX_WITH_LIBGVFS
+  VBoxClient_SOURCES += \
+	clipboard-gvfs.c
+  VBOX_VBOXCLIENT_GVFS_VER:=1.31.92
+  VBoxClient_INCS += \
+ 	gvfs-$(VBOX_VBOXCLIENT_GVFS_VER)/common \
+	gvfs-$(VBOX_VBOXCLIENT_GVFS_VER)/client \
+	gvfs-$(VBOX_VBOXCLIENT_GVFS_VER)/daemon \
+	/usr/lib/x86_64-linux-gnu/glib-2.0/include \
+	/usr/include/glib-2.0
+  VBoxClient_LIBS += \
+	libgio-2.0 \
+	libglib-2.0
+  endif
+ endif
 endif
 
Index: /trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp	(revision 78306)
+++ /trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp	(revision 78307)
@@ -152,5 +152,5 @@
     RT_NOREF1(pCtx);
     LogRelFlowFunc(("u32Formats=%d\n", u32Formats));
-    int rc = VbglR3ClipboardReportFormats(g_ctx.client, u32Formats);
+    int rc = VbglR3ClipboardWriteFormats(g_ctx.client, u32Formats);
     LogRelFlowFunc(("rc=%Rrc\n", rc));
 }
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardFiles.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardFiles.cpp	(revision 78307)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardFiles.cpp	(revision 78307)
@@ -0,0 +1,264 @@
+/* $Id$ */
+/** @file
+ * DnD - Directory handling.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/GuestHost/DragAndDrop.h>
+
+#include <iprt/assert.h>
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
+
+#include <VBox/log.h>
+
+DnDDroppedFiles::DnDDroppedFiles(void)
+    : m_fOpen(0)
+    , m_hDir(NULL) { }
+
+DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
+    : m_fOpen(0)
+    , m_hDir(NULL)
+{
+    OpenEx(pszPath, fFlags);
+}
+
+DnDDroppedFiles::~DnDDroppedFiles(void)
+{
+    /* Only make sure to not leak any handles and stuff, don't delete any
+     * directories / files here. */
+    closeInternal();
+}
+
+int DnDDroppedFiles::AddFile(const char *pszFile)
+{
+    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+
+    if (!this->m_lstFiles.contains(pszFile))
+        this->m_lstFiles.append(pszFile);
+    return VINF_SUCCESS;
+}
+
+int DnDDroppedFiles::AddDir(const char *pszDir)
+{
+    AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
+
+    if (!this->m_lstDirs.contains(pszDir))
+        this->m_lstDirs.append(pszDir);
+    return VINF_SUCCESS;
+}
+
+int DnDDroppedFiles::closeInternal(void)
+{
+    int rc;
+    if (this->m_hDir != NULL)
+    {
+        rc = RTDirClose(this->m_hDir);
+        if (RT_SUCCESS(rc))
+            this->m_hDir = NULL;
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDDroppedFiles::Close(void)
+{
+    return closeInternal();
+}
+
+const char *DnDDroppedFiles::GetDirAbs(void) const
+{
+    return this->m_strPathAbs.c_str();
+}
+
+bool DnDDroppedFiles::IsOpen(void) const
+{
+    return (this->m_hDir != NULL);
+}
+
+int DnDDroppedFiles::OpenEx(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
+{
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+    AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
+
+    int rc;
+
+    do
+    {
+        char pszDropDir[RTPATH_MAX];
+        RTStrPrintf(pszDropDir, sizeof(pszDropDir), "%s", pszPath);
+
+        /** @todo On Windows we also could use the registry to override
+         *        this path, on Posix a dotfile and/or a guest property
+         *        can be used. */
+
+        /* Append our base drop directory. */
+        rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), "VirtualBox Dropped Files"); /** @todo Make this tag configurable? */
+        if (RT_FAILURE(rc))
+            break;
+
+        /* Create it when necessary. */
+        if (!RTDirExists(pszDropDir))
+        {
+            rc = RTDirCreateFullPath(pszDropDir, RTFS_UNIX_IRWXU);
+            if (RT_FAILURE(rc))
+                break;
+        }
+
+        /* The actually drop directory consist of the current time stamp and a
+         * unique number when necessary. */
+        char pszTime[64];
+        RTTIMESPEC time;
+        if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
+        {
+            rc = VERR_BUFFER_OVERFLOW;
+            break;
+        }
+
+        rc = DnDPathSanitizeFilename(pszTime, sizeof(pszTime));
+        if (RT_FAILURE(rc))
+            break;
+
+        rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), pszTime);
+        if (RT_FAILURE(rc))
+            break;
+
+        /* Create it (only accessible by the current user) */
+        rc = RTDirCreateUniqueNumbered(pszDropDir, sizeof(pszDropDir), RTFS_UNIX_IRWXU, 3, '-');
+        if (RT_SUCCESS(rc))
+        {
+            RTDIR hDir;
+            rc = RTDirOpen(&hDir, pszDropDir);
+            if (RT_SUCCESS(rc))
+            {
+                this->m_hDir       = hDir;
+                this->m_strPathAbs = pszDropDir;
+                this->m_fOpen      = fFlags;
+            }
+        }
+
+    } while (0);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDDroppedFiles::OpenTemp(DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
+{
+    AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
+
+    /*
+     * Get the user's temp directory. Don't use the user's root directory (or
+     * something inside it) because we don't know for how long/if the data will
+     * be kept after the guest OS used it.
+     */
+    char szTemp[RTPATH_MAX];
+    int rc = RTPathTemp(szTemp, sizeof(szTemp));
+    if (RT_SUCCESS(rc))
+        rc = OpenEx(szTemp, fFlags);
+
+    return rc;
+}
+
+int DnDDroppedFiles::Reset(bool fRemoveDropDir)
+{
+    int rc = closeInternal();
+    if (RT_SUCCESS(rc))
+    {
+        if (fRemoveDropDir)
+        {
+            rc = Rollback();
+        }
+        else
+        {
+            this->m_lstDirs.clear();
+            this->m_lstFiles.clear();
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDDroppedFiles::Reopen(void)
+{
+    if (this->m_strPathAbs.isEmpty())
+        return VERR_NOT_FOUND;
+
+    return OpenEx(this->m_strPathAbs.c_str(), this->m_fOpen);
+}
+
+int DnDDroppedFiles::Rollback(void)
+{
+    if (this->m_strPathAbs.isEmpty())
+        return VINF_SUCCESS;
+
+    int rc = VINF_SUCCESS;
+
+    /* 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->m_lstFiles.size(); i++)
+    {
+        rc2 = RTFileDelete(this->m_lstFiles.at(i).c_str());
+        if (RT_SUCCESS(rc2))
+            this->m_lstFiles.removeAt(i);
+        else if (RT_SUCCESS(rc))
+           rc = rc2;
+        /* Keep going. */
+    }
+
+    for (size_t i = 0; i < this->m_lstDirs.size(); i++)
+    {
+        rc2 = RTDirRemove(this->m_lstDirs.at(i).c_str());
+        if (RT_SUCCESS(rc2))
+            this->m_lstDirs.removeAt(i);
+        else if (RT_SUCCESS(rc))
+            rc = rc2;
+        /* Keep going. */
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        Assert(this->m_lstFiles.isEmpty());
+        Assert(this->m_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->m_strPathAbs.c_str());
+        }
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardMIME.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardMIME.cpp	(revision 78307)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardMIME.cpp	(revision 78307)
@@ -0,0 +1,43 @@
+/* $Id$ */
+/** @file
+ * DnD - Path list class.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/GuestHost/DragAndDrop.h>
+
+#include <iprt/string.h>
+
+
+bool DnDMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax)
+{
+    /** @todo "text/uri" also an official variant? */
+    return (   RTStrNICmp(pcszFormat, "text/uri-list", cchFormatMax)             == 0
+            || RTStrNICmp(pcszFormat, "x-special/gnome-icon-list", cchFormatMax) == 0);
+}
+
+bool DnDMIMENeedsDropDir(const char *pcszFormat, size_t cchFormatMax)
+{
+    bool fNeedsDropDir = false;
+    if (!RTStrNICmp(pcszFormat, "text/uri-list", cchFormatMax)) /** @todo Add "x-special/gnome-icon-list"? */
+        fNeedsDropDir = true;
+
+    return fNeedsDropDir;
+}
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardPath.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardPath.cpp	(revision 78307)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardPath.cpp	(revision 78307)
@@ -0,0 +1,72 @@
+/* $Id$ */
+/** @file
+ * DnD - Path handling.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/GuestHost/DragAndDrop.h>
+
+#include <iprt/err.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
+
+/**
+ * Sanitizes the file name component so that unsupported characters
+ * will be replaced by an underscore ("_").
+ *
+ * @return  IPRT status code.
+ * @param   pszPath             Path to sanitize.
+ * @param   cbPath              Size (in bytes) of path to sanitize.
+ */
+int DnDPathSanitizeFilename(char *pszPath, size_t cbPath)
+{
+    int rc = VINF_SUCCESS;
+#ifdef RT_OS_WINDOWS
+    RT_NOREF1(cbPath);
+    /* Replace out characters not allowed on Windows platforms, put in by RTTimeSpecToString(). */
+    /** @todo Use something like RTPathSanitize() if available later some time. */
+    static const RTUNICP s_uszValidRangePairs[] =
+    {
+        ' ', ' ',
+        '(', ')',
+        '-', '.',
+        '0', '9',
+        'A', 'Z',
+        'a', 'z',
+        '_', '_',
+        0xa0, 0xd7af,
+        '\0'
+    };
+    ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, s_uszValidRangePairs, '_' /* chReplacement */);
+    if (cReplaced < 0)
+        rc = VERR_INVALID_UTF8_ENCODING;
+#else
+    RT_NOREF2(pszPath, cbPath);
+#endif
+    return rc;
+}
+
+int DnDPathSanitize(char *pszPath, size_t cbPath)
+{
+    /** @todo */
+    RT_NOREF2(pszPath, cbPath);
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIList.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIList.cpp	(revision 78307)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIList.cpp	(revision 78307)
@@ -0,0 +1,562 @@
+/* $Id$ */
+/** @file
+ * DnD - URI list class.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/GuestHost/DragAndDrop.h>
+
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/fs.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/symlink.h>
+#include <iprt/uri.h>
+
+#include <VBox/log.h>
+
+
+DnDURIList::DnDURIList(void)
+    : m_cTotal(0)
+    , m_cbTotal(0)
+{
+}
+
+DnDURIList::~DnDURIList(void)
+{
+    Clear();
+}
+
+int DnDURIList::addEntry(const char *pcszSource, const char *pcszTarget, DNDURILISTFLAGS fFlags)
+{
+    AssertPtrReturn(pcszSource, VERR_INVALID_POINTER);
+    AssertPtrReturn(pcszTarget, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("pcszSource=%s, pcszTarget=%s, fFlags=0x%x\n", pcszSource, pcszTarget, fFlags));
+
+    RTFSOBJINFO objInfo;
+    int rc = RTPathQueryInfo(pcszSource, &objInfo, RTFSOBJATTRADD_NOTHING);
+    if (RT_SUCCESS(rc))
+    {
+        if (RTFS_IS_FILE(objInfo.Attr.fMode))
+        {
+            LogFlowFunc(("File '%s' -> '%s' (%RU64 bytes, file mode 0x%x)\n",
+                         pcszSource, pcszTarget, (uint64_t)objInfo.cbObject, objInfo.Attr.fMode));
+
+            DnDURIObject *pObjFile = new DnDURIObject(DnDURIObject::Type_File, pcszSource, pcszTarget);
+            if (pObjFile)
+            {
+                /** @todo Add a standard fOpen mode for this list. */
+                rc = pObjFile->Open(DnDURIObject::View_Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
+                if (RT_SUCCESS(rc))
+                {
+                    m_lstTree.append(pObjFile);
+
+                    m_cTotal++;
+                    m_cbTotal += pObjFile->GetSize();
+
+                    if (!(fFlags & DNDURILIST_FLAGS_KEEP_OPEN)) /* Shall we keep the file open while being added to this list? */
+                        pObjFile->Close();
+                }
+                else
+                    delete pObjFile;
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+        else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
+        {
+            LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode));
+
+            DnDURIObject *pObjDir = new DnDURIObject(DnDURIObject::Type_Directory, pcszSource, pcszTarget);
+            if (pObjDir)
+            {
+                m_lstTree.append(pObjDir);
+
+                /** @todo Add DNDURILIST_FLAGS_KEEP_OPEN handling? */
+                m_cTotal++;
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+        /* Note: Symlinks already should have been resolved at this point. */
+        else
+            rc = VERR_NOT_SUPPORTED;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDURIList::appendPathRecursive(const char *pcszSrcPath,
+                                    const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase,
+                                    DNDURILISTFLAGS fFlags)
+{
+    AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER);
+    AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER);
+    AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu, fFlags=0x%x\n",
+                 pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase, fFlags));
+
+    RTFSOBJINFO objInfo;
+    int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING);
+    if (RT_SUCCESS(rc))
+    {
+        if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
+        {
+            rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
+            if (RT_SUCCESS(rc))
+            {
+                RTDIR hDir;
+                rc = RTDirOpen(&hDir, pcszSrcPath);
+                if (RT_SUCCESS(rc))
+                {
+                    size_t        cbDirEntry = 0;
+                    PRTDIRENTRYEX pDirEntry  = NULL;
+                    do
+                    {
+                        /* Retrieve the next directory entry. */
+                        rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+                        if (RT_FAILURE(rc))
+                        {
+                            if (rc == VERR_NO_MORE_FILES)
+                                rc = VINF_SUCCESS;
+                            break;
+                        }
+
+                        switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
+                        {
+                            case RTFS_TYPE_DIRECTORY:
+                            {
+                                /* Skip "." and ".." entries. */
+                                if (RTDirEntryExIsStdDotLink(pDirEntry))
+                                    break;
+
+                                char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
+                                if (pszSrc)
+                                {
+                                    char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName);
+                                    if (pszDst)
+                                    {
+                                        rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags);
+                                        RTStrFree(pszDst);
+                                    }
+                                    else
+                                        rc = VERR_NO_MEMORY;
+
+                                    RTStrFree(pszSrc);
+                                }
+                                else
+                                    rc = VERR_NO_MEMORY;
+                                break;
+                            }
+
+                            case RTFS_TYPE_FILE:
+                            {
+                                char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName);
+                                if (pszSrc)
+                                {
+                                    char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName);
+                                    if (pszDst)
+                                    {
+                                        rc = addEntry(pszSrc, &pszDst[cchDstBase], fFlags);
+                                        RTStrFree(pszDst);
+                                    }
+                                    else
+                                        rc = VERR_NO_MEMORY;
+                                    RTStrFree(pszSrc);
+                                }
+                                else
+                                    rc = VERR_NO_MEMORY;
+                                break;
+                            }
+                            case RTFS_TYPE_SYMLINK:
+                            {
+                                if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS)
+                                {
+                                    char *pszSrc = RTPathRealDup(pcszDstBase);
+                                    if (pszSrc)
+                                    {
+                                        rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
+                                        if (RT_SUCCESS(rc))
+                                        {
+                                            if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
+                                            {
+                                                LogFlowFunc(("Directory entry is symlink to directory\n"));
+                                                rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
+                                            }
+                                            else if (RTFS_IS_FILE(objInfo.Attr.fMode))
+                                            {
+                                                LogFlowFunc(("Directory entry is symlink to file\n"));
+                                                rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
+                                            }
+                                            else
+                                                rc = VERR_NOT_SUPPORTED;
+                                        }
+
+                                        RTStrFree(pszSrc);
+                                    }
+                                    else
+                                        rc = VERR_NO_MEMORY;
+                                }
+                                break;
+                            }
+
+                            default:
+                                break;
+                        }
+
+                    } while (RT_SUCCESS(rc));
+
+                    RTDirReadExAFree(&pDirEntry, &cbDirEntry);
+                    RTDirClose(hDir);
+                }
+            }
+        }
+        else if (RTFS_IS_FILE(objInfo.Attr.fMode))
+        {
+            rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags);
+        }
+        else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
+        {
+            if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS)
+            {
+                char *pszSrc = RTPathRealDup(pcszSrcPath);
+                if (pszSrc)
+                {
+                    rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING);
+                    if (RT_SUCCESS(rc))
+                    {
+                        if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
+                        {
+                            LogFlowFunc(("Symlink to directory\n"));
+                            rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags);
+                        }
+                        else if (RTFS_IS_FILE(objInfo.Attr.fMode))
+                        {
+                            LogFlowFunc(("Symlink to file\n"));
+                            rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags);
+                        }
+                        else
+                            rc = VERR_NOT_SUPPORTED;
+                    }
+
+                    RTStrFree(pszSrc);
+                }
+                else
+                    rc = VERR_NO_MEMORY;
+            }
+        }
+        else
+            rc = VERR_NOT_SUPPORTED;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDURIList::AppendNativePath(const char *pszPath, DNDURILISTFLAGS fFlags)
+{
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+
+    int rc;
+    char *pszPathNative = RTStrDup(pszPath);
+    if (pszPathNative)
+    {
+        RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */);
+
+        char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */,
+                                       pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */);
+        if (pszPathURI)
+        {
+            rc = AppendURIPath(pszPathURI, fFlags);
+            RTStrFree(pszPathURI);
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
+
+        RTStrFree(pszPathNative);
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
+                                          DNDURILISTFLAGS fFlags)
+{
+    AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER);
+    AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER);
+
+    RTCList<RTCString> lstPaths
+        = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n");
+    return AppendNativePathsFromList(lstPaths, fFlags);
+}
+
+int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
+                                          DNDURILISTFLAGS fFlags)
+{
+    int rc = VINF_SUCCESS;
+
+    for (size_t i = 0; i < lstNativePaths.size(); i++)
+    {
+        const RTCString &strPath = lstNativePaths.at(i);
+        rc = AppendNativePath(strPath.c_str(), fFlags);
+        if (RT_FAILURE(rc))
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDURIList::AppendURIPath(const char *pszURI, DNDURILISTFLAGS fFlags)
+{
+    AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
+    AssertReturn(!(fFlags & ~DNDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
+    /** @todo Check for string termination?  */
+
+    RTURIPARSED Parsed;
+    int rc = RTUriParse(pszURI, &Parsed);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    char *pszSrcPath = NULL;
+
+    /* file://host.example.com/path/to/file.txt */
+    const char *pszParsedAuthority = RTUriParsedAuthority(pszURI, &Parsed);
+    if (   pszParsedAuthority
+        && pszParsedAuthority[0] != '\0') /* Authority present? */
+    {
+        const char *pszParsedPath = RTUriParsedPath(pszURI, &Parsed);
+        if (pszParsedPath)
+        {
+            /* Always use UNIXy paths internally. */
+            if (RTStrAPrintf(&pszSrcPath,  "//%s%s", pszParsedAuthority, pszParsedPath) == -1)
+                rc = VERR_NO_MEMORY;
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
+    }
+    else
+    {
+        pszSrcPath = RTUriFilePath(pszURI);
+        if (!pszSrcPath)
+            rc = VERR_INVALID_PARAMETER;
+    }
+
+    LogFlowFunc(("pszURI=%s, fFlags=0x%x -> pszParsedAuthority=%s, pszSrcPath=%s, rc=%Rrc\n",
+                 pszURI, fFlags, pszParsedAuthority ? pszParsedAuthority : "<None>", pszSrcPath, rc));
+
+    if (RT_SUCCESS(rc))
+    {
+        /* Add the path to our internal file list (recursive in
+         * the case of a directory). */
+        size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath);
+        if (cbPathLen)
+        {
+            char *pszFileName = RTPathFilename(pszSrcPath);
+            if (pszFileName)
+            {
+                Assert(pszFileName >= pszSrcPath);
+                size_t cchDstBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS)
+                                  ? 0 /* Use start of path as root. */
+                                  : pszFileName - pszSrcPath;
+                char *pszDstPath = &pszSrcPath[cchDstBase];
+                m_lstRoot.append(pszDstPath);
+
+                LogFlowFunc(("pszSrcPath=%s, pszFileName=%s, pszRoot=%s\n",
+                             pszSrcPath, pszFileName, pszDstPath));
+
+                rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags);
+            }
+            else
+                rc = VERR_PATH_NOT_FOUND;
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
+    }
+
+    RTStrFree(pszSrcPath);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
+                                       DNDURILISTFLAGS fFlags)
+{
+    AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
+    AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
+
+    RTCList<RTCString> lstPaths
+        = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
+    return AppendURIPathsFromList(lstPaths, fFlags);
+}
+
+int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
+                                       DNDURILISTFLAGS fFlags)
+{
+    int rc = VINF_SUCCESS;
+
+    for (size_t i = 0; i < lstURI.size(); i++)
+    {
+        RTCString strURI = lstURI.at(i);
+        rc = AppendURIPath(strURI.c_str(), fFlags);
+
+        if (RT_FAILURE(rc))
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+void DnDURIList::Clear(void)
+{
+    m_lstRoot.clear();
+
+    for (size_t i = 0; i < m_lstTree.size(); i++)
+    {
+        DnDURIObject *pCurObj = m_lstTree.at(i);
+        AssertPtr(pCurObj);
+        RTMemFree(pCurObj);
+    }
+    m_lstTree.clear();
+
+    m_cTotal  = 0;
+    m_cbTotal = 0;
+}
+
+void DnDURIList::RemoveFirst(void)
+{
+    if (m_lstTree.isEmpty())
+        return;
+
+    DnDURIObject *pCurObj = m_lstTree.first();
+    AssertPtr(pCurObj);
+
+    uint64_t cbSize = pCurObj->GetSize();
+    Assert(m_cbTotal >= cbSize);
+    m_cbTotal -= cbSize; /* Adjust total size. */
+
+    pCurObj->Close();
+    RTMemFree(pCurObj);
+
+    m_lstTree.removeFirst();
+}
+
+int DnDURIList::SetFromURIData(const void *pvData, size_t cbData, DNDURILISTFLAGS fFlags)
+{
+    Assert(fFlags == 0); RT_NOREF1(fFlags);
+    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+    AssertReturn(cbData, VERR_INVALID_PARAMETER);
+
+    if (!RTStrIsValidEncoding(static_cast<const char *>(pvData)))
+        return VERR_INVALID_PARAMETER;
+
+    RTCList<RTCString> lstURI =
+        RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");
+    if (lstURI.isEmpty())
+        return VINF_SUCCESS;
+
+    int rc = VINF_SUCCESS;
+
+    for (size_t i = 0; i < lstURI.size(); ++i)
+    {
+        /* Query the path component of a file URI. If this hasn't a
+         * file scheme, NULL is returned. */
+        const char *pszURI = lstURI.at(i).c_str();
+        char *pszFilePath = RTUriFilePath(pszURI);
+#ifdef DEBUG_andy
+        LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
+#endif
+        if (pszFilePath)
+        {
+            rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
+            if (RT_SUCCESS(rc))
+            {
+                m_lstRoot.append(pszFilePath);
+                m_cTotal++;
+            }
+
+            RTStrFree(pszFilePath);
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
+
+        if (RT_FAILURE(rc))
+            break;
+    }
+
+    return rc;
+}
+
+RTCString DnDURIList::GetRootEntries(const RTCString &strPathBase /* = "" */,
+                                   const RTCString &strSeparator /* = "\r\n" */) const
+{
+    RTCString strRet;
+    for (size_t i = 0; i < m_lstRoot.size(); i++)
+    {
+        const char *pszCurRoot = m_lstRoot.at(i).c_str();
+#ifdef DEBUG_andy
+        LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));
+#endif
+        if (strPathBase.isNotEmpty())
+        {
+            char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);
+            if (pszPath)
+            {
+                char *pszPathURI = RTUriFileCreate(pszPath);
+                if (pszPathURI)
+                {
+                    strRet += RTCString(pszPathURI) + strSeparator;
+                    LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));
+                    RTStrFree(pszPathURI);
+                }
+
+                RTStrFree(pszPath);
+
+                if (!pszPathURI)
+                    break;
+            }
+            else
+                break;
+        }
+        else
+        {
+            char *pszPathURI = RTUriFileCreate(pszCurRoot);
+            if (pszPathURI)
+            {
+                strRet += RTCString(pszPathURI) + strSeparator;
+                LogFlowFunc(("URI: %s\n", strRet.c_str()));
+                RTStrFree(pszPathURI);
+            }
+            else
+                break;
+        }
+    }
+
+    return strRet;
+}
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIObject.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIObject.cpp	(revision 78307)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIObject.cpp	(revision 78307)
@@ -0,0 +1,579 @@
+/* $Id$ */
+/** @file
+ * DnD - URI object class. For handling creation/reading/writing to files and directories on host or guest side.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_GUEST_DND
+#include <VBox/GuestHost/DragAndDrop.h>
+
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/fs.h>
+#include <iprt/path.h>
+#include <iprt/uri.h>
+
+#include <VBox/log.h>
+
+
+DnDURIObject::DnDURIObject(void)
+    : m_enmType(Type_Unknown)
+    , m_enmView(View_Unknown)
+{
+    RT_ZERO(u);
+}
+
+DnDURIObject::DnDURIObject(Type enmType,
+                           const RTCString &strSrcPathAbs /* = 0 */,
+                           const RTCString &strDstPathAbs /* = 0 */)
+    : m_enmType(enmType)
+    , m_enmView(View_Unknown)
+    , m_strSrcPathAbs(strSrcPathAbs)
+    , m_strTgtPathAbs(strDstPathAbs)
+{
+    RT_ZERO(u);
+
+    switch (m_enmType)
+    {
+        case Type_File:
+        {
+            u.File.hFile = NIL_RTFILE;
+            break;
+        }
+
+        case Type_Directory:
+        {
+            u.Dir.hDir = NIL_RTDIR;
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+DnDURIObject::~DnDURIObject(void)
+{
+    closeInternal();
+}
+
+/**
+ * Closes the object's internal handles (to files / ...).
+ *
+ */
+void DnDURIObject::closeInternal(void)
+{
+    LogFlowThisFuncEnter();
+
+    switch (m_enmType)
+    {
+        case Type_File:
+        {
+            RTFileClose(u.File.hFile);
+            u.File.hFile = NIL_RTFILE;
+            RT_ZERO(u.File.objInfo);
+            break;
+        }
+
+        case Type_Directory:
+        {
+            RTDirClose(u.Dir.hDir);
+            u.Dir.hDir = NIL_RTDIR;
+            RT_ZERO(u.Dir.objInfo);
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+/**
+ * Closes the object.
+ * This also closes the internal handles associated with the object (to files / ...).
+ */
+void DnDURIObject::Close(void)
+{
+    closeInternal();
+}
+
+/**
+ * Returns the directory / file mode of the object.
+ *
+ * @return  File / directory mode.
+ */
+RTFMODE DnDURIObject::GetMode(void) const
+{
+    switch (m_enmType)
+    {
+        case Type_File:
+            return u.File.objInfo.Attr.fMode;
+
+        case Type_Directory:
+            return u.Dir.objInfo.Attr.fMode;
+
+        default:
+            break;
+    }
+
+    AssertFailed();
+    return 0;
+}
+
+/**
+ * Returns the bytes already processed (read / written).
+ *
+ * Note: Only applies if the object is of type DnDURIObject::Type_File.
+ *
+ * @return  Bytes already processed (read / written).
+ */
+uint64_t DnDURIObject::GetProcessed(void) const
+{
+    if (m_enmType == Type_File)
+        return u.File.cbProcessed;
+
+    return 0;
+}
+
+/**
+ * Returns the file's logical size (in bytes).
+ *
+ * Note: Only applies if the object is of type DnDURIObject::Type_File.
+ *
+ * @return  The file's logical size (in bytes).
+ */
+uint64_t DnDURIObject::GetSize(void) const
+{
+    if (m_enmType == Type_File)
+        return u.File.cbToProcess;
+
+    return 0;
+}
+
+/**
+ * Returns whether the processing of the object is complete or not.
+ * For file objects this means that all bytes have been processed.
+ *
+ * @return  True if complete, False if not.
+ */
+bool DnDURIObject::IsComplete(void) const
+{
+    bool fComplete;
+
+    switch (m_enmType)
+    {
+        case Type_File:
+            Assert(u.File.cbProcessed <= u.File.cbToProcess);
+            fComplete = u.File.cbProcessed == u.File.cbToProcess;
+            break;
+
+        case Type_Directory:
+            fComplete = true;
+            break;
+
+        default:
+            fComplete = true;
+            break;
+    }
+
+    return fComplete;
+}
+
+/**
+ * Returns whether the object is in an open state or not.
+ */
+bool DnDURIObject::IsOpen(void) const
+{
+    switch (m_enmType)
+    {
+        case Type_File:      return RTFileIsValid(u.File.hFile);
+        case Type_Directory: return RTDirIsValid(u.Dir.hDir);
+        default:             break;
+    }
+
+    return false;
+}
+
+/**
+ * (Re-)Opens the object with a specific view, open and file mode.
+ *
+ * @return  IPRT status code.
+ * @param   enmView             View to use for opening the object.
+ * @param   fOpen               File open flags to use.
+ * @param   fMode               File mode to use.
+ */
+int DnDURIObject::Open(View enmView, uint64_t fOpen /* = 0 */, RTFMODE fMode /* = 0 */)
+{
+    return OpenEx(  enmView == View_Source
+                  ? m_strSrcPathAbs : m_strTgtPathAbs
+                  , enmView, fOpen, fMode, DNDURIOBJECT_FLAGS_NONE);
+}
+
+/**
+ * Open the object with a specific file type, and, depending on the type, specifying additional parameters.
+ *
+ * @return  IPRT status code.
+ * @param   strPathAbs          Absolute path of the object (file / directory / ...).
+ * @param   enmView             View of the object.
+ * @param   fOpen               Open mode to use; only valid for file objects.
+ * @param   fMode               File mode to use; only valid for file objects.
+ * @param   fFlags              Additional DnD URI object flags.
+ */
+int DnDURIObject::OpenEx(const RTCString &strPathAbs, View enmView,
+                         uint64_t fOpen /* = 0 */, RTFMODE fMode /* = 0 */, DNDURIOBJECTFLAGS fFlags /* = DNDURIOBJECT_FLAGS_NONE */)
+{
+    AssertReturn(!(fFlags & ~DNDURIOBJECT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
+    RT_NOREF1(fFlags);
+
+    int rc = VINF_SUCCESS;
+
+    switch (enmView)
+    {
+        case View_Source:
+            m_strSrcPathAbs = strPathAbs;
+            break;
+
+        case View_Target:
+            m_strTgtPathAbs = strPathAbs;
+            break;
+
+        default:
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    if (   RT_SUCCESS(rc)
+        && fOpen) /* Opening mode specified? */
+    {
+        LogFlowThisFunc(("strPath=%s, enmView=%RU32, fOpen=0x%x, fMode=0x%x, fFlags=0x%x\n",
+                         strPathAbs.c_str(), enmView, fOpen, fMode, fFlags));
+        switch (m_enmType)
+        {
+            case Type_File:
+            {
+                /*
+                 * Open files on the source with RTFILE_O_DENY_WRITE to prevent races
+                 * where the OS writes to the file while the destination side transfers
+                 * it over.
+                 */
+                LogFlowThisFunc(("Opening ...\n"));
+                rc = RTFileOpen(&u.File.hFile, strPathAbs.c_str(), fOpen);
+                if (RT_SUCCESS(rc))
+                {
+                    if (   (fOpen & RTFILE_O_WRITE) /* Only set the file mode on write. */
+                        &&  fMode                   /* Some file mode to set specified? */)
+                    {
+                        rc = RTFileSetMode(u.File.hFile, fMode);
+                    }
+                    else if (fOpen & RTFILE_O_READ)
+                    {
+                        rc = queryInfoInternal(enmView);
+                    }
+                }
+
+                if (RT_SUCCESS(rc))
+                {
+                    LogFlowThisFunc(("File cbObject=%RU64, fMode=0x%x\n",
+                                     u.File.objInfo.cbObject, u.File.objInfo.Attr.fMode));
+                    u.File.cbToProcess = u.File.objInfo.cbObject;
+                    u.File.cbProcessed = 0;
+                }
+
+                break;
+            }
+
+            case Type_Directory:
+            {
+                rc = RTDirOpen(&u.Dir.hDir, strPathAbs.c_str());
+                if (RT_SUCCESS(rc))
+                    rc = queryInfoInternal(enmView);
+                break;
+            }
+
+            default:
+                rc = VERR_NOT_IMPLEMENTED;
+                break;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        m_enmView = enmView;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Queries information about the object using a specific view, internal version.
+ *
+ * @return  IPRT status code.
+ * @param   enmView             View to use for querying information. Currently ignored.
+ */
+int DnDURIObject::queryInfoInternal(View enmView)
+{
+    RT_NOREF(enmView);
+
+    int rc;
+
+    switch (m_enmType)
+    {
+        case Type_File:
+            AssertMsgReturn(RTFileIsValid(u.File.hFile), ("Object has invalid file handle\n"), VERR_INVALID_STATE);
+            rc = RTFileQueryInfo(u.File.hFile, &u.File.objInfo, RTFSOBJATTRADD_NOTHING);
+            break;
+
+        case Type_Directory:
+            AssertMsgReturn(RTDirIsValid(u.Dir.hDir), ("Object has invalid directory handle\n"), VERR_INVALID_STATE);
+            rc = RTDirQueryInfo(u.Dir.hDir, &u.Dir.objInfo, RTFSOBJATTRADD_NOTHING);
+            break;
+
+        default:
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    return rc;
+}
+
+/**
+ * Queries information about the object using a specific view.
+ *
+ * @return  IPRT status code.
+ * @param   enmView             View to use for querying information.
+ */
+int DnDURIObject::QueryInfo(View enmView)
+{
+    return queryInfoInternal(enmView);
+}
+
+/**
+ * Rebases an absolute URI path from an old path base to a new path base.
+ * This function is needed in order to transform path from the source side to the target side.
+ *
+ * @return  IPRT status code.
+ * @param   strPathAbs          Absolute URI path to rebase.
+ * @param   strBaseOld          Old base path to rebase from.
+ * @param   strBaseNew          New base path to rebase to.
+ *
+ ** @todo Put this into an own class like DnDURIPath : public RTCString?
+ */
+/* static */
+int DnDURIObject::RebaseURIPath(RTCString &strPathAbs,
+                                const RTCString &strBaseOld /* = "" */,
+                                const RTCString &strBaseNew /* = "" */)
+{
+    char *pszPath = RTUriFilePath(strPathAbs.c_str());
+    if (!pszPath) /* No URI? */
+         pszPath = RTStrDup(strPathAbs.c_str());
+
+    int rc;
+
+    if (pszPath)
+    {
+        const char *pszPathStart = pszPath;
+        const char *pszBaseOld = strBaseOld.c_str();
+        if (   pszBaseOld
+            && RTPathStartsWith(pszPath, pszBaseOld))
+        {
+            pszPathStart += strlen(pszBaseOld);
+        }
+
+        rc = VINF_SUCCESS;
+
+        if (RT_SUCCESS(rc))
+        {
+            char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart);
+            if (pszPathNew)
+            {
+                char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
+                                               pszPathNew /* pszPath */,
+                                               NULL /* pszQuery */, NULL /* pszFragment */);
+                if (pszPathURI)
+                {
+                    LogFlowFunc(("Rebasing \"%s\" to \"%s\"\n", strPathAbs.c_str(), pszPathURI));
+
+                    strPathAbs = RTCString(pszPathURI) + "\r\n";
+                    RTStrFree(pszPathURI);
+                }
+                else
+                    rc = VERR_INVALID_PARAMETER;
+
+                RTStrFree(pszPathNew);
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+
+        RTStrFree(pszPath);
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+/**
+ * Reads data from the object. Only applies to files objects.
+ *
+ * @return  IPRT status code.
+ * @param   pvBuf               Buffer where to store the read data.
+ * @param   cbBuf               Size (in bytes) of the buffer.
+ * @param   pcbRead             Pointer where to store how many bytes were read. Optional.
+ */
+int DnDURIObject::Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead)
+{
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
+    /* pcbRead is optional. */
+
+    AssertMsgReturn(m_enmView == View_Source, ("Cannot write to an object which is not in target view\n"),
+                    VERR_INVALID_STATE);
+
+    size_t cbRead = 0;
+
+    int rc;
+    switch (m_enmType)
+    {
+        case Type_File:
+        {
+            rc = RTFileRead(u.File.hFile, pvBuf, cbBuf, &cbRead);
+            if (RT_SUCCESS(rc))
+            {
+                u.File.cbProcessed += cbRead;
+                Assert(u.File.cbProcessed <= u.File.cbToProcess);
+
+                /* End of file reached or error occurred? */
+                if (   u.File.cbToProcess
+                    && u.File.cbProcessed == u.File.cbToProcess)
+                {
+                    rc = VINF_EOF;
+                }
+            }
+            break;
+        }
+
+        case Type_Directory:
+        {
+            rc = VINF_SUCCESS;
+            break;
+        }
+
+        default:
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcbRead)
+            *pcbRead = (uint32_t)cbRead;
+    }
+
+    LogFlowFunc(("Returning strSourcePath=%s, cbRead=%zu, rc=%Rrc\n", m_strSrcPathAbs.c_str(), cbRead, rc));
+    return rc;
+}
+
+/**
+ * Resets the object's state and closes all related handles.
+ */
+void DnDURIObject::Reset(void)
+{
+    LogFlowThisFuncEnter();
+
+    Close();
+
+    m_enmType       = Type_Unknown;
+    m_enmView       = View_Unknown;
+    m_strSrcPathAbs = "";
+    m_strTgtPathAbs = "";
+
+    RT_ZERO(u);
+}
+
+/**
+ * Sets the bytes to process by the object.
+ *
+ * Note: Only applies if the object is of type DnDURIObject::Type_File.
+ *
+ * @return  IPRT return code.
+ * @param   cbSize          Size (in bytes) to process.
+ */
+int DnDURIObject::SetSize(uint64_t cbSize)
+{
+    AssertReturn(m_enmType == Type_File, VERR_INVALID_PARAMETER);
+
+    /** @todo Implement sparse file support here. */
+
+    u.File.cbToProcess = cbSize;
+    return VINF_SUCCESS;
+}
+
+/**
+ * Writes data to an object. Only applies to file objects.
+ *
+ * @return  IPRT status code.
+ * @param   pvBuf               Buffer of data to write.
+ * @param   cbBuf               Size (in bytes) of data to write.
+ * @param   pcbWritten          Pointer where to store how many bytes were written. Optional.
+ */
+int DnDURIObject::Write(const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten)
+{
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
+    /* pcbWritten is optional. */
+
+    AssertMsgReturn(m_enmView == View_Target, ("Cannot write to an object which is not in target view\n"),
+                    VERR_INVALID_STATE);
+
+    size_t cbWritten = 0;
+
+    int rc;
+    switch (m_enmType)
+    {
+        case Type_File:
+        {
+            rc = RTFileWrite(u.File.hFile, pvBuf, cbBuf, &cbWritten);
+            if (RT_SUCCESS(rc))
+                u.File.cbProcessed += cbWritten;
+            break;
+        }
+
+        case Type_Directory:
+        {
+            rc = VINF_SUCCESS;
+            break;
+        }
+
+        default:
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcbWritten)
+            *pcbWritten = (uint32_t)cbWritten;
+    }
+
+    LogFlowThisFunc(("Returning strSourcePathAbs=%s, cbWritten=%zu, rc=%Rrc\n", m_strSrcPathAbs.c_str(), cbWritten, rc));
+    return rc;
+}
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp	(revision 78306)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp	(revision 78307)
@@ -303,4 +303,9 @@
                     break;
 
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+                case CF_HDROP:
+                    uFormats |= VBOX_SHARED_CLIPBOARD_FMT_URI_LIST;
+                    break;
+#endif
                 default:
                 {
Index: /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk	(revision 78306)
+++ /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk	(revision 78307)
@@ -27,5 +27,7 @@
 DLLS += VBoxSharedClipboard
 VBoxSharedClipboard_TEMPLATE  = VBOXR3
-VBoxSharedClipboard_DEFS      = VBOX_WITH_HGCM
+VBoxSharedClipboard_DEFS      = \
+	VBOX_WITH_HGCM \
+	$(if $(VBOX_WITH_SHARED_CLIPBOARD_URI_LIST),VBOX_WITH_SHARED_CLIPBOARD_URI_LIST,)
 VBoxSharedClipboard_INCS.win  = \
 	$(VBOX_PATH_SDK)
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 78306)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 78307)
@@ -32,5 +32,10 @@
 #include <iprt/thread.h>
 #include <iprt/ldr.h>
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+# include <iprt/utf16.h>
+#endif
+
 #include <process.h>
+#include <shlobj.h> /* Needed for shell objects. */
 
 #include "VBoxClipboard.h"
@@ -112,5 +117,5 @@
     LogFlow(("vboxClipboardGetData cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
 
-    if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
+    if (   u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
         && IsWindowsHTML((const char *)pvSrc))
     {
@@ -134,4 +139,10 @@
             *pcbActualDst = 0;
     }
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+    if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+    {
+        /* Convert data to URI list. */
+    }
+#endif
     else
     {
@@ -283,5 +294,5 @@
             UINT format = (UINT)wParam;
 
-            Log(("WM_RENDERFORMAT %d\n", format));
+            Log(("WM_RENDERFORMAT: Format %u\n", format));
 
             switch (format)
@@ -298,14 +309,15 @@
                     if (format >= 0xC000)
                     {
-                        TCHAR szFormatName[256];
-
-                        int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
-
+                        TCHAR szFormatName[256]; /** @todo r=andy Unicode, 256 is enough? */
+                        int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName) / sizeof (TCHAR));
                         if (cActual)
                         {
-                            if (strcmp (szFormatName, "HTML Format") == 0)
-                            {
+                            if (RTStrCmp(szFormatName, "HTML Format") == 0)
                                 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
-                            }
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+                            if (   RTStrCmp(szFormatName, CFSTR_FILEDESCRIPTOR) == 0
+                                || RTStrCmp(szFormatName, CFSTR_FILECONTENTS) == 0)
+                                u32Format |= VBOX_SHARED_CLIPBOARD_FMT_URI_LIST;
+#endif
                         }
                     }
@@ -321,5 +333,5 @@
             else
             {
-                int vboxrc = vboxClipboardReadDataFromClient (pCtx, u32Format);
+                int vboxrc = vboxClipboardReadDataFromClient(pCtx, u32Format);
 
                 LogFunc(("vboxClipboardReadDataFromClient vboxrc = %d, pv %p, cb %d, u32Format %d\n",
@@ -331,5 +343,5 @@
                     && pCtx->pClient->data.u32Format == u32Format)
                 {
-                    HANDLE hMem = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClient->data.cb);
+                    HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClient->data.cb);
 
                     LogFunc(("hMem %p\n", hMem));
@@ -337,7 +349,7 @@
                     if (hMem)
                     {
-                        void *pMem = GlobalLock (hMem);
-
-                        LogFunc(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
+                        void *pMem = GlobalLock(hMem);
+
+                        LogFunc(("pMem %p, GlobalSize %d\n", pMem, GlobalSize(hMem)));
 
                         if (pMem)
@@ -347,7 +359,7 @@
                             if (pCtx->pClient->data.pv)
                             {
-                                memcpy (pMem, pCtx->pClient->data.pv, pCtx->pClient->data.cb);
-
-                                RTMemFree (pCtx->pClient->data.pv);
+                                memcpy(pMem, pCtx->pClient->data.pv, pCtx->pClient->data.cb);
+
+                                RTMemFree(pCtx->pClient->data.pv);
                                 pCtx->pClient->data.pv        = NULL;
                             }
@@ -357,10 +369,10 @@
 
                             /* The memory must be unlocked before inserting to the Clipboard. */
-                            GlobalUnlock (hMem);
+                            GlobalUnlock(hMem);
 
                             /* 'hMem' contains the host clipboard data.
                              * size is 'cb' and format is 'format'.
                              */
-                            HANDLE hClip = SetClipboardData (format, hMem);
+                            HANDLE hClip = SetClipboardData(format, hMem);
 
                             LogFunc(("vboxClipboardHostEvent hClip %p\n", hClip));
@@ -373,9 +385,9 @@
                         }
 
-                        GlobalFree (hMem);
+                        GlobalFree(hMem);
                     }
                 }
 
-                RTMemFree (pCtx->pClient->data.pv);
+                RTMemFree(pCtx->pClient->data.pv);
                 pCtx->pClient->data.pv        = NULL;
                 pCtx->pClient->data.cb        = 0;
@@ -446,4 +458,12 @@
                 }
 
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+                {
+                    UINT format = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
+                    if (format)
+                        hClip = SetClipboardData(format, NULL);
+                }
+#endif
                 VBoxClipboardWinClose();
 
@@ -590,5 +610,5 @@
     g_ctx.hRenderEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
-    rc = RTThreadCreate(&g_ctx.hThread, VBoxClipboardThread, NULL, 65536,
+    rc = RTThreadCreate(&g_ctx.hThread, VBoxClipboardThread, NULL, _64K /* Stack size */,
                         RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
 
@@ -788,5 +808,169 @@
             }
         }
-
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+        else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+        {
+    #if 0
+            UINT format = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
+            if (format)
+            {
+                hClip = GetClipboardData(format);
+                if (hClip != NULL)
+                {
+                    LPVOID lp = GlobalLock(hClip);
+
+                    if (lp != NULL)
+                    {
+                        LogFunc(("CF_HTML\n"));
+
+                        vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip),
+                                             pv, cb, pcbActual);
+                        LogRelFlowFunc(("Raw HTML clipboard data from host :"));
+                        DumpHtml((char *)pv, cb);
+                        GlobalUnlock(hClip);
+                    }
+                    else
+                    {
+                        hClip = NULL;
+                    }
+                }
+            }
+    #else
+            /* Convert to a string list, separated by \r\n. */
+            DROPFILES *pDropFiles = (DROPFILES *)hClip;
+            AssertPtr(pDropFiles);
+
+            /* Do we need to do Unicode stuff? */
+            const bool fUnicode = RT_BOOL(pDropFiles->fWide);
+
+            /* Get the offset of the file list. */
+            Assert(pDropFiles->pFiles >= sizeof(DROPFILES));
+
+            /* Note: This is *not* pDropFiles->pFiles! DragQueryFile only
+             *       will work with the plain storage medium pointer! */
+            HDROP hDrop = (HDROP)(hClip);
+
+            /* First, get the file count. */
+            /** @todo Does this work on Windows 2000 / NT4? */
+            char *pszFiles = NULL;
+            uint32_t cchFiles = 0;
+            UINT cFiles = DragQueryFile(hDrop, UINT32_MAX /* iFile */, NULL /* lpszFile */, 0 /* cchFile */);
+
+            LogRel(("DnD: Got %RU16 file(s), fUnicode=%RTbool\n", cFiles, fUnicode));
+
+            for (UINT i = 0; i < cFiles; i++)
+            {
+                UINT cchFile = DragQueryFile(hDrop, i /* File index */, NULL /* Query size first */, 0 /* cchFile */);
+                Assert(cchFile);
+
+                if (RT_FAILURE(rc))
+                    break;
+
+                char *pszFileUtf8 = NULL; /* UTF-8 version. */
+                UINT cchFileUtf8 = 0;
+                if (fUnicode)
+                {
+                    /* Allocate enough space (including terminator). */
+                    WCHAR *pwszFile = (WCHAR *)RTMemAlloc((cchFile + 1) * sizeof(WCHAR));
+                    if (pwszFile)
+                    {
+                        const UINT cwcFileUtf16 = DragQueryFileW(hDrop, i /* File index */,
+                                                                 pwszFile, cchFile + 1 /* Include terminator */);
+
+                        AssertMsg(cwcFileUtf16 == cchFile, ("cchFileUtf16 (%RU16) does not match cchFile (%RU16)\n",
+                                                            cwcFileUtf16, cchFile));
+                        RT_NOREF(cwcFileUtf16);
+
+                        rc = RTUtf16ToUtf8(pwszFile, &pszFileUtf8);
+                        if (RT_SUCCESS(rc))
+                        {
+                            cchFileUtf8 = (UINT)strlen(pszFileUtf8);
+                            Assert(cchFileUtf8);
+                        }
+
+                        RTMemFree(pwszFile);
+                    }
+                    else
+                        rc = VERR_NO_MEMORY;
+                }
+                else /* ANSI */
+                {
+                    /* Allocate enough space (including terminator). */
+                    pszFileUtf8 = (char *)RTMemAlloc((cchFile + 1) * sizeof(char));
+                    if (pszFileUtf8)
+                    {
+                        cchFileUtf8 = DragQueryFileA(hDrop, i /* File index */,
+                                                     pszFileUtf8, cchFile + 1 /* Include terminator */);
+
+                        AssertMsg(cchFileUtf8 == cchFile, ("cchFileUtf8 (%RU16) does not match cchFile (%RU16)\n",
+                                                           cchFileUtf8, cchFile));
+                    }
+                    else
+                        rc = VERR_NO_MEMORY;
+                }
+
+                if (RT_SUCCESS(rc))
+                {
+                    LogFlowFunc(("\tFile: %s (cchFile=%RU16)\n", pszFileUtf8, cchFileUtf8));
+
+                    LogRel(("DnD: Adding guest file '%s'\n", pszFileUtf8));
+
+                    rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, pszFileUtf8, cchFileUtf8);
+                    if (RT_SUCCESS(rc))
+                        cchFiles += cchFileUtf8;
+                }
+                else
+                    LogRel(("DnD: Error handling file entry #%u, rc=%Rrc\n", i, rc));
+
+                if (pszFileUtf8)
+                    RTStrFree(pszFileUtf8);
+
+                if (RT_FAILURE(rc))
+                    break;
+
+                /* Add separation between filenames.
+                 * Note: Also do this for the last element of the list. */
+                rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, "\r\n", 2 /* Bytes */);
+                if (RT_SUCCESS(rc))
+                    cchFiles += 2; /* Include \r\n */
+            }
+
+            if (RT_SUCCESS(rc))
+            {
+                cchFiles += 1; /* Add string termination. */
+                uint32_t cbFiles = cchFiles * sizeof(char);
+
+                LogFlowFunc(("cFiles=%u, cchFiles=%RU32, cbFiles=%RU32, pszFiles=0x%p\n",
+                             cFiles, cchFiles, cbFiles, pszFiles));
+
+                /* Translate the list into URI elements. */
+                DnDURIList lstURI;
+                rc = lstURI.AppendNativePathsFromList(pszFiles, cbFiles,
+                                                      DNDURILIST_FLAGS_ABSOLUTE_PATHS);
+                if (RT_SUCCESS(rc))
+                {
+                    RTCString strRoot = lstURI.GetRootEntries();
+                    size_t cbRoot = strRoot.length() + 1; /* Include termination */
+
+                    mpvData = RTMemAlloc(cbRoot);
+                    if (mpvData)
+                    {
+                        memcpy(mpvData, strRoot.c_str(), cbRoot);
+                        mcbData = cbRoot;
+                    }
+                    else
+                        rc = VERR_NO_MEMORY;
+                }
+            }
+
+            LogFlowFunc(("Building CF_HDROP list rc=%Rrc, pszFiles=0x%p, cFiles=%RU16, cchFiles=%RU32\n",
+                         rc, pszFiles, cFiles, cchFiles));
+
+            if (pszFiles)
+                RTStrFree(pszFiles);
+            break;
+    #endif /* 0 */
+        }
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
         VBoxClipboardWinClose();
     }
@@ -893,6 +1077,6 @@
 
 
-/*
- * Converts clipboard data from CF_HTML format to mimie clipboard format
+/**
+ * Converts clipboard data from CF_HTML format to MIME clipboard format.
  *
  * Returns allocated buffer that contains html converted to text/html mime type
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 78306)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp	(revision 78307)
@@ -484,5 +484,5 @@
         } break;
 
-        case VBOX_SHARED_CLIPBOARD_FN_FORMATS:
+        case VBOX_SHARED_CLIPBOARD_FN_WRITE_FORMATS:
         {
             /* The guest reports that some formats are available. */
