VirtualBox

Changeset 58329 in vbox


Ignore:
Timestamp:
Oct 20, 2015 10:05:12 AM (9 years ago)
Author:
vboxsync
Message:

DnD: Updates/bugfixes:

  • Added separate VBOXDNDDISCONNECTMSG message for letting Main know about client disconnects.
  • Various cleanups and bugfixes.
Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/HostServices/DragAndDropSvc.h

    r58257 r58329  
    3232 * Protocol changelog:
    3333 *
    34  *     Protocol v1 (VBox < 5.0):
    35  *         - Initial implementation which only implemented host to guest transfers.
    36  *         - For file transfers all file information such as the file name and file size were
     34 *     Protocol v1 (VBox < 5.0, deprecated):
     35 *         | Initial implementation which only implemented host to guest transfers.
     36 *         | For file transfers all file information such as the file name and file size were
    3737 *           transferred with every file data chunk being sent.
    3838 *
    39  *     Protocol v2 (VBox 5.0):
    40  *         - Added support for guest to host transfers.
    41  *         - Added protocol version support through VBOXDNDCONNECTMSG. The host takes the installed
     39 *     Protocol v2 (VBox 5.0 - VBox 5.0.8, deprecated):
     40 *         + Added support for guest to host transfers.
     41 *         + Added protocol version support through VBOXDNDCONNECTMSG. The host takes the installed
    4242 *           Guest Additions version as indicator which protocol to use for communicating with the guest.
    4343 *           The guest itself uses VBOXDNDCONNECTMSG to report its supported protocol version to the DnD service.
    4444 *
    45  *     Protocol v3 (VBox 5.0+):
    46              Added context IDs for every HGCM message. Not used yet and must be 0.
    47  *         - Added VBOXDNDSNDDATAHDR and VBOXDNDCBSNDDATAHDRDATA to support (simple) accounting of objects
     45 *     Protocol v3 (VBox 5.0.10 and up, current):
     46 *         + Added VBOXDNDDISCONNECTMSG for being able to track client disconnects on host side (Main).
     47 *         + Added context IDs for every HGCM message. Not used yet and must be 0.
     48 *         + Added VBOXDNDSNDDATAHDR and VBOXDNDCBSNDDATAHDRDATA to support (simple) accounting of objects
    4849 *           being transferred, along with supplying separate meta data size (which is part of the total size being sent).
    49  *         - Added new HOST_DND_HG_SND_DATA_HDR + GUEST_DND_GH_SND_DATA_HDR commands which now allow specifying an optional
     50 *         + Added new HOST_DND_HG_SND_DATA_HDR + GUEST_DND_GH_SND_DATA_HDR commands which now allow specifying an optional
    5051 *           compression type and defining a checksum for the overall data transfer.
    51  *         - Enhannced VBOXDNDGHSENDDATAMSG to support (rolling) checksums for the supplied data block.
    52  *         - VBOXDNDHGSENDFILEDATAMSG and VBOXDNDGHSENDFILEDATAMSG are now sharing the same HGCM mesasge.
    53  *         - VBOXDNDHGSENDDATAMSG and VBOXDNDGHSENDDATAMSG can now contain an optional checksum for the current data block.
     52 *         + Enhannced VBOXDNDGHSENDDATAMSG to support (rolling) checksums for the supplied data block.
     53 *         + VBOXDNDHGSENDDATAMSG and VBOXDNDGHSENDDATAMSG can now contain an optional checksum for the current data block.
     54 *         | VBOXDNDHGSENDFILEDATAMSG and VBOXDNDGHSENDFILEDATAMSG are now sharing the same HGCM mesasge.
    5455 *         - Removed unused HOST_DND_GH_RECV_DIR, HOST_DND_GH_RECV_FILE_DATA and HOST_DND_GH_RECV_FILE_HDR commands.
    5556 */
     
    184185enum eGuestFn
    185186{
    186     /* Guest sends a connection request to the HGCM service.
     187    /* Guest sends a connection request to the HGCM service,
     188     * along with some additional information like supported
     189     * protocol version and flags.
    187190     * Note: New since protocol version 2. */
    188191    GUEST_DND_CONNECT                  = 10,
     192
     193    /* Sent when a guest client disconnected from the HGCM service. */
     194    GUEST_DND_DISCONNECT               = 11,
    189195
    190196    /**
     
    287293            HGCMFunctionParameter uAllActions;  /* OUT uint32_t */
    288294            HGCMFunctionParameter pvFormats;    /* OUT ptr */
    289             HGCMFunctionParameter cFormats;     /* OUT uint32_t */
     295            HGCMFunctionParameter cbFormats;    /* OUT uint32_t */
    290296        } v1;
    291297        struct
     
    299305            HGCMFunctionParameter uAllActions;  /* OUT uint32_t */
    300306            HGCMFunctionParameter pvFormats;    /* OUT ptr */
    301             HGCMFunctionParameter cFormats;     /* OUT uint32_t */
     307            HGCMFunctionParameter cbFormats;    /* OUT uint32_t */
    302308        } v3;
    303309    } u;
     
    680686
    681687/**
    682  * HG Acknowledge Operation event.
     688 * Acknowledges a host operation along with the allowed
     689 * action(s) on the guest.
    683690 *
    684691 * Used by:
     
    923930    uint32_t                    uFlags;
    924931} VBOXDNDCBCONNECTMSGDATA, *PVBOXDNDCBCONNECTMSGDATA;
     932
     933typedef struct VBOXDNDCBDISCONNECTMSGDATA
     934{
     935    /** Callback data header. */
     936    VBOXDNDCBHEADERDATA         hdr;
     937} VBOXDNDCBDISCONNECTMSGDATA, *PVBOXDNDCBDISCONNECTMSGDATA;
    925938
    926939typedef struct VBOXDNDCBHGGETNEXTHOSTMSG
  • trunk/include/VBox/HostServices/Service.h

    r58106 r58329  
    300300    }
    301301
    302 private:
     302protected:
    303303
    304304    uint32_t m_uClientId;
     
    310310    PVBOXHGCMSVCPARM m_paParms;
    311311};
     312
     313/**
     314 * Structure for keeping a HGCM service context.
     315 */
     316typedef struct VBOXHGCMSVCTX
     317{
     318    /** HGCM helper functions. */
     319    PVBOXHGCMSVCHELPERS pHelpers;
     320    /*
     321     * Callback function supplied by the host for notification of updates
     322     * to properties.
     323     */
     324    PFNHGCMSVCEXT       pfnHostCallback;
     325    /** User data pointer to be supplied to the host callback function. */
     326    void               *pvHostData;
     327} VBOXHGCMSVCTX, *PVBOXHGCMSVCTX;
    312328
    313329template <class T>
     
    383399protected:
    384400    explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers)
    385         : m_pHelpers(pHelpers)
    386         , m_pfnHostCallback(NULL)
    387         , m_pvHostData(NULL)
    388     {}
     401    {
     402        RT_ZERO(m_SvcCtx);
     403        m_SvcCtx.pHelpers = pHelpers;
     404    }
    389405    virtual int  init(VBOXHGCMSVCFNTABLE *ptable) { return VINF_SUCCESS; }
    390406    virtual int  uninit() { return VINF_SUCCESS; }
     
    396412    /** Type definition for use in callback functions. */
    397413    typedef AbstractService SELF;
    398     /** HGCM helper functions. */
    399     PVBOXHGCMSVCHELPERS m_pHelpers;
    400     /*
    401      * Callback function supplied by the host for notification of updates
    402      * to properties.
    403      */
    404     PFNHGCMSVCEXT m_pfnHostCallback;
    405     /** User data pointer to be supplied to the host callback function. */
    406     void *m_pvHostData;
     414    /** The HGCM service context this service is bound to. */
     415    VBOXHGCMSVCTX m_SvcCtx;
    407416
    408417    /**
     
    500509        LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension));
    501510        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
    502         pSelf->m_pfnHostCallback = pfnExtension;
    503         pSelf->m_pvHostData = pvExtension;
     511        pSelf->m_SvcCtx.pfnHostCallback = pfnExtension;
     512        pSelf->m_SvcCtx.pvHostData      = pvExtension;
    504513        return VINF_SUCCESS;
    505514    }
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r58257 r58329  
    131131        Msg.u.v1.uAllActions.SetUInt32(0);
    132132        Msg.u.v1.pvFormats.SetPtr(pszFormats, cbFormats);
    133         Msg.u.v1.cFormats.SetUInt32(0);
     133        Msg.u.v1.cbFormats.SetUInt32(0);
    134134    }
    135135    else
     
    144144        Msg.u.v3.uAllActions.SetUInt32(0);
    145145        Msg.u.v3.pvFormats.SetPtr(pszFormats, cbFormats);
    146         Msg.u.v3.cFormats.SetUInt32(0);
     146        Msg.u.v3.cbFormats.SetUInt32(0);
    147147    }
    148148
     
    160160                rc = Msg.u.v1.uDefAction.GetUInt32(puDefAction);   AssertRC(rc);
    161161                rc = Msg.u.v1.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
    162                 rc = Msg.u.v1.cFormats.GetUInt32(pcbFormatsRecv); AssertRC(rc);
     162                rc = Msg.u.v1.cbFormats.GetUInt32(pcbFormatsRecv); AssertRC(rc);
    163163            }
    164164            else
     
    170170                rc = Msg.u.v3.uDefAction.GetUInt32(puDefAction);   AssertRC(rc);
    171171                rc = Msg.u.v3.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
    172                 rc = Msg.u.v3.cFormats.GetUInt32(pcbFormatsRecv); AssertRC(rc);
     172                rc = Msg.u.v3.cbFormats.GetUInt32(pcbFormatsRecv); AssertRC(rc);
    173173            }
    174174
     
    447447}
    448448
    449 static int vbglR3DnDHGRecvURIData(PVBGLR3GUESTDNDCMDCTX pCtx, DnDDroppedFiles *pDroppedFiles)
     449static int vbglR3DnDHGRecvURIData(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr, DnDDroppedFiles *pDroppedFiles)
    450450{
    451451    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
     452    AssertPtrReturn(pDataHdr,      VERR_INVALID_POINTER);
    452453    AssertPtrReturn(pDroppedFiles, VERR_INVALID_POINTER);
     454
     455    /* Only count the raw data minus the already received meta data. */
     456    Assert(pDataHdr->cbTotal >= pDataHdr->cbMeta);
     457    uint64_t cbToRecvBytes = pDataHdr->cbTotal - pDataHdr->cbMeta;
     458    uint64_t cToRecvObjs   = pDataHdr->cObjects;
     459
     460    LogFlowFunc(("cbToRecvBytes=%RU64, cToRecvObjs=%RU64, (cbTotal=%RU64, cbMeta=%RU32)\n",
     461                 cbToRecvBytes, cToRecvObjs, pDataHdr->cbTotal, pDataHdr->cbMeta));
     462
     463    /*
     464     * Only do accounting for protocol v3 and up.
     465     * The older protocols did not have any data accounting available, so
     466     * we simply tried to receive as much data as available and bail out.
     467     */
     468    const bool fDoAccounting = pCtx->uProtocol >= 3;
     469
     470    /* Anything to do at all? */
     471    if (fDoAccounting)
     472    {
     473        if (   !cbToRecvBytes
     474            && !cToRecvObjs)
     475        {
     476            return VINF_SUCCESS;
     477        }
     478    }
    453479
    454480    /*
     
    484510    char szPathName[RTPATH_MAX] = { 0 };
    485511    uint32_t cbPathName = 0;
    486     uint32_t fFlags = 0;
    487     uint32_t fMode = 0;
    488 
    489     while (RT_SUCCESS(rc))
    490     {
     512    uint32_t fFlags     = 0;
     513    uint32_t fMode      = 0;
     514
     515    /*
     516     * Only wait for new incoming commands for protocol v3 and up.
     517     * The older protocols did not have any data accounting available, so
     518     * we simply tried to receive as much data as available and bail out.
     519     */
     520    const bool fWait = pCtx->uProtocol >= 3;
     521
     522    do
     523    {
     524        LogFlowFunc(("Wating for new message ...\n"));
     525
    491526        uint32_t uNextMsg;
    492527        uint32_t cNextParms;
    493         rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
     528        rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, fWait);
    494529        if (RT_SUCCESS(rc))
    495530        {
     
    519554                        if (RT_SUCCESS(rc))
    520555                            rc = pDroppedFiles->AddDir(pszPathAbs);
     556
     557                        if (   RT_SUCCESS(rc)
     558                            && fDoAccounting)
     559                        {
     560                            Assert(cToRecvObjs);
     561                            cToRecvObjs--;
     562                        }
    521563
    522564                        RTStrFree(pszPathAbs);
     
    623665                                /* Data transfer complete? Close the file. */
    624666                                fClose = objFile.IsComplete();
     667                                if (   fClose
     668                                    && fDoAccounting)
     669                                {
     670                                    Assert(cToRecvObjs);
     671                                    cToRecvObjs--;
     672                                }
    625673
    626674                                /* Only since protocol v2 we know the file size upfront. */
     
    631679
    632680                            cbFileWritten += cbChunkWritten;
     681
     682                            if (pCtx->uProtocol >= 3)
     683                            {
     684                                Assert(cbToRecvBytes >= cbChunkRead);
     685                                cbToRecvBytes -= cbChunkRead;
     686                            }
    633687                        }
    634688
     
    660714            break;
    661715
    662     } /* while */
     716        if (fDoAccounting)
     717        {
     718            LogFlowFunc(("cbToRecvBytes=%RU64, cToRecvObjs=%RU64\n", cbToRecvBytes, cToRecvObjs));
     719            if (   !cbToRecvBytes
     720                && !cToRecvObjs)
     721            {
     722                break;
     723            }
     724        }
     725
     726    } while (RT_SUCCESS(rc));
    663727
    664728    LogFlowFunc(("Loop ended with %Rrc\n", rc));
     
    723787        uint32_t cbDataRecv;
    724788
    725         if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
     789        if (pCtx->uProtocol < 3)
    726790        {
    727791            Msg.hdr.cParms  = 5;
     
    901965    uint32_t cbDataRecv;
    902966
    903     if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
     967    LogFlowFuncEnter();
     968
     969    if (pCtx->uProtocol < 3)
    904970    {
    905971        uint64_t cbDataTmp = pCtx->cbMaxChunkSize;
     
    9791045            RTMemFree(pvDataTmp);
    9801046    }
    981     else /* Protocol v3 and up. Since VBox 5.0.8. */
     1047    else /* Protocol v3 and up. */
    9821048    {
    9831049        rc = vbglR3DnDHGRecvDataHdr(pCtx, pDataHdr);
    9841050        if (RT_SUCCESS(rc))
    9851051        {
    986             LogFlowFunc(("cbMeta=%RU32\n", pDataHdr->cbMeta));
     1052            LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", pDataHdr->cbTotal, pDataHdr->cbMeta));
    9871053            if (pDataHdr->cbMeta)
    9881054            {
     
    10861152            rc = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
    10871153            if (RT_SUCCESS(rc))
    1088                 rc = vbglR3DnDHGRecvURIData(pCtx, &droppedFiles);
     1154                rc = vbglR3DnDHGRecvURIData(pCtx, &dataHdr, &droppedFiles);
    10891155
    10901156            if (RT_SUCCESS(rc)) /** @todo Remove this block as soon as we hand in DnDURIList. */
     
    15061572    Msg.hdr.u32Function = GUEST_DND_HG_ACK_OP;
    15071573
     1574    LogFlowFunc(("uProto=%RU32\n", pCtx->uProtocol));
     1575
    15081576    if (pCtx->uProtocol < 3)
    15091577    {
     
    16601728
    16611729    /* For protocol v3 and up we need to send the data header first. */
    1662     if (pCtx->uProtocol > 2)
     1730    if (pCtx->uProtocol >= 3)
    16631731    {
    16641732        AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     
    16751743        Msg.uScreenId.SetUInt32(0);                          /** @todo Not used for guest->host (yet). */
    16761744        Msg.cbTotal.SetUInt64(pDataHdr->cbTotal);
    1677         Msg.cbMeta.SetUInt64(pDataHdr->cbMeta);
     1745        Msg.cbMeta.SetUInt32(pDataHdr->cbMeta);
    16781746        Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
    16791747        Msg.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
     
    17001768        Msg.hdr.u32Function = GUEST_DND_GH_SND_DATA;
    17011769
    1702         if (pCtx->uProtocol > 2)
     1770        if (pCtx->uProtocol >= 3)
    17031771        {
    17041772            Msg.hdr.cParms = 5;
     
    17211789        uint32_t       cbSent     = 0;
    17221790
    1723         HGCMFunctionParameter *pParm = (pCtx->uProtocol > 2)
     1791        HGCMFunctionParameter *pParm = (pCtx->uProtocol >= 3)
    17241792                                     ? &Msg.u.v3.pvData
    17251793                                     : &Msg.u.v1.pvData;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp

    r58212 r58329  
    7575    : m_pSession(pSession)
    7676    , m_pParent(pParent)
    77     , m_enmMode(DNDMODE_UNKNOWN)
     77    , m_enmOpMode(DNDMODE_UNKNOWN)
    7878    , m_fIsPending(false)
    7979    , m_fDataRetrieved(false)
     
    9999                                       const QMimeData *pMimeData)
    100100{
    101     LogFlowFunc(("enmMode=%RU32, screenID=%RU32, x=%d, y=%d, action=%ld\n",
    102                  m_enmMode, screenID, x, y, toVBoxDnDAction(proposedAction)));
    103 
    104     if (   m_enmMode != DNDMODE_UNKNOWN
    105         && m_enmMode != DNDMODE_HOSTTOGUEST)
     101    LogFlowFunc(("enmOpMode=%RU32, screenID=%RU32, x=%d, y=%d, action=%ld\n",
     102                 m_enmOpMode, screenID, x, y, toVBoxDnDAction(proposedAction)));
     103
     104    if (   m_enmOpMode != DNDMODE_UNKNOWN
     105        && m_enmOpMode != DNDMODE_HOSTTOGUEST)
    106106        return Qt::IgnoreAction;
    107107
     
    114114                                          pMimeData->formats().toVector());
    115115    if (m_dndTarget.isOk())
    116         setMode(DNDMODE_HOSTTOGUEST);
    117 
    118     /* Set the DnD action returned by the guest. */
    119     return toQtDnDAction(result);
     116    {
     117        setOpMode(DNDMODE_HOSTTOGUEST);
     118        return toQtDnDAction(result);
     119    }
     120
     121    msgCenter().cannotDropDataToGuest(m_dndTarget, m_pParent);
     122    return Qt::IgnoreAction;
    120123}
    121124
     
    124127                                      const QMimeData *pMimeData)
    125128{
    126     LogFlowFunc(("enmMode=%RU32, screenID=%RU32, x=%d, y=%d, action=%ld\n",
    127                  m_enmMode, screenID, x, y, toVBoxDnDAction(proposedAction)));
    128 
    129     if (m_enmMode != DNDMODE_HOSTTOGUEST)
     129    LogFlowFunc(("enmOpMode=%RU32, screenID=%RU32, x=%d, y=%d, action=%ld\n",
     130                 m_enmOpMode, screenID, x, y, toVBoxDnDAction(proposedAction)));
     131
     132    if (m_enmOpMode != DNDMODE_HOSTTOGUEST)
    130133        return Qt::IgnoreAction;
    131134
     
    138141                                         toVBoxDnDActions(possibleActions),
    139142                                         pMimeData->formats().toVector());
    140     /* Set the DnD action returned by the guest. */
    141     return toQtDnDAction(result);
     143    if (m_dndTarget.isOk())
     144        return toQtDnDAction(result);
     145
     146    msgCenter().cannotDropDataToGuest(m_dndTarget, m_pParent);
     147    return Qt::IgnoreAction;
    142148}
    143149
     
    146152                                      const QMimeData *pMimeData)
    147153{
    148     LogFlowFunc(("enmMode=%RU32, screenID=%RU32, x=%d, y=%d, action=%ld\n",
    149                  m_enmMode, screenID, x, y, toVBoxDnDAction(proposedAction)));
    150 
    151     if (m_enmMode != DNDMODE_HOSTTOGUEST)
     154    LogFlowFunc(("enmOpMode=%RU32, screenID=%RU32, x=%d, y=%d, action=%ld\n",
     155                 m_enmOpMode, screenID, x, y, toVBoxDnDAction(proposedAction)));
     156
     157    if (m_enmOpMode != DNDMODE_HOSTTOGUEST)
    152158        return Qt::IgnoreAction;
    153159
     
    258264     * mode as well here.
    259265     */
    260     setMode(DNDMODE_UNKNOWN);
     266    setOpMode(DNDMODE_UNKNOWN);
    261267
    262268    return toQtDnDAction(enmResult);
     
    265271void UIDnDHandler::dragLeave(ulong screenID)
    266272{
    267     LogFlowFunc(("enmMode=%RU32, screenID=%RU32\n", m_enmMode, screenID));
    268 
    269     if (m_enmMode == DNDMODE_HOSTTOGUEST)
     273    LogFlowFunc(("enmOpMode=%RU32, screenID=%RU32\n", m_enmOpMode, screenID));
     274
     275    if (m_enmOpMode == DNDMODE_HOSTTOGUEST)
    270276    {
    271277        m_dndTarget.Leave(screenID);
    272         setMode(DNDMODE_UNKNOWN);
     278        setOpMode(DNDMODE_UNKNOWN);
    273279    }
    274280}
     
    448454#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    449455
    450     LogFlowFunc(("enmMode=%RU32, fIsPending=%RTbool, screenID=%RU32\n", m_enmMode, m_fIsPending, screenID));
     456    LogFlowFunc(("enmOpMode=%RU32, fIsPending=%RTbool, screenID=%RU32\n", m_enmOpMode, m_fIsPending, screenID));
    451457
    452458    {
    453459        QMutexLocker AutoReadLock(&m_ReadLock);
    454460
    455         if (   m_enmMode != DNDMODE_UNKNOWN
    456             && m_enmMode != DNDMODE_GUESTTOHOST) /* Wrong mode set? */
     461        if (   m_enmOpMode != DNDMODE_UNKNOWN
     462            && m_enmOpMode != DNDMODE_GUESTTOHOST) /* Wrong mode set? */
    457463            return VINF_SUCCESS;
    458464
     
    548554    }
    549555
    550     setMode(DNDMODE_GUESTTOHOST);
     556    setOpMode(DNDMODE_GUESTTOHOST);
    551557
    552558    rc = dragStartInternal(m_dataSource.lstFormats,
     
    594600    m_fIsPending = false;
    595601
    596     setMode(DNDMODE_UNKNOWN);
     602    setOpMode(DNDMODE_UNKNOWN);
    597603}
    598604
     
    684690                /* After we successfully retrieved data from the source we query it from Main. */
    685691                vecData = m_dndSource.ReceiveData(); /** @todo QVector.size() is "int" only!? */
    686                 if (vecData.isEmpty())
    687                     rc = VERR_NO_DATA;
     692                if (m_dndSource.isOk())
     693                {
     694                    if (vecData.isEmpty())
     695                        rc = VERR_NO_DATA;
     696                }
     697                else
     698                {
     699                    msgCenter().cannotDropDataToHost(m_dndSource, m_pParent);
     700                    rc = VERR_GENERAL_FAILURE; /** @todo Fudge; do a GetResultCode() to rc translation. */
     701                }
    688702            }
    689703            else
     
    699713    }
    700714
    701     setMode(DNDMODE_UNKNOWN);
     715    setOpMode(DNDMODE_UNKNOWN);
    702716
    703717    LogFlowFuncLeaveRC(rc);
     
    705719}
    706720
    707 void UIDnDHandler::setMode(DNDMODE enmMode)
     721void UIDnDHandler::setOpMode(DNDOPMODE enmMode)
    708722{
    709723    QMutexLocker AutoWriteLock(&m_WriteLock);
    710     m_enmMode = enmMode;
    711     LogFlowFunc(("Mode is now: %RU32\n", m_enmMode));
     724    m_enmOpMode = enmMode;
     725    LogFunc(("Operation mode is now: %RU32\n", m_enmOpMode));
    712726}
    713727
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h

    r57288 r58329  
    4949     *       drag and drop mode.
    5050     */
    51     typedef enum DNDMODE
     51    typedef enum DNDOPMODE
    5252    {
    5353        /** Unknown mode. */
     
    6060        /** The usual 32-bit type blow up. */
    6161        DNDMODE_32BIT_HACK = 0x7fffffff
    62     } DNDMODE;
     62    } DNDOPMODE;
    6363
    6464    /**
     
    125125    int                        dragStartInternal(const QStringList &lstFormats, Qt::DropAction defAction, Qt::DropActions actions);
    126126    int                        retrieveDataInternal(Qt::DropAction dropAction, const QString &strMIMEType, QVector<uint8_t> &vecData);
    127     void                       setMode(DNDMODE enmMode);
     127    void                       setOpMode(DNDOPMODE enmMode);
    128128
    129129protected:
     
    133133    /** Pointer to parent widget. */
    134134    QWidget          *m_pParent;
    135 
    136135    /** Drag and drop source instance. */
    137136    CDnDSource        m_dndSource;
    138137    /** Drag and drop target instance. */
    139138    CDnDTarget        m_dndTarget;
    140     /** Current transfer direction. */
    141     DNDMODE           m_enmMode;
     139    /** Current operation mode, indicating the transfer direction.
     140     *  Note: This is independent of the current drag and drop
     141     *        mode being set for this VM! */
     142    DNDOPMODE         m_enmOpMode;
    142143    /** Current data from the source (if any).
    143144     *  At the momenet we only support one source at a time. */
  • trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp

    r58212 r58329  
    2525#include <iprt/fs.h>
    2626#include <iprt/path.h>
     27#include <iprt/string.h>
    2728#include <iprt/symlink.h>
    2829#include <iprt/uri.h>
     
    448449    AssertReturn(cbData, VERR_INVALID_PARAMETER);
    449450
     451    if (!RTStrIsValidEncoding(static_cast<const char *>(pvData)))
     452        return VERR_INVALID_PARAMETER;
     453
    450454    RTCList<RTCString> lstURI =
    451         RTCString(static_cast<const char*>(pvData), cbData - 1).split("\r\n");
     455        RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");
    452456    if (lstURI.isEmpty())
    453457        return VINF_SUCCESS;
  • trunk/src/VBox/HostServices/DragAndDrop/service.cpp

    r58257 r58329  
    3030#define LOG_GROUP LOG_GROUP_GUEST_DND
    3131
     32#include <algorithm>
     33#include <list>
    3234#include <map>
    3335
     
    4446*********************************************************************************************************************************/
    4547
    46 /** Map holding pointers to HGCM clients. Key is the (unique) HGCM client ID. */
    47 typedef std::map<uint32_t, HGCM::Client*> DnDClientMap;
     48class DragAndDropClient : public HGCM::Client
     49{
     50public:
     51
     52    DragAndDropClient(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle = NULL,
     53                      uint32_t uMsg = 0, uint32_t cParms = 0, VBOXHGCMSVCPARM aParms[] = NULL)
     54        : HGCM::Client(uClientId, hHandle, uMsg, cParms, aParms)
     55        , m_fDeferred(false)
     56    {
     57        RT_ZERO(m_SvcCtx);
     58    }
     59
     60    virtual ~DragAndDropClient(void)
     61    {
     62        disconnect();
     63    }
     64
     65public:
     66
     67    void complete(VBOXHGCMCALLHANDLE hHandle, int rcOp);
     68    void completeDeferred(int rcOp);
     69    void disconnect(void);
     70    bool isDeferred(void) const { return m_fDeferred; }
     71    void setDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     72    void setSvcContext(const HGCM::VBOXHGCMSVCTX &SvcCtx) { m_SvcCtx = SvcCtx; }
     73
     74protected:
     75
     76    /** The HGCM service context this client is bound to. */
     77    HGCM::VBOXHGCMSVCTX m_SvcCtx;
     78    /** Flag indicating whether this client currently is deferred mode,
     79     *  meaning that it did not return to the caller yet. */
     80    bool                m_fDeferred;
     81};
     82
     83/** Map holding pointers to drag and drop clients. Key is the (unique) HGCM client ID. */
     84typedef std::map<uint32_t, DragAndDropClient*> DnDClientMap;
     85
     86/** Simple queue (list) which holds deferred (waiting) clients. */
     87typedef std::list<uint32_t> DnDClientQueue;
    4888
    4989/**
     
    68108
    69109    int modeSet(uint32_t u32Mode);
    70     inline uint32_t modeGet() { return m_u32Mode; };
     110    inline uint32_t modeGet(void) const { return m_u32Mode; };
    71111
    72112protected:
     
    76116protected:
    77117
    78     DnDManager             *m_pManager;
    79     /** Map of all connected clients. */
    80     DnDClientMap            m_clientMap;
     118    /** Pointer to our DnD manager instance. */
     119    DnDManager                        *m_pManager;
     120    /** Map of all connected clients.
     121     *  The primary key is the (unique) client ID, the secondary value
     122     *  an allocated pointer to the DragAndDropClient class, managed
     123     *  by this service class. */
     124    DnDClientMap                       m_clientMap;
    81125    /** List of all clients which are queued up (deferred return) and ready
    82      *  to process new commands. */
    83     RTCList<HGCM::Client*>  m_clientQueue;
    84     uint32_t                m_u32Mode;
     126     *  to process new commands. The key is the (unique) client ID. */
     127    DnDClientQueue                     m_clientQueue;
     128    /** Current drag and drop mode. */
     129    uint32_t                           m_u32Mode;
    85130};
    86131
     132
     133/*********************************************************************************************************************************
     134*   Client implementation                                                                                                        *
     135*********************************************************************************************************************************/
     136
     137/**
     138 * Completes the call by returning the control back to the guest
     139 * side code.
     140 */
     141void DragAndDropClient::complete(VBOXHGCMCALLHANDLE hHandle, int rcOp)
     142{
     143    LogFlowThisFunc(("uClientID=%RU32\n", m_uClientId));
     144
     145    if (   m_SvcCtx.pHelpers
     146        && m_SvcCtx.pHelpers->pfnCallComplete)
     147    {
     148        m_SvcCtx.pHelpers->pfnCallComplete(hHandle, rcOp);
     149    }
     150}
     151
     152/**
     153 * Completes a deferred call by returning the control back to the guest
     154 * side code.
     155 */
     156void DragAndDropClient::completeDeferred(int rcOp)
     157{
     158    AssertMsg(m_fDeferred, ("Client %RU32 is not in deferred mode\n", m_uClientId));
     159    Assert(m_hHandle != NULL);
     160
     161    LogFlowThisFunc(("uClientID=%RU32\n", m_uClientId));
     162
     163    complete(m_hHandle, rcOp);
     164    m_fDeferred = false;
     165}
     166
     167/**
     168 * Called when the HGCM client disconnected on the guest side.
     169 * This function takes care of the client's data cleanup and also lets the host
     170 * know that the client has been disconnected.
     171 *
     172 */
     173void DragAndDropClient::disconnect(void)
     174{
     175    LogFlowThisFunc(("uClient=%RU32\n", m_uClientId));
     176
     177    if (isDeferred())
     178        completeDeferred(VERR_INTERRUPTED);
     179
     180    /*
     181     * Let the host know.
     182     */
     183    VBOXDNDCBDISCONNECTMSGDATA data;
     184    RT_ZERO(data);
     185    /** @todo Magic needed? */
     186
     187    if (m_SvcCtx.pfnHostCallback)
     188    {
     189        int rc2 = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, GUEST_DND_DISCONNECT, &data, sizeof(data));
     190        if (RT_FAILURE(rc2))
     191            LogFlowFunc(("Warning: Unable to notify host about client %RU32 disconnect, rc=%Rrc\n", m_uClientId, rc2));
     192        /* Not fatal. */
     193    }
     194}
     195
     196/**
     197 * Set the client's status to deferred, meaning that it does not return to the caller
     198 * on the guest side yet.
     199 */
     200void DragAndDropClient::setDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     201{
     202    LogFlowThisFunc(("uClient=%RU32\n", m_uClientId));
     203
     204    AssertMsg(m_fDeferred == false, ("Client already in deferred mode\n"));
     205    m_fDeferred = true;
     206
     207    m_hHandle = hHandle;
     208    m_uMsg    = u32Function;
     209    m_cParms  = cParms;
     210    m_paParms = paParms;
     211}
    87212
    88213/*********************************************************************************************************************************
     
    118243int DragAndDropService::uninit(void)
    119244{
     245    LogFlowFuncEnter();
     246
    120247    if (m_pManager)
    121248    {
     
    124251    }
    125252
     253    DnDClientMap::iterator itClient =  m_clientMap.begin();
     254    while (itClient != m_clientMap.end())
     255    {
     256        delete itClient->second;
     257        m_clientMap.erase(itClient);
     258        itClient = m_clientMap.begin();
     259    }
     260
     261    LogFlowFuncLeave();
    126262    return VINF_SUCCESS;
    127263}
     
    147283        try
    148284        {
    149             m_clientMap[u32ClientID] = new HGCM::Client(u32ClientID);
     285            DragAndDropClient *pClient = new DragAndDropClient(u32ClientID);
     286            pClient->setSvcContext(m_SvcCtx);
     287            m_clientMap[u32ClientID] = pClient;
    150288        }
    151289        catch(std::bad_alloc &)
     
    179317     * Remove from waiters queue.
    180318     */
    181     for (size_t i = 0; i < m_clientQueue.size(); i++)
    182     {
    183         HGCM::Client *pClient = m_clientQueue.at(i);
    184         if (pClient->clientId() == u32ClientID)
    185         {
    186             if (m_pHelpers)
    187                 m_pHelpers->pfnCallComplete(pClient->handle(), VERR_INTERRUPTED);
    188 
    189             m_clientQueue.removeAt(i);
    190             delete pClient;
    191 
    192             break;
    193         }
    194     }
     319    m_clientQueue.remove(u32ClientID);
    195320
    196321    /*
     
    208333int DragAndDropService::modeSet(uint32_t u32Mode)
    209334{
    210     /** @todo Validate mode. */
     335#ifndef VBOX_WITH_DRAG_AND_DROP_GH
     336    if (   u32Mode == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST
     337        || u32Mode == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL)
     338    {
     339        m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
     340        return VERR_NOT_SUPPORTED;
     341    }
     342#endif
     343
    211344    switch (u32Mode)
    212345    {
     
    308441#endif
    309442
    310 #define DO_HOST_CALLBACK();                                                     \
    311     if (   RT_SUCCESS(rc)                                                       \
    312         && m_pfnHostCallback)                                                   \
    313     {                                                                           \
    314         rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); \
     443#define DO_HOST_CALLBACK();                                                                   \
     444    if (   RT_SUCCESS(rc)                                                                     \
     445        && m_SvcCtx.pfnHostCallback)                                                          \
     446    {                                                                                         \
     447        rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data)); \
     448    }
     449
     450    /*
     451     * Lookup client.
     452     */
     453    DragAndDropClient *pClient = NULL;
     454
     455    DnDClientMap::iterator itClient =  m_clientMap.find(u32ClientID);
     456    if (itClient != m_clientMap.end())
     457    {
     458        pClient = itClient->second;
     459        AssertPtr(pClient);
     460    }
     461    else
     462    {
     463        LogFunc(("Client %RU32 was not found\n", u32ClientID));
     464        rc = VERR_NOT_FOUND;
    315465    }
    316466
    317467    if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
    318468    {
    319         DnDClientMap::iterator itClient =  m_clientMap.find(u32ClientID);
    320         Assert(itClient != m_clientMap.end());
    321 
    322         HGCM::Client *pClient = itClient->second;
    323         AssertPtr(pClient);
    324 
    325469        LogFlowFunc(("Client %RU32: Protocol v%RU32\n", pClient->clientId(), pClient->protocol()));
    326470
     
    344488                    if (RT_FAILURE(rc)) /* No queued messages available? */
    345489                    {
    346                         if (m_pfnHostCallback) /* Try asking the host. */
     490                        if (m_SvcCtx.pfnHostCallback) /* Try asking the host. */
    347491                        {
    348492                            VBOXDNDCBHGGETNEXTHOSTMSG data;
    349493                            RT_ZERO(data);
    350494                            data.hdr.uMagic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
    351                             rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     495                            rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data));
    352496                            if (RT_SUCCESS(rc))
    353497                            {
     
    366510                        if (RT_FAILURE(rc))
    367511                        {
    368                             if (paParms[2].u.uint32) /* Blocking flag set? */
     512                            uint32_t fFlags = 0;
     513                            int rc2 = paParms[2].getUInt32(&fFlags);
     514                            if (   RT_SUCCESS(rc2)
     515                                && fFlags) /* Blocking flag set? */
    369516                            {
    370517                                /* Defer client returning. */
    371518                                rc = VINF_HGCM_ASYNC_EXECUTE;
    372519                            }
     520                            else
     521                                rc = VERR_INVALID_PARAMETER;
    373522
    374523                            LogFlowFunc(("Message queue is empty, returning %Rrc to guest\n", rc));
     
    390539                    if (cParms >= 3)
    391540                        rc = paParms[0].getUInt32(&data.hdr.uContextID);
     541                    else /* Older protocols don't have a context ID. */
     542                        rc = VINF_SUCCESS;
    392543                    if (RT_SUCCESS(rc))
    393544                        rc = paParms[idxProto].getUInt32(&data.uProtocol);
     
    660811                            rc = paParms[0].getUInt32(&data.hdr.uContextID);
    661812                            if (RT_SUCCESS(rc))
    662                                 rc = paParms[0].getPointer((void**)&data.pszPath, &data.cbPath);
    663                             if (RT_SUCCESS(rc))
    664                                 rc = paParms[1].getUInt32(&data.cbPath);
    665                             if (RT_SUCCESS(rc))
    666                                 rc = paParms[2].getUInt32(&data.fMode);
     813                                rc = paParms[1].getPointer((void**)&data.pszPath, &data.cbPath);
     814                            if (RT_SUCCESS(rc))
     815                                rc = paParms[2].getUInt32(&data.cbPath);
     816                            if (RT_SUCCESS(rc))
     817                                rc = paParms[3].getUInt32(&data.fMode);
    667818                        }
    668819                        break;
     
    842993                if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
    843994                {
    844                     if (m_pfnHostCallback)
     995                    if (m_SvcCtx.pfnHostCallback)
    845996                    {
    846997                        VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
     
    8511002                        data.paParms = paParms;
    8521003
    853                         rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     1004                        rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function,
     1005                                                      &data, sizeof(data));
    8541006                        if (RT_SUCCESS(rc))
    8551007                        {
     
    8751027        try
    8761028        {
    877             LogFlowFunc(("Deferring guest call completion of client ID=%RU32\n", u32ClientID));
    878             m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle,
    879                                                   u32Function, cParms, paParms));
     1029            AssertPtr(pClient);
     1030            pClient->setDeferred(callHandle, u32Function, cParms, paParms);
     1031            m_clientQueue.push_back(u32ClientID);
    8801032        }
    8811033        catch (std::bad_alloc)
     
    8851037        }
    8861038    }
    887     else if (m_pHelpers)
    888     {
    889         /* Complete call on guest side. */
    890         m_pHelpers->pfnCallComplete(callHandle, rc);
    891     }
     1039    else if (pClient)
     1040        pClient->complete(callHandle, rc);
    8921041    else
    8931042        rc = VERR_NOT_IMPLEMENTED;
     
    9211070                if (m_clientQueue.size()) /* Any clients in our queue ready for processing the next command? */
    9221071                {
    923                     HGCM::Client *pClient = m_clientQueue.first();
     1072                    uint32_t uClientNext = m_clientQueue.front();
     1073                    DnDClientMap::iterator itClientNext = m_clientMap.find(uClientNext);
     1074                    Assert(itClientNext != m_clientMap.end());
     1075
     1076                    DragAndDropClient *pClient = itClientNext->second;
    9241077                    AssertPtr(pClient);
    9251078
     
    9391092                        if (RT_SUCCESS(rc))
    9401093                        {
    941                             pClient->addMessageInfo(uMsg1, cParms1);
    942                             if (   m_pHelpers
    943                                 && m_pHelpers->pfnCallComplete)
    944                             {
    945                                 m_pHelpers->pfnCallComplete(pClient->handle(), rc);
    946                             }
    947 
    948                             m_clientQueue.removeFirst();
    949 
    950                             delete pClient;
    951                             pClient = NULL;
    952                         }
    953                         else
    954                             AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));
     1094                            rc = pClient->addMessageInfo(uMsg1, cParms1);
     1095
     1096                            /* Note: Report the current rc back to the guest. */
     1097                            pClient->completeDeferred(rc);
     1098
     1099                            m_clientQueue.pop_front();
     1100                        }
    9551101                    }
    9561102                    else
     
    9921138    AssertPtr(pSelf);
    9931139
    994     if (pSelf->m_pfnHostCallback)
     1140    if (pSelf->m_SvcCtx.pfnHostCallback)
    9951141    {
    9961142        LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
     
    10031149        data.rc           = rc; /** @todo uin32_t vs. int. */
    10041150
    1005         return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
    1006                                         GUEST_DND_HG_EVT_PROGRESS,
    1007                                         &data, sizeof(data));
     1151        return pSelf->m_SvcCtx.pfnHostCallback(pSelf->m_SvcCtx.pvHostData,
     1152                                               GUEST_DND_HG_EVT_PROGRESS,
     1153                                               &data, sizeof(data));
    10081154    }
    10091155
  • trunk/src/VBox/Main/include/GuestDnDPrivate.h

    r58232 r58329  
    5151typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
    5252
     53/*
     54 ** @todo Put most of the implementations below in GuestDnDPrivate.cpp!
     55 */
     56
    5357class GuestDnDCallbackEvent
    5458{
     
    100104    size_t add(const void *pvDataAdd, size_t cbDataAdd)
    101105    {
     106        LogFlowThisFunc(("pvDataAdd=%p, cbDataAdd=%zu\n", pvDataAdd, cbDataAdd));
     107
    102108        if (!cbDataAdd)
    103109            return 0;
     
    217223
    218224    GuestDnDData(void)
    219         : cbProcessed(0)
    220         , cbAddData(0)
     225        : cbEstTotal(0)
     226        , cbEstMeta(0)
     227        , cbProcessed(0)
    221228    {
    222229        RT_ZERO(dataHdr);
     
    241248    {
    242249        const uint64_t cbTotal = getTotal();
     250        LogFlowFunc(("cbProcessed=%RU64, cbTotal=%RU64\n", cbProcessed, cbTotal));
    243251        Assert(cbProcessed <= cbTotal);
    244252        return (cbProcessed == cbTotal);
     
    257265    uint8_t getPercentComplete(void) const
    258266    {
    259         int64_t cbTotal  = RT_MAX(getTotal(), 1);
     267        int64_t cbTotal = RT_MAX(getTotal(), 1);
    260268        return (uint8_t)(cbProcessed * 100 / cbTotal);
    261269    }
     
    270278    }
    271279
    272     uint64_t getTotal(void) const { return dataMeta.getSize() + cbAddData; }
     280    uint64_t getTotal(void) const { return cbEstTotal; }
    273281
    274282    void reset(void)
     
    280288
    281289        dataMeta.reset();
     290
     291        cbEstTotal  = 0;
     292        cbEstMeta   = 0;
    282293        cbProcessed = 0;
    283         cbAddData   = 0;
    284294    }
    285295
     
    306316    }
    307317
    308     void setAdditionalSize(uint64_t cbAdd)
    309     {
    310         LogFlowFunc(("cbAdd=%RU64\n", cbAdd));
    311 
    312         cbAddData = cbAdd;
    313 
    314         invalidate();
    315     }
    316 
    317318    void setEstimatedSize(uint64_t cbTotal, uint32_t cbMeta)
    318319    {
    319320        Assert(cbMeta <= cbTotal);
    320321
    321         LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU64\n", cbTotal, cbMeta));
    322 
    323         dataMeta.reset();
    324 
    325         dataHdr.cbMeta = cbMeta;
    326         setAdditionalSize(cbTotal - cbMeta);
     322        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", cbTotal, cbMeta));
     323
     324        cbEstTotal = cbTotal;
     325        cbEstMeta  = cbMeta;
    327326    }
    328327
     
    351350
    352351        dataHdr.cbMetaFmt = 0;
    353     }
    354 
    355     void invalidate(void)
    356     {
    357         /* Update data header. */
    358         dataHdr.cbMeta  = dataMeta.getSize();
    359         dataHdr.cbTotal = dataHdr.cbMeta + cbAddData;
    360 
    361         LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", dataHdr.cbTotal, dataHdr.cbMeta));
    362352    }
    363353
     
    370360     *  according to the format being sent. */
    371361    GuestDnDMetaData  dataMeta;
     362    /** Estimated total data size when receiving data. */
     363    uint64_t          cbEstTotal;
     364    /** Estimated meta data size when receiving data. */
     365    uint32_t          cbEstMeta;
    372366    /** Overall size (in bytes) of processed data. */
    373367    uint64_t          cbProcessed;
    374     /** Additional data to process which does not count
    375      *  as meta data. Just in here for accounting reasons. */
    376     uint64_t          cbAddData;
    377368};
     369
     370/** Initial state. */
     371#define DND_OBJCTX_STATE_NONE           0
     372/** The header was received/sent. */
     373#define DND_OBJCTX_STATE_HAS_HDR        RT_BIT(0)
    378374
    379375/**
     
    387383        : pObjURI(NULL)
    388384        , fIntermediate(false)
    389         , fHeaderSent(false) { }
     385        , fState(DND_OBJCTX_STATE_NONE) { }
    390386
    391387    virtual ~GuestDnDURIObjCtx(void)
     
    396392public:
    397393
    398     DnDURIObject *createIntermediate(void)
    399     {
     394    int createIntermediate(DnDURIObject::Type enmType = DnDURIObject::Unknown)
     395    {
     396        LogFlowThisFuncEnter();
     397
    400398        reset();
    401399
     400        int rc;
     401
    402402        try
    403403        {
    404             pObjURI       = new DnDURIObject();
     404            pObjURI       = new DnDURIObject(enmType);
    405405            fIntermediate = true;
     406
     407            rc = VINF_SUCCESS;
    406408        }
    407409        catch (std::bad_alloc &)
    408410        {
    409         }
    410 
    411         return pObjURI;
     411            rc = VERR_NO_MEMORY;
     412        }
     413
     414        return rc;
    412415    }
    413416
    414417    void destroy(void)
    415418    {
     419        LogFlowThisFuncEnter();
     420
    416421        if (   pObjURI
    417422            && fIntermediate)
    418423        {
    419424            delete pObjURI;
    420             fIntermediate = false;
    421         }
    422 
    423         pObjURI = NULL;
    424     }
     425        }
     426
     427        pObjURI       = NULL;
     428        fIntermediate = false;
     429    }
     430
     431    DnDURIObject *getObj(void) { return pObjURI; }
    425432
    426433    bool isIntermediate(void) { return fIntermediate; }
     
    428435    bool isValid(void) const { return (pObjURI != NULL); }
    429436
     437    uint32_t getState(void) const { return fState; }
     438
    430439    void reset(void)
    431440    {
     441        LogFlowThisFuncEnter();
     442
    432443        destroy();
    433444
    434445        fIntermediate = false;
    435         fHeaderSent   = false;
    436     }
     446        fState        = 0;
     447    }
     448
     449    void setObj(DnDURIObject *pObj)
     450    {
     451        LogFlowThisFunc(("%p\n", pObj));
     452
     453        destroy();
     454
     455        pObjURI = pObj;
     456    }
     457
     458    uint32_t setState(uint32_t fStateNew)
     459    {
     460        /** @todo Add validation. */
     461        fState = fStateNew;
     462        return fState;
     463    }
     464
     465protected:
    437466
    438467    /** Pointer to current object being handled. */
     
    440469    /** Flag whether pObjURI needs deletion after use. */
    441470    bool                      fIntermediate;
    442     /** Flag whether the object's file header has been sent already. */
    443     bool                      fHeaderSent;
     471    /** Internal context state, corresponding to DND_OBJCTX_STATE_XXX. */
     472    uint32_t                  fState;
    444473    /** @todo Add more statistics / information here. */
    445474};
     
    490519    bool isComplete(void) const
    491520    {
    492         LogFlowFunc(("cObjToProcess=%RU64, cObjProcessed=%RU64\n", cObjToProcess, cObjProcessed));
     521        LogFlowFunc(("cObjProcessed=%RU64, cObjToProcess=%RU64\n", cObjProcessed, cObjToProcess));
     522
     523        if (!cObjToProcess) /* Always return true if we don't have an object count. */
     524            return true;
     525
    493526        Assert(cObjProcessed <= cObjToProcess);
    494527        return (cObjProcessed == cObjToProcess);
     
    514547        {
    515548            /* Point the context object to the current DnDURIObject to process. */
    516             objCtx.pObjURI = pCurObj;
     549            objCtx.setObj(pCurObj);
    517550        }
    518551        else
     
    534567        {
    535568            case DnDURIObject::Directory:
    536                 rc = processDirectory(Obj.GetDestPath().c_str(), Obj.GetMode());
    537                 break;
    538 
    539569            case DnDURIObject::File:
    540570                rc = VINF_SUCCESS;
     
    570600    }
    571601
    572     void reset(uint64_t cObjs = 0)
    573     {
    574         cObjToProcess = cObjs;
     602    void reset(void)
     603    {
     604        LogFlowFuncEnter();
     605
     606        cObjToProcess = 0;
    575607        cObjProcessed = 0;
    576 
    577         LogFlowFunc(("cObjToProcess=%RU64\n", cObjToProcess));
    578608
    579609        droppedFiles.Close();
     
    583613    }
    584614
    585 public:
    586 
    587     int fromMetaData(const GuestDnDMetaData &Data)
     615    void setEstimatedObjects(uint64_t cObjs)
     616    {
     617        Assert(cObjToProcess == 0);
     618        cObjToProcess = cObjs;
     619        LogFlowFunc(("cObjToProcess=%RU64\n", cObjs));
     620    }
     621
     622public:
     623
     624    int fromLocalMetaData(const GuestDnDMetaData &Data)
    588625    {
    589626        reset();
    590627
    591         size_t      cbList  = Data.getSize();
    592         const char *pszList = (const char *)Data.getData();
    593         if (   !pszList
    594             || !cbList)
    595         {
     628        if (!Data.getSize())
    596629            return VINF_SUCCESS;
    597         }
    598 
    599         if (!RTStrIsValidEncoding(pszList))
    600             return VERR_INVALID_PARAMETER;
    601 
    602         RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
    603         if (lstURIOrg.isEmpty())
    604             return VINF_SUCCESS;
    605 
    606         /* Note: All files to be transferred will be kept open during the entire DnD
    607          *       operation, also to keep the accounting right. */
    608         return lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
     630
     631        char *pszList;
     632        int rc = RTStrCurrentCPToUtf8(&pszList, (const char *)Data.getData());
     633        if (RT_FAILURE(rc))
     634        {
     635            LogFlowThisFunc(("String conversion failed with rc=%Rrc\n", rc));
     636            return rc;
     637        }
     638
     639        const size_t cbList = Data.getSize();
     640        LogFlowThisFunc(("metaData=%p, cbList=%zu\n", &Data, cbList));
     641
     642        if (cbList)
     643        {
     644            RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
     645            if (!lstURIOrg.isEmpty())
     646            {
     647                /* Note: All files to be transferred will be kept open during the entire DnD
     648                 *       operation, also to keep the accounting right. */
     649                rc = lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
     650                if (RT_SUCCESS(rc))
     651                    cObjToProcess = lstURI.TotalCount();
     652            }
     653        }
     654
     655        RTStrFree(pszList);
     656        return rc;
     657    }
     658
     659    int fromRemoteMetaData(const GuestDnDMetaData &Data)
     660    {
     661        LogFlowFuncEnter();
     662
     663        int rc = lstURI.RootFromURIData(Data.getData(), Data.getSize(), 0 /* uFlags */);
     664        if (RT_SUCCESS(rc))
     665        {
     666            const size_t cRootCount = lstURI.RootCount();
     667            LogFlowFunc(("cRootCount=%zu, cObjToProcess=%RU64\n", cRootCount, cObjToProcess));
     668            if (cRootCount > cObjToProcess)
     669                rc = VERR_INVALID_PARAMETER;
     670        }
     671
     672        return rc;
    609673    }
    610674
     
    909973typedef std::map<uint32_t, GuestDnDCallback> GuestDnDCallbackMap;
    910974
     975/** @todo r=andy This class needs to go, as this now is too inflexible when it comes to all
     976 *               the callback handling/dispatching. It's part of the initial code and only adds
     977 *               unnecessary complexity. */
    911978class GuestDnDResponse
    912979{
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r58170 r58329  
    73857385#endif // 0
    73867386
    7387        
     7387
    73887388        /* setup task object and thread to carry out the operation
    73897389         * asynchronously */
     
    85908590
    85918591    int rc = pVMMDev->hgcmHostCall("VBoxDragAndDropSvc",
    8592                                    DragAndDropSvc::HOST_DND_SET_MODE, 1, &parm);
    8593     LogFlowFunc(("rc=%Rrc\n", rc));
     8592                                   DragAndDropSvc::HOST_DND_SET_MODE, 1 /* cParms */, &parm);
     8593    if (RT_FAILURE(rc))
     8594        LogRel(("Error changing drag and drop mode: %Rrc\n", rc));
     8595
    85948596    return rc;
    85958597}
  • trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp

    r58257 r58329  
    312312                case DragAndDropSvc::DND_PROGRESS_CANCELLED:
    313313                {
    314                     hr = m_pProgress->i_notifyComplete(S_OK);
     314                    hr = m_pProgress->Cancel();
     315                    AssertComRC(hr);
     316                    hr = m_pProgress->i_notifyComplete(S_FALSE);
    315317                    AssertComRC(hr);
    316318
     
    364366        case DragAndDropSvc::GUEST_DND_CONNECT:
    365367        {
    366             /* Not used in here (yet). */
     368            LogThisFunc(("Client connected\n"));
     369
     370            /* Nothing to do here (yet). */
    367371            rc = VINF_SUCCESS;
     372            break;
     373        }
     374
     375        case DragAndDropSvc::GUEST_DND_DISCONNECT:
     376        {
     377            LogThisFunc(("Client disconnected\n"));
     378            rc = setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
    368379            break;
    369380        }
     
    836847        && (uRevAdditions = m_pGuest->i_getAdditionsRevision()) > 0)
    837848    {
    838 #ifdef _DEBUG
    839 # if 0
     849#ifdef DEBUG
     850# if 1
    840851        /* Hardcode the to-used protocol version; nice for testing side effects. */
    841852        uProto = 3;
     853        rc = VINF_SUCCESS;
    842854# endif
    843855#endif
     
    851863                }
    852864                else
    853                     uProto = 2; /* VBox 5.0.0 - 5.0.6: Protocol v2. */
     865                    uProto = 2; /* VBox 5.0.0 - 5.0.8: Protocol v2. */
    854866            }
    855867
     
    940952
    941953    LogFlowFunc(("cbTotal=%RU64, cbProcessed=%RU64, cbRemaining=%RU64, cbDataAdd=%RU32\n",
    942                  pData->getProcessed(), pData->getProcessed(), pData->getRemaining(), cbDataAdd));
     954                 pData->getTotal(), pData->getProcessed(), pData->getRemaining(), cbDataAdd));
    943955
    944956    if (!pResp)
  • trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp

    r58257 r58329  
    407407    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    408408
     409    LogFlowThisFunc(("cTransfersPending=%RU32\n", mDataBase.m_cTransfersPending));
     410
    409411    /* Don't allow receiving the actual data until our transfer actually is complete. */
    410412    if (mDataBase.m_cTransfersPending)
     
    412414
    413415    PRECVDATACTX pCtx = &mData.mRecvCtx;
    414 
    415     if (pCtx->mData.getMeta().getSize() == 0)
    416     {
    417         LogFlowFunc(("No data available, returning 0\n"));
    418         aData.resize(0);
    419         return S_OK;
    420     }
    421 
    422416    HRESULT hr = S_OK;
    423     size_t cbData;
    424417
    425418    try
     
    435428        else
    436429        {
    437             cbData = pCtx->mData.getMeta().getSize();
    438 
    439             /* Copy the data into a safe array of bytes. */
    440             aData.resize(cbData);
    441             memcpy(&aData.front(), pCtx->mData.getMeta().getData(), cbData);
     430            const size_t cbData = pCtx->mData.getMeta().getSize();
     431            LogFlowFunc(("cbData=%zu\n", cbData));
     432            if (cbData)
     433            {
     434                /* Copy the data into a safe array of bytes. */
     435                aData.resize(cbData);
     436                memcpy(&aData.front(), pCtx->mData.getMeta().getData(), cbData);
     437            }
     438            else
     439                aData.resize(0);
    442440        }
    443441    }
     
    447445    }
    448446
    449     LogFlowFunc(("Returning cbData=%zu, hr=%Rhrc\n", cbData, hr));
     447    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
    450448    return hr;
    451449#endif /* VBOX_WITH_DRAG_AND_DROP */
     
    536534
    537535    Assert(pCtx->mURI.getObjToProcess() == 0);
    538     pCtx->mURI.reset(pDataHdr->cObjects);
     536    pCtx->mURI.reset();
     537    pCtx->mURI.setEstimatedObjects(pDataHdr->cObjects);
    539538
    540539    /** @todo Handle compression type. */
     
    554553    try
    555554    {
    556         GuestDnDData     *pData = &pCtx->mData;
    557         GuestDnDURIData  *pURI  = &pCtx->mURI;
     555        GuestDnDData    *pData = &pCtx->mData;
     556        GuestDnDURIData *pURI  = &pCtx->mURI;
    558557
    559558        uint32_t cbData;
    560559        void    *pvData;
    561         uint64_t cbToProcess;
     560        uint64_t cbTotal;
    562561        uint32_t cbMeta;
    563562
    564563        if (mDataBase.m_uProtocolVersion < 3)
    565564        {
    566             cbData = pSndData->u.v1.cbData;
    567             pvData = pSndData->u.v1.pvData;
     565            cbData  = pSndData->u.v1.cbData;
     566            pvData  = pSndData->u.v1.pvData;
    568567
    569568            /* Sends the total data size to receive for every data chunk. */
    570             cbToProcess = pSndData->u.v1.cbTotalSize;
     569            cbTotal = pSndData->u.v1.cbTotalSize;
    571570
    572571            /* Meta data size always is cbData, meaning there cannot be an
    573572             * extended data chunk transfer by sending further data. */
    574             cbMeta      = cbData;
     573            cbMeta  = cbData;
    575574        }
    576575        else
    577576        {
    578             cbData = pSndData->u.v3.cbData;
    579             pvData = pSndData->u.v3.pvData;
     577            cbData  = pSndData->u.v3.cbData;
     578            pvData  = pSndData->u.v3.pvData;
    580579
    581580            /* Note: Data sizes get updated in i_onReceiveDataHdr(). */
    582             cbToProcess = pData->getTotal();
    583             cbMeta      = pData->getMeta().getSize();
    584         }
    585         Assert(cbToProcess);
     581            cbTotal = pData->getTotal();
     582            cbMeta  = pData->getMeta().getSize();
     583        }
     584        Assert(cbTotal);
    586585
    587586        if (   cbData == 0
    588             || cbData >  cbToProcess /* Paranoia */)
     587            || cbData >  cbTotal /* Paranoia */)
    589588        {
    590589            LogFlowFunc(("Incoming data size invalid: cbData=%RU32, cbToProcess=%RU64\n", cbData, pData->getTotal()));
    591590            rc = VERR_INVALID_PARAMETER;
    592591        }
    593         else if (cbToProcess < cbMeta)
    594         {
    595             AssertMsgFailed(("cbToProcess (%RU64) is smaller than meta size (%zu)\n", cbToProcess, cbMeta));
     592        else if (cbTotal < cbMeta)
     593        {
     594            AssertMsgFailed(("cbTotal (%RU64) is smaller than cbMeta (%RU32)\n", cbTotal, cbMeta));
    596595            rc = VERR_INVALID_PARAMETER;
    597596        }
     
    599598        if (RT_SUCCESS(rc))
    600599        {
    601             pData->getMeta().add(pvData, cbData);
    602             LogFlowThisFunc(("cbMetaSize=%zu, cbData=%RU32, cbMeta=%RU32, cbToProcess=%RU64\n",
    603                              pData->getMeta().getSize(), cbData, cbMeta, cbToProcess));
     600            cbMeta = pData->getMeta().add(pvData, cbData);
     601            LogFlowThisFunc(("cbMetaSize=%zu, cbData=%RU32, cbMeta=%RU32, cbTotal=%RU64\n",
     602                             pData->getMeta().getSize(), cbData, cbMeta, cbTotal));
    604603        }
    605604
    606605        if (RT_SUCCESS(rc))
    607606        {
    608             /* (Meta) Data transfer complete? */
     607            /*
     608             * (Meta) Data transfer complete?
     609             */
    609610            Assert(cbMeta <= pData->getMeta().getSize());
    610611            if (cbMeta == pData->getMeta().getSize())
     
    615616                {
    616617                    /* Try parsing the data as URI list. */
    617                     rc = pURI->fromMetaData(pData->getMeta());
     618                    rc = pURI->fromRemoteMetaData(pData->getMeta());
    618619                    if (RT_SUCCESS(rc))
    619620                    {
    620621                        if (mDataBase.m_uProtocolVersion < 3)
    621                             pData->setEstimatedSize(cbToProcess, cbMeta);
     622                            pData->setEstimatedSize(cbTotal, cbMeta);
    622623
    623624                        /*
     
    655656        || cbPath > RTPATH_MAX)
    656657    {
     658        LogFlowFunc(("Path length invalid, bailing out\n"));
    657659        return VERR_INVALID_PARAMETER;
    658660    }
    659661
    660     if (!RTStrIsValidEncoding(pszPath))
     662    int rc = RTStrValidateEncodingEx(pszPath, RTSTR_MAX, 0);
     663    if (RT_FAILURE(rc))
     664    {
     665        LogFlowFunc(("Path validation failed with %Rrc, bailing out\n", rc));
    661666        return VERR_INVALID_PARAMETER;
     667    }
    662668
    663669    if (pCtx->mURI.isComplete())
     670    {
     671        LogFlowFunc(("Data transfer already complete, bailing out\n"));
    664672        return VERR_INVALID_PARAMETER;
    665 
    666     GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
    667     DnDURIObject *pObj       = objCtx.createIntermediate();
    668     if (!pObj)
    669         return VERR_NO_MEMORY;
    670 
    671     int rc;
     673    }
     674
     675    GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
     676
     677    rc = objCtx.createIntermediate(DnDURIObject::Directory);
     678    if (RT_FAILURE(rc))
     679        return rc;
     680
     681    DnDURIObject *pObj = objCtx.getObj();
     682    AssertPtr(pObj);
    672683
    673684    const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
     
    682693        rc = RTDirCreateFullPath(pszDir, fMode);
    683694        if (RT_SUCCESS(rc))
     695        {
     696            pCtx->mURI.processObject(*pObj);
     697            objCtx.reset();
    684698            LogRel2(("DnD: Created guest directory on host: %s\n", pszDir));
     699        }
    685700        else
    686701            LogRel(("DnD: Error creating guest directory '%s' on host, rc=%Rrc\n", pszDir, rc));
    687 
    688         pCtx->mURI.removeObjCurrent();
    689702
    690703        RTStrFree(pszDir);
     
    726739    }
    727740
    728     if (pCtx->mURI.isComplete())
     741    if (pCtx->mURI.getObjToProcess() && pCtx->mURI.isComplete())
    729742        return VERR_INVALID_PARAMETER;
    730743
     
    733746    do
    734747    {
    735         GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
    736         DnDURIObject *pObj       = objCtx.pObjURI;
     748        GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
     749        DnDURIObject *pObj        = objCtx.getObj();
    737750
    738751        /*
     
    760773         * Create new intermediate object to work with.
    761774         */
    762         pObj = objCtx.createIntermediate();
    763         if (!pObj)
    764             rc = VERR_NO_MEMORY;
    765 
     775        rc = objCtx.createIntermediate();
    766776        if (RT_SUCCESS(rc))
    767777        {
     778            pObj = objCtx.getObj();
     779
    768780            const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
    769781
     
    828840    int rc = VINF_SUCCESS;
    829841
     842    LogFlowFunc(("pvData=%p, cbData=%RU32, cbBlockSize=%RU32\n", pvData, cbData, mData.mcbBlockSize));
     843
    830844    /*
    831845     * Sanity checking.
     
    836850    do
    837851    {
    838         GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
    839         DnDURIObject *pObj       = objCtx.pObjURI;
     852        GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
     853        DnDURIObject *pObj        = objCtx.getObj();
    840854
    841855        if (!pObj)
    842856        {
    843             rc = VERR_INVALID_PARAMETER;
     857            LogFlowFunc(("Warning: No current object set\n"));
     858            rc = VERR_WRONG_ORDER;
    844859            break;
    845860        }
     
    880895                /** @todo Sanitize path. */
    881896                LogRel2(("DnD: File transfer to host complete: %s\n", pObj->GetDestPath().c_str()));
     897                pCtx->mURI.processObject(*pObj);
    882898                objCtx.reset();
    883 
    884                 rc = VINF_EOF;
    885899            }
    886900        }
     
    10281042     * Register callbacks.
    10291043     */
     1044    REGISTER_CALLBACK(GUEST_DND_CONNECT);
     1045    REGISTER_CALLBACK(GUEST_DND_DISCONNECT);
    10301046    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    10311047    REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
     
    10591075     * Unregister callbacks.
    10601076     */
     1077    UNREGISTER_CALLBACK(GUEST_DND_CONNECT);
     1078    UNREGISTER_CALLBACK(GUEST_DND_DISCONNECT);
    10611079    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    10621080    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
     
    11141132     */
    11151133    /* Guest callbacks. */
     1134    REGISTER_CALLBACK(GUEST_DND_CONNECT);
     1135    REGISTER_CALLBACK(GUEST_DND_DISCONNECT);
    11161136    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    11171137    if (mDataBase.m_uProtocolVersion >= 3)
     
    11641184     * Unregister callbacks.
    11651185     */
     1186    UNREGISTER_CALLBACK(GUEST_DND_CONNECT);
     1187    UNREGISTER_CALLBACK(GUEST_DND_DISCONNECT);
    11661188    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    11671189    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     
    12241246    switch (uMsg)
    12251247    {
     1248        case GUEST_DND_CONNECT:
     1249            /* Nothing to do here (yet). */
     1250            break;
     1251
     1252        case GUEST_DND_DISCONNECT:
     1253            rc = VERR_CANCELLED;
     1254            break;
     1255
    12261256#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    12271257        case GUEST_DND_GH_SND_DATA_HDR:
     
    12971327    switch (uMsg)
    12981328    {
     1329        case GUEST_DND_CONNECT:
     1330            /* Nothing to do here (yet). */
     1331            break;
     1332
     1333        case GUEST_DND_DISCONNECT:
     1334            rc = VERR_CANCELLED;
     1335            break;
     1336
    12991337#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    13001338        case GUEST_DND_GH_SND_DATA_HDR:
  • trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp

    r58257 r58329  
    866866    AssertPtrReturn(pMsg,    VERR_INVALID_POINTER);
    867867
    868     DnDURIObject *pObj = pObjCtx->pObjURI;
     868    DnDURIObject *pObj = pObjCtx->getObj();
    869869    AssertPtr(pObj);
    870870
     
    893893    AssertPtrReturn(pMsg,    VERR_INVALID_POINTER);
    894894
    895     DnDURIObject *pObj = pObjCtx->pObjURI;
     895    DnDURIObject *pObj = pObjCtx->getObj();
    896896    AssertPtr(pObj);
    897897
     
    920920        if (mDataBase.m_uProtocolVersion >= 2)
    921921        {
    922             if (!pObjCtx->fHeaderSent)
     922            uint32_t fState = pObjCtx->getState();
     923            if (!(fState & DND_OBJCTX_STATE_HAS_HDR))
    923924            {
    924925                /*
     
    941942                /** @todo Set progress object title to current file being transferred? */
    942943
    943                 pObjCtx->fHeaderSent = true;
     944                pObjCtx->setState(fState | DND_OBJCTX_STATE_HAS_HDR);
    944945            }
    945946            else
     
    972973    AssertPtrReturn(pMsg,    VERR_INVALID_POINTER);
    973974
    974     DnDURIObject *pObj = pObjCtx->pObjURI;
     975    DnDURIObject *pObj = pObjCtx->getObj();
    975976    AssertPtr(pObj);
    976977
     
    10581059    switch (uMsg)
    10591060    {
     1061        case GUEST_DND_CONNECT:
     1062            /* Nothing to do here (yet). */
     1063            break;
     1064
     1065        case GUEST_DND_DISCONNECT:
     1066            rc = VERR_CANCELLED;
     1067            break;
     1068
    10601069        case GUEST_DND_GET_NEXT_HOST_MSG:
    10611070        {
     
    12521261    rc = pCtx->mpResp->setCallback(x, i_sendURIDataCallback, pCtx); \
    12531262    if (RT_FAILURE(rc))                                             \
    1254         break;
     1263        return rc;
    12551264
    12561265#define UNREGISTER_CALLBACK(x)                        \
     
    12671276    if (RT_FAILURE(rc))
    12681277        return rc;
     1278
     1279    /*
     1280     * Register callbacks.
     1281     */
     1282    /* Guest callbacks. */
     1283    REGISTER_CALLBACK(GUEST_DND_CONNECT);
     1284    REGISTER_CALLBACK(GUEST_DND_DISCONNECT);
     1285    REGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
     1286    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     1287    /* Host callbacks. */
     1288    REGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
     1289    if (mDataBase.m_uProtocolVersion >= 2)
     1290        REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
     1291    REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
    12691292
    12701293    do
     
    12761299        GuestDnDURIData *pURI  = &pCtx->mURI;
    12771300
    1278         rc = pURI->fromMetaData(pData->getMeta());
     1301        rc = pURI->fromLocalMetaData(pData->getMeta());
    12791302        if (RT_FAILURE(rc))
    12801303            break;
     
    12911314
    12921315        /*
    1293          * Set the additional size we are going to send after the meta data header + meta data.
    1294          * This additional data will contain the actual file data we want to transfer.
     1316         * Set the estimated data sizes we are going to send.
     1317         * The total size also contains the meta data size.
    12951318         */
    1296         pData->setAdditionalSize(pURI->getURIList().TotalBytes());
    1297 
     1319        const uint32_t cbMeta = pData->getMeta().getSize();
     1320        pData->setEstimatedSize(pURI->getURIList().TotalBytes() + cbMeta /* cbTotal */,
     1321                                                                  cbMeta /* cbMeta  */);
     1322
     1323        /*
     1324         * Set the meta format.
     1325         */
    12981326        void    *pvFmt = (void *)pCtx->mFmtReq.c_str();
    12991327        uint32_t cbFmt = pCtx->mFmtReq.length() + 1;        /* Include terminating zero. */
     
    13261354        if (RT_SUCCESS(rc))
    13271355        {
    1328             /*
    1329              * Register callbacks.
    1330              */
    1331             /* Guest callbacks. */
    1332             REGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
    1333             REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    1334             /* Host callbacks. */
    1335             REGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
    1336             if (mDataBase.m_uProtocolVersion >= 2)
    1337                 REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
    1338             REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
    1339 
    13401356            rc = waitForEvent(&pCtx->mCBEvent, pCtx->mpResp, msTimeout);
    1341             if (RT_FAILURE(rc))
    1342             {
    1343                 if (rc == VERR_CANCELLED)
    1344                     rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
    1345                 else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
    1346                     rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
    1347                                                    GuestDnDTarget::i_hostErrorToString(rc));
    1348             }
    1349             else
    1350                 rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
    1351 
    1352             /*
    1353              * Unregister callbacks.
    1354              */
    1355             /* Guest callbacks. */
    1356             UNREGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
    1357             UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    1358             /* Host callbacks. */
    1359             UNREGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
    1360             if (mDataBase.m_uProtocolVersion >= 2)
    1361                 UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
    1362             UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
     1357            if (RT_SUCCESS(rc))
     1358                pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
    13631359        }
    13641360
    13651361    } while (0);
     1362
     1363    /*
     1364     * Unregister callbacks.
     1365     */
     1366    /* Guest callbacks. */
     1367    UNREGISTER_CALLBACK(GUEST_DND_CONNECT);
     1368    UNREGISTER_CALLBACK(GUEST_DND_DISCONNECT);
     1369    UNREGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
     1370    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     1371    /* Host callbacks. */
     1372    UNREGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
     1373    if (mDataBase.m_uProtocolVersion >= 2)
     1374        UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
     1375    UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
    13661376
    13671377#undef REGISTER_CALLBACK
    13681378#undef UNREGISTER_CALLBACK
     1379
     1380    if (RT_FAILURE(rc))
     1381    {
     1382        if (rc == VERR_CANCELLED)
     1383            pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
     1384        else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
     1385            pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
     1386                                      GuestDnDTarget::i_hostErrorToString(rc));
     1387    }
    13691388
    13701389    /*
     
    14011420        return VERR_WRONG_ORDER;
    14021421
    1403     DnDURIObject *pCurObj = objCtx.pObjURI;
     1422    DnDURIObject *pCurObj = objCtx.getObj();
    14041423    AssertPtr(pCurObj);
    14051424
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette