Changeset 100204 in vbox for trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
- Timestamp:
- Jun 19, 2023 9:11:37 AM (18 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
r99967 r100204 38 38 #include <iprt/win/shlwapi.h> 39 39 40 #include <iprt/thread.h> // REMOVE 41 40 42 #include <iprt/asm.h> 41 43 #include <iprt/err.h> … … 52 54 //#define VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 1 53 55 54 SharedClipboardWinDataObject::SharedClipboardWinDataObject( PSHCLTRANSFER pTransfer,55 LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)56 :m_enmStatus(Uninitialized)56 SharedClipboardWinDataObject::SharedClipboardWinDataObject(void) 57 : m_pCtx(NULL) 58 , m_enmStatus(Uninitialized) 57 59 , m_lRefCount(0) 58 60 , m_cFormats(0) 59 , m_pTransfer( pTransfer)61 , m_pTransfer(NULL) 60 62 , m_pStream(NULL) 61 63 , m_uObjIdx(0) 62 , m_f Running(false)64 , m_fThreadRunning(false) 63 65 , m_EventListComplete(NIL_RTSEMEVENT) 64 , m_EventTransferComplete(NIL_RTSEMEVENT) 65 { 66 AssertPtr(m_pTransfer); 67 68 HRESULT hr; 66 , m_EventStatusChanged(NIL_RTSEMEVENT) 67 { 68 } 69 70 SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void) 71 { 72 Destroy(); 73 74 LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount)); 75 } 76 77 /** 78 * Initializes a data object instance. 79 * 80 * @returns VBox status code. 81 * @param pFormatEtc FormatETC to use. 82 * @param pStgMed Storage medium to use. 83 * @param cFormats Number of formats in \a pFormatEtc and \a pStgMed. 84 */ 85 int SharedClipboardWinDataObject::Init(PSHCLCONTEXT pCtx, 86 LPFORMATETC pFormatEtc /* = NULL */, LPSTGMEDIUM pStgMed /* = NULL */, 87 ULONG cFormats /* = 0 */) 88 { 89 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 90 AssertReturn(cFormats == 0 || (RT_VALID_PTR(pFormatEtc) && RT_VALID_PTR(pStgMed)), VERR_INVALID_POINTER); 91 92 int rc = VINF_SUCCESS; 93 94 m_pCtx = pCtx; /* Save opaque context. */ 69 95 70 96 ULONG cFixedFormats = 3; /* CFSTR_FILEDESCRIPTORA + CFSTR_FILECONTENTS + CFSTR_PERFORMEDDROPEFFECT */ … … 74 100 const ULONG cAllFormats = cFormats + cFixedFormats; 75 101 76 try77 {78 m_pFormatEtc = new FORMATETC[cAllFormats];79 RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats);80 m_pStgMedium = new STGMEDIUM[cAllFormats];81 82 83 84 85 86 87 88 89 90 91 92 102 m_pFormatEtc = new FORMATETC[cAllFormats]; 103 AssertPtrReturn(m_pFormatEtc, VERR_NO_MEMORY); 104 RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats); 105 m_pStgMedium = new STGMEDIUM[cAllFormats]; 106 AssertPtrReturn(m_pStgMedium, VERR_NO_MEMORY); 107 RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cAllFormats); 108 109 /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */ 110 111 /* 112 * Register fixed formats. 113 */ 114 unsigned uIdx = 0; 115 116 LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n")); 117 m_cfFileDescriptorA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA); 118 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorA); 93 119 #ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 94 95 96 120 LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n")); 121 m_cfFileDescriptorW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); 122 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorW); 97 123 #endif 98 124 99 /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */ 100 LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n")); 101 m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS); 102 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */); 103 104 /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */ 105 LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n")); 106 m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); 107 registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT); 108 109 /* 110 * Registration of dynamic formats needed? 111 */ 112 LogFlowFunc(("%RU32 dynamic formats\n", cFormats)); 113 if (cFormats) 114 { 115 AssertPtr(pFormatEtc); 116 AssertPtr(pStgMed); 117 118 for (ULONG i = 0; i < cFormats; i++) 119 { 120 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n", 121 i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect)); 122 m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i]; 123 m_pStgMedium[cFixedFormats + i] = pStgMed[i]; 124 } 125 } 126 127 hr = S_OK; 128 } 129 catch (std::bad_alloc &) 130 { 131 hr = E_OUTOFMEMORY; 132 } 133 134 if (SUCCEEDED(hr)) 125 /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */ 126 LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n")); 127 m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS); 128 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */); 129 130 /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */ 131 LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n")); 132 m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); 133 registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT); 134 135 /* 136 * Registration of dynamic formats needed? 137 */ 138 LogFlowFunc(("%RU32 dynamic formats\n", cFormats)); 139 if (cFormats) 140 { 141 for (ULONG i = 0; i < cFormats; i++) 142 { 143 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n", 144 i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect)); 145 m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i]; 146 m_pStgMedium[cFixedFormats + i] = pStgMed[i]; 147 } 148 } 149 150 if (RT_SUCCESS(rc)) 135 151 { 136 152 m_cFormats = cAllFormats; 137 153 m_enmStatus = Initialized; 138 154 139 int rc2 = RTSemEventCreate(&m_EventListComplete); 140 AssertRC(rc2); 141 rc2 = RTSemEventCreate(&m_EventTransferComplete); 142 AssertRC(rc2); 143 } 144 145 LogFlowFunc(("cAllFormats=%RU32, hr=%Rhrc\n", cAllFormats, hr)); 146 } 147 148 SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void) 155 rc = RTCritSectInit(&m_CritSect); 156 if (RT_SUCCESS(rc)) 157 { 158 rc = RTSemEventCreate(&m_EventListComplete); 159 if (RT_SUCCESS(rc)) 160 rc = RTSemEventCreate(&m_EventStatusChanged); 161 } 162 } 163 164 LogFlowFunc(("cAllFormats=%RU32, rc=%Rrc\n", cAllFormats, rc)); 165 return rc; 166 } 167 168 /** 169 * Destroys a data object instance. 170 */ 171 void SharedClipboardWinDataObject::Destroy(void) 149 172 { 150 173 LogFlowFuncEnter(); 151 174 152 RTSemEventDestroy(m_EventListComplete); 153 m_EventListComplete = NIL_RTSEMEVENT; 154 155 RTSemEventDestroy(m_EventTransferComplete); 156 m_EventTransferComplete = NIL_RTSEMEVENT; 175 AssertReturnVoid(m_lRefCount == 0); 176 177 int rc = RTCritSectDelete(&m_CritSect); 178 AssertRC(rc); 179 180 if (m_EventListComplete != NIL_RTSEMEVENT) 181 { 182 rc = RTSemEventDestroy(m_EventListComplete); 183 AssertRC(rc); 184 m_EventListComplete = NIL_RTSEMEVENT; 185 } 186 187 if (m_EventStatusChanged != NIL_RTSEMEVENT) 188 { 189 rc = RTSemEventDestroy(m_EventStatusChanged); 190 AssertRC(rc); 191 m_EventStatusChanged = NIL_RTSEMEVENT; 192 } 157 193 158 194 if (m_pStream) 195 { 159 196 m_pStream->Release(); 197 m_pStream = NULL; 198 } 160 199 161 200 if (m_pFormatEtc) 201 { 162 202 delete[] m_pFormatEtc; 203 m_pFormatEtc = NULL; 204 } 163 205 164 206 if (m_pStgMedium) 207 { 165 208 delete[] m_pStgMedium; 166 167 LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount)); 168 } 169 170 /* 209 m_pStgMedium = NULL; 210 } 211 212 if (m_pTransfer) 213 ShClTransferRelease(m_pTransfer); 214 215 FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin(); 216 while (itRoot != m_lstEntries.end()) 217 { 218 RTStrFree(itRoot->pszPath); 219 ++itRoot; 220 } 221 m_lstEntries.clear(); 222 223 m_enmStatus = Uninitialized; 224 m_fThreadRunning = false; 225 m_pTransfer = NULL; 226 } 227 228 /** 229 * Sets the callbacks for this object. 230 * 231 * @param pCallbacks Pointer to callbacks table to use. 232 */ 233 void SharedClipboardWinDataObject::SetCallbacks(PSHCLCALLBACKS pCallbacks) 234 { 235 AssertPtrReturnVoid(pCallbacks); 236 237 RT_ZERO(m_Callbacks); 238 239 m_Callbacks.pfnOnRequestDataFromSource = pCallbacks->pfnOnRequestDataFromSource; 240 } 241 242 243 /********************************************************************************************************************************* 171 244 * IUnknown methods. 172 * /245 ********************************************************************************************************************************/ 173 246 174 247 STDMETHODIMP_(ULONG) SharedClipboardWinDataObject::AddRef(void) … … 270 343 { 271 344 LogFlowFunc(("cTotalObjects=%RU64, cbTotalSize=%RU64\n\n", 272 hdrList.c TotalObjects, hdrList.cbTotalSize));273 274 for (uint64_t o = 0; o < hdrList.c TotalObjects; o++)345 hdrList.cEntries, hdrList.cbTotalSize)); 346 347 for (uint64_t o = 0; o < hdrList.cEntries; o++) 275 348 { 276 349 SHCLLISTENTRY entryList; … … 291 364 entryList.pszName, pFsObjInfo->cbObject, strPath.c_str())); 292 365 293 if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode)) 366 if ( RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode) 367 || RTFS_IS_FILE (pFsObjInfo->Attr.fMode)) 294 368 { 295 FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo }; 296 297 m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ 298 299 rc = readDir(pTransfer, strPath.c_str()); 300 } 301 else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode)) 302 { 303 FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo }; 369 FSOBJENTRY objEntry; 370 objEntry.pszPath = RTStrDup(strPath.c_str()); 371 AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY); 372 objEntry.objInfo = *pFsObjInfo; 304 373 305 374 m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ 306 375 } 307 else 308 rc = VERR_NOT_SUPPORTED; 376 else /* Not fatal, just skip. */ 377 LogRel(("Shared Clipboard: Warning: File system object '%s' of type %#x not supported, skipping\n", 378 strPath.c_str(), pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK)); 309 379 310 380 /** @todo Handle symlinks. */ … … 330 400 } 331 401 402 if (RT_FAILURE(rc)) 403 LogRel(("Shared Clipboard: Reading directory '%s' failed with %Rrc\n", strDir.c_str(), rc)); 404 332 405 LogFlowFuncLeaveRC(rc); 333 406 return rc; … … 362 435 LogRel2(("Shared Clipboard: Calculating transfer ...\n")); 363 436 364 PSHCLROOTLIST pRootList; 365 int rc = ShClTransferRootsGet(pTransfer, &pRootList); 437 int rc = ShClTransferRootListRead(pTransfer); 366 438 if (RT_SUCCESS(rc)) 367 439 { 368 LogFlowFunc(("cRoots=%RU32\n\n", pRootList->Hdr.cRoots)); 369 370 for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++) 371 { 372 PSHCLLISTENTRY pRootEntry = &pRootList->paEntries[i]; 373 AssertPtr(pRootEntry); 374 375 Assert(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO)); 376 PSHCLFSOBJINFO pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo; 377 378 LogFlowFunc(("pszRoot=%s, fMode=0x%x\n", pRootEntry->pszName, pFsObjInfo->Attr.fMode)); 440 uint64_t const cRoots = ShClTransferRootsCount(pTransfer); 441 442 LogFlowFunc(("cRoots=%RU64\n\n", cRoots)); 443 444 for (uint32_t i = 0; i < cRoots; i++) 445 { 446 PCSHCLLISTENTRY pRootEntry = ShClTransferRootsEntryGet(pTransfer, i); 447 448 AssertBreakStmt(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO), rc = VERR_INVALID_PARAMETER); 449 PSHCLFSOBJINFO const pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo; 450 451 LogFlowFunc(("pszRoot=%s, fMode=0x%x (type %#x)\n", 452 pRootEntry->pszName, pFsObjInfo->Attr.fMode, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK))); 379 453 380 454 if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode)) 381 455 { 382 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo }; 456 FSOBJENTRY objEntry; 457 objEntry.pszPath = RTStrDup(pRootEntry->pszName); 458 AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY); 459 objEntry.objInfo = *pFsObjInfo; 383 460 384 461 pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ … … 388 465 else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode)) 389 466 { 390 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo }; 467 FSOBJENTRY objEntry; 468 objEntry.pszPath = RTStrDup(pRootEntry->pszName); 469 AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY); 470 objEntry.objInfo = *pFsObjInfo; 391 471 392 472 pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ 393 473 } 394 474 else 475 { 476 LogRel(("Shared Clipboard: Root entry '%s': File type %#x not supported\n", 477 pRootEntry->pszName, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK))); 395 478 rc = VERR_NOT_SUPPORTED; 479 } 396 480 397 481 if (ASMAtomicReadBool(&pTransfer->Thread.fStop)) … … 404 488 break; 405 489 } 406 407 ShClTransferRootListFree(pRootList);408 pRootList = NULL;409 490 410 491 if ( RT_SUCCESS(rc) … … 424 505 LogRel2(("Shared Clipboard: Waiting for transfer to complete ...\n")); 425 506 426 LogFlowFunc(("Waiting for transfer to complete ...\n"));427 428 507 /* Transferring stuff can take a while, so don't use any timeout here. */ 429 rc2 = RTSemEventWait(pThis->m_Event TransferComplete, RT_INDEFINITE_WAIT);508 rc2 = RTSemEventWait(pThis->m_EventStatusChanged, RT_INDEFINITE_WAIT); 430 509 AssertRC(rc2); 431 510 … … 499 578 char *pszFileSpec = NULL; 500 579 501 FsObjEntryList::const_iterator itRoot = m_lstEntries. begin();580 FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin(); 502 581 while (itRoot != m_lstEntries.end()) 503 582 { … … 505 584 RT_BZERO(pFD, cbFileDescriptor); 506 585 507 const char *pszFile = itRoot-> strPath.c_str();586 const char *pszFile = itRoot->pszPath; 508 587 AssertPtr(pszFile); 509 588 … … 584 663 585 664 /** 586 * Retrieves the data stored in this object and store the result in 587 * pMedium. 588 * 589 * @return IPRT status code. 665 * Retrieves the data stored in this object and store the result in pMedium. 666 * 590 667 * @return HRESULT 591 * @param pFormatEtc 592 * @param pMedium 668 * @param pFormatEtc Format to retrieve. 669 * @param pMedium Where to store the data on success. 670 * 671 * @thread Windows event thread. 593 672 */ 594 673 STDMETHODIMP SharedClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium) … … 597 676 AssertPtrReturn(pMedium, DV_E_FORMATETC); 598 677 599 LogFlowFuncEnter(); 600 601 LogFlowFunc(("lIndex=%RI32\n", pFormatEtc->lindex)); 678 int rc2 = RTCritSectEnter(&m_CritSect); 679 AssertRCReturn(rc2, E_UNEXPECTED); 680 681 LogFlowFunc(("lIndex=%RI32, enmStatus=%#x\n", pFormatEtc->lindex, m_enmStatus)); 602 682 603 683 /* … … 607 687 608 688 HRESULT hr = DV_E_FORMATETC; /* Play safe. */ 689 690 int rc = VINF_SUCCESS; 609 691 610 692 if ( pFormatEtc->cfFormat == m_cfFileDescriptorA … … 614 696 ) 615 697 { 616 const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW; 617 618 const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer); 619 RT_NOREF(enmTransferStatus); 620 621 LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n", 622 fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fRunning)); 623 624 int rc; 625 626 /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */ 627 if (!m_fRunning) 628 { 629 /* Start the transfer asynchronously in a separate thread. */ 630 rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this); 631 if (RT_SUCCESS(rc)) 698 switch (m_enmStatus) 699 { 700 case Initialized: 632 701 { 633 m_fRunning = true; 634 635 /* Don't block for too long here, as this also will screw other apps running on the OS. */ 636 LogFunc(("Waiting for listing to arrive ...\n")); 637 rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS); 702 LogRel2(("Shared Clipboard: Requesting data for IDataObject ...\n")); 703 704 /* Leave lock while requesting + waiting. */ 705 rc2 = RTCritSectLeave(&m_CritSect); 706 AssertRCReturn(rc2, E_UNEXPECTED); 707 708 /* Request the transfer from the source. 709 * This will generate a transfer status message which we're waiting for here. */ 710 AssertPtr(m_Callbacks.pfnOnRequestDataFromSource); 711 rc = m_Callbacks.pfnOnRequestDataFromSource(m_pCtx, 712 VBOX_SHCL_FMT_URI_LIST, NULL /* ppv */, NULL /* pv */, 713 this /* pvUser */); 714 AssertRCBreak(rc); 715 716 LogRel2(("Shared Clipboard: Waiting for IDataObject started status ...\n")); 717 718 rc = RTSemEventWait(m_EventStatusChanged, SHCL_TIMEOUT_DEFAULT_MS); 719 720 /* Re-acquire lock. */ 721 rc2 = RTCritSectEnter(&m_CritSect); 722 AssertRCReturn(rc2, E_UNEXPECTED); 723 638 724 if (RT_SUCCESS(rc)) 639 725 { 640 LogFunc(("Listing complete\n")); 726 if (m_enmStatus != Running) 727 { 728 LogRel(("Shared Clipboard: Received wrong IDataObject status (%#x)\n", m_enmStatus)); 729 rc = VERR_WRONG_ORDER; 730 break; 731 } 732 733 /* There now must be a transfer assigned. */ 734 AssertPtrBreakStmt(m_pTransfer, rc = VERR_WRONG_ORDER); 735 } 736 else /* Bail out on failure. */ 737 break; 738 739 RT_FALL_THROUGH(); 740 } 741 742 case Running: 743 { 744 const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW; 745 746 const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer); 747 RT_NOREF(enmTransferStatus); 748 749 LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n", 750 fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fThreadRunning)); 751 752 /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */ 753 if (!m_fThreadRunning) 754 { 755 /* Start the transfer asynchronously in a separate thread. */ 756 rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this /* pvUser */); 757 if (RT_SUCCESS(rc)) 758 { 759 m_fThreadRunning = true; 760 761 /* Leave lock while waiting. */ 762 rc2 = RTCritSectLeave(&m_CritSect); 763 AssertRCReturn(rc2, E_UNEXPECTED); 764 765 /* Don't block for too long here, as this also will screw other apps running on the OS. */ 766 LogRel2(("Shared Clipboard: Waiting for IDataObject listing to arrive ...\n")); 767 rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS); 768 769 /* Re-acquire lock. */ 770 rc2 = RTCritSectEnter(&m_CritSect); 771 AssertRCReturn(rc2, E_UNEXPECTED); 772 } 773 } 774 775 if (RT_SUCCESS(rc)) 776 { 777 HGLOBAL hGlobal; 778 rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal); 779 if (RT_SUCCESS(rc)) 780 { 781 pMedium->tymed = TYMED_HGLOBAL; 782 pMedium->hGlobal = hGlobal; 783 /* Note: hGlobal now is being owned by pMedium / the caller. */ 784 785 hr = S_OK; 786 } 787 } 788 789 break; 790 } 791 792 default: 793 break; 794 } 795 796 if (RT_FAILURE(rc)) 797 { 798 LogRel(("Shared Clipboard: Error getting data for IDataObject, rc=%Rrc\n", rc)); 799 hr = E_UNEXPECTED; /* We can't tell any better to the caller, unfortunately. */ 800 } 801 } 802 803 if (RT_SUCCESS(rc)) 804 { 805 if (pFormatEtc->cfFormat == m_cfFileContents) 806 { 807 if ( pFormatEtc->lindex >= 0 808 && (ULONG)pFormatEtc->lindex < m_lstEntries.size()) 809 { 810 m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */ 811 812 FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx); 813 814 LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.pszPath)); 815 816 LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.pszPath)); 817 818 /* Hand-in the provider so that our IStream implementation can continue working with it. */ 819 hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer, 820 fsObjEntry.pszPath /* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */, 821 &m_pStream); 822 if (SUCCEEDED(hr)) 823 { 824 /* Hand over the stream to the caller. */ 825 pMedium->tymed = TYMED_ISTREAM; 826 pMedium->pstm = m_pStream; 641 827 } 642 828 } 643 829 } 644 else 645 rc = VINF_SUCCESS; 646 647 if (RT_SUCCESS(rc)) 648 { 649 HGLOBAL hGlobal; 650 rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal); 651 if (RT_SUCCESS(rc)) 652 { 653 pMedium->tymed = TYMED_HGLOBAL; 654 pMedium->hGlobal = hGlobal; 655 /* Note: hGlobal now is being owned by pMedium / the caller. */ 656 657 hr = S_OK; 658 } 659 else /* We can't tell any better to the caller, unfortunately. */ 660 hr = E_UNEXPECTED; 661 } 662 663 if (RT_FAILURE(rc)) 664 LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc)); 665 } 666 667 if (pFormatEtc->cfFormat == m_cfFileContents) 668 { 669 if ( pFormatEtc->lindex >= 0 670 && (ULONG)pFormatEtc->lindex < m_lstEntries.size()) 671 { 672 m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */ 673 674 FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx); 675 676 LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.strPath.c_str())); 677 678 LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.strPath.c_str())); 679 680 /* Hand-in the provider so that our IStream implementation can continue working with it. */ 681 hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer, 682 fsObjEntry.strPath.c_str()/* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */, 683 &m_pStream); 684 if (SUCCEEDED(hr)) 685 { 686 /* Hand over the stream to the caller. */ 687 pMedium->tymed = TYMED_ISTREAM; 688 pMedium->pstm = m_pStream; 689 } 690 } 691 } 692 else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect) 693 { 694 HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD)); 695 696 DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal); 697 *pdwDropEffect = DROPEFFECT_COPY; 698 699 GlobalUnlock(hGlobal); 700 701 pMedium->tymed = TYMED_HGLOBAL; 702 pMedium->hGlobal = hGlobal; 703 pMedium->pUnkForRelease = NULL; 704 } 705 706 if ( FAILED(hr) 707 && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */ 708 { 709 LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr)); 710 } 830 else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect) 831 { 832 HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD)); 833 834 DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal); 835 *pdwDropEffect = DROPEFFECT_COPY; 836 837 GlobalUnlock(hGlobal); 838 839 pMedium->tymed = TYMED_HGLOBAL; 840 pMedium->hGlobal = hGlobal; 841 pMedium->pUnkForRelease = NULL; 842 } 843 844 if ( FAILED(hr) 845 && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */ 846 { 847 LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr)); 848 } 849 } 850 851 rc2 = RTCritSectLeave(&m_CritSect); 852 AssertRCReturn(rc2, E_UNEXPECTED); 711 853 712 854 LogFlowFunc(("hr=%Rhrc\n", hr)); … … 786 928 LogRel2(("Shared Clipboard: Transfer canceled by user interaction\n")); 787 929 788 OnTransferCanceled();930 SetStatus(Canceled); 789 931 } 790 932 /** @todo Detect move / overwrite actions here. */ … … 871 1013 */ 872 1014 873 int SharedClipboardWinDataObject::Init(void) 874 { 875 LogFlowFuncLeaveRC(VINF_SUCCESS); 876 return VINF_SUCCESS; 877 } 878 879 void SharedClipboardWinDataObject::OnTransferComplete(int rc /* = VINF_SUCESS */) 880 { 881 RT_NOREF(rc); 882 883 LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size())); 884 1015 /** 1016 * Assigns a transfer object and starts the transfer for the data object. 1017 * 1018 * @returns VBox status code. 1019 * @param pTransfer Transfer to assign. 1020 */ 1021 int SharedClipboardWinDataObject::SetAndStartTransfer(PSHCLTRANSFER pTransfer) 1022 { 1023 AssertReturn(m_pTransfer == NULL, VERR_WRONG_ORDER); /* Transfer already set? */ 1024 1025 int rc = RTCritSectEnter(&m_CritSect); 885 1026 if (RT_SUCCESS(rc)) 886 1027 { 887 const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */; 888 if (fComplete) 889 { 890 m_enmStatus = Completed; 891 } 892 } 893 else 894 m_enmStatus = Error; 895 896 if (m_enmStatus != Initialized) 897 { 898 if (m_EventTransferComplete != NIL_RTSEMEVENT) 899 { 900 int rc2 = RTSemEventSignal(m_EventTransferComplete); 901 AssertRC(rc2); 902 } 903 } 904 905 LogFlowFuncLeaveRC(rc); 906 } 907 908 void SharedClipboardWinDataObject::OnTransferCanceled(void) 909 { 910 LogFlowFuncEnter(); 911 912 m_enmStatus = Canceled; 913 914 if (m_EventTransferComplete != NIL_RTSEMEVENT) 915 { 916 int rc2 = RTSemEventSignal(m_EventTransferComplete); 917 AssertRC(rc2); 918 } 919 920 LogFlowFuncLeave(); 1028 if (m_enmStatus == Initialized) 1029 { 1030 m_pTransfer = pTransfer; 1031 1032 ShClTransferAcquire(pTransfer); 1033 1034 rc = setStatusLocked(Running); 1035 } 1036 else 1037 AssertFailedStmt(rc = VERR_WRONG_ORDER); 1038 1039 RTCritSectLeave(&m_CritSect); 1040 } 1041 1042 return rc; 1043 } 1044 1045 /** 1046 * Sets a new status to the data object and signals its waiter. 1047 * 1048 * @returns VBox status code. 1049 * @param enmStatus New status to signal. 1050 * @param rc Result code. Optional. 1051 * 1052 * @note Called by the main clipboard thread + SharedClipboardWinStreamImpl. 1053 */ 1054 int SharedClipboardWinDataObject::SetStatus(Status enmStatus, int rc /* = VINF_SUCCESS */) 1055 { 1056 int rc2 = RTCritSectEnter(&m_CritSect); 1057 if (RT_SUCCESS(rc2)) 1058 { 1059 setStatusLocked(enmStatus, rc); 1060 1061 RTCritSectLeave(&m_CritSect); 1062 } 1063 1064 return rc2; 921 1065 } 922 1066 … … 977 1121 logFormat(pFormatEtc->cfFormat); 978 1122 } 1123 1124 /** 1125 * Sets a new status to the data object and signals its waiter. 1126 * 1127 * @returns VBox status code. 1128 * @param enmStatus New status to signal. 1129 * @param rc Result code. Optional. 1130 * 1131 * @note Caller must have taken the critical section. 1132 */ 1133 int SharedClipboardWinDataObject::setStatusLocked(Status enmStatus, int rc /* = VINF_SUCCESS */) 1134 { 1135 AssertReturn(enmStatus == Error || RT_SUCCESS(rc), VERR_INVALID_PARAMETER); 1136 AssertReturn(RTCritSectIsOwned(&m_CritSect), VERR_WRONG_ORDER); 1137 1138 RT_NOREF(rc); 1139 1140 int rc2 = RTCritSectEnter(&m_CritSect); 1141 if (RT_SUCCESS(rc2)) 1142 { 1143 LogFlowFunc(("enmStatus=%#x (current is: %#x)\n", enmStatus, m_enmStatus)); 1144 1145 switch (enmStatus) 1146 { 1147 case Completed: 1148 { 1149 LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size())); 1150 1151 const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */; 1152 if (fComplete) 1153 m_enmStatus = Completed; 1154 break; 1155 } 1156 1157 default: 1158 { 1159 m_enmStatus = enmStatus; 1160 break; 1161 } 1162 } 1163 1164 if (RT_FAILURE(rc)) 1165 LogRel(("Shared Clipboard: Data object received error %Rrc (status %#x)\n", rc, enmStatus)); 1166 1167 if (m_EventStatusChanged != NIL_RTSEMEVENT) 1168 rc2 = RTSemEventSignal(m_EventStatusChanged); 1169 1170 RTCritSectLeave(&m_CritSect); 1171 } 1172 1173 return rc2; 1174 } 1175
Note:
See TracChangeset
for help on using the changeset viewer.