Index: /trunk/include/VBox/GuestHost/SharedClipboard-uri.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-uri.h	(revision 79701)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-uri.h	(revision 79702)
@@ -382,5 +382,5 @@
     /** Size (in bytes) of string list. */
     uint32_t cbRoots;
-    /** String list (separated with CRLF) containing the root items. */
+    /** String list (separated with \r\n) containing the root items. */
     char    *pszRoots;
 } VBOXCLIPBOARDROOTS, *PVBOXCLIPBOARDROOTS;
@@ -699,8 +699,8 @@
     SHAREDCLIPBOARDURITRANSFEREVENTTYPE_LIST_ENTRY_READ,
     SHAREDCLIPBOARDURITRANSFEREVENTTYPE_LIST_ENTRY_WRITE,
-    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_FILE_OPEN,
-    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_FILE_CLOSE,
-    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_FILE_READ,
-    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_FILE_WRITE,
+    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_OBJ_OPEN,
+    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_OBJ_CLOSE,
+    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_OBJ_READ,
+    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_OBJ_WRITE,
     SHAREDCLIPBOARDURITRANSFEREVENTTYPE_ERROR,
     /** Marks the end of the event list. */
@@ -814,7 +814,4 @@
 SHAREDCLIPBOARDPROVIDERFUNCDECL(OBJREAD, SHAREDCLIPBOARDOBJHANDLE hObj, void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
 SHAREDCLIPBOARDPROVIDERFUNCDECL(OBJWRITE, SHAREDCLIPBOARDOBJHANDLE hObj, void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
-SHAREDCLIPBOARDPROVIDERFUNCDECLRET(uint64_t, OBJGETSIZE, SHAREDCLIPBOARDOBJHANDLE hObj)
-SHAREDCLIPBOARDPROVIDERFUNCDECLRET(uint64_t, OBJGETPROCESSED, SHAREDCLIPBOARDOBJHANDLE hObj)
-SHAREDCLIPBOARDPROVIDERFUNCDECLRET(const char *, OBJGETPATH, SHAREDCLIPBOARDOBJHANDLE hObj)
 
 /**
@@ -836,7 +833,4 @@
     SHAREDCLIPBOARDPROVIDERFUNCMEMBER(OBJREAD, pfnObjRead);
     SHAREDCLIPBOARDPROVIDERFUNCMEMBER(OBJWRITE, pfnObjWrite);
-    SHAREDCLIPBOARDPROVIDERFUNCMEMBER(OBJGETSIZE, pfnObjGetSize);
-    SHAREDCLIPBOARDPROVIDERFUNCMEMBER(OBJGETPROCESSED, pfnObjGetProcessed);
-    SHAREDCLIPBOARDPROVIDERFUNCMEMBER(OBJGETPATH, pfnObjGetPath);
 } SHAREDCLIPBOARDPROVIDERINTERFACE, *PSHAREDCLIPBOARDPROVIDERINTERFACE;
 
@@ -1056,2 +1050,3 @@
 
 #endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_uri_h */
+
Index: /trunk/include/VBox/GuestHost/SharedClipboard-win.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 79701)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 79702)
@@ -36,10 +36,15 @@
 
 # ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+#  include <vector>
+
 #  include <iprt/cpp/ministring.h> /* For RTCString. */
-#  include <iprt/win/shlobj.h> /* For DROPFILES and friends. */
+#  include <iprt/win/shlobj.h>     /* For DROPFILES and friends. */
+#  include <VBox/com/string.h>     /* For Utf8Str. */
 #  include <oleidl.h>
 
 # include <VBox/GuestHost/SharedClipboard-uri.h>
-# endif
+
+using namespace com;
+# endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
 
 #ifndef WM_CLIPBOARDUPDATE
@@ -163,14 +168,4 @@
     };
 
-    enum FormatIndex
-    {
-        /** File descriptor, ANSI version. */
-        FormatIndex_FileDescriptorA = 0,
-        /** File descriptor, Unicode version. */
-        FormatIndex_FileDescriptorW,
-        /** File contents. */
-        FormatIndex_FileContents
-    };
-
 public:
 
@@ -232,4 +227,18 @@
 protected:
 
+    /**
+     * Structure for keeping a single file system object entry.
+     */
+    struct FSOBJENTRY
+    {
+        /** Relative path of the object. */
+        Utf8Str                  strPath;
+        /** Related (cached) object information. */
+        SHAREDCLIPBOARDFSOBJINFO objInfo;
+    };
+
+    /** Vector containing file system objects with its (cached) objection information. */
+    typedef std::vector<FSOBJENTRY> FsObjEntryList;
+
     Status                      m_enmStatus;
     LONG                        m_lRefCount;
@@ -240,7 +249,13 @@
     IStream                    *m_pStream;
     ULONG                       m_uObjIdx;
-    /** Event being triggered when reading the transfer list been completed.*/
+    /** List of (cached) file system root objects. */
+    FsObjEntryList              m_lstRootEntries;
+    /** Event being triggered when reading the transfer list been completed. */
     RTSEMEVENT                  m_EventListComplete;
+    /** Event being triggered when the transfer has been completed. */
     RTSEMEVENT                  m_EventTransferComplete;
+    UINT                        m_cfFileDescriptorA;
+    UINT                        m_cfFileDescriptorW;
+    UINT                        m_cfFileContents;
 };
 
@@ -286,6 +301,6 @@
 public:
 
-    VBoxClipboardWinStreamImpl(VBoxClipboardWinDataObject *pParent,
-                               PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDOBJHANDLE hObj);
+    VBoxClipboardWinStreamImpl(VBoxClipboardWinDataObject *pParent, PSHAREDCLIPBOARDURITRANSFER pTransfer,
+                               const Utf8Str &strPath, PSHAREDCLIPBOARDFSOBJINFO pObjInfo);
     virtual ~VBoxClipboardWinStreamImpl(void);
 
@@ -312,7 +327,6 @@
 public: /* Own methods. */
 
-    static HRESULT Create(VBoxClipboardWinDataObject *pParent,
-                          PSHAREDCLIPBOARDURITRANSFER pTransfer, uint64_t uObjIdx, IStream **ppStream);
-
+    static HRESULT Create(VBoxClipboardWinDataObject *pParent, PSHAREDCLIPBOARDURITRANSFER pTransfer, const Utf8Str &strPath,
+                          PSHAREDCLIPBOARDFSOBJINFO pObjInfo, IStream **ppStream);
 private:
 
@@ -323,6 +337,14 @@
     /** Pointer to the associated URI transfer. */
     PSHAREDCLIPBOARDURITRANSFER    m_pURITransfer;
-    /** Handle to the associated URI object. */
+    /** The object handle to use. */
     SHAREDCLIPBOARDOBJHANDLE       m_hObj;
+    /** Object path. */
+    Utf8Str                        m_strPath;
+    /** (Cached) object information. */
+    SHAREDCLIPBOARDFSOBJINFO       m_objInfo;
+    /** Number of bytes already processed. */
+    uint64_t                       m_cbProcessed;
+    /** Whether we already notified the parent of completion or not. */
+    bool                           m_fNotifiedComplete;
 };
 
Index: /trunk/include/VBox/HostServices/VBoxClipboardSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/VBoxClipboardSvc.h	(revision 79701)
+++ /trunk/include/VBox/HostServices/VBoxClipboardSvc.h	(revision 79702)
@@ -361,5 +361,7 @@
 #define VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_INVALID           0
 #define VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_LIST_OPEN         1
-#define VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_OBJ_OPEN          2
+#define VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_LIST_CLOSE        2
+#define VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_OBJ_OPEN          3
+#define VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_OBJ_CLOSE         4
 
 /**
@@ -413,5 +415,5 @@
     /** uin32_t, out: Size (in bytes) of string list. */
     HGCMFunctionParameter cbRoots;
-    /** pointer, out: string list (separated with CRLF) containing the root items. */
+    /** pointer, out: string list (separated with \r\n) containing the root items. */
     HGCMFunctionParameter pvRoots;
 } VBoxClipboardRootsMsg;
@@ -650,2 +652,3 @@
 
 #endif /* !VBOX_INCLUDED_HostServices_VBoxClipboardSvc_h */
+
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 79701)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 79702)
@@ -801,5 +801,6 @@
                                if (RT_SUCCESS(rc))
                                {
-                                   rc = SharedClipboardURILTransferSetRoots(pTransfer, papszList, cbList);
+                                   rc = SharedClipboardURILTransferSetRoots(pTransfer,
+                                                                            papszList, cbList + 1 /* Include termination */);
                                    if (RT_SUCCESS(rc))
                                    {
Index: /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 79701)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp	(revision 79702)
@@ -423,4 +423,26 @@
 }
 
+VBGLR3DECL(int) VbglR3ClipboardListCloseReply(HGCMCLIENTID idClient, int rcReply, SHAREDCLIPBOARDLISTHANDLE hList)
+{
+    VBoxClipboardReplyMsg Msg;
+    RT_ZERO(Msg);
+
+    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
+                       VBOX_SHARED_CLIPBOARD_GUEST_FN_REPLY, 6);
+
+    Msg.uContext.SetUInt32(0); /** @todo Context ID not used yet. */
+    Msg.enmType.SetUInt32(VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_LIST_CLOSE);
+    Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
+    Msg.cbPayload.SetUInt32(0);
+    Msg.pvPayload.SetPtr(0, NULL);
+
+    Msg.u.ListOpen.uHandle.SetUInt64(hList);
+
+    int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
 VBGLR3DECL(int) VbglR3ClipboardListCloseSend(HGCMCLIENTID idClient, SHAREDCLIPBOARDLISTHANDLE hList)
 {
@@ -671,5 +693,5 @@
                     if (RT_SUCCESS(rc))
                     {
-                        /** @todo Handle fFlags. */
+                        /** @todo Handle Roots.fRoots flags. */
 
                         char    *pszRoots = NULL;
@@ -680,6 +702,9 @@
                             /** @todo Split up transfers in _64K each. */
 
-                            rc = VbglR3ClipboardRootsWrite(idClient, cRoots,
-                                                           pszRoots, pszRoots ? (uint32_t)strlen(pszRoots) : NULL);
+                            const uint32_t cbRoots = pszRoots
+                                                   ? (uint32_t)strlen(pszRoots) + 1 /* Include termination. */
+                                                   : 0;
+
+                            rc = VbglR3ClipboardRootsWrite(idClient, cRoots, pszRoots, cbRoots);
                         }
                     }
@@ -725,4 +750,8 @@
                 {
                     rc = SharedClipboardURITransferListClose(pTransfer, hList);
+
+                    /* Reply in any case. */
+                    int rc2 = VbglR3ClipboardListCloseReply(idClient, rc, hList);
+                    AssertRC(rc2);
                 }
 
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 79701)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 79702)
@@ -43,11 +43,12 @@
 #include <VBox/log.h>
 
-/** Also handle Unicode entries. */
-#define VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 1
+/** @todo Also handle Unicode entries.
+ *        !!! WARNING: Buggy, doesn't work yet (some memory corruption / garbage in the file name descriptions) !!! */
+//#define VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 0
 
 VBoxClipboardWinDataObject::VBoxClipboardWinDataObject(PSHAREDCLIPBOARDURITRANSFER pTransfer,
                                                        LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
     : m_enmStatus(Uninitialized)
-    , m_lRefCount(1)
+    , m_lRefCount(0)
     , m_cFormats(0)
     , m_pTransfer(pTransfer)
@@ -77,18 +78,19 @@
          * Register fixed formats.
          */
+        unsigned uIdx = 0;
 
         LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n"));
-        registerFormat(&m_pFormatEtc[FormatIndex_FileDescriptorA],
-                       RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA));
+        m_cfFileDescriptorA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
+        registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorA);
 #ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
         LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n"));
-        registerFormat(&m_pFormatEtc[FormatIndex_FileDescriptorW],
-                       RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW));
+        m_cfFileDescriptorW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
+        registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorW);
 #endif
+
         /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */
         LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n"));
-        registerFormat(&m_pFormatEtc[FormatIndex_FileContents],
-                       RegisterClipboardFormat(CFSTR_FILECONTENTS),
-                       TYMED_ISTREAM, 0 /* lIndex */);
+        m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
+        registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */);
 
         /*
@@ -296,4 +298,7 @@
 
                                     LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
+
+                                    FSOBJENTRY objEntry = { entryList.pszName, *pObjInfo };
+                                    pThis->m_lstRootEntries.push_back(objEntry); /** @todo Can this throw? */
                                 }
                                 else
@@ -362,7 +367,8 @@
     const size_t cbFileDescriptor = fUnicode ? sizeof(FILEDESCRIPTORW) : sizeof(FILEDESCRIPTORA);
 
-    const UINT   cItems = (UINT)0; /** @todo UINT vs. uint64_t */
+    const UINT   cItems = (UINT)m_lstRootEntries.size(); /** UINT vs. size_t. */
     if (!cItems)
         return VERR_NOT_FOUND;
+          UINT   curIdx = 0; /* Current index of the handled file group descriptor (FGD). */
 
     const size_t cbFGD  = cbFileGroupDescriptor + (cbFileDescriptor * (cItems - 1));
@@ -371,5 +377,5 @@
 
     /* FILEGROUPDESCRIPTORA / FILEGROUPDESCRIPTOR matches except the cFileName member (TCHAR vs. WCHAR). */
-    FILEGROUPDESCRIPTOR *pFGD = (FILEGROUPDESCRIPTOR *)RTMemAlloc(cbFGD);
+    FILEGROUPDESCRIPTOR *pFGD = (FILEGROUPDESCRIPTOR *)RTMemAllocZ(cbFGD);
     if (!pFGD)
         return VERR_NO_MEMORY;
@@ -380,13 +386,12 @@
 
     char *pszFileSpec = NULL;
-#if 0
-    for (UINT i = 0; i < cItems; i++)
-    {
-        FILEDESCRIPTOR *pFD = &pFGD->fgd[i];
+
+    FsObjEntryList::const_iterator itRoot = m_lstRootEntries.begin();
+    while (itRoot != m_lstRootEntries.end())
+    {
+        FILEDESCRIPTOR *pFD = &pFGD->fgd[curIdx];
         RT_BZERO(pFD, cbFileDescriptor);
 
-        const SharedClipboardURIObject *pObj = pURIList->At(i);
-        AssertPtr(pObj);
-        const char *pszFile = pObj->GetSourcePathAbs().c_str();
+        const char *pszFile = itRoot->strPath.c_str();
         AssertPtr(pszFile);
 
@@ -403,8 +408,13 @@
                                    pwszFileSpec, RTUtf16Len(pwszFileSpec));
                 RTUtf16Free(pwszFileSpec);
+
+                LogFlowFunc(("pFD->cFileNameW=%ls\n", pFD->cFileName));
             }
         }
         else
+        {
             rc = RTStrCopy(pFD->cFileName, sizeof(pFD->cFileName), pszFileSpec);
+            LogFlowFunc(("pFD->cFileNameA=%s\n", pFD->cFileName));
+        }
 
         RTStrFree(pszFileSpec);
@@ -419,31 +429,25 @@
         pFD->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
 
-        switch (pObj->GetType())
-        {
-            case SharedClipboardURIObject::Type_Directory:
-                pFD->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
-
-                LogFunc(("pszDir=%s\n", pszFile));
-                break;
-
-            case SharedClipboardURIObject::Type_File:
-            {
-                pFD->dwFlags |= FD_FILESIZE;
-
-                const uint64_t cbObjSize = pObj->GetSize();
-
-                pFD->nFileSizeHigh = RT_HI_U32(cbObjSize);
-                pFD->nFileSizeLow  = RT_LO_U32(cbObjSize);
-
-                LogFunc(("pszFile=%s, cbObjSize=%RU64\n", pszFile, cbObjSize));
-                break;
-            }
-
-            default:
-                AssertFailed();
-                break;
-        }
-#if 0
-        pFD->dwFlags = FD_ATTRIBUTES | FD_CREATETIME | FD_ACCESSTIME | FD_WRITESTIME | FD_FILESIZE; /** @todo Implement this. */
+        const SHAREDCLIPBOARDFSOBJINFO *pObjInfo = &itRoot->objInfo;
+
+        if (RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
+        {
+            pFD->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+        }
+        else if (RTFS_IS_FILE(pObjInfo->Attr.fMode))
+        {
+            pFD->dwFlags |= FD_FILESIZE;
+
+            const uint64_t cbObjSize = pObjInfo->cbObject;
+
+            pFD->nFileSizeHigh = RT_HI_U32(cbObjSize);
+            pFD->nFileSizeLow  = RT_LO_U32(cbObjSize);
+        }
+        else if (RTFS_IS_SYMLINK(pObjInfo->Attr.fMode))
+        {
+            /** @todo Implement. */
+        }
+#if 0 /** @todo Implement this. */
+        pFD->dwFlags = FD_ATTRIBUTES | FD_CREATETIME | FD_ACCESSTIME | FD_WRITESTIME | FD_FILESIZE;
         pFD->dwFileAttributes =
         pFD->ftCreationTime   =
@@ -451,6 +455,7 @@
         pFD->ftLastWriteTime  =
 #endif
-    }
-#endif
+        ++curIdx;
+        ++itRoot;
+    }
 
     if (pszFileSpec)
@@ -458,11 +463,7 @@
 
     if (RT_SUCCESS(rc))
-    {
         rc = copyToHGlobal(pFGD, cbFGD, GMEM_MOVEABLE, phGlobal);
-    }
-    else
-    {
-        RTMemFree(pFGD);
-    }
+
+    RTMemFree(pFGD);
 
     LogFlowFuncLeaveRC(rc);
@@ -486,92 +487,85 @@
     LogFlowFuncEnter();
 
-    ULONG lIndex;
-    if (!lookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */
-        return DV_E_FORMATETC;
-    if (lIndex >= m_cFormats) /* Paranoia. */
-        return DV_E_LINDEX;
-
-    LPFORMATETC pThisFormat = &m_pFormatEtc[lIndex];
-    AssertPtr(pThisFormat);
-
-    LPSTGMEDIUM pThisMedium = &m_pStgMedium[lIndex];
-    AssertPtr(pThisMedium);
-
-    LogFlowFunc(("Using pThisFormat=%p, pThisMedium=%p\n", pThisFormat, pThisMedium));
-
-    HRESULT hr = DV_E_FORMATETC; /* Play safe. */
-
-    LogRel2(("Shared Clipboard: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32 -> lIndex=%u\n",
-             pThisFormat->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
-             pThisFormat->tymed, pThisFormat->dwAspect, lIndex));
+    LogFlowFunc(("lIndex=%RI32\n", pFormatEtc->lindex));
 
     /*
      * Initialize default values.
      */
-    pMedium->tymed          = pThisFormat->tymed;
-    pMedium->pUnkForRelease = NULL; /* Caller is responsible for deleting the data. */
-
-    switch (lIndex)
-    {
-        case FormatIndex_FileDescriptorA: /* ANSI */
+    RT_BZERO(pMedium, sizeof(STGMEDIUM));
+
+    HRESULT hr = DV_E_FORMATETC; /* Play safe. */
+
+    if (   pFormatEtc->cfFormat == m_cfFileDescriptorA
 #ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
-            RT_FALL_THROUGH();
-        case FormatIndex_FileDescriptorW: /* Unicode */
+        || pFormatEtc->cfFormat == m_cfFileDescriptorW
 #endif
-        {
-            const bool fUnicode = lIndex == FormatIndex_FileDescriptorW;
-
-            LogFlowFunc(("FormatIndex_FileDescriptor%s\n", fUnicode ? "W" : "A"));
-
-            int rc;
-
-            /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
-            if (SharedClipboardURITransferGetStatus(m_pTransfer) == SHAREDCLIPBOARDURITRANSFERSTATUS_NONE)
+       )
+    {
+        const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW;
+
+        LogFlowFunc(("FormatIndex_FileDescriptor%s\n", fUnicode ? "W" : "A"));
+
+        int rc;
+
+        /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
+        if (SharedClipboardURITransferGetStatus(m_pTransfer) == SHAREDCLIPBOARDURITRANSFERSTATUS_NONE)
+        {
+            rc = SharedClipboardURITransferPrepare(m_pTransfer);
+            if (RT_SUCCESS(rc))
             {
-                rc = SharedClipboardURITransferPrepare(m_pTransfer);
+                /* Start the transfer asynchronously in a separate thread. */
+                rc = SharedClipboardURITransferRun(m_pTransfer, &VBoxClipboardWinDataObject::readThread, this);
                 if (RT_SUCCESS(rc))
                 {
-                    /* Start the transfer asynchronously in a separate thread. */
-                    rc = SharedClipboardURITransferRun(m_pTransfer, &VBoxClipboardWinDataObject::readThread, this);
+                    /* Don't block for too long here, as this also will screw other apps running on the OS. */
+                    LogFunc(("Waiting for listing to arrive ...\n"));
+                    rc = RTSemEventWait(m_EventListComplete, 10 * 1000 /* 10s timeout */);
                     if (RT_SUCCESS(rc))
                     {
-                        /* Don't block for too long here, as this also will screw other apps running on the OS. */
-                        LogFunc(("Waiting for listing to arrive ...\n"));
-                        rc = RTSemEventWait(m_EventListComplete, 10 * 1000 /* 10s timeout */);
-                        if (RT_SUCCESS(rc))
-                        {
-                            LogFunc(("Listing complete\n"));
-
-                            HGLOBAL hGlobal;
-                            rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
-                            if (RT_SUCCESS(rc))
-                            {
-                                pMedium->tymed   = TYMED_HGLOBAL;
-                                pMedium->hGlobal = hGlobal;
-                                /* Note: hGlobal now is being owned by pMedium / the caller. */
-
-                                hr = S_OK;
-                            }
-                        }
+                        LogFunc(("Listing complete\n"));
+
+
                     }
                 }
             }
-            else
-                rc = VERR_ALREADY_EXISTS;
-
-            if (RT_FAILURE(rc))
-                LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc));
-
-            break;
-        }
-
-        case FormatIndex_FileContents:
-        {
+        }
+        else
+            rc = VINF_SUCCESS;
+
+        if (RT_SUCCESS(rc))
+        {
+            HGLOBAL hGlobal;
+            rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
+            if (RT_SUCCESS(rc))
+            {
+                pMedium->tymed   = TYMED_HGLOBAL;
+                pMedium->hGlobal = hGlobal;
+                /* Note: hGlobal now is being owned by pMedium / the caller. */
+
+                hr = S_OK;
+            }
+        }
+
+        if (RT_FAILURE(rc))
+            LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc));
+    }
+
+    if (pFormatEtc->cfFormat == m_cfFileContents)
+    {
+        if (   pFormatEtc->lindex >= 0
+            && pFormatEtc->lindex < m_lstRootEntries.size())
+        {
+            m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */
+
             LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u\n", m_uObjIdx));
 
-            SHAREDCLIPBOARDOBJHANDLE hObj = 0; /** @todo */
+            FSOBJENTRY &fsObjEntry = m_lstRootEntries.at(m_uObjIdx);
+
+            LogRel2(("Shared Clipboard: Receiving file '%s' ...\n", fsObjEntry.strPath.c_str()));
 
             /* Hand-in the provider so that our IStream implementation can continue working with it. */
-            hr = VBoxClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer, hObj, &m_pStream);
+            hr = VBoxClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer,
+                                                    fsObjEntry.strPath.c_str()/* File name */, &fsObjEntry.objInfo /* PSHAREDCLIPBOARDFSOBJINFO */,
+                                                    &m_pStream);
             if (SUCCEEDED(hr))
             {
@@ -579,13 +573,6 @@
                 pMedium->tymed = TYMED_ISTREAM;
                 pMedium->pstm  = m_pStream;
-
-                /* Handle next object. */
-                m_uObjIdx++;
             }
-            break;
-        }
-
-        default:
-            break;
+        }
     }
 
@@ -595,6 +582,6 @@
         LogFunc(("Failed; copying medium ...\n"));
 
-        pMedium->tymed          = pThisFormat->tymed;
-        pMedium->pUnkForRelease = NULL;
+        //pMedium->tymed          = pThisFormat->tymed;
+        //pMedium->pUnkForRelease = NULL;
     }
 
@@ -734,4 +721,13 @@
     RT_NOREF(rc);
 
+    LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstRootEntries.size()));
+
+    const bool fComplete = m_uObjIdx == m_lstRootEntries.size() - 1 /* Object index is zero-based */;
+    if (fComplete)
+    {
+        int rc2 = RTSemEventSignal(m_EventTransferComplete);
+        AssertRC(rc2);
+    }
+
     LogFlowFuncLeaveRC(rc);
 }
@@ -739,4 +735,9 @@
 void VBoxClipboardWinDataObject::OnTransferCanceled(void)
 {
+    LogFlowFuncEnter();
+
+    int rc2 = RTSemEventSignal(m_EventTransferComplete);
+    AssertRC(rc2);
+
     LogFlowFuncLeave();
 }
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp	(revision 79701)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp	(revision 79702)
@@ -46,14 +46,18 @@
 
 
-VBoxClipboardWinStreamImpl::VBoxClipboardWinStreamImpl(VBoxClipboardWinDataObject *pParent,
-                                                       PSHAREDCLIPBOARDURITRANSFER pTransfer, SHAREDCLIPBOARDOBJHANDLE hObj)
+VBoxClipboardWinStreamImpl::VBoxClipboardWinStreamImpl(VBoxClipboardWinDataObject *pParent, PSHAREDCLIPBOARDURITRANSFER pTransfer,
+                                                       const Utf8Str &strPath, PSHAREDCLIPBOARDFSOBJINFO pObjInfo)
     : m_pParent(pParent)
-    , m_lRefCount(1)
+    , m_lRefCount(1) /* Our IDataObjct *always* holds the last reference to this object; needed for the callbacks. */
     , m_pURITransfer(pTransfer)
-    , m_hObj(hObj)
+    , m_strPath(strPath)
+    , m_hObj(SHAREDCLIPBOARDOBJHANDLE_INVALID)
+    , m_objInfo(*pObjInfo)
+    , m_cbProcessed(0)
+    , m_fNotifiedComplete(false)
 {
     AssertPtr(m_pURITransfer);
 
-    LogFunc(("m_hObj=%RU64\n", m_hObj));
+    LogFunc(("m_strPath=%s\n", m_strPath.c_str()));
 }
 
@@ -109,6 +113,9 @@
     if (lCount == 0)
     {
-        if (m_pParent)
+        if (  !m_fNotifiedComplete
+            && m_pParent)
+        {
             m_pParent->OnTransferComplete();
+        }
 
         delete this;
@@ -156,50 +163,92 @@
 }
 
+/* Note: Windows seems to assume EOF if nBytesRead < nBytesToRead. */
 STDMETHODIMP VBoxClipboardWinStreamImpl::Read(void *pvBuffer, ULONG nBytesToRead, ULONG *nBytesRead)
 {
-    LogFlowThisFuncEnter();
-
-    const uint64_t cbSize      = m_pURITransfer->ProviderIface.pfnObjGetSize(&m_pURITransfer->ProviderCtx, m_hObj);
-          uint64_t cbProcessed = m_pURITransfer->ProviderIface.pfnObjGetProcessed(&m_pURITransfer->ProviderCtx, m_hObj);
-
-    if (cbProcessed == cbSize)
-    {
-        /* There can be 0-byte files. */
-        AssertMsg(cbSize == 0, ("Object is complete -- can't read from it anymore\n"));
+    LogFlowThisFunc(("Enter: m_cbProcessed=%RU64\n", m_cbProcessed));
+
+    /** @todo Is there any locking required so that parallel reads aren't possible? */
+
+    if (!pvBuffer)
+        return STG_E_INVALIDPOINTER;
+
+    if (nBytesToRead == 0)
+    {
         if (nBytesRead)
-            *nBytesRead = 0; /** @todo If the file size is 0, already return at least 1 byte, else the whole operation will fail. */
-        return S_OK; /* Don't report any failures back to Windows. */
-    }
-
-    const uint32_t cbToRead = RT_MIN(cbSize - cbProcessed, nBytesToRead);
-          uint32_t cbRead   = 0;
-
-    int rc = VINF_SUCCESS;
-
-    if (cbToRead)
-    {
-        rc = m_pURITransfer->ProviderIface.pfnObjRead(&m_pURITransfer->ProviderCtx, m_hObj,
-                                                      pvBuffer, cbToRead, 0 /* fFlags */, &cbRead);
+            *nBytesRead = 0;
+        return S_OK;
+    }
+
+    int rc;
+
+    try
+    {
+        if (   m_hObj == SHAREDCLIPBOARDOBJHANDLE_INVALID
+            && m_pURITransfer->ProviderIface.pfnObjOpen)
+        {
+            VBOXCLIPBOARDCREATEPARMS createParms;
+            RT_ZERO(createParms);
+
+            rc = m_pURITransfer->ProviderIface.pfnObjOpen(&m_pURITransfer->ProviderCtx, m_strPath.c_str(), &createParms, &m_hObj);
+        }
+        else
+            rc = VINF_SUCCESS;
+
+        uint32_t cbRead = 0;
+
+        const uint64_t cbSize   = (uint64_t)m_objInfo.cbObject;
+        const uint32_t cbToRead = RT_MIN(cbSize - m_cbProcessed, nBytesToRead);
+
+        bool fComplete = false;
+
         if (RT_SUCCESS(rc))
         {
-            cbProcessed += cbRead;
-            Assert(cbProcessed <= cbSize);
-
-            if (cbProcessed == cbSize)
-                m_pParent->OnTransferComplete();
-
-    #if 0
-            m_pObj->State.cbProcessed = cbProcessed;
-            Assert(m_pObj->State.cbProcessed <= m_pObj->objInfo.cbObject);
-    #endif
-        }
-    }
-
-    if (nBytesRead)
-        *nBytesRead = (ULONG)cbRead;
-
-    LogFlowThisFunc(("rc=%Rrc, cbSize=%RU64, cbProcessed=%RU64 -> cbToRead=%zu, cbRead=%zu\n",
-                     rc, cbSize, cbProcessed, cbToRead, cbRead));
-    return RT_SUCCESS(rc) ? S_OK : E_FAIL;
+            if (cbToRead)
+            {
+                rc = m_pURITransfer->ProviderIface.pfnObjRead(&m_pURITransfer->ProviderCtx, m_hObj,
+                                                              pvBuffer, cbToRead, 0 /* fFlags */, &cbRead);
+                if (RT_SUCCESS(rc))
+                {
+                    m_cbProcessed += cbRead;
+                    Assert(m_cbProcessed <= cbSize);
+                }
+            }
+
+            /* Transfer complete? Make sure to close the object again. */
+            fComplete = m_cbProcessed == cbSize;
+
+            if (fComplete)
+            {
+                if (m_pURITransfer->ProviderIface.pfnObjClose)
+                {
+                    int rc2 = m_pURITransfer->ProviderIface.pfnObjClose(&m_pURITransfer->ProviderCtx, m_hObj);
+                    AssertRC(rc2);
+                }
+
+                if (m_pParent)
+                {
+                    m_pParent->OnTransferComplete();
+                    m_fNotifiedComplete = true;
+                }
+            }
+        }
+
+        LogFlowThisFunc(("Leave: rc=%Rrc, cbSize=%RU64, cbProcessed=%RU64 -> nBytesToRead=%RU32, cbToRead=%RU32, cbRead=%RU32\n",
+                         rc, cbSize, m_cbProcessed, nBytesToRead, cbToRead, cbRead));
+
+        if (nBytesRead)
+            *nBytesRead = (ULONG)cbRead;
+
+        if (nBytesToRead != cbRead)
+            return S_FALSE;
+
+        return S_OK;
+    }
+    catch (...)
+    {
+        LogFunc(("Caught exception\n"));
+    }
+
+    return E_FAIL;
 }
 
@@ -207,5 +256,5 @@
 {
     LogFlowThisFuncEnter();
-    return STG_E_INVALIDFUNCTION;
+    return E_NOTIMPL;
 }
 
@@ -214,6 +263,7 @@
     RT_NOREF(nMove, dwOrigin, nNewPos);
 
-    LogFlowThisFuncEnter();
-    return STG_E_INVALIDFUNCTION;
+    LogFlowThisFunc(("nMove=%RI64, dwOrigin=%RI32\n", nMove, dwOrigin));
+
+    return E_NOTIMPL;
 }
 
@@ -223,5 +273,5 @@
 
     LogFlowThisFuncEnter();
-    return STG_E_INVALIDFUNCTION;
+    return E_NOTIMPL;
 }
 
@@ -242,6 +292,5 @@
             case STATFLAG_DEFAULT:
             {
-                int rc2 = RTStrToUtf16(m_pURITransfer->ProviderIface.pfnObjGetPath(&m_pURITransfer->ProviderCtx, m_hObj),
-                                       &pStatStg->pwcsName);
+                int rc2 = RTStrToUtf16(m_strPath.c_str(), &pStatStg->pwcsName);
                 if (RT_FAILURE(rc2))
                     hr = E_FAIL;
@@ -259,5 +308,5 @@
             pStatStg->grfMode           = STGM_READ;
             pStatStg->grfLocksSupported = 0;
-            pStatStg->cbSize.QuadPart   = m_pURITransfer->ProviderIface.pfnObjGetSize(&m_pURITransfer->ProviderCtx, m_hObj);
+            pStatStg->cbSize.QuadPart   = (uint64_t)m_objInfo.cbObject;
         }
     }
@@ -274,5 +323,5 @@
 
     LogFlowThisFuncEnter();
-    return STG_E_INVALIDFUNCTION;
+    return E_NOTIMPL;
 }
 
@@ -295,14 +344,16 @@
  * @param   pParent             Pointer to the parent data object.
  * @param   pTransfer           Pointer to URI transfer object to use.
- * @param   hObj                Handle of URI transfer object.
+ * @param   strPath             Path of object to handle for the stream.
+ * @param   pObjInfo            Pointer to object information.
  * @param   ppStream            Where to return the created stream object on success.
  */
 /* static */
 HRESULT VBoxClipboardWinStreamImpl::Create(VBoxClipboardWinDataObject *pParent, PSHAREDCLIPBOARDURITRANSFER pTransfer,
-                                           SHAREDCLIPBOARDOBJHANDLE hObj, IStream **ppStream)
+                                           const Utf8Str &strPath, PSHAREDCLIPBOARDFSOBJINFO pObjInfo,
+                                           IStream **ppStream)
 {
     AssertPtrReturn(pTransfer, E_POINTER);
 
-    VBoxClipboardWinStreamImpl *pStream = new VBoxClipboardWinStreamImpl(pParent, pTransfer, hObj);
+    VBoxClipboardWinStreamImpl *pStream = new VBoxClipboardWinStreamImpl(pParent, pTransfer, strPath, pObjInfo);
     if (pStream)
     {
Index: /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-uri.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-uri.cpp	(revision 79701)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-uri.cpp	(revision 79702)
@@ -658,49 +658,54 @@
         if (pInfo)
         {
+            LogFlowFunc(("pszPath=%RU32\n", pOpenParms->pszPath));
+
             RTFSOBJINFO objInfo;
             rc = RTPathQueryInfo(pOpenParms->pszPath, &objInfo, RTFSOBJATTRADD_NOTHING);
-            if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
-            {
-                rc = RTDirOpen(&pInfo->u.Local.hDirRoot, pOpenParms->pszPath);
-            }
-            else if (RTFS_IS_FILE(objInfo.Attr.fMode))
-            {
-                rc = RTFileOpen(&pInfo->u.Local.hFile, pOpenParms->pszPath,
-                                RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
-            }
-            else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
-            {
-                rc = VERR_NOT_IMPLEMENTED; /** @todo */
-            }
-            else
-                AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
-
             if (RT_SUCCESS(rc))
-                rc = SharedClipboardURIListOpenParmsCopy(&pInfo->OpenParms, pOpenParms);
-
-            if (RT_SUCCESS(rc))
-            {
-                pInfo->fMode = objInfo.Attr.fMode;
-
-                hList = sharedClipboardURITransferListHandleNew(pTransfer);
-
-                pTransfer->pMapLists->insert(
-                    std::pair<SHAREDCLIPBOARDLISTHANDLE, PSHAREDCLIPBOARDURILISTHANDLEINFO>(hList, pInfo));
-            }
-            else
             {
                 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
                 {
-                    if (RTDirIsValid(pInfo->u.Local.hDirRoot))
-                        RTDirClose(pInfo->u.Local.hDirRoot);
+                    rc = RTDirOpen(&pInfo->u.Local.hDirRoot, pOpenParms->pszPath);
                 }
                 else if (RTFS_IS_FILE(objInfo.Attr.fMode))
                 {
-                    if (RTFileIsValid(pInfo->u.Local.hFile))
-                        RTFileClose(pInfo->u.Local.hFile);
+                    rc = RTFileOpen(&pInfo->u.Local.hFile, pOpenParms->pszPath,
+                                    RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
                 }
-
-                RTMemFree(pInfo);
-                pInfo = NULL;
+                else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
+                {
+                    rc = VERR_NOT_IMPLEMENTED; /** @todo */
+                }
+                else
+                    AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
+
+                if (RT_SUCCESS(rc))
+                    rc = SharedClipboardURIListOpenParmsCopy(&pInfo->OpenParms, pOpenParms);
+
+                if (RT_SUCCESS(rc))
+                {
+                    pInfo->fMode = objInfo.Attr.fMode;
+
+                    hList = sharedClipboardURITransferListHandleNew(pTransfer);
+
+                    pTransfer->pMapLists->insert(
+                        std::pair<SHAREDCLIPBOARDLISTHANDLE, PSHAREDCLIPBOARDURILISTHANDLEINFO>(hList, pInfo));
+                }
+                else
+                {
+                    if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
+                    {
+                        if (RTDirIsValid(pInfo->u.Local.hDirRoot))
+                            RTDirClose(pInfo->u.Local.hDirRoot);
+                    }
+                    else if (RTFS_IS_FILE(objInfo.Attr.fMode))
+                    {
+                        if (RTFileIsValid(pInfo->u.Local.hFile))
+                            RTFileClose(pInfo->u.Local.hFile);
+                    }
+
+                    RTMemFree(pInfo);
+                    pInfo = NULL;
+                }
             }
         }
@@ -1333,8 +1338,10 @@
         for (size_t i = 0; i < pTransfer->lstRootEntries.size(); ++i)
         {
-            if (pszRoots)
-                rc = RTStrAAppend(&pszRoots, "\r\n");
+            rc = RTStrAAppend(&pszRoots, pTransfer->lstRootEntries.at(i).c_str());
+
+            /* Add separation between paths.
+             * Note: Also do this for the last element of the list. */
             if (RT_SUCCESS(rc))
-                rc = RTStrAAppend(&pszRoots, pTransfer->lstRootEntries.at(i).c_str());
+                rc = RTStrAAppendExN(&pszRoots, 1 /* cPairs */, "\r\n", 2 /* Bytes */);
 
             if (RT_FAILURE(rc))
@@ -1347,5 +1354,5 @@
 
             *ppszRoots = pszRoots;
-            *pcRoots     = (uint32_t)pTransfer->lstRootEntries.size();
+            *pcRoots   = (uint32_t)pTransfer->lstRootEntries.size();
         }
         else
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-uri.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-uri.cpp	(revision 79701)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-uri.cpp	(revision 79702)
@@ -51,4 +51,6 @@
 int VBoxSvcClipboardURISetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
                                    PVBOXCLIPBOARDLISTOPENPARMS pOpenParms);
+int VBoxSvcClipboardURISetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
+                                    SHAREDCLIPBOARDLISTHANDLE hList);
 
 
@@ -186,6 +188,4 @@
                                               PVBOXCLIPBOARDLISTOPENPARMS pOpenParms, PSHAREDCLIPBOARDLISTHANDLE phList)
 {
-    RT_NOREF(phList);
-
     LogFlowFuncEnter();
 
@@ -241,9 +241,39 @@
 DECLCALLBACK(int) vboxSvcClipboardURIListClose(PSHAREDCLIPBOARDPROVIDERCTX pCtx, SHAREDCLIPBOARDLISTHANDLE hList)
 {
-    RT_NOREF(pCtx, hList);
-
-    LogFlowFuncEnter();
-
-    int rc = VINF_SUCCESS;
+    LogFlowFuncEnter();
+
+    PVBOXCLIPBOARDCLIENT pClient = (PVBOXCLIPBOARDCLIENT)pCtx->pvUser;
+    AssertPtr(pClient);
+
+    int rc;
+
+    PVBOXCLIPBOARDCLIENTMSG pMsg = vboxSvcClipboardMsgAlloc(VBOX_SHARED_CLIPBOARD_HOST_MSG_URI_LIST_CLOSE,
+                                                            VBOX_SHARED_CLIPBOARD_CPARMS_LIST_CLOSE);
+    if (pMsg)
+    {
+        rc = VBoxSvcClipboardURISetListClose(pMsg->m_cParms, pMsg->m_paParms, hList);
+        if (RT_SUCCESS(rc))
+        {
+            rc = vboxSvcClipboardMsgAdd(pClient->pData, pMsg, true /* fAppend */);
+            if (RT_SUCCESS(rc))
+            {
+                int rc2 = SharedClipboardURITransferEventRegister(pCtx->pTransfer, SHAREDCLIPBOARDURITRANSFEREVENTTYPE_LIST_CLOSE);
+                AssertRC(rc2);
+
+                vboxSvcClipboardClientWakeup(pClient);
+            }
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    if (RT_SUCCESS(rc))
+    {
+        PSHAREDCLIPBOARDURITRANSFERPAYLOAD pPayload;
+        rc = SharedClipboardURITransferEventWait(pCtx->pTransfer, SHAREDCLIPBOARDURITRANSFEREVENTTYPE_LIST_CLOSE,
+                                                 30 * 1000 /* Timeout in ms */, &pPayload);
+        if (RT_SUCCESS(rc))
+            SharedClipboardURITransferPayloadFree(pPayload);
+    }
 
     LogFlowFuncLeaveRC(rc);
@@ -378,13 +408,4 @@
     LogFlowFuncEnter();
 
-    return VERR_NOT_IMPLEMENTED;
-}
-
-int vboxSvcClipboardURIObjClose(PSHAREDCLIPBOARDPROVIDERCTX pCtx, SHAREDCLIPBOARDOBJHANDLE hObj)
-{
-    RT_NOREF(pCtx, hObj);
-
-    LogFlowFuncEnter();
-
     int rc = VINF_SUCCESS;
 
@@ -396,12 +417,32 @@
 }
 
+int vboxSvcClipboardURIObjClose(PSHAREDCLIPBOARDPROVIDERCTX pCtx, SHAREDCLIPBOARDOBJHANDLE hObj)
+{
+    RT_NOREF(pCtx, hObj);
+
+    LogFlowFuncEnter();
+
+    int rc = VINF_SUCCESS;
+
+    PVBOXCLIPBOARDCONTEXT pThisCtx = (PVBOXCLIPBOARDCONTEXT)pCtx->pvUser;
+    AssertPtr(pThisCtx);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
 int vboxSvcClipboardURIObjRead(PSHAREDCLIPBOARDPROVIDERCTX pCtx, SHAREDCLIPBOARDOBJHANDLE hObj,
                                void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
 {
-    RT_NOREF(pCtx, pCtx, hObj, pvData, cbData, fFlags, pcbRead);
-
-    LogFlowFuncEnter();
-
-    return VERR_NOT_IMPLEMENTED;
+    RT_NOREF(pCtx, hObj, pvData, cbData, fFlags, pcbRead);
+
+    LogFlowFuncEnter();
+
+    int rc = VINF_SUCCESS;
+
+    *pcbRead = cbData;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
 }
 
@@ -454,4 +495,8 @@
     LogRel(("Shared Clipboard: Transfer failed with %Rrc\n", rc));
 }
+
+/*********************************************************************************************************************************
+*   HGCM getters / setters                                                                                                       *
+*********************************************************************************************************************************/
 
 /**
@@ -522,4 +567,12 @@
 }
 
+/**
+ * Gets the URI root entries from HGCM service parameters.
+ *
+ * @returns VBox status code.
+ * @param   cParms              Number of HGCM parameters supplied in \a paParms.
+ * @param   paParms             Array of HGCM parameters.
+ * @param   pRoots              Where to store the URI root entries on success.
+ */
 int VBoxSvcClipboardURIGetRoots(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
                                 PVBOXCLIPBOARDROOTS pRoots)
@@ -604,4 +657,12 @@
 }
 
+/**
+ * Sets an URI list open request to HGCM service parameters.
+ *
+ * @returns VBox status code.
+ * @param   cParms              Number of HGCM parameters supplied in \a paParms.
+ * @param   paParms             Array of HGCM parameters.
+ * @param   pOpenParms          List open parameters to set.
+ */
 int VBoxSvcClipboardURISetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
                                    PVBOXCLIPBOARDLISTOPENPARMS pOpenParms)
@@ -618,4 +679,31 @@
         HGCMSvcSetPv (&paParms[5], pOpenParms->pszPath, pOpenParms->cbPath);
         HGCMSvcSetU64(&paParms[6], 0); /* OUT: uHandle */
+
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_INVALID_PARAMETER;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Sets an URI list close request to HGCM service parameters.
+ *
+ * @returns VBox status code.
+ * @param   cParms              Number of HGCM parameters supplied in \a paParms.
+ * @param   paParms             Array of HGCM parameters.
+ * @param   hList               Handle of list to close.
+ */
+int VBoxSvcClipboardURISetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
+                                    SHAREDCLIPBOARDLISTHANDLE hList)
+{
+    int rc;
+
+    if (cParms == VBOX_SHARED_CLIPBOARD_CPARMS_LIST_CLOSE)
+    {
+        HGCMSvcSetU32(&paParms[0], 0 /* uContextID */);
+        HGCMSvcSetU64(&paParms[1], hList);
 
         rc = VINF_SUCCESS;
@@ -809,4 +897,13 @@
 }
 
+/**
+ * Handles a guest reply (VBOX_SHARED_CLIPBOARD_GUEST_FN_REPLY) message.
+ *
+ * @returns VBox status code.
+ * @param   pClient             Pointer to associated client.
+ * @param   pTransfer           Pointer to transfer to handle guest reply for.
+ * @param   cParms              Number of function parameters supplied.
+ * @param   paParms             Array function parameters supplied.
+ */
 int VBoxSvcClipboardURITransferHandleReply(PVBOXCLIPBOARDCLIENT pClient, PSHAREDCLIPBOARDURITRANSFER pTransfer,
                                            uint32_t cParms, VBOXHGCMSVCPARM paParms[])
@@ -836,4 +933,25 @@
                         rc = SharedClipboardURITransferEventSignal(pTransfer,
                                                                    SHAREDCLIPBOARDURITRANSFEREVENTTYPE_LIST_OPEN, pPayload);
+                        break;
+                    }
+
+                    case VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_LIST_CLOSE:
+                    {
+                        rc = SharedClipboardURITransferEventSignal(pTransfer,
+                                                                   SHAREDCLIPBOARDURITRANSFEREVENTTYPE_LIST_CLOSE, pPayload);
+                        break;
+                    }
+
+                    case VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_OBJ_OPEN:
+                    {
+                        rc = SharedClipboardURITransferEventSignal(pTransfer,
+                                                                   SHAREDCLIPBOARDURITRANSFEREVENTTYPE_OBJ_OPEN, pPayload);
+                        break;
+                    }
+
+                    case VBOX_SHAREDCLIPBOARD_REPLYMSGTYPE_OBJ_CLOSE:
+                    {
+                        rc = SharedClipboardURITransferEventSignal(pTransfer,
+                                                                   SHAREDCLIPBOARDURITRANSFEREVENTTYPE_OBJ_CLOSE, pPayload);
                         break;
                     }
@@ -999,8 +1117,8 @@
                         if (enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
                         {
-                            creationCtx.Interface.pfnGetRoots      = vboxSvcClipboardURIGetRoots;
-                            creationCtx.Interface.pfnListHdrRead   = vboxSvcClipboardURIListHdrRead;
-                            creationCtx.Interface.pfnListEntryRead = vboxSvcClipboardURIListEntryRead;
-                            creationCtx.Interface.pfnObjRead       = vboxSvcClipboardURIObjRead;
+                            creationCtx.Interface.pfnGetRoots        = vboxSvcClipboardURIGetRoots;
+                            creationCtx.Interface.pfnListHdrRead     = vboxSvcClipboardURIListHdrRead;
+                            creationCtx.Interface.pfnListEntryRead   = vboxSvcClipboardURIListEntryRead;
+                            creationCtx.Interface.pfnObjRead         = vboxSvcClipboardURIObjRead;
                         }
                         else
