- Timestamp:
- Jul 30, 2020 6:55:32 AM (4 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/GuestDnDPrivate.h
r85436 r85537 89 89 : pvData(NULL) 90 90 , cbData(0) 91 , cbAllocated(0) { } 91 , cbAllocated(0) 92 , cbAnnounced(0) { } 92 93 93 94 virtual ~GuestDnDMetaData(void) … … 98 99 size_t add(const void *pvDataAdd, size_t cbDataAdd) 99 100 { 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)); 102 103 if (!cbDataAdd) 103 104 return 0; 104 105 AssertPtrReturn(pvDataAdd, 0); 105 106 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 } 109 114 110 115 Assert(cbAllocated >= cbData + cbDataAdd); … … 138 143 } 139 144 145 cbData = 0; 140 146 cbAllocated = 0; 141 cb Data= 0;147 cbAnnounced = 0; 142 148 } 143 149 … … 154 160 155 161 if (cbSize > _32M) /* Meta data can be up to 32MB. */ 156 return VERR_ INVALID_PARAMETER;162 return VERR_BUFFER_OVERFLOW; 157 163 158 164 void *pvTmp = NULL; … … 160 166 { 161 167 Assert(cbData == 0); 162 pvTmp = RTMemAllocZ( cbSize);168 pvTmp = RTMemAllocZ(RT_ALIGN_Z(cbSize, 4096)); 163 169 } 164 170 else 165 171 { 166 172 AssertPtr(pvData); 167 pvTmp = RTMemRealloc(pvData, cbSize);173 pvTmp = RTMemRealloc(pvData, RT_ALIGN_Z(cbSize, 4096)); 168 174 RT_BZERO(pvTmp, cbSize); 169 175 } … … 187 193 /** Size (in bytes) of allocated meta data. */ 188 194 size_t cbAllocated; 195 /** Size (in bytes) of announced meta data. */ 196 size_t cbAnnounced; 189 197 }; 190 198 … … 205 213 size_t addProcessed(size_t cbDataAdd) 206 214 { 207 const size_t cbTotal = Meta.cbData + cbExtra; RT_NOREF(cbTotal);215 const size_t cbTotal = getTotalAnnounced(); RT_NOREF(cbTotal); 208 216 AssertReturn(cbProcessed + cbDataAdd <= cbTotal, 0); 209 217 cbProcessed += cbDataAdd; … … 213 221 bool isComplete(void) const 214 222 { 215 const size_t cbTotal = Meta.cbData + cbExtra;223 const size_t cbTotal = getTotalAnnounced(); 216 224 LogFlowFunc(("cbProcessed=%zu, cbTotal=%zu\n", cbProcessed, cbTotal)); 217 225 AssertReturn(cbProcessed <= cbTotal, true); … … 221 229 uint8_t getPercentComplete(void) const 222 230 { 223 const size_t cbTotal = Meta.cbData + cbExtra;231 const size_t cbTotal = getTotalAnnounced(); 224 232 return (uint8_t)(cbProcessed * 100 / RT_MAX(cbTotal, 1)); 225 233 } … … 227 235 size_t getRemaining(void) const 228 236 { 229 const size_t cbTotal = Meta.cbData + cbExtra;237 const size_t cbTotal = getTotalAnnounced(); 230 238 AssertReturn(cbProcessed <= cbTotal, 0); 231 239 return cbTotal - cbProcessed; 232 240 } 233 241 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 235 248 { 236 249 return Meta.cbData + cbExtra; … … 373 386 struct GuestDnDSendCtx : public GuestDnDData 374 387 { 388 GuestDnDSendCtx(void); 389 390 void reset(void); 391 375 392 /** Pointer to guest target class this context belongs to. */ 376 393 GuestDnDTarget *pTarget; 377 394 /** Pointer to guest response class this context belongs to. */ 378 395 GuestDnDResponse *pResp; 379 /** Flag indicating whether a file transfer is active and380 * initiated by the host. */381 bool fIsActive;382 396 /** Target (VM) screen ID. */ 383 397 uint32_t uScreenID; … … 440 454 struct GuestDnDRecvCtx : public GuestDnDData 441 455 { 456 GuestDnDRecvCtx(void); 457 458 void reset(void); 459 442 460 /** Pointer to guest source class this context belongs to. */ 443 461 GuestDnDSource *pSource; 444 462 /** Pointer to guest response class this context belongs to. */ 445 463 GuestDnDResponse *pResp; 446 /** Flag indicating whether a file transfer is active and447 * initiated by the host. */448 bool fIsActive;449 464 /** Formats offered by the guest (and supported by the host). */ 450 465 GuestDnDMIMEList lstFmtOffered; … … 693 708 694 709 /** 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. 698 711 * 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. 700 714 */ 701 715 class GuestDnD … … 727 741 protected: 728 742 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. */ 729 749 GuestDnD(const ComObjPtr<Guest>& pGuest); 730 750 virtual ~GuestDnD(void); … … 738 758 GuestDnDResponse *response(void) { return m_pResponse; } 739 759 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); 740 770 /** @} */ 741 771 … … 765 795 * @{ */ 766 796 /** List of supported default MIME/Content-type formats. */ 767 GuestDnDMIMEList m_strDefaultFormats;797 GuestDnDMIMEList m_strDefaultFormats; 768 798 /** Pointer to guest implementation. */ 769 const ComObjPtr<Guest> m_pGuest;799 const ComObjPtr<Guest> m_pGuest; 770 800 /** The current (last) response from the guest. At the 771 801 * 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; 773 809 /** @} */ 774 810 775 811 private: 776 812 777 /** Sta ic pointer to singleton instance. */813 /** Static pointer to singleton instance. */ 778 814 static GuestDnD *s_pInstance; 779 815 }; 780 816 781 817 /** Access to the GuestDnD's singleton instance. */ 782 #define G UESTDNDINST() GuestDnD::getInstance()818 #define GuestDnDInst() GuestDnD::getInstance() 783 819 784 820 /** List of pointers to guest DnD Messages. */ … … 833 869 /** List of offered MIME types to the counterpart. */ 834 870 GuestDnDMIMEList m_lstFmtOffered; 871 /** Whether the object still is in pending state. */ 872 bool m_fIsPending; 835 873 /** @} */ 836 874 … … 840 878 struct 841 879 { 842 /** Number of active transfers (guest->host or host->guest). */843 uint32_t cTransfersPending;844 880 /** The DnD protocol version to use, depending on the 845 881 * installed Guest Additions. See DragAndDropSvc.h for -
trunk/src/VBox/Main/include/GuestDnDSourceImpl.h
r85402 r85537 70 70 protected: 71 71 72 void i_reset(void); 73 72 74 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 73 75 /** @name Dispatch handlers for the HGCM callbacks. … … 85 87 static Utf8Str i_guestErrorToString(int guestRc); 86 88 static Utf8Str i_hostErrorToString(int hostRc); 87 88 /** @name Thread task .89 * @{ */90 static void i_receiveDataThreadTask(GuestDnDRecvDataTask *pTask);91 /** @} */92 89 93 90 /** @name Callbacks for dispatch handler. -
trunk/src/VBox/Main/include/GuestDnDTargetImpl.h
r85423 r85537 74 74 static Utf8Str i_hostErrorToString(int hostRc); 75 75 76 /** @name Thread task workers.77 * @{ */78 static void i_sendDataThreadTask(GuestDnDSendDataTask *pTask);79 /** @} */80 81 76 /** @name Callbacks for dispatch handler. 82 77 * @{ */ … … 85 80 86 81 protected: 82 83 void i_reset(void); 87 84 88 85 int i_sendData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout); … … 104 101 struct 105 102 { 106 /** Flag indicating whether a data transfer currently is active. */107 bool mfTransferIsPending;108 103 /** 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; 110 108 } mData; 111 109 -
trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
r85357 r85537 3186 3186 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc", 3187 3187 &GuestDnD::notifyDnDDispatcher, 3188 G UESTDNDINST());3188 GuestDnDInst()); 3189 3189 if (RT_FAILURE(rc)) 3190 3190 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc)); -
trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
r85423 r85537 156 156 */ 157 157 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 187 GuestDnDSendCtx::GuestDnDSendCtx(void) 188 : pTarget(NULL) 189 , pResp(NULL) 190 { 191 reset(); 192 } 193 194 void 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 213 GuestDnDRecvCtx::GuestDnDRecvCtx(void) 214 : pSource(NULL) 215 , pResp(NULL) 216 { 217 reset(); 218 } 219 220 void 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 158 242 GuestDnDCallbackEvent::~GuestDnDCallbackEvent(void) 159 243 { … … 184 268 } 185 269 186 /////////////////////////////////////////////////////////////////////////////// 270 /******************************************************************************************************************************** 271 * 272 ********************************************************************************************************************************/ 187 273 188 274 GuestDnDResponse::GuestDnDResponse(const ComObjPtr<Guest>& pGuest) … … 523 609 } 524 610 525 /////////////////////////////////////////////////////////////////////////////// 611 /********************************************************************************************************************************* 612 * * 613 ********************************************************************************************************************************/ 526 614 527 615 GuestDnD* GuestDnD::s_pInstance = NULL; … … 529 617 GuestDnD::GuestDnD(const ComObjPtr<Guest> &pGuest) 530 618 : m_pGuest(pGuest) 619 , m_cTransfersPending(0) 531 620 { 532 621 LogFlowFuncEnter(); 533 622 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; 535 635 536 636 /* List of supported default MIME types. */ … … 547 647 { 548 648 LogFlowFuncEnter(); 649 650 Assert(m_cTransfersPending == 0); /* Sanity. */ 651 652 RTCritSectDelete(&m_CritSect); 549 653 550 654 if (m_pResponse) … … 596 700 } 597 701 702 int 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 713 int 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 725 size_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 735 int 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 746 int 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 758 size_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 598 768 /* static */ 599 769 DECLCALLBACK(int) GuestDnD::notifyDnDDispatcher(void *pvExtension, uint32_t u32Function, … … 626 796 { 627 797 GuestDnDMIMEList lstFormats; 628 RTCList<RTCString> lstFormatsTmp = strFormats.split( "\r\n");798 RTCList<RTCString> lstFormatsTmp = strFormats.split(DND_FORMATS_SEPARATOR); 629 799 630 800 for (size_t i = 0; i < lstFormatsTmp.size(); i++) … … 641 811 { 642 812 const com::Utf8Str &f = lstFormats.at(i); 643 strFormat += f + "\r\n";813 strFormat += f + DND_FORMATS_SEPARATOR; 644 814 } 645 815 … … 670 840 GuestDnDMIMEList lstFmt; 671 841 672 RTCList<RTCString> lstFormats = strFormatsWanted.split( "\r\n");842 RTCList<RTCString> lstFormats = strFormatsWanted.split(DND_FORMATS_SEPARATOR); 673 843 size_t i = 0; 674 844 while (i < lstFormats.size()) … … 775 945 } 776 946 777 /////////////////////////////////////////////////////////////////////////////// 947 /********************************************************************************************************************************* 948 * * 949 ********************************************************************************************************************************/ 778 950 779 951 GuestDnDBase::GuestDnDBase(void) 952 : m_fIsPending(false) 780 953 { 781 954 /* Initialize public attributes. */ 782 m_lstFmtSupported = G UESTDNDINST()->defaultFormats();955 m_lstFmtSupported = GuestDnDInst()->defaultFormats(); 783 956 784 957 /* Initialzie private stuff. */ 785 m_DataBase.cTransfersPending = 0;786 958 m_DataBase.uProtocolVersion = 0; 787 959 } … … 943 1115 Msg.setNextUInt32(0); /** @todo ContextID not used yet. */ 944 1116 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; 948 1124 } 949 1125 -
trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
r85451 r85537 59 59 int getRC(void) const { return mRC; } 60 60 bool isOk(void) const { return RT_SUCCESS(mRC); } 61 const ComObjPtr<GuestDnDSource> &getSource(void) const { return mSource; }62 61 63 62 protected: … … 84 83 void handler() 85 84 { 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 } 87 103 } 88 104 89 105 virtual ~GuestDnDRecvDataTask(void) { } 90 91 GuestDnDRecvCtx *getCtx(void) { return mpCtx; }92 106 93 107 protected: … … 266 280 Msg.setNextUInt32(uScreenId); 267 281 268 int rc = G UESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());282 int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 269 283 if (RT_SUCCESS(rc)) 270 284 { 271 GuestDnDResponse *pResp = G UESTDNDINST()->response();285 GuestDnDResponse *pResp = GuestDnDInst()->response(); 272 286 AssertPtr(pResp); 273 287 … … 337 351 return setError(E_INVALIDARG, tr("Specified format '%s' is not supported"), aFormat.c_str()); 338 352 353 /* Check that the given action is supported by us. */ 339 354 VBOXDNDACTION dndAction = GuestDnD::toHGCMAction(aAction); 340 355 if (isDnDIgnoreAction(dndAction)) /* If there is no usable action, ignore this request. */ … … 343 358 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 344 359 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 345 367 /* At the moment we only support one transfer at a time. */ 346 if ( m_DataBase.cTransfersPending)347 return setError(E_INVALIDARG, tr("Another dr op operationalready is in progress"));348 349 /* Dito. */350 GuestDnDResponse *pResp = G UESTDNDINST()->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(); 351 373 AssertPtr(pResp); 352 353 374 HRESULT hr = pResp->resetProgress(m_pGuest); 354 375 if (FAILED(hr)) … … 359 380 try 360 381 { 361 mData.mRecvCtx.fIsActive = false;362 382 mData.mRecvCtx.pSource = this; 363 383 mData.mRecvCtx.pResp = pResp; 384 mData.mRecvCtx.enmAction = dndAction; 364 385 mData.mRecvCtx.strFmtReq = aFormat; 365 386 mData.mRecvCtx.lstFmtOffered = m_lstFmtOffered; 366 387 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())); 368 389 369 390 pTask = new GuestDnDRecvDataTask(this, &mData.mRecvCtx); … … 371 392 { 372 393 delete pTask; 373 LogRel2(("DnD: Could not create RecvDataTask object\n"));394 LogRel2(("DnD: Receive data task failed to initialize\n")); 374 395 throw hr = E_FAIL; 375 396 } … … 395 416 if (SUCCEEDED(hr)) 396 417 { 397 /* Re-acquire write lock. */ 398 alock.acquire(); 399 400 m_DataBase.cTransfersPending++; 418 /* Register ourselves at the DnD manager. */ 419 GuestDnDInst()->registerSource(this); 401 420 402 421 hr = pResp->queryProgressTo(aProgress.asOutParam()); … … 405 424 } 406 425 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); 409 427 410 428 LogFlowFunc(("Returning hr=%Rhrc\n", hr)); … … 422 440 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 423 441 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); 427 443 428 444 /* 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")); 431 447 432 448 HRESULT hr = S_OK; … … 442 458 AssertPtr(pcszDropDirAbs); 443 459 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); 450 468 if (RT_SUCCESS(rc)) 451 469 { 470 Assert(cbBuf); 471 AssertPtr(pszBuf); 472 452 473 aData.resize(cbBuf); 453 474 memcpy(&aData.front(), pszBuf, cbBuf); … … 457 478 LogRel(("DnD: Unable to build source root list, rc=%Rrc\n", rc)); 458 479 } 459 else 480 else /* Raw data. */ 460 481 { 461 482 if (pCtx->Meta.cbData) … … 558 579 } 559 580 581 void 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 560 593 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 594 561 595 /** 562 596 * Handles receiving a send data header from the guest. … … 576 610 AssertReturn(pDataHdr->cbTotal >= pDataHdr->cbMeta, VERR_INVALID_PARAMETER); 577 611 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; 582 614 583 615 Assert(pCtx->Transfer.cObjToProcess == 0); /* Sanity. */ … … 615 647 size_t cbData; 616 648 void *pvData; 617 size_t cbTotal ;618 size_t cbMeta ;649 size_t cbTotalAnnounced; 650 size_t cbMetaAnnounced; 619 651 620 652 if (m_DataBase.uProtocolVersion < 3) … … 624 656 625 657 /* Sends the total data size to receive for every data chunk. */ 626 cbTotal = pSndData->u.v1.cbTotalSize;658 cbTotalAnnounced = pSndData->u.v1.cbTotalSize; 627 659 628 660 /* Meta data size always is cbData, meaning there cannot be an 629 661 * extended data chunk transfer by sending further data. */ 630 cbMeta = cbData;662 cbMetaAnnounced = cbData; 631 663 } 632 664 else … … 637 669 /* Note: Data sizes get initialized in i_onReceiveDataHdr(). 638 670 * 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)); 647 678 rc = VERR_INVALID_PARAMETER; 648 679 } 649 else if ( cbTotal == 0650 || 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)); 653 684 rc = VERR_INVALID_PARAMETER; 654 685 } … … 659 690 AssertReturn(cbData <= mData.mcbBlockSize, VERR_BUFFER_OVERFLOW); 660 691 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)); 665 700 666 701 /* 667 702 * (Meta) Data transfer complete? 668 703 */ 669 if (cbMeta == pCtx->Meta.cbData)704 if (cbMetaAnnounced == cbMetaRecv) 670 705 { 671 706 LogRel2(("DnD: Receiving meta data complete\n")); … … 673 708 if (DnDMIMENeedsDropDir(pCtx->strFmtRecv.c_str(), pCtx->strFmtRecv.length())) 674 709 { 675 LogRel2(("DnD: Building root entry list from meta data ...\n"));676 677 710 rc = DnDTransferListInitEx(&pTransfer->List, 678 DnDDroppedFilesGetDirAbs(&p Ctx->Transfer.DroppedFiles));711 DnDDroppedFilesGetDirAbs(&pTransfer->DroppedFiles), DNDTRANSFERLISTFMT_NATIVE); 679 712 if (RT_SUCCESS(rc)) 680 713 rc = DnDTransferListAppendRootsFromBuffer(&pTransfer->List, DNDTRANSFERLISTFMT_URI, … … 685 718 { 686 719 uint64_t cRoots = DnDTransferListGetRootCount(&pTransfer->List); 720 721 LogRel2(("DnD: Received %RU64 root entries from guest\n", cRoots)); 722 687 723 if ( cRoots == 0 688 724 || cRoots > pTransfer->cObjToProcess) 725 { 726 LogRel(("DnD: Number of root entries invalid / mismatch: Got %RU64, expected %RU64\n", 727 cRoots, pTransfer->cObjToProcess)); 689 728 rc = VERR_INVALID_PARAMETER; 729 } 690 730 } 691 731 … … 693 733 { 694 734 /* Update our process with the data we already received. */ 695 rc = updateProgress(pCtx, pCtx->pResp, cbMeta );735 rc = updateProgress(pCtx, pCtx->pResp, cbMetaAnnounced); 696 736 AssertRC(rc); 697 737 } … … 727 767 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", pszPath, cbPath, fMode)); 728 768 729 AssertMsgReturn(pCtx->isComplete() == false,730 ("Data transfer already complete, bailing out\n"), VERR_INVALID_PARAMETER);731 732 769 const PDNDTRANSFEROBJECT pObj = &pCtx->Transfer.ObjCur; 733 770 const PDNDDROPPEDFILES pDF = &pCtx->Transfer.DroppedFiles; … … 753 790 DnDTransferObjectDestroy(pObj); 754 791 755 if (RT_ SUCCESS(rc))792 if (RT_FAILURE(rc)) 756 793 LogRel2(("DnD: Created guest directory '%s' on host\n", pcszPathAbs)); 757 794 } … … 937 974 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 938 975 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); 961 981 962 982 /* … … 996 1016 } 997 1017 1018 int rc = VINF_SUCCESS; 1019 998 1020 if (fFoundFormat) 999 1021 { 1000 Assert(!pCtx->strFmtReq.isEmpty());1001 Assert(!pCtx->strFmtRecv.isEmpty());1002 1003 1022 if (!pCtx->strFmtRecv.equals(pCtx->strFmtReq)) 1004 1023 LogRel2(("DnD: Requested data in format '%s', receiving in intermediate format '%s' now\n", … … 1024 1043 for (size_t i = 0; i < pCtx->lstFmtOffered.size(); i++) 1025 1044 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 } 1029 1056 1030 1057 LogFlowFuncLeaveRC(rc); … … 1032 1059 } 1033 1060 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 1063 1061 int GuestDnDSource::i_receiveRawData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout) 1064 1062 { … … 1072 1070 AssertPtr(pCtx->pResp); 1073 1071 1074 GuestDnD *pInst = G UESTDNDINST();1072 GuestDnD *pInst = GuestDnDInst(); 1075 1073 if (!pInst) 1076 1074 return VERR_INVALID_POINTER; … … 1177 1175 AssertPtr(pCtx->pResp); 1178 1176 1179 GuestDnD *pInst = G UESTDNDINST();1177 GuestDnD *pInst = GuestDnDInst(); 1180 1178 if (!pInst) 1181 1179 return VERR_INVALID_POINTER; -
trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp
r85451 r85537 62 62 int getRC(void) const { return mRC; } 63 63 bool isOk(void) const { return RT_SUCCESS(mRC); } 64 const ComObjPtr<GuestDnDTarget> &getTarget(void) const { return mTarget; }65 64 66 65 protected: … … 87 86 void handler() 88 87 { 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) { } 103 107 104 108 protected: … … 295 299 296 300 LogRel2(("DnD: Offered formats to guest:\n")); 297 RTCList<RTCString> lstFormats = strFormats.split( "\r\n");301 RTCList<RTCString> lstFormats = strFormats.split(DND_PATH_SEPARATOR); 298 302 for (size_t i = 0; i < lstFormats.size(); i++) 299 303 LogRel2(("DnD: \t%s\n", lstFormats[i].c_str())); … … 307 311 308 312 /* Adjust the coordinates in a multi-monitor setup. */ 309 int rc = G UESTDNDINST()->adjustScreenCoordinates(aScreenId, &aX, &aY);313 int rc = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY); 310 314 if (RT_SUCCESS(rc)) 311 315 { … … 322 326 Msg.setNextUInt32(cbFormats); 323 327 324 rc = G UESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());328 rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 325 329 if (RT_SUCCESS(rc)) 326 330 { 327 GuestDnDResponse *pResp = G UESTDNDINST()->response();331 GuestDnDResponse *pResp = GuestDnDInst()->response(); 328 332 if (pResp && RT_SUCCESS(pResp->waitForGuestResponse())) 329 333 resAction = GuestDnD::toMainAction(pResp->getActionDefault()); … … 385 389 HRESULT hr = S_OK; 386 390 387 int rc = G UESTDNDINST()->adjustScreenCoordinates(aScreenId, &aX, &aY);391 int rc = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY); 388 392 if (RT_SUCCESS(rc)) 389 393 { … … 400 404 Msg.setNextUInt32(cbFormats); 401 405 402 rc = G UESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());406 rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 403 407 if (RT_SUCCESS(rc)) 404 408 { 405 GuestDnDResponse *pResp = G UESTDNDINST()->response();409 GuestDnDResponse *pResp = GuestDnDInst()->response(); 406 410 if (pResp && RT_SUCCESS(pResp->waitForGuestResponse())) 407 411 resAction = GuestDnD::toMainAction(pResp->getActionDefault()); … … 440 444 Msg.setNextUInt32(0); /** @todo ContextID not used yet. */ 441 445 442 int rc = G UESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());446 int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 443 447 if (RT_SUCCESS(rc)) 444 448 { 445 GuestDnDResponse *pResp = G UESTDNDINST()->response();449 GuestDnDResponse *pResp = GuestDnDInst()->response(); 446 450 if (pResp) 447 451 pResp->waitForGuestResponse(); … … 479 483 480 484 /* Default action is ignoring. */ 481 DnDAction_T resAction = DnDAction_Ignore; 485 DnDAction_T resAct = DnDAction_Ignore; 486 Utf8Str resFmt; 482 487 483 488 /* Check & convert the drag & drop actions to HGCM codes. */ … … 507 512 508 513 /* Adjust the coordinates in a multi-monitor setup. */ 509 HRESULT hr = G UESTDNDINST()->adjustScreenCoordinates(aScreenId, &aX, &aY);514 HRESULT hr = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY); 510 515 if (SUCCEEDED(hr)) 511 516 { … … 522 527 Msg.setNextUInt32(cbFormats); 523 528 524 int vrc = G UESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());529 int vrc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 525 530 if (RT_SUCCESS(vrc)) 526 531 { 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())) 532 534 { 533 resAct ion= GuestDnD::toMainAction(pResp->getActionDefault());535 resAct = GuestDnD::toMainAction(pResp->getActionDefault()); 534 536 535 537 GuestDnDMIMEList lstFormats = pResp->formats(); 536 538 if (lstFormats.size() == 1) /* Exactly one format to use specified? */ 537 539 { 538 aFormat = lstFormats.at(0); 539 LogFlowFunc(("resFormat=%s, resAction=%RU32\n", aFormat.c_str(), pResp->getActionDefault())); 540 resFmt = lstFormats.at(0); 540 541 } 541 542 else … … 552 553 hr = setError(hr, tr("Retrieving drop coordinates failed")); 553 554 555 LogFlowFunc(("resFmt=%s, resAct=%RU32, vrc=%Rhrc\n", resFmt.c_str(), resAct, hr)); 556 554 557 if (SUCCEEDED(hr)) 555 558 { 559 aFormat = resFmt; 556 560 if (aResultAction) 557 *aResultAction = resAction; 558 } 559 560 LogFlowFunc(("Returning hr=%Rhrc\n", hr)); 561 *aResultAction = resAct; 562 } 563 561 564 return hr; 562 565 #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));597 566 } 598 567 … … 626 595 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 627 596 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 628 604 /* At the moment we only support one transfer at a time. */ 629 if ( m_DataBase.cTransfersPending)630 return setError(E_INVALIDARG, tr("Another dr op operationalready is in progress"));631 632 /* Ditto. */633 GuestDnDResponse *pResp = G UESTDNDINST()->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(); 634 610 AssertPtr(pResp); 635 636 611 HRESULT hr = pResp->resetProgress(m_pGuest); 637 612 if (FAILED(hr)) 638 613 return hr; 639 614 640 GuestDnDSendDataTask *pTask = NULL; 641 GuestDnDSendCtx *pSendCtx = NULL; 615 GuestDnDSendDataTask *pTask = NULL; 642 616 643 617 try 644 618 { 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); 656 629 if (!pTask->isOk()) 657 630 { … … 660 633 throw hr = E_FAIL; 661 634 } 662 663 /* Drop write lock before creating thread. */664 alock.release();665 635 666 636 /* This function delete pTask in case of exceptions, … … 681 651 if (SUCCEEDED(hr)) 682 652 { 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. */ 688 657 hr = pResp->queryProgressTo(aProgress.asOutParam()); 689 658 ComAssertComRC(hr); 690 659 } 691 660 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); 693 662 694 663 LogFlowFunc(("Returning hr=%Rhrc\n", hr)); … … 767 736 768 737 return strError; 738 } 739 740 void 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); 769 750 } 770 751 … … 780 761 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 781 762 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")); 786 766 787 767 /* Clear all remaining outgoing messages. */ … … 810 790 } 811 791 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(); 813 797 814 798 LogFlowFuncLeaveRC(rc); … … 839 823 840 824 #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); 842 826 LogFlowFunc(("lstFilesURI=%zu\n", lstFilesURI.size())); 843 827 for (size_t i = 0; i < lstFilesURI.size(); i++) … … 871 855 } 872 856 873 rc = G UESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());857 rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 874 858 if (RT_FAILURE(rc)) 875 859 break; … … 907 891 908 892 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)); 910 894 911 895 Msg.setNextUInt32(0); /** @todo uContext; not used yet. */ 912 896 Msg.setNextUInt32(0); /** @todo uFlags; not used yet. */ 913 897 Msg.setNextUInt32(pCtx->uScreenID); /* uScreen */ 914 Msg.setNextUInt64(pCtx->getTotal ());/* cbTotal */898 Msg.setNextUInt64(pCtx->getTotalAnnounced()); /* cbTotal */ 915 899 Msg.setNextUInt32((uint32_t)pCtx->Meta.cbData); /* cbMeta*/ 916 900 Msg.setNextPointer(unconst(pCtx->Meta.strFmt.c_str()), (uint32_t)pCtx->Meta.strFmt.length() + 1); /* pvMetaFmt */ … … 922 906 Msg.setNextUInt32(0); /** @todo cbChecksum; not used yet. */ 923 907 924 int rc = G UESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());908 int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 925 909 926 910 LogFlowFuncLeaveRC(rc); … … 1398 1382 * Update internal state to reflect everything we need to work with it. 1399 1383 */ 1400 pCtx->cbExtra = DnDTransferListObjTotalBytes(&pCtx->Transfer.List);1384 pCtx->cbExtra = DnDTransferListObjTotalBytes(&pCtx->Transfer.List); 1401 1385 /* cbExtra can be 0, if all files are of 0 bytes size. */ 1402 1386 pCtx->Transfer.cObjToProcess = DnDTransferListObjCount(&pCtx->Transfer.List); … … 1431 1415 pCtx->Meta.cbData = cbData; 1432 1416 pCtx->Meta.cbAllocated = cbData; 1417 pCtx->Meta.cbAnnounced = cbData; 1433 1418 } 1434 1419 … … 1530 1515 AssertRCReturn(rc, rc); 1531 1516 1532 if (pCtx->isComplete()) 1533 { 1534 Assert(pCtx->Transfer.isComplete()); 1517 PDNDTRANSFEROBJECT pObj = DnDTransferListObjGetFirst(pList); 1518 if (!pObj) /* Transfer complete? */ 1535 1519 return VINF_EOF; 1536 }1537 1538 PDNDTRANSFEROBJECT pObj = DnDTransferListObjGetFirst(pList);1539 AssertPtrReturn(pObj, VERR_WRONG_ORDER);1540 1520 1541 1521 switch (DnDTransferObjectGetType(pObj))
Note:
See TracChangeset
for help on using the changeset viewer.