Changeset 97788 in vbox
- Timestamp:
- Dec 12, 2022 6:36:50 PM (2 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/DragAndDrop/VBoxDragAndDropSvc.cpp
r97763 r97788 285 285 286 286 /* 287 * Reset the message queue as soon as a new client s connect287 * Reset the message queue as soon as a new client connects 288 288 * to ensure that every client has the same state. 289 289 */ 290 290 if (m_pManager) 291 m_pManager->Reset( );291 m_pManager->Reset(true /* fForce */); 292 292 293 293 LogFlowFunc(("Client %RU32 connected (VINF_SUCCESS)\n", idClient)); … … 574 574 if (cParms == 3) 575 575 { 576 rc = m_pManager->GetNextMsgInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */); 576 /* Make sure to increase the reference count so that the next message doesn't get removed between 577 * the guest's GUEST_DND_FN_GET_NEXT_HOST_MSG call and the actual message retrieval call. */ 578 rc = m_pManager->GetNextMsgInfo(true /* fAddRef */, 579 &paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */); 577 580 if (RT_FAILURE(rc)) /* No queued messages available? */ 578 581 { … … 589 592 /* Note: paParms[2] was set by the guest as blocking flag. */ 590 593 } 594 595 LogFlowFunc(("Host callback returned %Rrc\n", rc)); 591 596 } 592 597 else /* No host callback in place, so drag and drop is not supported by the host. */ … … 1001 1006 data.paParms = paParms; 1002 1007 1003 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, 1004 &data, sizeof(data)); 1008 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data)); 1005 1009 if (RT_SUCCESS(rc)) 1006 1010 { … … 1010 1014 else 1011 1015 { 1012 /* 1013 * In case the guest is too fast asking for the next message 1014 * and the host did not supply it yet, just defer the client's 1015 * return until a response from the host available. 1016 */ 1017 LogFlowFunc(("No new messages from the host (yet), deferring request: %Rrc\n", rc)); 1018 rc = VINF_HGCM_ASYNC_EXECUTE; 1016 if (rc == VERR_CANCELLED) 1017 { 1018 /* Host indicated that the current operation was cancelled. Tell the guest. */ 1019 LogFunc(("Host indicated that operation was cancelled\n", rc)); 1020 } 1021 else 1022 { 1023 /* 1024 * In case the guest is too fast asking for the next message 1025 * and the host did not supply it yet, just defer the client's 1026 * return until a response from the host available. 1027 */ 1028 LogFunc(("No new messages from the host (%Rrc), deferring request\n", rc)); 1029 rc = VINF_HGCM_ASYNC_EXECUTE; 1030 } 1019 1031 } 1020 1032 } … … 1036 1048 if (rc == VINF_HGCM_ASYNC_EXECUTE) 1037 1049 { 1038 LogF lowFunc(("Deferring client %RU32\n", idClient));1050 LogFunc(("Deferring client %RU32\n", idClient)); 1039 1051 1040 1052 try … … 1061 1073 } 1062 1074 1063 LogF lowFunc(("Returning rc=%Rrc\n", rc));1075 LogFunc(("Returning %Rrc to guest\n", rc)); 1064 1076 } 1065 1077 … … 1170 1182 LogFlowFunc(("Cancelling all waiting clients ...\n")); 1171 1183 1172 /* Reset the message queue as the host cancelled the whole operation. */ 1173 m_pManager->Reset(); 1174 1175 rc = m_pManager->AddMsg(u32Function, cParms, paParms, true /* fAppend */); 1176 if (RT_FAILURE(rc)) 1177 { 1178 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n", u32Function, rc)); 1179 break; 1180 } 1184 /* Forcefully reset the message queue, as the host has cancelled the current operation. */ 1185 m_pManager->Reset(true /* fForce */); 1181 1186 1182 1187 /* … … 1196 1201 /* Protocol v3+ also contains the context ID. */ 1197 1202 pClient->uProtocolVerDeprecated >= 3 ? 1 : 0); 1198 pClient->CompleteDeferred(rc2); 1203 AssertRC(rc2); 1204 1205 /* Return VERR_CANCELLED when waking up the guest side. */ 1206 pClient->CompleteDeferred(VERR_CANCELLED); 1199 1207 1200 1208 m_clientQueue.erase(itQueue); … … 1212 1220 { 1213 1221 /* Reset the message queue as a new DnD operation just began. */ 1214 m_pManager->Reset( );1222 m_pManager->Reset(false /* fForce */); 1215 1223 1216 1224 fSendToGuest = true; … … 1272 1280 uint32_t uMsgNext = 0; 1273 1281 uint32_t cParmsNext = 0; 1274 int rcNext = m_pManager->GetNextMsgInfo(&uMsgNext, &cParmsNext); 1282 /* Note: We only want to peek for the next message, hence fAddRef is false. */ 1283 int rcNext = m_pManager->GetNextMsgInfo(false /* fAddRef */, &uMsgNext, &cParmsNext); 1275 1284 1276 1285 LogFlowFunc(("uMsgClient=%s (%#x), uMsgNext=%s (%#x), cParmsNext=%RU32, rcNext=%Rrc\n", -
trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp
r97747 r97788 112 112 if (i > 0) 113 113 Log((" - ")); 114 uint32_t const uType = m_queueMsg[i]->GetType(); 115 Log(("%s (%d / %#x)", DnDHostMsgToStr(uType), uType, uType)); 114 DnDMessage const *pMsg = m_queueMsg[i]; 115 uint32_t const uType = pMsg->GetType(); 116 Log(("%s (%d / %#x) cRefS=%RU32", DnDHostMsgToStr(uType), uType, uType, pMsg->RefCount())); 116 117 } 117 118 Log(("\n")); … … 123 124 * 124 125 * @returns IPRT status code. VERR_NO_DATA if no next message is available. 126 * @param fAddRef Set to \c true to increase the message's reference count, or \c false if not. 125 127 * @param puType Where to store the message type. 126 128 * @param pcParms Where to store the message parameter count. 127 129 */ 128 int DnDManager::GetNextMsgInfo( uint32_t *puType, uint32_t *pcParms)130 int DnDManager::GetNextMsgInfo(bool fAddRef, uint32_t *puType, uint32_t *pcParms) 129 131 { 130 132 AssertPtrReturn(puType, VERR_INVALID_POINTER); … … 133 135 int rc; 134 136 135 #ifdef DEBUG136 DumpQueue();137 #endif138 139 137 if (m_queueMsg.isEmpty()) 140 138 { … … 149 147 *pcParms = pMsg->GetParamCount(); 150 148 149 if (fAddRef) 150 pMsg->AddRef(); 151 151 152 rc = VINF_SUCCESS; 152 153 } 153 154 154 LogFlowFunc(("Returning uMsg=%s (%#x), cParms=%RU32, rc=%Rrc\n", DnDHostMsgToStr(*puType), *puType, *pcParms, rc)); 155 #ifdef DEBUG 156 DumpQueue(); 157 #endif 158 159 LogFlowFunc(("Returning uMsg=%s (%#x), cParms=%RU32, fAddRef=%RTbool, rc=%Rrc\n", 160 DnDHostMsgToStr(*puType), *puType, *pcParms, fAddRef, rc)); 155 161 return rc; 156 162 } … … 158 164 /** 159 165 * Retrieves the next queued up message and removes it from the queue on success. 160 * Will return VERR_NO_DATA if no next message is available.161 * 162 * @ret urns IPRT status code.166 * 167 * @returns VBox status code. 168 * @retval VERR_NO_DATA if no next message is available. 163 169 * @param uMsg Message type to retrieve. 164 170 * @param cParms Number of parameters the \@a paParms array can store. … … 173 179 return VERR_NO_DATA; 174 180 181 #ifdef DEBUG 182 DumpQueue(); 183 #endif 184 175 185 /* Get the current message. */ 176 186 DnDMessage *pMsg = m_queueMsg.first(); 177 187 AssertPtr(pMsg); 178 188 179 m_queueMsg.removeFirst(); /* Remove the current message from the queue. */ 189 if (pMsg->Release() == 0) /* Not referenced by any client anymore? */ 190 m_queueMsg.removeFirst(); /* Remove the current message from the queue. */ 180 191 181 192 /* Fetch the current message info. */ … … 184 195 /* 185 196 * If there was an error handling the current message or the user has canceled 186 * the operation, we need to cleanup all pending events and inform the progress 187 * callback about our exit. 197 * the operation, we need to cleanup all pending events. 188 198 */ 189 199 if (RT_FAILURE(rc)) 190 200 { 191 201 /* Clear any pending messages. */ 192 Reset(); 193 194 /* Create a new cancel message to inform the guest + call 195 * the host whether the current transfer was canceled or aborted 196 * due to an error. */ 197 try 198 { 199 if (rc == VERR_CANCELLED) 200 LogFlowFunc(("Operation was cancelled\n")); 201 202 DnDHGCancelMessage *pMsgCancel = new DnDHGCancelMessage(); 203 204 int rc2 = AddMsg(pMsgCancel, false /* Prepend */); 205 AssertRC(rc2); 206 207 if (m_pfnProgressCallback) 208 { 209 LogFlowFunc(("Notifying host about aborting operation (%Rrc) ...\n", rc)); 210 m_pfnProgressCallback( rc == VERR_CANCELLED 211 ? DragAndDropSvc::DND_PROGRESS_CANCELLED 212 : DragAndDropSvc::DND_PROGRESS_ERROR, 213 100 /* Percent */, rc, 214 m_pvProgressUser); 215 } 216 } 217 catch(std::bad_alloc &) 218 { 219 rc = VERR_NO_MEMORY; 220 } 202 Reset(true /* fForce */); 221 203 } 222 204 … … 227 209 /** 228 210 * Resets the manager by clearing the message queue and internal state. 229 */ 230 void DnDManager::Reset(void) 211 * 212 * @param fForce Set to \c true to forcefully also remove still referenced messages, or \c false to only 213 * remove non-referenced messages. 214 */ 215 void DnDManager::Reset(bool fForce) 231 216 { 232 217 LogFlowFuncEnter(); 233 218 234 while (!m_queueMsg.isEmpty()) 235 { 236 delete m_queueMsg.last(); 237 m_queueMsg.removeLast(); 238 } 239 } 240 219 #ifdef DEBUG 220 DumpQueue(); 221 #endif 222 223 for (size_t i = 0; i < m_queueMsg.size(); i++) 224 { 225 if ( fForce 226 || m_queueMsg[i]->RefCount() == 0) 227 { 228 m_queueMsg.removeAt(i); 229 i = i > 0 ? i - 1 : 0; 230 } 231 } 232 } 233 -
trunk/src/VBox/HostServices/DragAndDrop/dndmanager.h
r97731 r97788 50 50 51 51 DnDMessage(void) 52 { 53 } 52 : m_cRefs(0) { } 54 53 55 54 DnDMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) 56 : Message(uMsg, cParms, aParms) { } 55 : Message(uMsg, cParms, aParms) 56 , m_cRefs(0) { } 57 57 58 58 virtual ~DnDMessage(void) { } 59 60 uint32_t AddRef(void) { Assert(m_cRefs < 32); return ++m_cRefs; } 61 uint32_t Release(void) { if (m_cRefs) return --m_cRefs; return m_cRefs; } 62 uint32_t RefCount(void) const { return m_cRefs; } 63 64 protected: 65 66 /** The message's current reference count. */ 67 uint32_t m_cRefs; 59 68 }; 60 69 … … 100 109 virtual ~DnDManager(void) 101 110 { 102 Reset( );111 Reset(true /* fForce */); 103 112 } 104 113 … … 110 119 #endif 111 120 112 int GetNextMsgInfo( uint32_t *puType, uint32_t *pcParms);121 int GetNextMsgInfo(bool fAddRef, uint32_t *puType, uint32_t *pcParms); 113 122 int GetNextMsg(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 114 123 115 void Reset( void);124 void Reset(bool fForce); 116 125 117 126 protected: -
trunk/src/VBox/Main/include/GuestDnDPrivate.h
r97786 r97788 844 844 void reset(void); 845 845 846 /** @name Callback handling. 847 * @{ */ 848 static DECLCALLBACK(int) i_defaultCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser); 849 int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL); 850 /** @} */ 851 852 /** @name Progress handling. 853 * @{ */ 846 854 bool isProgressCanceled(void) const; 847 int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL);848 855 int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS, const Utf8Str &strMsg = ""); 849 856 HRESULT resetProgress(const ComObjPtr<Guest>& pParent); 850 857 HRESULT queryProgressTo(IProgress **ppProgress); 858 /** @} */ 851 859 852 860 public: -
trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
r97784 r97788 204 204 void GuestDnDSendCtx::reset(void) 205 205 { 206 if (pState)207 pState->reset();208 209 206 uScreenID = 0; 210 207 … … 233 230 void GuestDnDRecvCtx::reset(void) 234 231 { 235 if (pState)236 pState->reset();237 238 232 lstFmtOffered.clear(); 239 233 strFmtReq = ""; … … 354 348 355 349 m_lstFormats.clear(); 350 m_mapCallbacks.clear(); 356 351 357 352 m_rcGuest = VERR_IPE_UNINITIALIZED_STATUS; 353 } 354 355 /** 356 * Default callback handler for guest callbacks. 357 * 358 * This handler acts as a fallback in case important callback messages are not being handled 359 * by the specific callers. 360 * 361 * @returns VBox status code. Will get sent back to the host service. 362 * @retval VERR_CANCELLED for indicating that the current operation was cancelled. 363 * @param uMsg HGCM message ID (function number). 364 * @param pvParms Pointer to additional message data. Optional and can be NULL. 365 * @param cbParms Size (in bytes) additional message data. Optional and can be 0. 366 * @param pvUser User-supplied pointer on callback registration. 367 */ 368 /* static */ 369 DECLCALLBACK(int) GuestDnDState::i_defaultCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser) 370 { 371 GuestDnDState *pThis = (GuestDnDState *)pvUser; 372 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 373 374 LogFlowFunc(("uMsg=%RU32 (%#x)\n", uMsg, uMsg)); 375 376 int vrc = VERR_IPE_UNINITIALIZED_STATUS; 377 378 switch (uMsg) 379 { 380 case GUEST_DND_FN_EVT_ERROR: 381 { 382 PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<PVBOXDNDCBEVTERRORDATA>(pvParms); 383 AssertPtr(pCBData); 384 AssertReturn(sizeof(VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER); 385 AssertReturn(CB_MAGIC_DND_EVT_ERROR == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER); 386 387 if (RT_SUCCESS(pCBData->rc)) 388 { 389 AssertMsgFailed(("Guest has sent an error event but did not specify an actual error code\n")); 390 pCBData->rc = VERR_GENERAL_FAILURE; /* Make sure some error is set. */ 391 } 392 393 vrc = pThis->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc, 394 Utf8StrFmt("Received error from guest: %Rrc", pCBData->rc)); 395 AssertRCBreak(vrc); 396 vrc = pThis->notifyAboutGuestResponse(pCBData->rc); 397 AssertRCBreak(vrc); 398 break; 399 } 400 401 default: 402 AssertMsgBreakStmt(pThis->isProgressCanceled(), ("Transfer not cancelled (yet)!\n"), vrc = VERR_INVALID_STATE); 403 vrc = VERR_CANCELLED; 404 break; 405 } 406 407 LogFlowFunc(("Returning rc=%Rrc\n", vrc)); 408 return vrc; 358 409 } 359 410 … … 399 450 400 451 /** 401 * Sets a callback for a specific HGCM message.452 * Sets (registers or unregisters) a callback for a specific HGCM message. 402 453 * 403 454 * @returns VBox status code. 404 455 * @param uMsg HGCM message ID to set callback for. 405 * @param pfnCallback Callback function pointer to use. 456 * @param pfnCallback Callback function pointer to use. Pass NULL to unregister. 406 457 * @param pvUser User-provided arguments for the callback function. Optional and can be NULL. 407 458 */ … … 410 461 GuestDnDCallbackMap::iterator it = m_mapCallbacks.find(uMsg); 411 462 412 /* Add. */463 /* Register. */ 413 464 if (pfnCallback) 414 465 { 415 if (it == m_mapCallbacks.end())466 try 416 467 { 417 468 m_mapCallbacks[uMsg] = GuestDnDCallback(pfnCallback, uMsg, pvUser); 418 return VINF_SUCCESS; 419 } 420 421 AssertMsgFailed(("Callback for message %RU32 already registered\n", uMsg)); 422 return VERR_ALREADY_EXISTS; 423 } 424 425 /* Remove. */ 469 } 470 catch (std::bad_alloc &) 471 { 472 return VERR_NO_MEMORY; 473 } 474 return VINF_SUCCESS; 475 } 476 477 /* Unregister. */ 426 478 if (it != m_mapCallbacks.end()) 427 479 m_mapCallbacks.erase(it); … … 472 524 COM_IIDOF(IGuest), 473 525 m_pParent->getComponentName(), strMsg.c_str()); 474 reset();475 526 break; 476 527 } … … 491 542 AssertComRC(hr); 492 543 } 493 494 reset();495 544 break; 496 545 } … … 574 623 break; 575 624 } 625 626 /* Note: GUEST_DND_FN_EVT_ERROR is handled in either the state's default callback or in specific 627 * (overriden) callbacks (e.g. GuestDnDSendCtx / GuestDnDRecvCtx). */ 576 628 577 629 case DragAndDropSvc::GUEST_DND_FN_DISCONNECT: … … 694 746 else 695 747 { 696 LogFlowFunc(("No callback for function %RU32 defined\n", u32Function));697 rc = VERR_NOT_SUPPORTED; /* Tell the guest. */748 /* Invoke the default callback handler in case we don't have any registered callback above. */ 749 rc = i_defaultCallback(u32Function, pvParms, cbParms, this /* pvUser */); 698 750 } 699 751 } -
trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
r97784 r97788 617 617 void GuestDnDSource::i_reset(void) 618 618 { 619 Log FlowThisFunc(("\n"));619 LogRel2(("DnD: Source reset\n")); 620 620 621 621 mData.mRecvCtx.reset(); -
trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp
r97784 r97788 107 107 return; 108 108 109 int vrc = pThis->i_sendData(mpCtx, RT_INDEFINITE_WAIT /* msTimeout */); 110 if (RT_FAILURE(vrc)) /* In case we missed some error handling within i_sendData(). */ 111 { 112 if (vrc != VERR_CANCELLED) 113 LogRel(("DnD: Sending data to guest failed with %Rrc\n", vrc)); 114 115 /* Make sure to fire a cancel request to the guest side in case something went wrong. */ 116 pThis->sendCancel(); 117 } 109 /* ignore rc */ pThis->i_sendData(mpCtx, RT_INDEFINITE_WAIT /* msTimeout */); 118 110 } 119 111 … … 720 712 return setError(E_FAIL, tr("Current drop operation to guest still in progress")); 721 713 722 /* Reset our internal state. */723 i_reset();724 725 714 /* At the moment we only support one transfer at a time. */ 726 715 if (GuestDnDInst()->getTargetCount()) … … 878 867 void GuestDnDTarget::i_reset(void) 879 868 { 880 Log FlowThisFunc(("\n"));869 LogRel2(("DnD: Target reset\n")); 881 870 882 871 mData.mSendCtx.reset();
Note:
See TracChangeset
for help on using the changeset viewer.