VirtualBox

Changeset 85537 in vbox for trunk


Ignore:
Timestamp:
Jul 30, 2020 6:55:32 AM (4 years ago)
Author:
vboxsync
Message:

DnD/Main: More fixes and cleanups.

Location:
trunk/src/VBox/Main
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/GuestDnDPrivate.h

    r85436 r85537  
    8989        : pvData(NULL)
    9090        , cbData(0)
    91         , cbAllocated(0) { }
     91        , cbAllocated(0)
     92        , cbAnnounced(0) { }
    9293
    9394    virtual ~GuestDnDMetaData(void)
     
    9899    size_t add(const void *pvDataAdd, size_t cbDataAdd)
    99100    {
    100         LogFlowThisFunc(("pvDataAdd=%p, cbDataAdd=%zu\n", pvDataAdd, cbDataAdd));
    101 
     101        LogFlowThisFunc(("cbAllocated=%zu, cbAnnounced=%zu, pvDataAdd=%p, cbDataAdd=%zu\n",
     102                         cbAllocated, cbAnnounced, pvDataAdd, cbDataAdd));
    102103        if (!cbDataAdd)
    103104            return 0;
    104105        AssertPtrReturn(pvDataAdd, 0);
    105106
    106         int rc = resize(cbAllocated + cbDataAdd);
    107         if (RT_FAILURE(rc))
    108             return 0;
     107        const size_t cbAllocatedTmp = cbData + cbDataAdd;
     108        if (cbAllocatedTmp > cbAllocated)
     109        {
     110            int rc = resize(cbAllocatedTmp);
     111            if (RT_FAILURE(rc))
     112                return 0;
     113        }
    109114
    110115        Assert(cbAllocated >= cbData + cbDataAdd);
     
    138143        }
    139144
     145        cbData      = 0;
    140146        cbAllocated = 0;
    141         cbData      = 0;
     147        cbAnnounced = 0;
    142148    }
    143149
     
    154160
    155161        if (cbSize > _32M) /* Meta data can be up to 32MB. */
    156             return VERR_INVALID_PARAMETER;
     162            return VERR_BUFFER_OVERFLOW;
    157163
    158164        void *pvTmp = NULL;
     
    160166        {
    161167            Assert(cbData == 0);
    162             pvTmp = RTMemAllocZ(cbSize);
     168            pvTmp = RTMemAllocZ(RT_ALIGN_Z(cbSize, 4096));
    163169        }
    164170        else
    165171        {
    166172            AssertPtr(pvData);
    167             pvTmp = RTMemRealloc(pvData, cbSize);
     173            pvTmp = RTMemRealloc(pvData, RT_ALIGN_Z(cbSize, 4096));
    168174            RT_BZERO(pvTmp, cbSize);
    169175        }
     
    187193    /** Size (in bytes) of allocated meta data. */
    188194    size_t       cbAllocated;
     195    /** Size (in bytes) of announced meta data. */
     196    size_t       cbAnnounced;
    189197};
    190198
     
    205213    size_t addProcessed(size_t cbDataAdd)
    206214    {
    207         const size_t cbTotal = Meta.cbData + cbExtra; RT_NOREF(cbTotal);
     215        const size_t cbTotal = getTotalAnnounced(); RT_NOREF(cbTotal);
    208216        AssertReturn(cbProcessed + cbDataAdd <= cbTotal, 0);
    209217        cbProcessed += cbDataAdd;
     
    213221    bool isComplete(void) const
    214222    {
    215         const size_t cbTotal = Meta.cbData + cbExtra;
     223        const size_t cbTotal = getTotalAnnounced();
    216224        LogFlowFunc(("cbProcessed=%zu, cbTotal=%zu\n", cbProcessed, cbTotal));
    217225        AssertReturn(cbProcessed <= cbTotal, true);
     
    221229    uint8_t getPercentComplete(void) const
    222230    {
    223         const size_t cbTotal = Meta.cbData + cbExtra;
     231        const size_t cbTotal = getTotalAnnounced();
    224232        return (uint8_t)(cbProcessed * 100 / RT_MAX(cbTotal, 1));
    225233    }
     
    227235    size_t getRemaining(void) const
    228236    {
    229         const size_t cbTotal = Meta.cbData + cbExtra;
     237        const size_t cbTotal = getTotalAnnounced();
    230238        AssertReturn(cbProcessed <= cbTotal, 0);
    231239        return cbTotal - cbProcessed;
    232240    }
    233241
    234     size_t getTotal(void) const
     242    size_t getTotalAnnounced(void) const
     243    {
     244        return Meta.cbAnnounced + cbExtra;
     245    }
     246
     247    size_t getTotalAvailable(void) const
    235248    {
    236249        return Meta.cbData + cbExtra;
     
    373386struct GuestDnDSendCtx : public GuestDnDData
    374387{
     388    GuestDnDSendCtx(void);
     389
     390    void reset(void);
     391
    375392    /** Pointer to guest target class this context belongs to. */
    376393    GuestDnDTarget                     *pTarget;
    377394    /** Pointer to guest response class this context belongs to. */
    378395    GuestDnDResponse                   *pResp;
    379     /** Flag indicating whether a file transfer is active and
    380      *  initiated by the host. */
    381     bool                                fIsActive;
    382396    /** Target (VM) screen ID. */
    383397    uint32_t                            uScreenID;
     
    440454struct GuestDnDRecvCtx : public GuestDnDData
    441455{
     456    GuestDnDRecvCtx(void);
     457
     458    void reset(void);
     459
    442460    /** Pointer to guest source class this context belongs to. */
    443461    GuestDnDSource                     *pSource;
    444462    /** Pointer to guest response class this context belongs to. */
    445463    GuestDnDResponse                   *pResp;
    446     /** Flag indicating whether a file transfer is active and
    447      *  initiated by the host. */
    448     bool                                fIsActive;
    449464    /** Formats offered by the guest (and supported by the host). */
    450465    GuestDnDMIMEList                    lstFmtOffered;
     
    693708
    694709/**
    695  * Private singleton class for the guest's DnD
    696  * implementation. Can't be instanciated directly, only via
    697  * the factory pattern.
     710 * Private singleton class for the guest's DnD implementation.
    698711 *
    699  ** @todo Move this into GuestDnDBase.
     712 * Can't be instanciated directly, only via the factory pattern.
     713 * Keeps track of all ongoing DnD transfers.
    700714 */
    701715class GuestDnD
     
    727741protected:
    728742
     743    /** List of registered DnD sources. */
     744    typedef std::list< ComObjPtr<GuestDnDSource> > GuestDnDSrcList;
     745    /** List of registered DnD targets. */
     746    typedef std::list< ComObjPtr<GuestDnDTarget> > GuestDnDTgtList;
     747
     748    /** Constructor; will throw rc on failure. */
    729749    GuestDnD(const ComObjPtr<Guest>& pGuest);
    730750    virtual ~GuestDnD(void);
     
    738758    GuestDnDResponse *response(void) { return m_pResponse; }
    739759    GuestDnDMIMEList  defaultFormats(void) const { return m_strDefaultFormats; }
     760    /** @}  */
     761
     762    /** @name Source / target management. */
     763    int               registerSource(const ComObjPtr<GuestDnDSource> &Source);
     764    int               unregisterSource(const ComObjPtr<GuestDnDSource> &Source);
     765    size_t            getSourceCount(void);
     766
     767    int               registerTarget(const ComObjPtr<GuestDnDTarget> &Target);
     768    int               unregisterTarget(const ComObjPtr<GuestDnDTarget> &Target);
     769    size_t            getTargetCount(void);
    740770    /** @}  */
    741771
     
    765795     * @{ */
    766796    /** List of supported default MIME/Content-type formats. */
    767     GuestDnDMIMEList           m_strDefaultFormats;
     797    GuestDnDMIMEList            m_strDefaultFormats;
    768798    /** Pointer to guest implementation. */
    769     const ComObjPtr<Guest>     m_pGuest;
     799    const ComObjPtr<Guest>      m_pGuest;
    770800    /** The current (last) response from the guest. At the
    771801     *  moment we only support only response a time (ARQ-style). */
    772     GuestDnDResponse          *m_pResponse;
     802    GuestDnDResponse           *m_pResponse;
     803    /** Critical section to serialize access. */
     804    RTCRITSECT                  m_CritSect;
     805    /** Number of active transfers (guest->host or host->guest). */
     806    uint32_t                    m_cTransfersPending;
     807    GuestDnDSrcList             m_lstSrc;
     808    GuestDnDTgtList             m_lstTgt;
    773809    /** @}  */
    774810
    775811private:
    776812
    777     /** Staic pointer to singleton instance. */
     813    /** Static pointer to singleton instance. */
    778814    static GuestDnD           *s_pInstance;
    779815};
    780816
    781817/** Access to the GuestDnD's singleton instance. */
    782 #define GUESTDNDINST() GuestDnD::getInstance()
     818#define GuestDnDInst() GuestDnD::getInstance()
    783819
    784820/** List of pointers to guest DnD Messages. */
     
    833869    /** List of offered MIME types to the counterpart. */
    834870    GuestDnDMIMEList                m_lstFmtOffered;
     871    /** Whether the object still is in pending state. */
     872    bool                            m_fIsPending;
    835873    /** @}  */
    836874
     
    840878    struct
    841879    {
    842         /** Number of active transfers (guest->host or host->guest). */
    843         uint32_t                    cTransfersPending;
    844880        /** The DnD protocol version to use, depending on the
    845881         *  installed Guest Additions. See DragAndDropSvc.h for
  • trunk/src/VBox/Main/include/GuestDnDSourceImpl.h

    r85402 r85537  
    7070protected:
    7171
     72    void i_reset(void);
     73
    7274#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    7375    /** @name Dispatch handlers for the HGCM callbacks.
     
    8587    static Utf8Str i_guestErrorToString(int guestRc);
    8688    static Utf8Str i_hostErrorToString(int hostRc);
    87 
    88     /** @name Thread task .
    89      * @{ */
    90     static void i_receiveDataThreadTask(GuestDnDRecvDataTask *pTask);
    91     /** @}  */
    9289
    9390    /** @name Callbacks for dispatch handler.
  • trunk/src/VBox/Main/include/GuestDnDTargetImpl.h

    r85423 r85537  
    7474    static Utf8Str i_hostErrorToString(int hostRc);
    7575
    76     /** @name Thread task workers.
    77      * @{ */
    78     static void i_sendDataThreadTask(GuestDnDSendDataTask *pTask);
    79     /** @}  */
    80 
    8176    /** @name Callbacks for dispatch handler.
    8277     * @{ */
     
    8580
    8681protected:
     82
     83    void i_reset(void);
    8784
    8885    int i_sendData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout);
     
    104101    struct
    105102    {
    106         /** Flag indicating whether a data transfer currently is active. */
    107         bool     mfTransferIsPending;
    108103        /** Maximum data block size (in bytes) the target can handle. */
    109         uint32_t mcbBlockSize;
     104        uint32_t        mcbBlockSize;
     105        /** The context for sending data to the guest.
     106         *  At the moment only one transfer at a time is supported. */
     107        GuestDnDSendCtx mSendCtx;
    110108    } mData;
    111109
  • trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp

    r85357 r85537  
    31863186                rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
    31873187                                                      &GuestDnD::notifyDnDDispatcher,
    3188                                                       GUESTDNDINST());
     3188                                                      GuestDnDInst());
    31893189                if (RT_FAILURE(rc))
    31903190                    Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
  • trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp

    r85423 r85537  
    156156 */
    157157
     158
     159/********************************************************************************************************************************
     160 *
     161 ********************************************************************************************************************************/
     162
     163#define GUESTDND_LOCK() \
     164    { \
     165        int rcLock = RTCritSectEnter(&m_CritSect); \
     166        if (RT_FAILURE(rcLock)) \
     167            return rcLock; \
     168    }
     169
     170#define GUESTDND_LOCK_RET(a_Ret) \
     171    { \
     172        int rcLock = RTCritSectEnter(&m_CritSect); \
     173        if (RT_FAILURE(rcLock)) \
     174            return a_Ret; \
     175    }
     176
     177#define GUESTDND_UNLOCK() \
     178    { \
     179        int rcUnlock = RTCritSectLeave(&m_CritSect); RT_NOREF(rcUnlock); \
     180        AssertRC(rcUnlock); \
     181    }
     182
     183/********************************************************************************************************************************
     184 *
     185 ********************************************************************************************************************************/
     186
     187GuestDnDSendCtx::GuestDnDSendCtx(void)
     188    : pTarget(NULL)
     189    , pResp(NULL)
     190{
     191    reset();
     192}
     193
     194void GuestDnDSendCtx::reset(void)
     195{
     196    if (pResp)
     197        pResp->reset();
     198
     199    uScreenID  = 0;
     200
     201    Transfer.reset();
     202
     203    int rc2 = EventCallback.Reset();
     204    AssertRC(rc2);
     205
     206    GuestDnDData::reset();
     207}
     208
     209/*********************************************************************************************************************************
     210 *                                                                                                                               *
     211 ********************************************************************************************************************************/
     212
     213GuestDnDRecvCtx::GuestDnDRecvCtx(void)
     214    : pSource(NULL)
     215    , pResp(NULL)
     216{
     217    reset();
     218}
     219
     220void GuestDnDRecvCtx::reset(void)
     221{
     222    if (pResp)
     223        pResp->reset();
     224
     225    lstFmtOffered.clear();
     226    strFmtReq  = "";
     227    strFmtRecv = "";
     228    enmAction  = 0;
     229
     230    Transfer.reset();
     231
     232    int rc2 = EventCallback.Reset();
     233    AssertRC(rc2);
     234
     235    GuestDnDData::reset();
     236}
     237
     238/*********************************************************************************************************************************
     239 *                                                                                                                               *
     240 ********************************************************************************************************************************/
     241
    158242GuestDnDCallbackEvent::~GuestDnDCallbackEvent(void)
    159243{
     
    184268}
    185269
    186 ///////////////////////////////////////////////////////////////////////////////
     270/********************************************************************************************************************************
     271 *
     272 ********************************************************************************************************************************/
    187273
    188274GuestDnDResponse::GuestDnDResponse(const ComObjPtr<Guest>& pGuest)
     
    523609}
    524610
    525 ///////////////////////////////////////////////////////////////////////////////
     611/*********************************************************************************************************************************
     612 *                                                                                                                               *
     613 ********************************************************************************************************************************/
    526614
    527615GuestDnD* GuestDnD::s_pInstance = NULL;
     
    529617GuestDnD::GuestDnD(const ComObjPtr<Guest> &pGuest)
    530618    : m_pGuest(pGuest)
     619    , m_cTransfersPending(0)
    531620{
    532621    LogFlowFuncEnter();
    533622
    534     m_pResponse = new GuestDnDResponse(pGuest);
     623    try
     624    {
     625        m_pResponse = new GuestDnDResponse(pGuest);
     626    }
     627    catch (std::bad_alloc &)
     628    {
     629        throw VERR_NO_MEMORY;
     630    }
     631
     632    int rc = RTCritSectInit(&m_CritSect);
     633    if (RT_FAILURE(rc))
     634        throw rc;
    535635
    536636    /* List of supported default MIME types. */
     
    547647{
    548648    LogFlowFuncEnter();
     649
     650    Assert(m_cTransfersPending == 0); /* Sanity. */
     651
     652    RTCritSectDelete(&m_CritSect);
    549653
    550654    if (m_pResponse)
     
    596700}
    597701
     702int GuestDnD::registerSource(const ComObjPtr<GuestDnDSource> &Source)
     703{
     704    GUESTDND_LOCK();
     705
     706    Assert(m_lstSrc.size() == 0); /* We only support one source at a time at the moment. */
     707    m_lstSrc.push_back(Source);
     708
     709    GUESTDND_UNLOCK();
     710    return VINF_SUCCESS;
     711}
     712
     713int GuestDnD::unregisterSource(const ComObjPtr<GuestDnDSource> &Source)
     714{
     715    GUESTDND_LOCK();
     716
     717    GuestDnDSrcList::iterator itSrc = std::find(m_lstSrc.begin(), m_lstSrc.end(), Source);
     718    if (itSrc != m_lstSrc.end())
     719        m_lstSrc.erase(itSrc);
     720
     721    GUESTDND_UNLOCK();
     722    return VINF_SUCCESS;
     723}
     724
     725size_t GuestDnD::getSourceCount(void)
     726{
     727    GUESTDND_LOCK_RET(0);
     728
     729    size_t cSources = m_lstSrc.size();
     730
     731    GUESTDND_UNLOCK();
     732    return cSources;
     733}
     734
     735int GuestDnD::registerTarget(const ComObjPtr<GuestDnDTarget> &Target)
     736{
     737    GUESTDND_LOCK();
     738
     739    Assert(m_lstTgt.size() == 0); /* We only support one target at a time at the moment. */
     740    m_lstTgt.push_back(Target);
     741
     742    GUESTDND_UNLOCK();
     743    return VINF_SUCCESS;
     744}
     745
     746int GuestDnD::unregisterTarget(const ComObjPtr<GuestDnDTarget> &Target)
     747{
     748    GUESTDND_LOCK();
     749
     750    GuestDnDTgtList::iterator itTgt = std::find(m_lstTgt.begin(), m_lstTgt.end(), Target);
     751    if (itTgt != m_lstTgt.end())
     752        m_lstTgt.erase(itTgt);
     753
     754    GUESTDND_UNLOCK();
     755    return VINF_SUCCESS;
     756}
     757
     758size_t GuestDnD::getTargetCount(void)
     759{
     760    GUESTDND_LOCK_RET(0);
     761
     762    size_t cTargets = m_lstTgt.size();
     763
     764    GUESTDND_UNLOCK();
     765    return cTargets;
     766}
     767
    598768/* static */
    599769DECLCALLBACK(int) GuestDnD::notifyDnDDispatcher(void *pvExtension, uint32_t u32Function,
     
    626796{
    627797    GuestDnDMIMEList lstFormats;
    628     RTCList<RTCString> lstFormatsTmp = strFormats.split("\r\n");
     798    RTCList<RTCString> lstFormatsTmp = strFormats.split(DND_FORMATS_SEPARATOR);
    629799
    630800    for (size_t i = 0; i < lstFormatsTmp.size(); i++)
     
    641811    {
    642812        const com::Utf8Str &f = lstFormats.at(i);
    643         strFormat += f + "\r\n";
     813        strFormat += f + DND_FORMATS_SEPARATOR;
    644814    }
    645815
     
    670840    GuestDnDMIMEList lstFmt;
    671841
    672     RTCList<RTCString> lstFormats = strFormatsWanted.split("\r\n");
     842    RTCList<RTCString> lstFormats = strFormatsWanted.split(DND_FORMATS_SEPARATOR);
    673843    size_t i = 0;
    674844    while (i < lstFormats.size())
     
    775945}
    776946
    777 ///////////////////////////////////////////////////////////////////////////////
     947/*********************************************************************************************************************************
     948 *                                                                                                                               *
     949 ********************************************************************************************************************************/
    778950
    779951GuestDnDBase::GuestDnDBase(void)
     952    : m_fIsPending(false)
    780953{
    781954    /* Initialize public attributes. */
    782     m_lstFmtSupported = GUESTDNDINST()->defaultFormats();
     955    m_lstFmtSupported = GuestDnDInst()->defaultFormats();
    783956
    784957    /* Initialzie private stuff. */
    785     m_DataBase.cTransfersPending = 0;
    786958    m_DataBase.uProtocolVersion  = 0;
    787959}
     
    9431115        Msg.setNextUInt32(0); /** @todo ContextID not used yet. */
    9441116
    945     LogRel2(("DnD: Cancelling operation on guest ..."));
    946 
    947     return GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     1117    LogRel2(("DnD: Cancelling operation on guest ...\n"));
     1118
     1119    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     1120    if (RT_FAILURE(rc))
     1121        LogRel(("DnD: Cancelling operation on guest failed with %Rrc\n", rc));
     1122
     1123    return rc;
    9481124}
    9491125
  • trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp

    r85451 r85537  
    5959    int getRC(void) const { return mRC; }
    6060    bool isOk(void) const { return RT_SUCCESS(mRC); }
    61     const ComObjPtr<GuestDnDSource> &getSource(void) const { return mSource; }
    6261
    6362protected:
     
    8483    void handler()
    8584    {
    86         GuestDnDSource::i_receiveDataThreadTask(this);
     85        LogFlowThisFunc(("\n"));
     86
     87        const ComObjPtr<GuestDnDSource> pThis(mSource);
     88        Assert(!pThis.isNull());
     89
     90        AutoCaller autoCaller(pThis);
     91        if (FAILED(autoCaller.rc()))
     92            return;
     93
     94        int vrc = pThis->i_receiveData(mpCtx, RT_INDEFINITE_WAIT /* msTimeout */);
     95        if (RT_FAILURE(vrc)) /* In case we missed some error handling within i_receiveData(). */
     96        {
     97            if (vrc != VERR_CANCELLED)
     98                LogRel(("DnD: Receiving data from guest failed with %Rrc\n", vrc));
     99
     100            /* Make sure to fire a cancel request to the guest side in case something went wrong. */
     101            pThis->sendCancel();
     102        }
    87103    }
    88104
    89105    virtual ~GuestDnDRecvDataTask(void) { }
    90 
    91     GuestDnDRecvCtx *getCtx(void) { return mpCtx; }
    92106
    93107protected:
     
    266280    Msg.setNextUInt32(uScreenId);
    267281
    268     int rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     282    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    269283    if (RT_SUCCESS(rc))
    270284    {
    271         GuestDnDResponse *pResp = GUESTDNDINST()->response();
     285        GuestDnDResponse *pResp = GuestDnDInst()->response();
    272286        AssertPtr(pResp);
    273287
     
    337351        return setError(E_INVALIDARG, tr("Specified format '%s' is not supported"), aFormat.c_str());
    338352
     353    /* Check that the given action is supported by us. */
    339354    VBOXDNDACTION dndAction = GuestDnD::toHGCMAction(aAction);
    340355    if (isDnDIgnoreAction(dndAction)) /* If there is no usable action, ignore this request. */
     
    343358    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    344359
     360    /* Check if this object still is in a pending state and bail out if so. */
     361    if (m_fIsPending)
     362        return setError(E_FAIL, tr("Current drop operation to host still in progress"));
     363
     364    /* Reset our internal state. */
     365    i_reset();
     366
    345367    /* At the moment we only support one transfer at a time. */
    346     if (m_DataBase.cTransfersPending)
    347         return setError(E_INVALIDARG, tr("Another drop operation already is in progress"));
    348 
    349     /* Dito. */
    350     GuestDnDResponse *pResp = GUESTDNDINST()->response();
     368    if (GuestDnDInst()->getSourceCount())
     369        return setError(E_INVALIDARG, tr("Another drag and drop operation to the host already is in progress"));
     370
     371    /* Reset progress object. */
     372    GuestDnDResponse *pResp = GuestDnDInst()->response();
    351373    AssertPtr(pResp);
    352 
    353374    HRESULT hr = pResp->resetProgress(m_pGuest);
    354375    if (FAILED(hr))
     
    359380    try
    360381    {
    361         mData.mRecvCtx.fIsActive     = false;
    362382        mData.mRecvCtx.pSource       = this;
    363383        mData.mRecvCtx.pResp         = pResp;
     384        mData.mRecvCtx.enmAction     = dndAction;
    364385        mData.mRecvCtx.strFmtReq     = aFormat;
    365386        mData.mRecvCtx.lstFmtOffered = m_lstFmtOffered;
    366387
    367         LogRel2(("DnD: Requesting data from guest in format: %s\n", aFormat.c_str()));
     388        LogRel2(("DnD: Requesting data from guest in format '%s'\n", aFormat.c_str()));
    368389
    369390        pTask = new GuestDnDRecvDataTask(this, &mData.mRecvCtx);
     
    371392        {
    372393            delete pTask;
    373             LogRel2(("DnD: Could not create RecvDataTask object \n"));
     394            LogRel2(("DnD: Receive data task failed to initialize\n"));
    374395            throw hr = E_FAIL;
    375396        }
     
    395416    if (SUCCEEDED(hr))
    396417    {
    397         /* Re-acquire write lock. */
    398         alock.acquire();
    399 
    400         m_DataBase.cTransfersPending++;
     418        /* Register ourselves at the DnD manager. */
     419        GuestDnDInst()->registerSource(this);
    401420
    402421        hr = pResp->queryProgressTo(aProgress.asOutParam());
     
    405424    }
    406425    else
    407         hr = setError(hr, tr("Starting thread for GuestDnDSource::i_receiveDataThread failed (%Rhrc)"), hr);
    408     /* Note: m_DataBase.mfTransferIsPending will be set to false again by i_receiveDataThread. */
     426        hr = setError(hr, tr("Starting thread for GuestDnDSource failed (%Rhrc)"), hr);
    409427
    410428    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     
    422440    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    423441
    424     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    425 
    426     LogFlowThisFunc(("cTransfersPending=%RU32\n", m_DataBase.cTransfersPending));
     442    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    427443
    428444    /* Don't allow receiving the actual data until our current transfer is complete. */
    429     if (m_DataBase.cTransfersPending)
    430         return setError(E_FAIL, tr("Current drop operation still in progress"));
     445    if (m_fIsPending)
     446        return setError(E_FAIL, tr("Current drop operation to host still in progress"));
    431447
    432448    HRESULT hr = S_OK;
     
    442458            AssertPtr(pcszDropDirAbs);
    443459
    444             LogRel2(("DnD: Using drop directory '%s'\n", pcszDropDirAbs));
    445 
    446             char  *pszBuf;
    447             size_t cbBuf;
    448             int rc = DnDTransferListGetRootsEx(&pCtx->Transfer.List, DNDTRANSFERLISTFMT_NATIVE,
    449                                                pcszDropDirAbs, "\n" /* On all platforms */, &pszBuf, &cbBuf);
     460            LogRel2(("DnD: Using drop directory '%s', got %RU64 root entries\n",
     461                     pcszDropDirAbs, DnDTransferListGetRootCount(&pCtx->Transfer.List)));
     462
     463            /* We return the data as "text/uri-list" MIME data here. */
     464            char  *pszBuf = NULL;
     465            size_t cbBuf  = 0;
     466            int rc = DnDTransferListGetRootsEx(&pCtx->Transfer.List, DNDTRANSFERLISTFMT_URI,
     467                                               pcszDropDirAbs, DND_PATH_SEPARATOR, &pszBuf, &cbBuf);
    450468            if (RT_SUCCESS(rc))
    451469            {
     470                Assert(cbBuf);
     471                AssertPtr(pszBuf);
     472
    452473                aData.resize(cbBuf);
    453474                memcpy(&aData.front(), pszBuf, cbBuf);
     
    457478                LogRel(("DnD: Unable to build source root list, rc=%Rrc\n", rc));
    458479        }
    459         else
     480        else /* Raw data. */
    460481        {
    461482            if (pCtx->Meta.cbData)
     
    558579}
    559580
     581void GuestDnDSource::i_reset(void)
     582{
     583    LogFlowThisFunc(("\n"));
     584
     585    mData.mRecvCtx.reset();
     586
     587    m_fIsPending = false;
     588
     589    /* Unregister ourselves from the DnD manager. */
     590    GuestDnDInst()->unregisterSource(this);
     591}
     592
    560593#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     594
    561595/**
    562596 * Handles receiving a send data header from the guest.
     
    576610    AssertReturn(pDataHdr->cbTotal >= pDataHdr->cbMeta, VERR_INVALID_PARAMETER);
    577611
    578     int rc = pCtx->Meta.resize(pDataHdr->cbMeta);
    579     AssertRCReturn(rc, rc);
    580 
    581     pCtx->cbExtra = pDataHdr->cbTotal - pDataHdr->cbMeta;
     612    pCtx->Meta.cbAnnounced = pDataHdr->cbMeta;
     613    pCtx->cbExtra          = pDataHdr->cbTotal - pDataHdr->cbMeta;
    582614
    583615    Assert(pCtx->Transfer.cObjToProcess == 0); /* Sanity. */
     
    615647        size_t  cbData;
    616648        void   *pvData;
    617         size_t  cbTotal;
    618         size_t  cbMeta;
     649        size_t  cbTotalAnnounced;
     650        size_t  cbMetaAnnounced;
    619651
    620652        if (m_DataBase.uProtocolVersion < 3)
     
    624656
    625657            /* Sends the total data size to receive for every data chunk. */
    626             cbTotal = pSndData->u.v1.cbTotalSize;
     658            cbTotalAnnounced = pSndData->u.v1.cbTotalSize;
    627659
    628660            /* Meta data size always is cbData, meaning there cannot be an
    629661             * extended data chunk transfer by sending further data. */
    630             cbMeta  = cbData;
     662            cbMetaAnnounced  = cbData;
    631663        }
    632664        else
     
    637669            /* Note: Data sizes get initialized in i_onReceiveDataHdr().
    638670             *       So just use the set values here. */
    639             cbTotal = pCtx->getTotal();
    640             cbMeta  = pCtx->Meta.cbData;
    641         }
    642 
    643         if (   cbData == 0
    644             || cbData > cbTotal /* Paranoia */)
    645         {
    646             LogFlowFunc(("Incoming data size invalid: cbData=%zu, cbToProcess=%zu\n", cbData, cbTotal));
     671            cbTotalAnnounced = pCtx->getTotalAnnounced();
     672            cbMetaAnnounced  = pCtx->Meta.cbAnnounced;
     673        }
     674
     675        if (cbData > cbTotalAnnounced)
     676        {
     677            AssertMsgFailed(("Incoming data size invalid: cbData=%zu, cbTotal=%zu\n", cbData, cbTotalAnnounced));
    647678            rc = VERR_INVALID_PARAMETER;
    648679        }
    649         else if (   cbTotal == 0
    650                  || cbTotal  < cbMeta)
    651         {
    652             AssertMsgFailed(("cbTotal (%zu) is smaller than cbMeta (%zu)\n", cbTotal, cbMeta));
     680        else if (   cbTotalAnnounced == 0
     681                 || cbTotalAnnounced  < cbMetaAnnounced)
     682        {
     683            AssertMsgFailed(("cbTotal (%zu) is smaller than cbMeta (%zu)\n", cbTotalAnnounced, cbMetaAnnounced));
    653684            rc = VERR_INVALID_PARAMETER;
    654685        }
     
    659690        AssertReturn(cbData <= mData.mcbBlockSize, VERR_BUFFER_OVERFLOW);
    660691
    661         cbMeta = pCtx->Meta.add(pvData, cbData);
    662         AssertReturn(cbMeta <= pCtx->Meta.cbData, VERR_BUFFER_OVERFLOW);
    663 
    664         LogFlowThisFunc(("cbData=%zu, cbMeta=%zu, cbTotal=%zu\n", cbData, cbMeta, cbTotal));
     692        const size_t cbMetaRecv = pCtx->Meta.add(pvData, cbData);
     693        AssertReturn(cbMetaRecv <= pCtx->Meta.cbData, VERR_BUFFER_OVERFLOW);
     694
     695        LogFlowThisFunc(("cbData=%zu, cbMetaRecv=%zu, cbMetaAnnounced=%zu, cbTotalAnnounced=%zu\n",
     696                         cbData, cbMetaRecv, cbMetaAnnounced, cbTotalAnnounced));
     697
     698        LogRel2(("DnD: %RU8%% of meta data complete (%zu/%zu bytes)\n",
     699                 (uint8_t)(cbMetaRecv * 100 / RT_MAX(cbMetaAnnounced, 1)), cbMetaRecv, cbMetaAnnounced));
    665700
    666701        /*
    667702         * (Meta) Data transfer complete?
    668703         */
    669         if (cbMeta == pCtx->Meta.cbData)
     704        if (cbMetaAnnounced == cbMetaRecv)
    670705        {
    671706            LogRel2(("DnD: Receiving meta data complete\n"));
     
    673708            if (DnDMIMENeedsDropDir(pCtx->strFmtRecv.c_str(), pCtx->strFmtRecv.length()))
    674709            {
    675                 LogRel2(("DnD: Building root entry list from meta data ...\n"));
    676 
    677710                rc = DnDTransferListInitEx(&pTransfer->List,
    678                                            DnDDroppedFilesGetDirAbs(&pCtx->Transfer.DroppedFiles));
     711                                           DnDDroppedFilesGetDirAbs(&pTransfer->DroppedFiles), DNDTRANSFERLISTFMT_NATIVE);
    679712                if (RT_SUCCESS(rc))
    680713                    rc = DnDTransferListAppendRootsFromBuffer(&pTransfer->List, DNDTRANSFERLISTFMT_URI,
     
    685718                {
    686719                    uint64_t cRoots = DnDTransferListGetRootCount(&pTransfer->List);
     720
     721                    LogRel2(("DnD: Received %RU64 root entries from guest\n", cRoots));
     722
    687723                    if (   cRoots == 0
    688724                        || cRoots > pTransfer->cObjToProcess)
     725                    {
     726                        LogRel(("DnD: Number of root entries invalid / mismatch: Got %RU64, expected %RU64\n",
     727                                cRoots, pTransfer->cObjToProcess));
    689728                        rc = VERR_INVALID_PARAMETER;
     729                    }
    690730                }
    691731
     
    693733                {
    694734                    /* Update our process with the data we already received. */
    695                     rc = updateProgress(pCtx, pCtx->pResp, cbMeta);
     735                    rc = updateProgress(pCtx, pCtx->pResp, cbMetaAnnounced);
    696736                    AssertRC(rc);
    697737                }
     
    727767    LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", pszPath, cbPath, fMode));
    728768
    729     AssertMsgReturn(pCtx->isComplete() == false,
    730                     ("Data transfer already complete, bailing out\n"), VERR_INVALID_PARAMETER);
    731 
    732769    const PDNDTRANSFEROBJECT pObj = &pCtx->Transfer.ObjCur;
    733770    const PDNDDROPPEDFILES   pDF  = &pCtx->Transfer.DroppedFiles;
     
    753790            DnDTransferObjectDestroy(pObj);
    754791
    755             if (RT_SUCCESS(rc))
     792            if (RT_FAILURE(rc))
    756793                LogRel2(("DnD: Created guest directory '%s' on host\n", pcszPathAbs));
    757794        }
     
    937974    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    938975
    939     GuestDnD *pInst = GUESTDNDINST();
    940     if (!pInst)
    941         return VERR_INVALID_POINTER;
    942 
    943     GuestDnDResponse *pResp = pCtx->pResp;
    944     AssertPtr(pCtx->pResp);
    945 
    946     int rc = pCtx->EventCallback.Reset();
    947     if (RT_FAILURE(rc))
    948         return rc;
    949 
    950     /* Is this context already in receiving state? */
    951     if (ASMAtomicReadBool(&pCtx->fIsActive))
    952         return VERR_WRONG_ORDER;
    953     ASMAtomicWriteBool(&pCtx->fIsActive, true);
    954 
    955     /*
    956      * Reset any old data.
    957      */
    958     pCtx->reset();
    959     pCtx->Transfer.reset();
    960     pResp->reset();
     976    /* Sanity. */
     977    AssertMsgReturn(pCtx->enmAction,
     978                    ("Action to perform is none when it shouldn't\n"), VERR_INVALID_PARAMETER);
     979    AssertMsgReturn(pCtx->strFmtReq.isNotEmpty(),
     980                    ("Requested format from host is empty when it shouldn't\n"), VERR_INVALID_PARAMETER);
    961981
    962982    /*
     
    9961016    }
    9971017
     1018    int rc = VINF_SUCCESS;
     1019
    9981020    if (fFoundFormat)
    9991021    {
    1000         Assert(!pCtx->strFmtReq.isEmpty());
    1001         Assert(!pCtx->strFmtRecv.isEmpty());
    1002 
    10031022        if (!pCtx->strFmtRecv.equals(pCtx->strFmtReq))
    10041023            LogRel2(("DnD: Requested data in format '%s', receiving in intermediate format '%s' now\n",
     
    10241043        for (size_t i = 0; i < pCtx->lstFmtOffered.size(); i++)
    10251044            LogRel(("DnD:\tFormat #%zu: %s\n", i, pCtx->lstFmtOffered.at(i).c_str()));
    1026     }
    1027 
    1028     ASMAtomicWriteBool(&pCtx->fIsActive, false);
     1045
     1046        rc = VERR_NOT_SUPPORTED;
     1047    }
     1048
     1049    if (RT_FAILURE(rc))
     1050    {
     1051        LogRel(("DnD: Receiving data from guest failed with %Rrc\n", rc));
     1052
     1053        /* Reset state. */
     1054        i_reset();
     1055    }
    10291056
    10301057    LogFlowFuncLeaveRC(rc);
     
    10321059}
    10331060
    1034 /* static */
    1035 void GuestDnDSource::i_receiveDataThreadTask(GuestDnDRecvDataTask *pTask)
    1036 {
    1037     LogFlowFunc(("pTask=%p\n", pTask));
    1038     AssertPtrReturnVoid(pTask);
    1039 
    1040     const ComObjPtr<GuestDnDSource> pThis(pTask->getSource());
    1041     Assert(!pThis.isNull());
    1042 
    1043     AutoCaller autoCaller(pThis);
    1044     if (FAILED(autoCaller.rc()))
    1045         return;
    1046 
    1047     int vrc = pThis->i_receiveData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
    1048     if (RT_FAILURE(vrc)) /* In case we missed some error handling within i_receiveData(). */
    1049     {
    1050         AssertFailed();
    1051         LogRel(("DnD: Receiving data from guest failed with %Rrc\n", vrc));
    1052     }
    1053 
    1054     AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
    1055 
    1056     Assert(pThis->m_DataBase.cTransfersPending);
    1057     if (pThis->m_DataBase.cTransfersPending)
    1058         pThis->m_DataBase.cTransfersPending--;
    1059 
    1060     LogFlowFunc(("pSource=%p, vrc=%Rrc (ignored)\n", (GuestDnDSource *)pThis, vrc));
    1061 }
    1062 
    10631061int GuestDnDSource::i_receiveRawData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout)
    10641062{
     
    10721070    AssertPtr(pCtx->pResp);
    10731071
    1074     GuestDnD *pInst = GUESTDNDINST();
     1072    GuestDnD *pInst = GuestDnDInst();
    10751073    if (!pInst)
    10761074        return VERR_INVALID_POINTER;
     
    11771175    AssertPtr(pCtx->pResp);
    11781176
    1179     GuestDnD *pInst = GUESTDNDINST();
     1177    GuestDnD *pInst = GuestDnDInst();
    11801178    if (!pInst)
    11811179        return VERR_INVALID_POINTER;
  • trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp

    r85451 r85537  
    6262    int getRC(void) const { return mRC; }
    6363    bool isOk(void) const { return RT_SUCCESS(mRC); }
    64     const ComObjPtr<GuestDnDTarget> &getTarget(void) const { return mTarget; }
    6564
    6665protected:
     
    8786    void handler()
    8887    {
    89         GuestDnDTarget::i_sendDataThreadTask(this);
    90     }
    91 
    92     virtual ~GuestDnDSendDataTask(void)
    93     {
    94         if (mpCtx)
    95         {
    96             delete mpCtx;
    97             mpCtx = NULL;
    98         }
    99     }
    100 
    101 
    102     GuestDnDSendCtx *getCtx(void) { return mpCtx; }
     88        const ComObjPtr<GuestDnDTarget> pThis(mTarget);
     89        Assert(!pThis.isNull());
     90
     91        AutoCaller autoCaller(pThis);
     92        if (FAILED(autoCaller.rc()))
     93            return;
     94
     95        int vrc = pThis->i_sendData(mpCtx, RT_INDEFINITE_WAIT /* msTimeout */);
     96        if (RT_FAILURE(vrc)) /* In case we missed some error handling within i_sendData(). */
     97        {
     98            if (vrc != VERR_CANCELLED)
     99                LogRel(("DnD: Sending data to guest failed with %Rrc\n", vrc));
     100
     101            /* Make sure to fire a cancel request to the guest side in case something went wrong. */
     102            pThis->sendCancel();
     103        }
     104    }
     105
     106    virtual ~GuestDnDSendDataTask(void) { }
    103107
    104108protected:
     
    295299
    296300    LogRel2(("DnD: Offered formats to guest:\n"));
    297     RTCList<RTCString> lstFormats = strFormats.split("\r\n");
     301    RTCList<RTCString> lstFormats = strFormats.split(DND_PATH_SEPARATOR);
    298302    for (size_t i = 0; i < lstFormats.size(); i++)
    299303        LogRel2(("DnD: \t%s\n", lstFormats[i].c_str()));
     
    307311
    308312    /* Adjust the coordinates in a multi-monitor setup. */
    309     int rc = GUESTDNDINST()->adjustScreenCoordinates(aScreenId, &aX, &aY);
     313    int rc = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY);
    310314    if (RT_SUCCESS(rc))
    311315    {
     
    322326        Msg.setNextUInt32(cbFormats);
    323327
    324         rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     328        rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    325329        if (RT_SUCCESS(rc))
    326330        {
    327             GuestDnDResponse *pResp = GUESTDNDINST()->response();
     331            GuestDnDResponse *pResp = GuestDnDInst()->response();
    328332            if (pResp && RT_SUCCESS(pResp->waitForGuestResponse()))
    329333                resAction = GuestDnD::toMainAction(pResp->getActionDefault());
     
    385389    HRESULT hr = S_OK;
    386390
    387     int rc = GUESTDNDINST()->adjustScreenCoordinates(aScreenId, &aX, &aY);
     391    int rc = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY);
    388392    if (RT_SUCCESS(rc))
    389393    {
     
    400404        Msg.setNextUInt32(cbFormats);
    401405
    402         rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     406        rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    403407        if (RT_SUCCESS(rc))
    404408        {
    405             GuestDnDResponse *pResp = GUESTDNDINST()->response();
     409            GuestDnDResponse *pResp = GuestDnDInst()->response();
    406410            if (pResp && RT_SUCCESS(pResp->waitForGuestResponse()))
    407411                resAction = GuestDnD::toMainAction(pResp->getActionDefault());
     
    440444        Msg.setNextUInt32(0); /** @todo ContextID not used yet. */
    441445
    442     int rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     446    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    443447    if (RT_SUCCESS(rc))
    444448    {
    445         GuestDnDResponse *pResp = GUESTDNDINST()->response();
     449        GuestDnDResponse *pResp = GuestDnDInst()->response();
    446450        if (pResp)
    447451            pResp->waitForGuestResponse();
     
    479483
    480484    /* Default action is ignoring. */
    481     DnDAction_T resAction    = DnDAction_Ignore;
     485    DnDAction_T resAct = DnDAction_Ignore;
     486    Utf8Str     resFmt;
    482487
    483488    /* Check & convert the drag & drop actions to HGCM codes. */
     
    507512
    508513    /* Adjust the coordinates in a multi-monitor setup. */
    509     HRESULT hr = GUESTDNDINST()->adjustScreenCoordinates(aScreenId, &aX, &aY);
     514    HRESULT hr = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY);
    510515    if (SUCCEEDED(hr))
    511516    {
     
    522527        Msg.setNextUInt32(cbFormats);
    523528
    524         int vrc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     529        int vrc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    525530        if (RT_SUCCESS(vrc))
    526531        {
    527             GuestDnDResponse *pResp = GUESTDNDINST()->response();
    528             AssertPtr(pResp);
    529 
    530             vrc = pResp->waitForGuestResponse();
    531             if (RT_SUCCESS(vrc))
     532            GuestDnDResponse *pResp = GuestDnDInst()->response();
     533            if (pResp && RT_SUCCESS(pResp->waitForGuestResponse()))
    532534            {
    533                 resAction = GuestDnD::toMainAction(pResp->getActionDefault());
     535                resAct = GuestDnD::toMainAction(pResp->getActionDefault());
    534536
    535537                GuestDnDMIMEList lstFormats = pResp->formats();
    536538                if (lstFormats.size() == 1) /* Exactly one format to use specified? */
    537539                {
    538                     aFormat = lstFormats.at(0);
    539                     LogFlowFunc(("resFormat=%s, resAction=%RU32\n", aFormat.c_str(), pResp->getActionDefault()));
     540                    resFmt = lstFormats.at(0);
    540541                }
    541542                else
     
    552553        hr = setError(hr, tr("Retrieving drop coordinates failed"));
    553554
     555    LogFlowFunc(("resFmt=%s, resAct=%RU32, vrc=%Rhrc\n", resFmt.c_str(), resAct, hr));
     556
    554557    if (SUCCEEDED(hr))
    555558    {
     559        aFormat = resFmt;
    556560        if (aResultAction)
    557             *aResultAction = resAction;
    558     }
    559 
    560     LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     561            *aResultAction = resAct;
     562    }
     563
    561564    return hr;
    562565#endif /* VBOX_WITH_DRAG_AND_DROP */
    563 }
    564 
    565 /**
    566  * Thread handler function for sending data to the guest.
    567  *
    568  * @param   pTask               Thread task this handler is associated with.
    569  */
    570 /* static */
    571 void GuestDnDTarget::i_sendDataThreadTask(GuestDnDSendDataTask *pTask)
    572 {
    573     LogFlowFunc(("pTask=%p\n", pTask));
    574     AssertPtrReturnVoid(pTask);
    575 
    576     const ComObjPtr<GuestDnDTarget> pThis(pTask->getTarget());
    577     Assert(!pThis.isNull());
    578 
    579     AutoCaller autoCaller(pThis);
    580     if (FAILED(autoCaller.rc()))
    581         return;
    582 
    583     int vrc = pThis->i_sendData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
    584     if (RT_FAILURE(vrc)) /* In case we missed some error handling within i_sendData(). */
    585     {
    586         AssertFailed();
    587         LogRel(("DnD: Sending data to guest failed with %Rrc\n", vrc));
    588     }
    589 
    590     AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
    591 
    592     Assert(pThis->m_DataBase.cTransfersPending);
    593     if (pThis->m_DataBase.cTransfersPending)
    594         pThis->m_DataBase.cTransfersPending--;
    595 
    596     LogFlowFunc(("pTarget=%p, vrc=%Rrc (ignored)\n", (GuestDnDTarget *)pThis, vrc));
    597566}
    598567
     
    626595    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    627596
     597    /* Check if this object still is in a pending state and bail out if so. */
     598    if (m_fIsPending)
     599        return setError(E_FAIL, tr("Current drop operation to guest still in progress"));
     600
     601    /* Reset our internal state. */
     602    i_reset();
     603
    628604    /* At the moment we only support one transfer at a time. */
    629     if (m_DataBase.cTransfersPending)
    630         return setError(E_INVALIDARG, tr("Another drop operation already is in progress"));
    631 
    632     /* Ditto. */
    633     GuestDnDResponse *pResp = GUESTDNDINST()->response();
     605    if (GuestDnDInst()->getTargetCount())
     606        return setError(E_INVALIDARG, tr("Another drag and drop operation to the guest already is in progress"));
     607
     608    /* Reset progress object. */
     609    GuestDnDResponse *pResp = GuestDnDInst()->response();
    634610    AssertPtr(pResp);
    635 
    636611    HRESULT hr = pResp->resetProgress(m_pGuest);
    637612    if (FAILED(hr))
    638613        return hr;
    639614
    640     GuestDnDSendDataTask *pTask    = NULL;
    641     GuestDnDSendCtx      *pSendCtx = NULL;
     615    GuestDnDSendDataTask *pTask = NULL;
    642616
    643617    try
    644618    {
    645         /* pSendCtx is passed into SendDataTask where one is deleted in destructor. */
    646         pSendCtx = new GuestDnDSendCtx();
    647         pSendCtx->pTarget   = this;
    648         pSendCtx->pResp     = pResp;
    649         pSendCtx->uScreenID = aScreenId;
    650 
    651         pSendCtx->Meta.strFmt = aFormat;
    652         pSendCtx->Meta.add(aData);
    653 
    654         /* pTask is responsible for deletion of pSendCtx after creating */
    655         pTask = new GuestDnDSendDataTask(this, pSendCtx);
     619        mData.mSendCtx.reset();
     620
     621        mData.mSendCtx.pTarget   = this;
     622        mData.mSendCtx.pResp     = pResp;
     623        mData.mSendCtx.uScreenID = aScreenId;
     624
     625        mData.mSendCtx.Meta.strFmt = aFormat;
     626        mData.mSendCtx.Meta.add(aData);
     627
     628        pTask = new GuestDnDSendDataTask(this, &mData.mSendCtx);
    656629        if (!pTask->isOk())
    657630        {
     
    660633            throw hr = E_FAIL;
    661634        }
    662 
    663         /* Drop write lock before creating thread. */
    664         alock.release();
    665635
    666636        /* This function delete pTask in case of exceptions,
     
    681651    if (SUCCEEDED(hr))
    682652    {
    683         /* Re-acquire write lock. */
    684         alock.acquire();
    685 
    686         m_DataBase.cTransfersPending++;
    687 
     653        /* Register ourselves at the DnD manager. */
     654        GuestDnDInst()->registerTarget(this);
     655
     656        /* Return progress to caller. */
    688657        hr = pResp->queryProgressTo(aProgress.asOutParam());
    689658        ComAssertComRC(hr);
    690659    }
    691660    else
    692         hr = setError(hr, tr("Starting thread for GuestDnDTarget::i_sendDataThread (%Rhrc)"), hr);
     661        hr = setError(hr, tr("Starting thread for GuestDnDTarget failed (%Rhrc)"), hr);
    693662
    694663    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     
    767736
    768737    return strError;
     738}
     739
     740void GuestDnDTarget::i_reset(void)
     741{
     742    LogFlowThisFunc(("\n"));
     743
     744    mData.mSendCtx.reset();
     745
     746    m_fIsPending = false;
     747
     748    /* Unregister ourselves from the DnD manager. */
     749    GuestDnDInst()->unregisterTarget(this);
    769750}
    770751
     
    780761    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    781762
    782     /* Is this context already in sending state? */
    783     if (ASMAtomicReadBool(&pCtx->fIsActive))
    784         return VERR_WRONG_ORDER;
    785     ASMAtomicWriteBool(&pCtx->fIsActive, true);
     763    /* Don't allow receiving the actual data until our current transfer is complete. */
     764    if (m_fIsPending)
     765        return setError(E_FAIL, tr("Current drop operation to guest still in progress"));
    786766
    787767    /* Clear all remaining outgoing messages. */
     
    810790    }
    811791
    812     ASMAtomicWriteBool(&pCtx->fIsActive, false);
     792    if (RT_FAILURE(rc))
     793        LogRel(("DnD: Sending data to guest failed with %Rrc\n", rc));
     794
     795    /* Reset state. */
     796    i_reset();
    813797
    814798    LogFlowFuncLeaveRC(rc);
     
    839823
    840824#ifdef DEBUG
    841     RTCList<RTCString> lstFilesURI = RTCString((char *)pvData, cbData).split("\r\n");
     825    RTCList<RTCString> lstFilesURI = RTCString((char *)pvData, cbData).split(DND_PATH_SEPARATOR);
    842826    LogFlowFunc(("lstFilesURI=%zu\n", lstFilesURI.size()));
    843827    for (size_t i = 0; i < lstFilesURI.size(); i++)
     
    871855        }
    872856
    873         rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     857        rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    874858        if (RT_FAILURE(rc))
    875859            break;
     
    907891
    908892    LogRel2(("DnD: Sending meta data header to guest (%RU64 bytes total data, %RU32 bytes meta data, %RU64 objects)\n",
    909              pCtx->getTotal(), pCtx->Meta.cbData, pCtx->Transfer.cObjToProcess));
     893             pCtx->getTotalAnnounced(), pCtx->Meta.cbData, pCtx->Transfer.cObjToProcess));
    910894
    911895    Msg.setNextUInt32(0);                                                /** @todo uContext; not used yet. */
    912896    Msg.setNextUInt32(0);                                                /** @todo uFlags; not used yet. */
    913897    Msg.setNextUInt32(pCtx->uScreenID);                                  /* uScreen */
    914     Msg.setNextUInt64(pCtx->getTotal());                                 /* cbTotal */
     898    Msg.setNextUInt64(pCtx->getTotalAnnounced());                        /* cbTotal */
    915899    Msg.setNextUInt32((uint32_t)pCtx->Meta.cbData);                      /* cbMeta*/
    916900    Msg.setNextPointer(unconst(pCtx->Meta.strFmt.c_str()), (uint32_t)pCtx->Meta.strFmt.length() + 1); /* pvMetaFmt */
     
    922906    Msg.setNextUInt32(0);                                                /** @todo cbChecksum; not used yet. */
    923907
    924     int rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     908    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    925909
    926910    LogFlowFuncLeaveRC(rc);
     
    13981382         * Update internal state to reflect everything we need to work with it.
    13991383         */
    1400         pCtx->cbExtra               = DnDTransferListObjTotalBytes(&pCtx->Transfer.List);
     1384        pCtx->cbExtra                = DnDTransferListObjTotalBytes(&pCtx->Transfer.List);
    14011385        /* cbExtra can be 0, if all files are of 0 bytes size. */
    14021386        pCtx->Transfer.cObjToProcess = DnDTransferListObjCount(&pCtx->Transfer.List);
     
    14311415            pCtx->Meta.cbData      = cbData;
    14321416            pCtx->Meta.cbAllocated = cbData;
     1417            pCtx->Meta.cbAnnounced = cbData;
    14331418        }
    14341419
     
    15301515    AssertRCReturn(rc, rc);
    15311516
    1532     if (pCtx->isComplete())
    1533     {
    1534         Assert(pCtx->Transfer.isComplete());
     1517    PDNDTRANSFEROBJECT pObj = DnDTransferListObjGetFirst(pList);
     1518    if (!pObj) /* Transfer complete? */
    15351519        return VINF_EOF;
    1536     }
    1537 
    1538     PDNDTRANSFEROBJECT pObj = DnDTransferListObjGetFirst(pList);
    1539     AssertPtrReturn(pObj, VERR_WRONG_ORDER);
    15401520
    15411521    switch (DnDTransferObjectGetType(pObj))
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