Index: /trunk/src/VBox/Main/include/GuestDnDPrivate.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestDnDPrivate.h	(revision 85738)
+++ /trunk/src/VBox/Main/include/GuestDnDPrivate.h	(revision 85739)
@@ -837,8 +837,14 @@
     /** @}  */
 
-protected:
+public:
 
     /** Pointer to context this class is tied to. */
     void                 *m_pvCtx;
+    /** The DnD protocol version to use, depending on the
+     *  installed Guest Additions. See DragAndDropSvc.h for
+     *  a protocol changelog. */
+    uint32_t              m_uProtocolVersion;
+    /** The guest feature flags reported to the host (VBOX_DND_GF_XXX).  */
+    uint64_t              m_fGuestFeatures0;
     /** Event for waiting for response. */
     RTSEMEVENT            m_EventSem;
@@ -1003,11 +1009,7 @@
     HRESULT i_addFormats(const GuestDnDMIMEList &aFormats);
     HRESULT i_removeFormats(const GuestDnDMIMEList &aFormats);
-
-    HRESULT i_getProtocolVersion(ULONG *puVersion);
     /** @}  */
 
 protected:
-
-    int getProtocolVersion(uint32_t *puVersion);
 
     /** @name Functions for handling a simple host HGCM message queue.
@@ -1035,4 +1037,6 @@
     /** Whether the object still is in pending state. */
     bool                            m_fIsPending;
+    /** Pointer to response bound to this object. */
+    GuestDnDResponse               *m_pResp;
     /** @}  */
 
@@ -1042,8 +1046,4 @@
     struct
     {
-        /** The DnD protocol version to use, depending on the
-         *  installed Guest Additions. See DragAndDropSvc.h for
-         *  a protocol changelog. */
-        uint32_t                    uProtocolVersion;
         /** Outgoing message queue (FIFO). */
         GuestDnDMsgList             lstMsgOut;
Index: /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 85738)
+++ /trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp	(revision 85739)
@@ -291,5 +291,7 @@
 
 GuestDnDResponse::GuestDnDResponse(const ComObjPtr<Guest>& pGuest)
-    : m_EventSem(NIL_RTSEMEVENT)
+    : m_uProtocolVersion(0)
+    , m_fGuestFeatures0(VBOX_DND_GF_NONE)
+    , m_EventSem(NIL_RTSEMEVENT)
     , m_dndActionDefault(0)
     , m_dndLstActionsAllowed(0)
@@ -519,4 +521,6 @@
 
     int rc = VERR_WRONG_ORDER; /* Play safe. */
+
+    /* Whether or not to try calling host-installed callbacks after successfully processing the message. */
     bool fTryCallbacks = false;
 
@@ -525,7 +529,29 @@
         case DragAndDropSvc::GUEST_DND_CONNECT:
         {
-            LogThisFunc(("Client connected\n"));
-
-            /* Nothing to do here (yet). */
+            DragAndDropSvc::PVBOXDNDCBCONNECTDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBCONNECTDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBCONNECTDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_CONNECT == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER);
+
+            m_uProtocolVersion = pCBData->uProtocolVersion;
+            /** @todo Handle flags. */
+
+            LogThisFunc(("Client connected, using protocol v%RU32\n", m_uProtocolVersion));
+
+            rc = VINF_SUCCESS;
+            break;
+        }
+
+        case DragAndDropSvc::GUEST_DND_REPORT_FEATURES:
+        {
+            DragAndDropSvc::PVBOXDNDCBREPORTFEATURESDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBREPORTFEATURESDATA>(pvParms);
+            AssertPtr(pCBData);
+            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBREPORTFEATURESDATA) == cbParms, VERR_INVALID_PARAMETER);
+            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_REPORT_FEATURES == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER);
+
+            m_fGuestFeatures0 = pCBData->fGuestFeatures0;
+
+            LogThisFunc(("Client reported features: %#RX64\n", m_fGuestFeatures0));
+
             rc = VINF_SUCCESS;
             break;
@@ -1151,7 +1177,4 @@
     /* Initialize public attributes. */
     m_lstFmtSupported = GuestDnDInst()->defaultFormats();
-
-    /* Initialzie private stuff. */
-    m_DataBase.uProtocolVersion  = 0;
 }
 
@@ -1218,71 +1241,4 @@
 }
 
-/* Deprecated. */
-HRESULT GuestDnDBase::i_getProtocolVersion(ULONG *puVersion)
-{
-    int rc = getProtocolVersion((uint32_t *)puVersion);
-    return RT_SUCCESS(rc) ? S_OK : E_FAIL;
-}
-
-/**
- * Tries to guess the DnD protocol version to use on the guest, based on the
- * installed Guest Additions version + revision.
- *
- * Deprecated.
- *
- * If unable to retrieve the protocol version, VERR_NOT_FOUND is returned along
- * with protocol version 1.
- *
- * @return  IPRT status code.
- * @param   puProto                 Where to store the protocol version.
- */
-int GuestDnDBase::getProtocolVersion(uint32_t *puProto)
-{
-    AssertPtrReturn(puProto, VERR_INVALID_POINTER);
-
-    int rc;
-
-    uint32_t uProto = 0;
-    uint32_t uVerAdditions;
-    uint32_t uRevAdditions;
-    if (   m_pGuest
-        && (uVerAdditions = m_pGuest->i_getAdditionsVersion())  > 0
-        && (uRevAdditions = m_pGuest->i_getAdditionsRevision()) > 0)
-    {
-#if 0 && defined(DEBUG)
-        /* Hardcode the to-used protocol version; nice for testing side effects. */
-        if (true)
-            uProto = 3;
-        else
-#endif
-        if (uVerAdditions >= VBOX_FULL_VERSION_MAKE(5, 0, 0))
-        {
-/** @todo
- *  r=bird: This is just too bad for anyone using an OSE additions build...
- */
-            if (uRevAdditions >= 103344) /* Since r103344: Protocol v3. */
-                uProto = 3;
-            else
-                uProto = 2; /* VBox 5.0.0 - 5.0.8: Protocol v2. */
-        }
-        /* else: uProto: 0 */
-
-        LogFlowFunc(("uVerAdditions=%RU32 (%RU32.%RU32.%RU32), r%RU32\n",
-                     uVerAdditions, VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions),
-                                    VBOX_FULL_VERSION_GET_BUILD(uVerAdditions), uRevAdditions));
-        rc = VINF_SUCCESS;
-    }
-    else
-    {
-        uProto = 1; /* Fallback. */
-        rc = VERR_NOT_FOUND;
-    }
-
-    LogRel2(("DnD: Guest is using protocol v%RU32, rc=%Rrc\n", uProto, rc));
-
-    *puProto = uProto;
-    return rc;
-}
-
 /**
  * Adds a new guest DnD message to the internal message queue.
@@ -1352,5 +1308,5 @@
     GuestDnDMsg Msg;
     Msg.setType(HOST_DND_CANCEL);
-    if (m_DataBase.uProtocolVersion >= 3)
+    if (m_pResp->m_uProtocolVersion >= 3)
         Msg.appendUInt32(0); /** @todo ContextID not used yet. */
 
Index: /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 85738)
+++ /trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp	(revision 85739)
@@ -156,4 +156,14 @@
     unconst(m_pGuest) = pGuest;
 
+    /* Set the response we're going to use for this object.
+     *
+     * At the moment we only have one response total, as we
+     * don't allow
+     *      1) parallel transfers (multiple G->H at the same time)
+     *  nor 2) mixed transfers (G->H + H->G at the same time).
+     */
+    m_pResp = GuestDnDInst()->response();
+    AssertPtrReturn(m_pResp, VERR_INVALID_POINTER);
+
     /* Confirm a successful initialization when it's the case. */
     autoInitSpan.setSucceeded();
@@ -254,5 +264,7 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    return GuestDnDBase::i_getProtocolVersion(aProtocolVersion);
+    *aProtocolVersion = m_pResp->m_uProtocolVersion;
+
+    return S_OK;
 #endif /* VBOX_WITH_DRAG_AND_DROP */
 }
@@ -273,7 +285,4 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    /* Determine guest DnD protocol to use. */
-    GuestDnDBase::getProtocolVersion(&m_DataBase.uProtocolVersion);
-
     /* Default is ignoring the action. */
     if (aDefaultAction)
@@ -284,5 +293,5 @@
     GuestDnDMsg Msg;
     Msg.setType(HOST_DND_GH_REQ_PENDING);
-    if (m_DataBase.uProtocolVersion >= 3)
+    if (m_pResp->m_uProtocolVersion >= 3)
         Msg.appendUInt32(0); /** @todo ContextID not used yet. */
     Msg.appendUInt32(uScreenId);
@@ -673,5 +682,5 @@
         size_t  cbMetaAnnounced;
 
-        if (m_DataBase.uProtocolVersion < 3)
+        if (m_pResp->m_uProtocolVersion < 3)
         {
             cbData  = pSndData->u.v1.cbData;
@@ -890,5 +899,5 @@
 
         /* Note: Protocol v1 does not send any file sizes, so always 0. */
-        if (m_DataBase.uProtocolVersion >= 2)
+        if (m_pResp->m_uProtocolVersion >= 2)
             rc = DnDTransferObjectSetSize(pObj, cbSize);
 
@@ -1138,5 +1147,5 @@
     REGISTER_CALLBACK(GUEST_DND_DISCONNECT);
     REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
-    if (m_DataBase.uProtocolVersion >= 3)
+    if (m_pResp->m_uProtocolVersion >= 3)
         REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
@@ -1149,5 +1158,5 @@
         GuestDnDMsg Msg;
         Msg.setType(HOST_DND_GH_EVT_DROPPED);
-        if (m_DataBase.uProtocolVersion >= 3)
+        if (m_pResp->m_uProtocolVersion >= 3)
             Msg.appendUInt32(0); /** @todo ContextID not used yet. */
         Msg.appendPointer((void*)pCtx->strFmtRecv.c_str(), (uint32_t)pCtx->strFmtRecv.length() + 1);
@@ -1173,5 +1182,5 @@
     UNREGISTER_CALLBACK(GUEST_DND_DISCONNECT);
     UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
-    if (m_DataBase.uProtocolVersion >= 3)
+    if (m_pResp->m_uProtocolVersion >= 3)
         UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
@@ -1251,9 +1260,9 @@
     REGISTER_CALLBACK(GUEST_DND_DISCONNECT);
     REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
-    if (m_DataBase.uProtocolVersion >= 3)
+    if (m_pResp->m_uProtocolVersion >= 3)
         REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
     REGISTER_CALLBACK(GUEST_DND_GH_SND_DIR);
-    if (m_DataBase.uProtocolVersion >= 2)
+    if (m_pResp->m_uProtocolVersion >= 2)
         REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_HDR);
     REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_DATA);
@@ -1276,5 +1285,5 @@
         GuestDnDMsg Msg;
         Msg.setType(HOST_DND_GH_EVT_DROPPED);
-        if (m_DataBase.uProtocolVersion >= 3)
+        if (m_pResp->m_uProtocolVersion >= 3)
             Msg.appendUInt32(0); /** @todo ContextID not used yet. */
         Msg.appendPointer((void*)pCtx->strFmtRecv.c_str(), (uint32_t)pCtx->strFmtRecv.length() + 1);
@@ -1572,5 +1581,5 @@
             AssertReturn(CB_MAGIC_DND_GH_SND_FILE_DATA == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER);
 
-            if (pThis->m_DataBase.uProtocolVersion <= 1)
+            if (pThis->m_pResp->m_uProtocolVersion <= 1)
             {
                 /**
Index: /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp	(revision 85738)
+++ /trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp	(revision 85739)
@@ -154,4 +154,14 @@
     unconst(m_pGuest) = pGuest;
 
+    /* Set the response we're going to use for this object.
+     *
+     * At the moment we only have one response total, as we
+     * don't allow
+     *      1) parallel transfers (multiple G->H at the same time)
+     *  nor 2) mixed transfers (G->H + H->G at the same time).
+     */
+    m_pResp = GuestDnDInst()->response();
+    AssertPtrReturn(m_pResp, VERR_INVALID_POINTER);
+
     /* Confirm a successful initialization when it's the case. */
     autoInitSpan.setSucceeded();
@@ -252,5 +262,7 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    return GuestDnDBase::i_getProtocolVersion(aProtocolVersion);
+    *aProtocolVersion = m_pResp->m_uProtocolVersion;
+
+    return S_OK;
 #endif /* VBOX_WITH_DRAG_AND_DROP */
 }
@@ -279,7 +291,4 @@
     AutoCaller autoCaller(this);
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    /* Determine guest DnD protocol to use. */
-    GuestDnDBase::getProtocolVersion(&m_DataBase.uProtocolVersion);
 
     /* Default action is ignoring. */
@@ -324,5 +333,5 @@
         GuestDnDMsg Msg;
         Msg.setType(HOST_DND_HG_EVT_ENTER);
-        if (m_DataBase.uProtocolVersion >= 3)
+        if (m_pResp->m_uProtocolVersion >= 3)
             Msg.appendUInt32(0); /** @todo ContextID not used yet. */
         Msg.appendUInt32(aScreenId);
@@ -337,7 +346,6 @@
         if (RT_SUCCESS(rc))
         {
-            GuestDnDResponse *pResp = GuestDnDInst()->response();
-            if (pResp && RT_SUCCESS(pResp->waitForGuestResponse()))
-                resAction = GuestDnD::toMainAction(pResp->getActionDefault());
+            if (RT_SUCCESS(m_pResp->waitForGuestResponse()))
+                resAction = GuestDnD::toMainAction(m_pResp->getActionDefault());
         }
     }
@@ -402,5 +410,5 @@
         GuestDnDMsg Msg;
         Msg.setType(HOST_DND_HG_EVT_MOVE);
-        if (m_DataBase.uProtocolVersion >= 3)
+        if (m_pResp->m_uProtocolVersion >= 3)
             Msg.appendUInt32(0); /** @todo ContextID not used yet. */
         Msg.appendUInt32(aScreenId);
@@ -449,5 +457,5 @@
     GuestDnDMsg Msg;
     Msg.setType(HOST_DND_HG_EVT_LEAVE);
-    if (m_DataBase.uProtocolVersion >= 3)
+    if (m_pResp->m_uProtocolVersion >= 3)
         Msg.appendUInt32(0); /** @todo ContextID not used yet. */
 
@@ -525,5 +533,5 @@
         GuestDnDMsg Msg;
         Msg.setType(HOST_DND_HG_EVT_DROPPED);
-        if (m_DataBase.uProtocolVersion >= 3)
+        if (m_pResp->m_uProtocolVersion >= 3)
             Msg.appendUInt32(0); /** @todo ContextID not used yet. */
         Msg.appendUInt32(aScreenId);
@@ -844,5 +852,5 @@
     const char   *pcszFmt = pCtx->Meta.strFmt.c_str();
 
-    LogFlowFunc(("uProto=%u, szFmt=%s, cbFmt=%RU32, cbData=%zu\n", m_DataBase.uProtocolVersion, pcszFmt, cbFmt, cbData));
+    LogFlowFunc(("uProtoVer=%RU32, szFmt=%s, cbFmt=%RU32, cbData=%zu\n", m_pResp->m_uProtocolVersion, pcszFmt, cbFmt, cbData));
 
     LogRel2(("DnD: Sending meta data to guest as '%s' (%zu bytes)\n", pcszFmt, cbData));
@@ -862,5 +870,5 @@
         Msg.setType(HOST_DND_HG_SND_DATA);
 
-        if (m_DataBase.uProtocolVersion < 3)
+        if (m_pResp->m_uProtocolVersion < 3)
         {
             Msg.appendUInt32(pCtx->uScreenID);                                 /* uScreenId */
@@ -910,5 +918,5 @@
     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
 
-    if (m_DataBase.uProtocolVersion < 3) /* Protocol < v3 did not support this, skip. */
+    if (m_pResp->m_uProtocolVersion < 3) /* Protocol < v3 did not support this, skip. */
         return VINF_SUCCESS;
 
@@ -959,5 +967,5 @@
 
     pMsg->setType(HOST_DND_HG_SND_DIR);
-    if (m_DataBase.uProtocolVersion >= 3)
+    if (m_pResp->m_uProtocolVersion >= 3)
         pMsg->appendUInt32(0); /** @todo ContextID not used yet. */
     pMsg->appendString(pcszDstPath);                    /* path */
@@ -1006,5 +1014,5 @@
     if (RT_SUCCESS(rc))
     {
-        if (m_DataBase.uProtocolVersion >= 2)
+        if (m_pResp->m_uProtocolVersion >= 2)
         {
             if (!(pCtx->Transfer.fObjState & DND_OBJ_STATE_HAS_HDR))
@@ -1088,5 +1096,5 @@
     /* Protocol version 1 sends the file path *every* time with a new file chunk.
      * In protocol version 2 we only do this once with HOST_DND_HG_SND_FILE_HDR. */
-    if (m_DataBase.uProtocolVersion <= 1)
+    if (m_pResp->m_uProtocolVersion <= 1)
     {
         const size_t cchDstPath = RTStrNLen(pcszDstPath, RTPATH_MAX);
@@ -1095,5 +1103,5 @@
         pMsg->appendUInt32((uint32_t)cchDstPath + 1); /* cbName */
     }
-    else if (m_DataBase.uProtocolVersion >= 2)
+    else if (m_pResp->m_uProtocolVersion >= 2)
     {
         pMsg->appendUInt32(0);                        /** @todo ContextID not used yet. */
@@ -1112,5 +1120,5 @@
         LogFlowFunc(("cbBufe=%zu, cbRead=%RU32\n", cbBuf, cbRead));
 
-        if (m_DataBase.uProtocolVersion <= 1)
+        if (m_pResp->m_uProtocolVersion <= 1)
         {
             pMsg->appendPointer(pvBuf, cbRead);                            /* pvData */
@@ -1123,5 +1131,5 @@
             pMsg->appendUInt32(cbRead);                                    /* cbData */
 
-            if (m_DataBase.uProtocolVersion >= 3)
+            if (m_pResp->m_uProtocolVersion >= 3)
             {
                 /** @todo Calculate checksum. */
@@ -1415,5 +1423,5 @@
     /* Host callbacks. */
     REGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
-    if (m_DataBase.uProtocolVersion >= 2)
+    if (m_pResp->m_uProtocolVersion >= 2)
         REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
     REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
@@ -1482,5 +1490,5 @@
          * Send the data header first.
          */
-        if (m_DataBase.uProtocolVersion >= 3)
+        if (m_pResp->m_uProtocolVersion >= 3)
             rc = i_sendMetaDataHeader(pCtx);
 
@@ -1510,5 +1518,5 @@
     /* Host callbacks. */
     UNREGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
-    if (m_DataBase.uProtocolVersion >= 2)
+    if (m_pResp->m_uProtocolVersion >= 2)
         UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
     UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
