Index: /trunk/include/VBox/GuestHost/SharedClipboard-uri.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-uri.h	(revision 78439)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-uri.h	(revision 78440)
@@ -302,5 +302,5 @@
      *  Note: All paths are kept internally as UNIX paths for
      *        easier conversion/handling!  */
-    RTCList<RTCString>      m_lstRoot;
+    RTCList<RTCString>                  m_lstRoot;
     /** List of all URI objects added. The list's content
      *  might vary depending on how the objects are being
@@ -308,10 +308,10 @@
     RTCList<SharedClipboardURIObject *> m_lstTree;
     /** Total number of all URI objects. */
-    uint64_t                m_cTotal;
+    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;
+    uint64_t                            m_cbTotal;
 };
 
Index: /trunk/include/VBox/GuestHost/SharedClipboard-win.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 78439)
+++ /trunk/include/VBox/GuestHost/SharedClipboard-win.h	(revision 78440)
@@ -33,4 +33,8 @@
 #include <iprt/win/windows.h>
 
+# ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+#  include <iprt/cpp/ministring.h> /* For RTCString. */
+# endif
+
 #ifndef WM_CLIPBOARDUPDATE
 # define WM_CLIPBOARDUPDATE 0x031D
@@ -40,5 +44,4 @@
 
 #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. */
@@ -100,4 +103,106 @@
 int VBoxClipboardWinGetFormats(PVBOXCLIPBOARDWINCTX pCtx, uint32_t *puFormats);
 
+# ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+class VBoxClipboardWinDataObject : public IDataObject
+{
+public:
+
+    enum Status
+    {
+        Uninitialized = 0,
+        Initialized,
+        Dropping,
+        Dropped,
+        Aborted
+    };
+
+public:
+
+    VBoxClipboardWinDataObject(LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0);
+    virtual ~VBoxClipboardWinDataObject(void);
+
+public: /* IUnknown methods. */
+
+    STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
+    STDMETHOD_(ULONG, AddRef)(void);
+    STDMETHOD_(ULONG, Release)(void);
+
+public: /* IDataObject methods. */
+
+    STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
+    STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
+    STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc);
+    STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct,  LPFORMATETC pFormatEtcOut);
+    STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease);
+    STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
+    STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
+    STDMETHOD(DUnadvise)(DWORD dwConnection);
+    STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise);
+
+public:
+
+    static const char* ClipboardFormatToString(CLIPFORMAT fmt);
+
+    int Abort(void);
+    void SetStatus(Status status);
+    int Signal(const RTCString &strFormat, const void *pvData, uint32_t cbData);
+
+protected:
+
+    bool LookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex);
+    static HGLOBAL MemDup(HGLOBAL hMemSource);
+    void RegisterFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
+                        LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
+
+    Status      mStatus;
+    LONG        mRefCount;
+    ULONG       mcFormats;
+    LPFORMATETC mpFormatEtc;
+    LPSTGMEDIUM mpStgMedium;
+    RTSEMEVENT  mEventDropped;
+    RTCString   mstrFormat;
+    void       *mpvData;
+    uint32_t    mcbData;
+};
+
+class VBoxClipboardWinEnumFormatEtc : public IEnumFORMATETC
+{
+public:
+
+    VBoxClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats);
+    virtual ~VBoxClipboardWinEnumFormatEtc(void);
+
+public:
+
+    STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
+    STDMETHOD_(ULONG, AddRef)(void);
+    STDMETHOD_(ULONG, Release)(void);
+
+    STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched);
+    STDMETHOD(Skip)(ULONG cFormats);
+    STDMETHOD(Reset)(void);
+    STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc);
+
+public:
+
+    static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource);
+    static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
+
+private:
+
+    LONG        m_lRefCount;
+    ULONG       m_nIndex;
+    ULONG       m_nNumFormats;
+    LPFORMATETC m_pFormatEtc;
+};
+
+#  if 0
+class VBoxClipboardWinStreamImpl : public IDataObject
+{
+
+};
+#  endif
+
+# endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
 #endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */
 
Index: /trunk/include/VBox/GuestHost/SharedClipboard.h
===================================================================
--- /trunk/include/VBox/GuestHost/SharedClipboard.h	(revision 78439)
+++ /trunk/include/VBox/GuestHost/SharedClipboard.h	(revision 78440)
@@ -33,7 +33,15 @@
 #include <iprt/types.h>
 
+/** A single Shared Clipboard format. */
+typedef uint32_t VBOXCLIPBOARDFORMAT;
+
+/** Bit map of Shared Clipboard format. */
+typedef uint32_t VBOXCLIPBOARDFORMATS;
+
 /**
  * Supported data formats for Shared Clipboard. Bit mask.
  */
+/** No format set. */
+#define VBOX_SHARED_CLIPBOARD_FMT_NONE          0
 /** Shared Clipboard format is an Unicode text. */
 #define VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT   UINT32_C(0x01)
Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 78439)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 78440)
@@ -566,6 +566,31 @@
 /** @} */
 
-/** @name Shared clipboard
- * @{ */
+# ifdef VBOX_WITH_SHARED_CLIPBOARD
+/** @name Shared Clipboard
+ * @{ */
+/**
+ * Structure containing the context required for Shared Clipboard operations.
+ *
+ * Note: Do not change parameter order without also
+ *       adapting all structure initializers.
+ */
+typedef struct _VBGLR3GUESTCLIPBOARDCMDCTX
+{
+    /** @todo This struct could be handy if we want to implement
+     *        a second communication channel, e.g. via TCP/IP.
+     *        Use a union for the HGCM stuff then. */
+
+    /** HGCM client ID to use for communication. */
+    uint32_t uClientID;
+    /** The VM's current session ID. */
+    uint64_t uSessionID;
+    /** The transfer ID to use. */
+    uint32_t uTransferID;
+    /** Number of parameters retrieved for the current command. */
+    uint32_t uNumParms;
+    /** Max chunk size (in bytes) for data transfers. */
+    uint32_t cbMaxChunkSize;
+} VBGLR3GUESTCLIPBOARDCMDCTX, *PVBGLR3GUESTCLIPBOARDCMDCTX;
+
 VBGLR3DECL(int)     VbglR3ClipboardConnect(HGCMCLIENTID *pidClient);
 VBGLR3DECL(int)     VbglR3ClipboardDisconnect(HGCMCLIENTID idClient);
@@ -574,8 +599,9 @@
 VBGLR3DECL(int)     VbglR3ClipboardReportFormats(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
+#  ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
 VBGLR3DECL(int)     VbglR3ClipboardSendError(HGCMCLIENTID idClient, int rcErr);
-#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
-/** @} */
+#  endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
+/** @} */
+# endif /* VBOX_WITH_SHARED_CLIPBOARD */
 
 /** @name Seamless mode
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 78439)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 78440)
@@ -52,4 +52,13 @@
 	VBoxClipboard.cpp \
 	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp
+ ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+ VBoxTray_SOURCES  += \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardURIList.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardURIObject.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardPath.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardEnumFormatEtcImpl-win.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp
+ endif
 endif
 ifdef VBOX_WITH_DRAG_AND_DROP
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 78439)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp	(revision 78440)
@@ -174,30 +174,32 @@
         {
            /* Insert the requested clipboard format data into the clipboard. */
-           uint32_t u32Format = 0;
-           UINT format = (UINT)wParam;
-
-           LogFlowFunc(("WM_RENDERFORMAT, format = %x\n", format));
-           switch (format)
+           uint32_t fFormat = VBOX_SHARED_CLIPBOARD_FMT_NONE;
+
+           const UINT cfFormat = (UINT)wParam;
+           switch (cfFormat)
            {
               case CF_UNICODETEXT:
-                  u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
+                  fFormat = VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
                   break;
 
               case CF_DIB:
-                  u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
+                  fFormat = VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
                   break;
 
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+              case CF_HDROP:
+                  fFormat = VBOX_SHARED_CLIPBOARD_FMT_URI_LIST;
+                  break;
+#endif
               default:
-                  if (format >= 0xC000)
+                  if (cfFormat >= 0xC000) /** @todo r=andy Explain. */
                   {
-                      TCHAR szFormatName[256];
-
-                      int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName) / sizeof(TCHAR));
+                      TCHAR szFormatName[256]; /** @todo r=andy Do we need Unicode support here as well? */
+
+                      int cActual = GetClipboardFormatName(cfFormat, szFormatName, sizeof(szFormatName) / sizeof(TCHAR));
                       if (cActual)
                       {
                           if (strcmp(szFormatName, "HTML Format") == 0)
-                          {
-                              u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
-                          }
+                              fFormat = VBOX_SHARED_CLIPBOARD_FMT_HTML;
                       }
                   }
@@ -205,13 +207,21 @@
            }
 
-           if (u32Format == 0)
+           LogFunc(("WM_RENDERFORMAT: format=%u -> fFormat=0x%x\n", cfFormat, fFormat));
+
+           if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_NONE)
            {
                /* Unsupported clipboard format is requested. */
-               LogFlowFunc(("Unsupported clipboard format requested: %ld\n", u32Format));
+               LogRel(("Clipboard: Unsupported clipboard format requested (0x%x)\n", fFormat));
                VBoxClipboardWinClear();
            }
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+           else if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+           {
+
+           }
+#endif
            else
            {
-               const uint32_t cbPrealloc = 4096; /** @todo r=andy Make it dynamic for supporting larger text buffers! */
+               const uint32_t cbPrealloc = _4K;
                uint32_t cb = 0;
 
@@ -228,5 +238,5 @@
                    {
                        /* Read the host data to the preallocated buffer. */
-                       int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cbPrealloc, &cb);
+                       int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cbPrealloc, &cb);
                        LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n",  vboxrc));
 
@@ -259,5 +269,5 @@
                                        /* Read the host data to the preallocated buffer. */
                                        uint32_t cbNew = 0;
-                                       vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cb, &cbNew);
+                                       vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cb, &cbNew);
                                        LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew));
 
@@ -287,5 +297,5 @@
                                 * must have the exact string size.
                                 */
-                               if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
+                               if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
                                {
                                    size_t cbActual = 0;
@@ -319,5 +329,5 @@
                                    /* 'hMem' contains the host clipboard data.
                                     * size is 'cb' and format is 'format'. */
-                                   HANDLE hClip = SetClipboardData(format, hMem);
+                                   HANDLE hClip = SetClipboardData(cfFormat, hMem);
                                    LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip));
 
@@ -362,7 +372,7 @@
         {
            /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
-           uint32_t u32Formats = (uint32_t)lParam;
-
-           LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: u32Formats=0x%x\n", u32Formats));
+           VBOXCLIPBOARDFORMATS fFormats = (uint32_t)lParam;
+
+           LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: fFormats=0x%x\n", fFormats));
 
            int vboxrc = VBoxClipboardWinOpen(hwnd);
@@ -373,11 +383,11 @@
                HANDLE hClip = NULL;
 
-               if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
+               if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
                    hClip = SetClipboardData(CF_UNICODETEXT, NULL);
 
-               if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
+               if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
                    hClip = SetClipboardData(CF_DIB, NULL);
 
-               if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
+               if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
                {
                    UINT format = RegisterClipboardFormat("HTML Format");
@@ -387,7 +397,13 @@
 
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
-               if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
+               if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
                    hClip = SetClipboardData(CF_HDROP, NULL);
 #endif
+
+               /** @todo Implement more flexible clipboard precedence for supported formats. */
+
+               if (hClip == NULL)
+                   LogRel(("Clipboard: Unsupported format(s) from host (0x%x), ignoring\n", fFormats));
+
                VBoxClipboardWinClose();
 
@@ -479,6 +495,6 @@
                        if (hDrop)
                        {
-                           vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_URI_LIST,
-                                                             );
+       /*                    vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_URI_LIST,
+                                                             );*/
                            GlobalUnlock(hClip);
                        }
@@ -681,5 +697,5 @@
                 break;
 
-            LogFlowFunc(("Error getting host message, rc=%Rrc\n", rc));
+            LogFunc(("Error getting host message, rc=%Rrc\n", rc));
 
             if (*pfShutdown)
@@ -701,6 +717,6 @@
                     * respond to WM_RENDERFORMAT message. */
                    ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS, 0, u32Formats);
-               }
                    break;
+               }
 
                case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
@@ -708,6 +724,6 @@
                    /* The host needs data in the specified format. */
                    ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_READ_DATA, 0, u32Formats);
-               }
                    break;
+               }
 
                case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
@@ -716,6 +732,6 @@
                    LogRel(("Clipboard: Terminating ...\n"));
                    ASMAtomicXchgBool(pfShutdown, true);
-               }
                    break;
+               }
 
                default:
@@ -725,6 +741,6 @@
                    /* Wait a bit before retrying. */
                    RTThreadSleep(1000);
-               }
                    break;
+               }
             }
         }
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 78440)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp	(revision 78440)
@@ -0,0 +1,704 @@
+/* $Id$ */
+/** @file
+ * ClipboardDataObjectImpl-win.cpp - Shared Clipboard IDataObject implementation.
+ */
+
+/*
+ * 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.
+ */
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
+#include <VBox/GuestHost/SharedClipboard-win.h>
+
+#include <iprt/win/windows.h>
+#include <new> /* For bad_alloc. */
+#include <iprt/win/shlobj.h>
+
+#include <iprt/path.h>
+#include <iprt/semaphore.h>
+#include <iprt/uri.h>
+#include <iprt/utf16.h>
+
+#include <VBox/log.h>
+
+VBoxClipboardWinDataObject::VBoxClipboardWinDataObject(LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
+    : mStatus(Uninitialized),
+      mRefCount(1),
+      mcFormats(0),
+      mpvData(NULL),
+      mcbData(0)
+{
+    HRESULT hr;
+
+    ULONG cFixedFormats = 1;
+    ULONG cAllFormats   = cFormats + cFixedFormats;
+
+    try
+    {
+        mpFormatEtc = new FORMATETC[cAllFormats];
+        RT_BZERO(mpFormatEtc, sizeof(FORMATETC) * cAllFormats);
+        mpStgMedium = new STGMEDIUM[cAllFormats];
+        RT_BZERO(mpStgMedium, sizeof(STGMEDIUM) * cAllFormats);
+
+        /*
+         * Registration of dynamic formats needed?
+         */
+        LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
+        if (cFormats)
+        {
+            AssertPtr(pFormatEtc);
+            AssertPtr(pStgMed);
+
+            for (ULONG i = 0; i < cFormats; i++)
+            {
+                LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
+                             i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
+                mpFormatEtc[i] = pFormatEtc[i];
+                mpStgMedium[i] = pStgMed[i];
+            }
+        }
+
+        hr = S_OK;
+    }
+    catch (std::bad_alloc &)
+    {
+        hr = E_OUTOFMEMORY;
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        int rc2 = RTSemEventCreate(&mEventDropped);
+        AssertRC(rc2);
+
+        /*
+         * Register fixed formats.
+         */
+#if 0
+        /* CF_HDROP. */
+        RegisterFormat(&mpFormatEtc[cFormats], CF_HDROP);
+        mpStgMedium[cFormats++].tymed = TYMED_HGLOBAL;
+
+        /* IStream. */
+        RegisterFormat(&mpFormatEtc[cFormats++],
+                       RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));
+        RegisterFormat(&mpFormatEtc[cFormats++],
+                       RegisterClipboardFormat(CFSTR_FILECONTENTS),
+                       TYMED_ISTREAM, 0 /* lIndex */);
+
+        /* Required for e.g. Windows Media Player. */
+        RegisterFormat(&mpFormatEtc[cFormats++],
+                       RegisterClipboardFormat(CFSTR_FILENAME));
+        RegisterFormat(&mpFormatEtc[cFormats++],
+                       RegisterClipboardFormat(CFSTR_FILENAMEW));
+        RegisterFormat(&mpFormatEtc[cFormats++],
+                       RegisterClipboardFormat(CFSTR_SHELLIDLIST));
+        RegisterFormat(&mpFormatEtc[cFormats++],
+                       RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET));
+#endif
+        mcFormats = cFormats;
+        mStatus   = Initialized;
+    }
+
+    LogFlowFunc(("cFormats=%RU32, hr=%Rhrc\n", cFormats, hr));
+}
+
+VBoxClipboardWinDataObject::~VBoxClipboardWinDataObject(void)
+{
+    if (mpFormatEtc)
+        delete[] mpFormatEtc;
+
+    if (mpStgMedium)
+        delete[] mpStgMedium;
+
+    if (mpvData)
+        RTMemFree(mpvData);
+
+    LogFlowFunc(("mRefCount=%RI32\n", mRefCount));
+}
+
+/*
+ * IUnknown methods.
+ */
+
+STDMETHODIMP_(ULONG) VBoxClipboardWinDataObject::AddRef(void)
+{
+    return InterlockedIncrement(&mRefCount);
+}
+
+STDMETHODIMP_(ULONG) VBoxClipboardWinDataObject::Release(void)
+{
+    LONG lCount = InterlockedDecrement(&mRefCount);
+    if (lCount == 0)
+    {
+        delete this;
+        return 0;
+    }
+
+    return lCount;
+}
+
+STDMETHODIMP VBoxClipboardWinDataObject::QueryInterface(REFIID iid, void **ppvObject)
+{
+    AssertPtrReturn(ppvObject, E_INVALIDARG);
+
+    if (   iid == IID_IDataObject
+        || iid == IID_IUnknown)
+    {
+        AddRef();
+        *ppvObject = this;
+        return S_OK;
+    }
+
+    *ppvObject = 0;
+    return E_NOINTERFACE;
+}
+
+/**
+ * Retrieves the data stored in this object and store the result in
+ * pMedium.
+ *
+ * @return  IPRT status code.
+ * @return  HRESULT
+ * @param   pFormatEtc
+ * @param   pMedium
+ */
+STDMETHODIMP VBoxClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
+{
+    AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
+    AssertPtrReturn(pMedium, DV_E_FORMATETC);
+
+    ULONG lIndex;
+    if (!LookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */
+        return DV_E_FORMATETC;
+    if (lIndex >= mcFormats) /* Paranoia. */
+        return DV_E_FORMATETC;
+
+    LPFORMATETC pThisFormat = &mpFormatEtc[lIndex];
+    AssertPtr(pThisFormat);
+
+    LPSTGMEDIUM pThisMedium = &mpStgMedium[lIndex];
+    AssertPtr(pThisMedium);
+
+    LogFlowFunc(("Using pThisFormat=%p, pThisMedium=%p\n", pThisFormat, pThisMedium));
+
+    HRESULT hr = DV_E_FORMATETC; /* Play safe. */
+
+    LogFlowFunc(("mStatus=%ld\n", mStatus));
+    if (mStatus == Dropping)
+    {
+        LogRel2(("Clipboard: Waiting for drop event ...\n"));
+        int rc2 = RTSemEventWait(mEventDropped, RT_INDEFINITE_WAIT);
+        LogFlowFunc(("rc2=%Rrc, mStatus=%ld\n", rc2, mStatus)); RT_NOREF(rc2);
+    }
+
+    if (mStatus == Dropped)
+    {
+        LogRel2(("Clipboard: Drop event received\n"));
+        LogRel3(("Clipboard: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n",
+                 pThisFormat->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
+                 pThisFormat->tymed, pThisFormat->dwAspect));
+        LogRel3(("Clipboard: Got strFormat=%s, pvData=%p, cbData=%RU32\n",
+                  mstrFormat.c_str(), mpvData, mcbData));
+
+        /*
+         * Initialize default values.
+         */
+        pMedium->tymed          = pThisFormat->tymed;
+        pMedium->pUnkForRelease = NULL;
+
+        /*
+         * URI list handling.
+         */
+        if (mstrFormat.equalsIgnoreCase("text/uri-list"))
+        {
+            int rc = VINF_SUCCESS;
+
+            RTCList<RTCString> lstFilesURI = RTCString((char*)mpvData, mcbData).split("\r\n");
+            RTCList<RTCString> lstFiles;
+            for (size_t i = 0; i < lstFilesURI.size(); i++)
+            {
+                char *pszFilePath = RTUriFilePath(lstFilesURI.at(i).c_str());
+                if (pszFilePath)
+                {
+                    lstFiles.append(pszFilePath);
+                    RTStrFree(pszFilePath);
+                }
+                else /* Unable to parse -- refuse entire request. */
+                {
+                    lstFiles.clear();
+                    rc = VERR_INVALID_PARAMETER;
+                    break;
+                }
+            }
+
+            size_t cFiles = lstFiles.size();
+            if (   RT_SUCCESS(rc)
+                && cFiles)
+            {
+#ifdef DEBUG
+                LogFlowFunc(("Files (%zu)\n", cFiles));
+                for (size_t i = 0; i < cFiles; i++)
+                    LogFlowFunc(("\tFile: %s\n", lstFiles.at(i).c_str()));
+#endif
+
+#if 0
+                if (   (pFormatEtc->tymed & TYMED_ISTREAM)
+                    && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
+                    && (pFormatEtc->cfFormat == CF_FILECONTENTS))
+                {
+
+                }
+                else if  (   (pFormatEtc->tymed & TYMED_HGLOBAL)
+                          && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
+                          && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR))
+                {
+
+                }
+                else if (   (pFormatEtc->tymed & TYMED_HGLOBAL)
+                         && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT))
+                {
+                    HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD));
+                    DWORD *pdwEffect = (DWORD *)GlobalLock(hData);
+                    AssertPtr(pdwEffect);
+                    *pdwEffect = DROPEFFECT_COPY;
+                    GlobalUnlock(hData);
+
+                    pMedium->hGlobal = hData;
+                    pMedium->tymed = TYMED_HGLOBAL;
+                }
+                else
+#endif
+                if (   (pFormatEtc->tymed & TYMED_HGLOBAL)
+                    && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
+                    && (pFormatEtc->cfFormat == CF_TEXT))
+                {
+                    pMedium->hGlobal = GlobalAlloc(GHND, mcbData + 1);
+                    if (pMedium->hGlobal)
+                    {
+                        char *pcDst  = (char *)GlobalLock(pMedium->hGlobal);
+                        memcpy(pcDst, mpvData, mcbData);
+                        pcDst[mcbData] = '\0';
+                        GlobalUnlock(pMedium->hGlobal);
+
+                        hr = S_OK;
+                    }
+                }
+                else if (   (pFormatEtc->tymed & TYMED_HGLOBAL)
+                         && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
+                         && (pFormatEtc->cfFormat == CF_HDROP))
+                {
+                    size_t cchFiles = 0; /* Number of ASCII characters. */
+                    for (size_t i = 0; i < cFiles; i++)
+                    {
+                        cchFiles += strlen(lstFiles.at(i).c_str());
+                        cchFiles += 1; /* Terminating '\0'. */
+                    }
+
+                    size_t cbBuf = sizeof(DROPFILES) + ((cchFiles + 1) * sizeof(RTUTF16));
+                    DROPFILES *pBuf = (DROPFILES *)RTMemAllocZ(cbBuf);
+                    if (pBuf)
+                    {
+                        pBuf->pFiles = sizeof(DROPFILES);
+                        pBuf->fWide = 1; /* We use unicode. Always. */
+
+                        uint8_t *pCurFile = (uint8_t *)pBuf + pBuf->pFiles;
+                        AssertPtr(pCurFile);
+
+                        for (size_t i = 0; i < cFiles && RT_SUCCESS(rc); i++)
+                        {
+                            size_t cchCurFile;
+                            PRTUTF16 pwszFile;
+                            rc = RTStrToUtf16(lstFiles.at(i).c_str(), &pwszFile);
+                            if (RT_SUCCESS(rc))
+                            {
+                                cchCurFile = RTUtf16Len(pwszFile);
+                                Assert(cchCurFile);
+                                memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16));
+                                RTUtf16Free(pwszFile);
+                            }
+                            else
+                                break;
+
+                            pCurFile += cchCurFile * sizeof(RTUTF16);
+
+                            /* Terminate current file name. */
+                            *pCurFile = L'\0';
+                            pCurFile += sizeof(RTUTF16);
+                        }
+
+                        if (RT_SUCCESS(rc))
+                        {
+                            *pCurFile = L'\0'; /* Final list terminator. */
+
+                            pMedium->tymed = TYMED_HGLOBAL;
+                            pMedium->pUnkForRelease = NULL;
+                            pMedium->hGlobal = GlobalAlloc(  GMEM_ZEROINIT
+                                                           | GMEM_MOVEABLE
+                                                           | GMEM_DDESHARE, cbBuf);
+                            if (pMedium->hGlobal)
+                            {
+                                LPVOID pMem = GlobalLock(pMedium->hGlobal);
+                                if (pMem)
+                                {
+                                    memcpy(pMem, pBuf, cbBuf);
+                                    GlobalUnlock(pMedium->hGlobal);
+
+                                    hr = S_OK;
+                                }
+                            }
+                        }
+
+                        RTMemFree(pBuf);
+                    }
+                    else
+                        rc = VERR_NO_MEMORY;
+                }
+            }
+
+            if (RT_FAILURE(rc))
+                hr = DV_E_FORMATETC;
+        }
+        /*
+         * Plain text handling.
+         */
+        else if (   mstrFormat.equalsIgnoreCase("text/plain")
+                 || mstrFormat.equalsIgnoreCase("text/html")
+                 || mstrFormat.equalsIgnoreCase("text/plain;charset=utf-8")
+                 || mstrFormat.equalsIgnoreCase("text/plain;charset=utf-16")
+                 || mstrFormat.equalsIgnoreCase("text/richtext")
+                 || mstrFormat.equalsIgnoreCase("UTF8_STRING")
+                 || mstrFormat.equalsIgnoreCase("TEXT")
+                 || mstrFormat.equalsIgnoreCase("STRING"))
+        {
+            pMedium->hGlobal = GlobalAlloc(GHND, mcbData + 1);
+            if (pMedium->hGlobal)
+            {
+                char *pcDst  = (char *)GlobalLock(pMedium->hGlobal);
+                memcpy(pcDst, mpvData, mcbData);
+                pcDst[mcbData] = '\0';
+                GlobalUnlock(pMedium->hGlobal);
+
+                hr = S_OK;
+            }
+        }
+        else
+            LogRel(("Clipboard: Error: Format '%s' not implemented\n", mstrFormat.c_str()));
+    }
+
+    /* Error handling; at least return some basic data. */
+    if (FAILED(hr))
+    {
+        LogFlowFunc(("Copying medium ...\n"));
+        switch (pThisMedium->tymed)
+        {
+
+        case TYMED_HGLOBAL:
+            pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal,
+                                                         pThisFormat->cfFormat, NULL);
+            break;
+
+        default:
+            break;
+        }
+
+        pMedium->tymed          = pThisFormat->tymed;
+        pMedium->pUnkForRelease = NULL;
+    }
+
+    if (hr == DV_E_FORMATETC)
+        LogRel(("Clipboard: Error handling format '%s' (%RU32 bytes)\n", mstrFormat.c_str(), mcbData));
+
+    LogFlowFunc(("hr=%Rhrc\n", hr));
+    return hr;
+}
+
+/**
+ * Only required for IStream / IStorage interfaces.
+ *
+ * @return  IPRT status code.
+ * @return  HRESULT
+ * @param   pFormatEtc
+ * @param   pMedium
+ */
+STDMETHODIMP VBoxClipboardWinDataObject::GetDataHere(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
+{
+    RT_NOREF(pFormatEtc, pMedium);
+    LogFlowFunc(("\n"));
+    return DATA_E_FORMATETC;
+}
+
+/**
+ * Query if this objects supports a specific format.
+ *
+ * @return  IPRT status code.
+ * @return  HRESULT
+ * @param   pFormatEtc
+ */
+STDMETHODIMP VBoxClipboardWinDataObject::QueryGetData(LPFORMATETC pFormatEtc)
+{
+    LogFlowFunc(("\n"));
+    return (LookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC;
+}
+
+STDMETHODIMP VBoxClipboardWinDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatEtc, LPFORMATETC pFormatEtcOut)
+{
+    RT_NOREF(pFormatEtc);
+    LogFlowFunc(("\n"));
+
+    /* Set this to NULL in any case. */
+    pFormatEtcOut->ptd = NULL;
+    return E_NOTIMPL;
+}
+
+STDMETHODIMP VBoxClipboardWinDataObject::SetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease)
+{
+    RT_NOREF(pFormatEtc, pMedium, fRelease);
+    return E_NOTIMPL;
+}
+
+STDMETHODIMP VBoxClipboardWinDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
+{
+    LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n", dwDirection, mcFormats, mpFormatEtc));
+
+    HRESULT hr;
+    if (dwDirection == DATADIR_GET)
+        hr = VBoxClipboardWinEnumFormatEtc::CreateEnumFormatEtc(mcFormats, mpFormatEtc, ppEnumFormatEtc);
+    else
+        hr = E_NOTIMPL;
+
+    LogFlowFunc(("hr=%Rhrc\n", hr));
+    return hr;
+}
+
+STDMETHODIMP VBoxClipboardWinDataObject::DAdvise(LPFORMATETC pFormatEtc, DWORD fAdvise, IAdviseSink *pAdvSink, DWORD *pdwConnection)
+{
+    RT_NOREF(pFormatEtc, fAdvise, pAdvSink, pdwConnection);
+    return OLE_E_ADVISENOTSUPPORTED;
+}
+
+STDMETHODIMP VBoxClipboardWinDataObject::DUnadvise(DWORD dwConnection)
+{
+    RT_NOREF(dwConnection);
+    return OLE_E_ADVISENOTSUPPORTED;
+}
+
+STDMETHODIMP VBoxClipboardWinDataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
+{
+    RT_NOREF(ppEnumAdvise);
+    return OLE_E_ADVISENOTSUPPORTED;
+}
+
+/*
+ * Own stuff.
+ */
+
+int VBoxClipboardWinDataObject::Abort(void)
+{
+    LogFlowFunc(("Aborting ...\n"));
+    mStatus = Aborted;
+    return RTSemEventSignal(mEventDropped);
+}
+
+/* static */
+const char* VBoxClipboardWinDataObject::ClipboardFormatToString(CLIPFORMAT fmt)
+{
+#if 0
+    char szFormat[128];
+    if (GetClipboardFormatName(fmt, szFormat, sizeof(szFormat)))
+        LogFlowFunc(("wFormat=%RI16, szName=%s\n", fmt, szFormat));
+#endif
+
+    switch (fmt)
+    {
+
+    case 1:
+        return "CF_TEXT";
+    case 2:
+        return "CF_BITMAP";
+    case 3:
+        return "CF_METAFILEPICT";
+    case 4:
+        return "CF_SYLK";
+    case 5:
+        return "CF_DIF";
+    case 6:
+        return "CF_TIFF";
+    case 7:
+        return "CF_OEMTEXT";
+    case 8:
+        return "CF_DIB";
+    case 9:
+        return "CF_PALETTE";
+    case 10:
+        return "CF_PENDATA";
+    case 11:
+        return "CF_RIFF";
+    case 12:
+        return "CF_WAVE";
+    case 13:
+        return "CF_UNICODETEXT";
+    case 14:
+        return "CF_ENHMETAFILE";
+    case 15:
+        return "CF_HDROP";
+    case 16:
+        return "CF_LOCALE";
+    case 17:
+        return "CF_DIBV5";
+    case 18:
+        return "CF_MAX";
+    case 49158:
+        return "FileName";
+    case 49159:
+        return "FileNameW";
+    case 49161:
+        return "DATAOBJECT";
+    case 49171:
+        return "Ole Private Data";
+    case 49314:
+        return "Shell Object Offsets";
+    case 49316:
+        return "File Contents";
+    case 49317:
+        return "File Group Descriptor";
+    case 49323:
+        return "Preferred Drop Effect";
+    case 49380:
+        return "Shell Object Offsets";
+    case 49382:
+        return "FileContents";
+    case 49383:
+        return "FileGroupDescriptor";
+    case 49389:
+        return "Preferred DropEffect";
+    case 49268:
+        return "Shell IDList Array";
+    case 49619:
+        return "RenPrivateFileAttachments";
+    default:
+        break;
+    }
+
+    return "unknown";
+}
+
+bool VBoxClipboardWinDataObject::LookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex)
+{
+    AssertReturn(pFormatEtc, false);
+    /* puIndex is optional. */
+
+    for (ULONG i = 0; i < mcFormats; i++)
+    {
+        if(    (pFormatEtc->tymed & mpFormatEtc[i].tymed)
+            && pFormatEtc->cfFormat == mpFormatEtc[i].cfFormat
+            && pFormatEtc->dwAspect == mpFormatEtc[i].dwAspect)
+        {
+            LogRel3(("Clipboard: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
+                      pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(mpFormatEtc[i].cfFormat),
+                      pFormatEtc->dwAspect, i));
+            if (puIndex)
+                *puIndex = i;
+            return true;
+        }
+    }
+
+    LogRel3(("Clipboard: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
+             pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
+             pFormatEtc->dwAspect));
+
+    return false;
+}
+
+/* static */
+HGLOBAL VBoxClipboardWinDataObject::MemDup(HGLOBAL hMemSource)
+{
+    DWORD dwLen    = GlobalSize(hMemSource);
+    AssertReturn(dwLen, NULL);
+    PVOID pvSource = GlobalLock(hMemSource);
+    if (pvSource)
+    {
+        PVOID pvDest = GlobalAlloc(GMEM_FIXED, dwLen);
+        if (pvDest)
+            memcpy(pvDest, pvSource, dwLen);
+
+        GlobalUnlock(hMemSource);
+        return pvDest;
+    }
+
+    return NULL;
+}
+
+void VBoxClipboardWinDataObject::RegisterFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat,
+                                       TYMED tyMed, LONG lIndex, DWORD dwAspect,
+                                       DVTARGETDEVICE *pTargetDevice)
+{
+    AssertPtr(pFormatEtc);
+
+    pFormatEtc->cfFormat = clipFormat;
+    pFormatEtc->tymed    = tyMed;
+    pFormatEtc->lindex   = lIndex;
+    pFormatEtc->dwAspect = dwAspect;
+    pFormatEtc->ptd      = pTargetDevice;
+
+    LogFlowFunc(("Registered format=%ld, sFormat=%s\n",
+                 pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat)));
+}
+
+void VBoxClipboardWinDataObject::SetStatus(Status status)
+{
+    LogFlowFunc(("Setting status to %ld\n", status));
+    mStatus = status;
+}
+
+int VBoxClipboardWinDataObject::Signal(const RTCString &strFormat,
+                              const void *pvData, uint32_t cbData)
+{
+    int rc;
+
+    if (cbData)
+    {
+        mpvData = RTMemAlloc(cbData);
+        if (mpvData)
+        {
+            memcpy(mpvData, pvData, cbData);
+            mcbData = cbData;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    if (RT_SUCCESS(rc))
+    {
+        mStatus    = Dropped;
+        mstrFormat = strFormat;
+    }
+    else
+    {
+        mStatus = Aborted;
+    }
+
+    /* Signal in any case. */
+    LogRel2(("Clipboard: Signalling drop event\n"));
+
+    int rc2 = RTSemEventSignal(mEventDropped);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFunc(("mStatus=%RU32, rc=%Rrc\n", mStatus, rc));
+    return rc;
+}
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardEnumFormatEtcImpl-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardEnumFormatEtcImpl-win.cpp	(revision 78440)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardEnumFormatEtcImpl-win.cpp	(revision 78440)
@@ -0,0 +1,194 @@
+/* $Id$ */
+/** @file
+ * ClipboardEnumFormatEtcImpl-win.cpp - Shared Clipboard IEnumFORMATETC ("Format et cetera") implementation.
+ */
+
+/*
+ * Copyright (C) 2013-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                                                                                                                 *
+*********************************************************************************************************************************/
+#include <new> /* For bad_alloc. */
+
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
+#include <VBox/GuestHost/SharedClipboard-win.h>
+
+#include <iprt/win/windows.h>
+
+#include <VBox/log.h>
+
+
+
+VBoxClipboardWinEnumFormatEtc::VBoxClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats)
+    : m_lRefCount(1),
+      m_nIndex(0)
+{
+    HRESULT hr;
+
+    try
+    {
+        LogFlowFunc(("pFormatEtc=%p, cFormats=%RU32\n", pFormatEtc, cFormats));
+        m_pFormatEtc  = new FORMATETC[cFormats];
+
+        for (ULONG i = 0; i < cFormats; i++)
+        {
+            LogFlowFunc(("Format %RU32: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n",
+                         i, pFormatEtc[i].cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc[i].cfFormat),
+                         pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
+            VBoxClipboardWinEnumFormatEtc::CopyFormat(&m_pFormatEtc[i], &pFormatEtc[i]);
+        }
+
+        m_nNumFormats = cFormats;
+        hr = S_OK;
+    }
+    catch (std::bad_alloc &)
+    {
+        hr = E_OUTOFMEMORY;
+    }
+
+    LogFlowFunc(("hr=%Rhrc\n", hr));
+}
+
+VBoxClipboardWinEnumFormatEtc::~VBoxClipboardWinEnumFormatEtc(void)
+{
+    if (m_pFormatEtc)
+    {
+        for (ULONG i = 0; i < m_nNumFormats; i++)
+        {
+            if(m_pFormatEtc[i].ptd)
+                CoTaskMemFree(m_pFormatEtc[i].ptd);
+        }
+
+        delete[] m_pFormatEtc;
+        m_pFormatEtc = NULL;
+    }
+
+    LogFlowFunc(("m_lRefCount=%RI32\n", m_lRefCount));
+}
+
+/*
+ * IUnknown methods.
+ */
+
+STDMETHODIMP_(ULONG) VBoxClipboardWinEnumFormatEtc::AddRef(void)
+{
+    return InterlockedIncrement(&m_lRefCount);
+}
+
+STDMETHODIMP_(ULONG) VBoxClipboardWinEnumFormatEtc::Release(void)
+{
+    LONG lCount = InterlockedDecrement(&m_lRefCount);
+    if (lCount == 0)
+    {
+        delete this;
+        return 0;
+    }
+
+    return lCount;
+}
+
+STDMETHODIMP VBoxClipboardWinEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject)
+{
+    if (   iid == IID_IEnumFORMATETC
+        || iid == IID_IUnknown)
+    {
+        AddRef();
+        *ppvObject = this;
+        return S_OK;
+    }
+
+    *ppvObject = 0;
+    return E_NOINTERFACE;
+}
+
+STDMETHODIMP VBoxClipboardWinEnumFormatEtc::Next(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched)
+{
+    ULONG ulCopied  = 0;
+
+    if(cFormats == 0 || pFormatEtc == 0)
+        return E_INVALIDARG;
+
+    while (   m_nIndex < m_nNumFormats
+           && ulCopied < cFormats)
+    {
+        VBoxClipboardWinEnumFormatEtc::CopyFormat(&pFormatEtc[ulCopied],
+                                         &m_pFormatEtc[m_nIndex]);
+        ulCopied++;
+        m_nIndex++;
+    }
+
+    if (pcFetched)
+        *pcFetched = ulCopied;
+
+    return (ulCopied == cFormats) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP VBoxClipboardWinEnumFormatEtc::Skip(ULONG cFormats)
+{
+    m_nIndex += cFormats;
+    return (m_nIndex <= m_nNumFormats) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP VBoxClipboardWinEnumFormatEtc::Reset(void)
+{
+    m_nIndex = 0;
+    return S_OK;
+}
+
+STDMETHODIMP VBoxClipboardWinEnumFormatEtc::Clone(IEnumFORMATETC **ppEnumFormatEtc)
+{
+    HRESULT hResult =
+        CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
+
+    if (hResult == S_OK)
+        ((VBoxClipboardWinEnumFormatEtc *) *ppEnumFormatEtc)->m_nIndex = m_nIndex;
+
+    return hResult;
+}
+
+/* static */
+void VBoxClipboardWinEnumFormatEtc::CopyFormat(LPFORMATETC pDest, LPFORMATETC pSource)
+{
+    AssertPtrReturnVoid(pDest);
+    AssertPtrReturnVoid(pSource);
+
+    *pDest = *pSource;
+
+    if (pSource->ptd)
+    {
+        pDest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
+        *(pDest->ptd) = *(pSource->ptd);
+    }
+}
+
+/* static */
+HRESULT VBoxClipboardWinEnumFormatEtc::CreateEnumFormatEtc(UINT nNumFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc)
+{
+    AssertReturn(nNumFormats, E_INVALIDARG);
+    AssertPtrReturn(pFormatEtc, E_INVALIDARG);
+    AssertPtrReturn(ppEnumFormatEtc, E_INVALIDARG);
+
+    HRESULT hr;
+    try
+    {
+        *ppEnumFormatEtc = new VBoxClipboardWinEnumFormatEtc(pFormatEtc, nNumFormats);
+        hr = S_OK;
+    }
+    catch(std::bad_alloc &)
+    {
+        hr = E_OUTOFMEMORY;
+    }
+
+    return hr;
+}
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp	(revision 78440)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp	(revision 78440)
@@ -0,0 +1,44 @@
+/* $Id$ */
+/** @file
+ * ClipboardStreamImpl-win.cpp - Shared Clipboard IStream object implementation (for CF_HDROP).
+ */
+
+/*
+ * 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.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
+#include <VBox/GuestHost/SharedClipboard-win.h>
+
+#include <iprt/asm.h>
+#include <iprt/ldr.h>
+
+#include <VBox/GuestHost/SharedClipboard.h>
+#include <VBox/GuestHost/SharedClipboard-win.h>
+#include <strsafe.h>
+
+#include <VBox/log.h>
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+
+
+/*********************************************************************************************************************************
+*   Static variables                                                                                                             *
+*********************************************************************************************************************************/
+
Index: /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp	(revision 78439)
+++ /trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp	(revision 78440)
@@ -22,5 +22,7 @@
 #include <iprt/thread.h>
 
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
 #include <VBox/log.h>
+
 #include <VBox/GuestHost/SharedClipboard.h>
 #include <VBox/GuestHost/SharedClipboard-win.h>
@@ -275,11 +277,5 @@
     AssertPtrReturn(puFormats, VERR_INVALID_POINTER);
 
-    if (!pCtx)
-    {
-        *puFormats = 0;
-        return VINF_SUCCESS;
-    }
-
-    uint32_t uFormats = 0;
+    uint32_t uFormats = VBOX_SHARED_CLIPBOARD_FMT_NONE;
 
     /* Query list of available formats and report to host. */
@@ -336,7 +332,10 @@
     }
     else
+    {
+        LogFlowFunc(("uFormats = 0x%08X\n", uFormats));
         *puFormats = uFormats;
-
-    return rc;
-}
-
+    }
+
+    return rc;
+}
+
Index: /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk	(revision 78439)
+++ /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk	(revision 78440)
@@ -43,4 +43,10 @@
 	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \
 	darwin-pasteboard.cpp
+ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+ VBoxSharedClipboard_SOURCES += \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardURIList.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardURIObject.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardPath.cpp
+endif
 if1of ($(KBUILD_TARGET), linux solaris freebsd) ## @todo X11
  ifndef VBOX_HEADLESS
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 78439)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 78440)
@@ -25,4 +25,7 @@
 #include <VBox/HostServices/VBoxClipboardSvc.h>
 #include <VBox/GuestHost/SharedClipboard-win.h>
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
+# include <VBox/GuestHost/SharedClipboard-uri.h>
+#endif
 
 #include <iprt/alloc.h>
@@ -30,6 +33,7 @@
 #include <iprt/asm.h>
 #include <iprt/assert.h>
+#include <iprt/ldr.h>
+#include <iprt/semaphore.h>
 #include <iprt/thread.h>
-#include <iprt/ldr.h>
 #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
 # include <iprt/utf16.h>
@@ -58,5 +62,5 @@
     RTTHREAD                 hThread;
     /** Event which gets triggered if the host clipboard needs to render its data. */
-    HANDLE                   hRenderEvent;
+    RTSEMEVENT               hRenderEvent;
     /** Structure for keeping and communicating with client data (from the guest). */
     PVBOXCLIPBOARDCLIENTDATA pClient;
@@ -115,5 +119,5 @@
                                  void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
 {
-    LogFlow(("vboxClipboardGetData cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
+    LogFlowFunc(("cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
 
     if (   u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
@@ -139,10 +143,4 @@
             *pcbActualDst = 0;
     }
-#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
-    if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
-    {
-        /* Convert data to URI list. */
-    }
-#endif
     else
     {
@@ -163,5 +161,5 @@
 }
 
-static int vboxClipboardReadDataFromClient(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format)
+static int vboxClipboardReadDataFromClient(VBOXCLIPBOARDCONTEXT *pCtx, VBOXCLIPBOARDFORMAT fFormat)
 {
     Assert(pCtx->pClient);
@@ -169,15 +167,9 @@
     Assert(pCtx->pClient->data.pv == NULL && pCtx->pClient->data.cb == 0 && pCtx->pClient->data.u32Format == 0);
 
-    LogFlow(("vboxClipboardReadDataFromClient u32Format = %02X\n", u32Format));
-
-    ResetEvent(pCtx->hRenderEvent);
-
-    vboxSvcClipboardReportMsg(pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
-
-    DWORD ret = WaitForSingleObject(pCtx->hRenderEvent, INFINITE);
-    LogFlow(("vboxClipboardReadDataFromClient wait completed, ret 0x%08X, err %d\n",
-             ret, GetLastError())); NOREF(ret);
-
-    return VINF_SUCCESS;
+    LogFlowFunc(("fFormat=%02X\n", fFormat));
+
+    vboxSvcClipboardReportMsg(pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, fFormat);
+
+    return RTSemEventWait(pCtx->hRenderEvent, 30 * 1000 /* Timeout in ms */);
 }
 
@@ -193,5 +185,5 @@
         case WM_CLIPBOARDUPDATE:
         {
-            Log(("WM_CLIPBOARDUPDATE\n"));
+            LogFunc(("WM_CLIPBOARDUPDATE\n"));
 
             if (GetClipboardOwner() != hwnd)
@@ -205,5 +197,5 @@
         case WM_CHANGECBCHAIN:
         {
-            Log(("WM_CHANGECBCHAIN\n"));
+            LogFunc(("WM_CHANGECBCHAIN\n"));
 
             if (VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
@@ -240,5 +232,5 @@
         case WM_DRAWCLIPBOARD:
         {
-            Log(("WM_DRAWCLIPBOARD\n"));
+            LogFunc(("WM_DRAWCLIPBOARD\n"));
 
             if (GetClipboardOwner() != hwnd)
@@ -251,5 +243,5 @@
             if (pWinCtx->hWndNextInChain)
             {
-                Log(("WM_DRAWCLIPBOARD next %p\n", pWinCtx->hWndNextInChain));
+                LogFunc(("WM_DRAWCLIPBOARD next %p\n", pWinCtx->hWndNextInChain));
                 /* Pass the message to next windows in the clipboard chain. */
                 DWORD_PTR dwResult;
@@ -290,18 +282,18 @@
         {
             /* Insert the requested clipboard format data into the clipboard. */
-            uint32_t u32Format = 0;
+            VBOXCLIPBOARDFORMAT fFormat = VBOX_SHARED_CLIPBOARD_FMT_NONE;
 
             UINT format = (UINT)wParam;
 
-            Log(("WM_RENDERFORMAT: Format %u\n", format));
+            LogFunc(("WM_RENDERFORMAT: Format %u\n", format));
 
             switch (format)
             {
                 case CF_UNICODETEXT:
-                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
+                    fFormat |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
                     break;
 
                 case CF_DIB:
-                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
+                    fFormat |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
                     break;
 
@@ -314,9 +306,9 @@
                         {
                             if (RTStrCmp(szFormatName, "HTML Format") == 0)
-                                u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
+                                fFormat |= 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;
+                                fFormat |= VBOX_SHARED_CLIPBOARD_FMT_URI_LIST;
 #endif
                         }
@@ -325,13 +317,14 @@
             }
 
-            if (u32Format == 0 || pCtx->pClient == NULL)
+            if (   fFormat       == VBOX_SHARED_CLIPBOARD_FMT_NONE
+                || pCtx->pClient == NULL)
             {
                 /* Unsupported clipboard format is requested. */
-                Log(("WM_RENDERFORMAT unsupported format requested or client is not active.\n"));
-                EmptyClipboard ();
+                LogFunc(("WM_RENDERFORMAT unsupported format requested or client is not active\n"));
+                EmptyClipboard();
             }
             else
             {
-                int vboxrc = vboxClipboardReadDataFromClient(pCtx, u32Format);
+                int vboxrc = vboxClipboardReadDataFromClient(pCtx, fFormat);
 
                 LogFunc(("vboxClipboardReadDataFromClient vboxrc = %d, pv %p, cb %d, u32Format %d\n",
@@ -341,5 +334,5 @@
                     && pCtx->pClient->data.pv != NULL
                     && pCtx->pClient->data.cb > 0
-                    && pCtx->pClient->data.u32Format == u32Format)
+                    && pCtx->pClient->data.u32Format == fFormat)
                 {
                     HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClient->data.cb);
@@ -355,5 +348,5 @@
                         if (pMem)
                         {
-                            Log(("WM_RENDERFORMAT setting data\n"));
+                            LogFunc(("WM_RENDERFORMAT setting data\n"));
 
                             if (pCtx->pClient->data.pv)
@@ -401,5 +394,5 @@
         case WM_RENDERALLFORMATS:
         {
-            Log(("WM_RENDERALLFORMATS\n"));
+            LogFunc(("WM_RENDERALLFORMATS\n"));
 
             /* Do nothing. The clipboard formats will be unavailable now, because the
@@ -414,5 +407,5 @@
             else
             {
-                LogFlow(("vboxClipboardWndProc: WM_RENDERALLFORMATS: error in open clipboard. hwnd: %x, rc: %Rrc\n", hwnd, vboxrc));
+                LogFlowFunc(("WM_RENDERALLFORMATS: error in open clipboard. hwnd: %x, rc: %Rrc\n", hwnd, vboxrc));
             }
         } break;
@@ -425,5 +418,5 @@
                  * because host clipboard has more priority.
                  */
-                Log(("VBOX_CLIPBOARD_WM_SET_FORMATS ignored\n"));
+                LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS ignored\n"));
                 break;
             }
@@ -432,5 +425,5 @@
             uint32_t u32Formats = (uint32_t)lParam;
 
-            Log(("VBOX_CLIPBOARD_WM_SET_FORMATS: u32Formats=%02X\n", u32Formats));
+            LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS: u32Formats=%02X\n", u32Formats));
 
             int vboxrc = VBoxClipboardWinOpen(hwnd);
@@ -439,5 +432,5 @@
                 VBoxClipboardWinClear();
 
-                Log(("VBOX_CLIPBOARD_WM_SET_FORMATS emptied clipboard\n"));
+                LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS emptied clipboard\n"));
 
                 HANDLE hClip = NULL;
@@ -486,10 +479,10 @@
         default:
         {
-            Log(("WM_ %p\n", msg));
+            LogFunc(("WM_ %p\n", msg));
             rc = DefWindowProc(hwnd, msg, wParam, lParam);
         }
     }
 
-    Log(("WM_ rc %d\n", rc));
+    LogFunc(("WM_ rc %d\n", rc));
     return rc;
 }
@@ -497,9 +490,10 @@
 DECLCALLBACK(int) VBoxClipboardThread(RTTHREAD hThreadSelf, void *pvUser)
 {
-    RT_NOREF2(hThreadSelf, pvUser);
+    RT_NOREF(hThreadSelf, pvUser);
+
     /* Create a window and make it a clipboard viewer. */
     int rc = VINF_SUCCESS;
 
-    LogFlow(("VBoxClipboardThread\n"));
+    LogFlowFuncEnter();
 
     const PVBOXCLIPBOARDCONTEXT pCtx    = &g_ctx;
@@ -522,5 +516,5 @@
     if (atomWindowClass == 0)
     {
-        Log(("Failed to register window class\n"));
+        LogFunc(("Failed to register window class\n"));
         rc = VERR_NOT_SUPPORTED;
     }
@@ -534,5 +528,5 @@
         if (pWinCtx->hWnd == NULL)
         {
-            Log(("Failed to create window\n"));
+            LogFunc(("Failed to create window\n"));
             rc = VERR_NOT_SUPPORTED;
         }
@@ -559,5 +553,5 @@
             */
             Assert(msgret >= 0);
-            Log(("VBoxClipboardThread Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
+            LogFunc(("Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
         }
     }
@@ -578,5 +572,5 @@
  * formats to the guest.
  *
- * @returns VBox status code.
+ * @returns VBox status code, VINF_NO_CHANGE if no synchronization was required.
  * @param   pCtx                Clipboard context to synchronize.
  */
@@ -585,12 +579,17 @@
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
 
-    if (pCtx->pClient == NULL) /* If we don't have any client data (yet), bail out. */
-        return VINF_SUCCESS;
-
-    uint32_t uFormats;
-    int rc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
-    if (RT_SUCCESS(rc))
-        vboxSvcClipboardReportMsg(pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS, uFormats);
-
+    int rc;
+
+    if (pCtx->pClient)
+    {
+        uint32_t uFormats;
+        rc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
+        if (RT_SUCCESS(rc))
+            vboxSvcClipboardReportMsg(pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS, uFormats);
+    }
+    else /* If we don't have any client data (yet), bail out. */
+        rc = VINF_NO_CHANGE;
+
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -601,20 +600,18 @@
 int vboxClipboardInit(void)
 {
-    int rc = VINF_SUCCESS;
-
-    RT_ZERO(g_ctx);
+    RT_ZERO(g_ctx); /* Be careful not messing up non-POD types! */
 
     /* Check that new Clipboard API is available. */
     VBoxClipboardWinCheckAndInitNewAPI(&g_ctx.Win.newAPI);
 
-    g_ctx.hRenderEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
-    rc = RTThreadCreate(&g_ctx.hThread, VBoxClipboardThread, NULL, _64K /* Stack size */,
-                        RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
+    int rc = RTSemEventCreate(&g_ctx.hRenderEvent);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTThreadCreate(&g_ctx.hThread, VBoxClipboardThread, NULL, _64K /* Stack size */,
+                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
+    }
 
     if (RT_FAILURE(rc))
-    {
-        CloseHandle(g_ctx.hRenderEvent);
-    }
+        RTSemEventDestroy(g_ctx.hRenderEvent);
 
     return rc;
@@ -623,5 +620,5 @@
 void vboxClipboardDestroy(void)
 {
-    Log(("vboxClipboardDestroy\n"));
+    LogFlowFuncEnter();
 
     if (g_ctx.Win.hWnd)
@@ -630,8 +627,11 @@
     }
 
-    CloseHandle(g_ctx.hRenderEvent);
+    int rc = RTSemEventDestroy(g_ctx.hRenderEvent);
+    AssertRC(rc);
 
     /* Wait for the window thread to terminate. */
-    RTThreadWait(g_ctx.hThread, RT_INDEFINITE_WAIT, NULL);
+    rc = RTThreadWait(g_ctx.hThread, 30 * 1000 /* Timeout in ms */, NULL);
+    if (RT_FAILURE(rc))
+        LogRel(("Shared Clipboard: Waiting for window thread termination failed with rc=%Rrc\n", rc));
 
     g_ctx.hThread = NIL_RTTHREAD;
@@ -640,6 +640,7 @@
 int vboxClipboardConnect(VBOXCLIPBOARDCLIENTDATA *pClient, bool fHeadless)
 {
-    NOREF(fHeadless);
-    Log(("vboxClipboardConnect\n"));
+    RT_NOREF(fHeadless);
+
+    LogFlowFuncEnter();
 
     if (g_ctx.pClient != NULL)
@@ -667,6 +668,7 @@
 void vboxClipboardDisconnect(VBOXCLIPBOARDCLIENTDATA *pClient)
 {
-    RT_NOREF1(pClient);
-    Log(("vboxClipboardDisconnect\n"));
+    RT_NOREF(pClient);
+
+    LogFlowFuncEnter();
 
     g_ctx.pClient = NULL;
@@ -684,5 +686,6 @@
 }
 
-int DumpHtml(const char *pszSrc, size_t cb)
+#ifdef VBOX_STRICT
+static int vboxClipboardDbgDumpHtml(const char *pszSrc, size_t cb)
 {
     size_t cchIgnored = 0;
@@ -701,6 +704,6 @@
             }
             else
-                Log(("Error in copying string.\n"));
-            Log(("Removed \\r\\n: %s\n", pszBuf));
+                LogFunc(("Error in copying string\n"));
+            LogFunc(("Removed \\r\\n: %s\n", pszBuf));
             RTMemFree(pszBuf);
         }
@@ -708,9 +711,10 @@
         {
             rc = VERR_NO_MEMORY;
-            Log(("Not enough memory to allocate buffer.\n"));
+            LogFunc(("Not enough memory to allocate buffer\n"));
         }
     }
     return rc;
 }
+#endif
 
 int vboxClipboardReadData(VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv, uint32_t cb, uint32_t *pcbActual)
@@ -719,5 +723,5 @@
     AssertPtrReturn(pClient->pCtx, VERR_INVALID_POINTER);
 
-    LogFlow(("vboxClipboardReadData: u32Format = %02X\n", u32Format));
+    LogFlowFunc(("u32Format=%02X\n", u32Format));
 
     HANDLE hClip = NULL;
@@ -731,10 +735,9 @@
     if (RT_SUCCESS(rc))
     {
-        LogFunc(("Clipboard opened.\n"));
+        LogFunc(("Clipboard opened\n"));
 
         if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
         {
             hClip = GetClipboardData(CF_DIB);
-
             if (hClip != NULL)
             {
@@ -759,5 +762,4 @@
         {
             hClip = GetClipboardData(CF_UNICODETEXT);
-
             if (hClip != NULL)
             {
@@ -782,13 +784,10 @@
         {
             UINT format = RegisterClipboardFormat("HTML Format");
-
             if (format != 0)
             {
                 hClip = GetClipboardData(format);
-
                 if (hClip != NULL)
                 {
                     LPVOID lp = GlobalLock(hClip);
-
                     if (lp != NULL)
                     {
@@ -797,6 +796,8 @@
                         vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip),
                                              pv, cb, pcbActual);
-                        LogRelFlowFunc(("Raw HTML clipboard data from host :"));
-                        DumpHtml((char *)pv, cb);
+#ifdef VBOX_STRICT
+                        LogFlowFunc(("Raw HTML clipboard data from host:"));
+                        vboxClipboardDbgDumpHtml((char *)pv, cb);
+#endif
                         GlobalUnlock(hClip);
                     }
@@ -811,186 +812,161 @@
         else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
         {
-    #if 0
-            UINT format = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
-            if (format)
-            {
-                hClip = GetClipboardData(format);
-                if (hClip != NULL)
+            hClip = GetClipboardData(CF_HDROP);
+            if (hClip != NULL)
+            {
+                LPVOID lp = GlobalLock(hClip);
+                if (lp)
                 {
-                    LPVOID lp = GlobalLock(hClip);
-
-                    if (lp != NULL)
+                    /* 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(("Shared Clipboard: Got %RU16 file(s), fUnicode=%RTbool\n", cFiles, fUnicode));
+
+                    for (UINT i = 0; i < cFiles; i++)
                     {
-                        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);
+                        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))
                         {
-                            cchFileUtf8 = (UINT)strlen(pszFileUtf8);
-                            Assert(cchFileUtf8);
+                            LogFlowFunc(("\tFile: %s (cchFile=%RU16)\n", pszFileUtf8, cchFileUtf8));
+
+                            LogRel2(("Shared Clipboard: Adding host file '%s'\n", pszFileUtf8));
+
+                            rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, pszFileUtf8, cchFileUtf8);
+                            if (RT_SUCCESS(rc))
+                                cchFiles += cchFileUtf8;
                         }
-
-                        RTMemFree(pwszFile);
+                        else
+                            LogRel(("Shared Clipboard: 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 */
                     }
-                    else
-                        rc = VERR_NO_MEMORY;
+
+                    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. */
+                        SharedClipboardURIList lstURI;
+                        rc = lstURI.AppendNativePathsFromList(pszFiles, cbFiles,
+                                                              SHAREDCLIPBOARDURILIST_FLAGS_ABSOLUTE_PATHS);
+                        if (RT_SUCCESS(rc))
+                        {
+                            RTCString strRoot = lstURI.GetRootEntries();
+                            size_t cbRoot = strRoot.length() + 1; /* Include termination */
+
+                            if (cbRoot > cb) /** @todo Add overflow handling! */
+                                cbRoot = cb; /* Never copy more than the available buffer supplies. */
+
+                            memcpy(pv, strRoot.c_str(), cbRoot);
+
+                            *pcbActual = (uint32_t)cbRoot;
+                        }
+                    }
+
+                    LogFlowFunc(("Building CF_HDROP list rc=%Rrc, pszFiles=0x%p, cFiles=%RU16, cchFiles=%RU32\n",
+                                 rc, pszFiles, cFiles, cchFiles));
+
+                    if (pszFiles)
+                        RTStrFree(pszFiles);
+
+                    GlobalUnlock(hClip);
                 }
-                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();
     }
-    else
-    {
-        LogFunc(("vboxClipboardReadData: failed to open clipboard, rc: %Rrc\n", rc));
-    }
 
     if (hClip == NULL)
     {
         /* Reply with empty data. */
-        vboxClipboardGetData(0, NULL, 0,
-                             pv, cb, pcbActual);
-    }
-
-    return VINF_SUCCESS;
+        vboxClipboardGetData(0, NULL, 0, pv, cb, pcbActual);
+    }
+
+    return VINF_SUCCESS; /** @todo r=andy Return rc here? */
 }
 
 void vboxClipboardWriteData(VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format)
 {
-    LogFlow(("vboxClipboardWriteData\n"));
+    LogFlowFuncEnter();
 
     /*
@@ -1032,5 +1008,9 @@
     }
 
-    SetEvent(pClient->pCtx->hRenderEvent);
+    AssertPtr(pClient->pCtx);
+    int rc = RTSemEventSignal(pClient->pCtx->hRenderEvent);
+    AssertRC(rc);
+
+    /** @todo Return rc. */
 }
 
@@ -1127,5 +1107,5 @@
                 else
                 {
-                    LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment.\n"));
+                    LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment\n"));
                     rc = VERR_NO_MEMORY;
                 }
@@ -1139,5 +1119,5 @@
         else
         {
-            LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc.\n", rc));
+            LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc\n", rc));
             rc = VERR_INVALID_PARAMETER;
         }
@@ -1145,5 +1125,5 @@
     else
     {
-        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected StartFragment. rc = %Rrc.\n", rc));
+        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected StartFragment. rc = %Rrc\n", rc));
         rc = VERR_INVALID_PARAMETER;
     }
@@ -1190,5 +1170,5 @@
     if (!RT_SUCCESS(rc))
     {
-        LogRelFlowFunc(("Error: invalid source fragment. rc = %Rrc.\n"));
+        LogRelFlowFunc(("Error: invalid source fragment. rc = %Rrc\n"));
         return VERR_INVALID_PARAMETER;
     }
@@ -1230,5 +1210,5 @@
     if (pszResult == NULL)
     {
-        LogRelFlowFunc(("Error: Cannot allocate memory for result buffer. rc = %Rrc.\n"));
+        LogRelFlowFunc(("Error: Cannot allocate memory for result buffer. rc = %Rrc\n"));
         return VERR_NO_MEMORY;
     }
@@ -1259,2 +1239,3 @@
     return VINF_SUCCESS;
 }
+
