VirtualBox

Ignore:
Timestamp:
Jun 19, 2023 9:11:37 AM (20 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
157911
Message:

Shared Clipboard: Unified root list entry code to also use the generic list entry code, a lot of updates for the cross OS transfer handling code, more updates for HTTP server transfer handling.

This also changed the handling of how that transfers are being initiated, as we needed to have this for X11: Before, transfers were initiated as soon as on side announced the URI list format -- now we postpone initiating the transfer until the receiving side requests the data as URI list.

bugref:9437

Location:
trunk/src/VBox/HostServices/SharedClipboard
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp

    r98103 r100204  
    262262     * Now, request the data from the guest.
    263263     */
    264     return ShClSvcGuestDataRequest(pClient, fFormats, NULL /* pidEvent */);
     264    return ShClSvcReadDataFromGuestAsync(pClient, fFormats, NULL /* ppEvent */);
    265265}
    266266
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h

    r99951 r100204  
    186186    /** Transfer context. */
    187187    SHCLTRANSFERCTX             Ctx;
     188    /** Transfers callbacks to use. */
     189    SHCLTRANSFERCALLBACKTABLE   Callbacks;
    188190} SHCLIENTTRANSFERS, *PSHCLIENTTRANSFERS;
    189191#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     
    302304# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    303305int shClSvcTransferModeSet(uint32_t fMode);
    304 int shClSvcTransferStart(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, PSHCLTRANSFER *ppTransfer);
    305 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     306int shClSvcTransferInit(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, PSHCLTRANSFER *ppTransfer);
     307int shClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     308int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest);
    306309bool shClSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg);
    307310void shClSvcClientTransfersReset(PSHCLCLIENT pClient);
     
    312315 * @{
    313316 */
    314 int ShClSvcGuestDataRequest(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent);
     317int ShClSvcReadDataFromGuestAsync(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent);
    315318int ShClSvcGuestDataSignal(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData);
    316319int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats);
     
    493496#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
    494497
    495 int shClSvcTransferIfaceRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList);
    496 
     498int shClSvcTransferIfaceRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLLIST pRootList);
    497499int shClSvcTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList);
    498500int shClSvcTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList);
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp

    r99969 r100204  
    9797*********************************************************************************************************************************/
    9898
    99 /** @copydoc SHCLTXPROVIDERIFACE::pfnRootsGet */
    100 DECLCALLBACK(int) shClSvcTransferIfaceRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
     99/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
     100DECLCALLBACK(int) shClSvcTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx)
    101101{
    102102    LogFlowFuncEnter();
     
    132132                if (RT_SUCCESS(rc))
    133133                {
    134                     PSHCLROOTLISTHDR pSrcRootListHdr = (PSHCLROOTLISTHDR)pPayloadHdr->pvData;
    135                     Assert(pPayloadHdr->cbData == sizeof(SHCLROOTLISTHDR));
    136 
    137                     LogFlowFunc(("cRoots=%RU32, fRoots=0x%x\n", pSrcRootListHdr->cRoots, pSrcRootListHdr->fRoots));
    138 
    139                     PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
    140                     if (pRootList)
     134                    PSHCLLISTHDR pRootListHdr = (PSHCLLISTHDR)pPayloadHdr->pvData;
     135                    Assert(pPayloadHdr->cbData == sizeof(SHCLLISTHDR));
     136
     137                    LogFlowFunc(("cRoots=%RU32, fFeatures=0x%x\n", pRootListHdr->cEntries, pRootListHdr->fFeatures));
     138
     139                    for (uint32_t i = 0; i < pRootListHdr->cEntries; i++)
    141140                    {
    142                         if (pSrcRootListHdr->cRoots)
    143                         {
    144                             pRootList->paEntries =
    145                                 (PSHCLROOTLISTENTRY)RTMemAllocZ(pSrcRootListHdr->cRoots * sizeof(SHCLROOTLISTENTRY));
    146 
    147                             if (pRootList->paEntries)
    148                             {
    149                                 for (uint32_t i = 0; i < pSrcRootListHdr->cRoots; i++)
    150                                 {
    151                                     PSHCLCLIENTMSG pMsgEntry = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
    152                                                                                VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
    153 
    154                                     PSHCLEVENT pEvRoot;
    155                                     rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvRoot);
    156                                     if (RT_SUCCESS(rc))
    157                                     {
    158                                         HGCMSvcSetU64(&pMsgEntry->aParms[0],
    159                                                       VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID,
    160                                                                                pCtx->pTransfer->State.uID, pEvRoot->idEvent));
    161                                         HGCMSvcSetU32(&pMsgEntry->aParms[1], 0 /* fRoots */);
    162                                         HGCMSvcSetU32(&pMsgEntry->aParms[2], i /* uIndex */);
    163 
    164                                         shClSvcClientLock(pClient);
    165                                         shClSvcMsgAdd(pClient, pMsgEntry, true /* fAppend */);
    166                                         shClSvcClientUnlock(pClient);
    167 
    168                                         PSHCLEVENTPAYLOAD pPayloadEntry;
    169                                         rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayloadEntry);
    170                                         if (RT_FAILURE(rc))
    171                                             break;
    172 
    173                                         PSHCLROOTLISTENTRY pSrcRootListEntry = (PSHCLROOTLISTENTRY)pPayloadEntry->pvData;
    174                                         Assert(pPayloadEntry->cbData == sizeof(SHCLROOTLISTENTRY));
    175 
    176                                         rc = ShClTransferListEntryCopy(&pRootList->paEntries[i], pSrcRootListEntry);
    177 
    178                                         ShClPayloadFree(pPayloadEntry);
    179 
    180                                         ShClEventRelease(pEvRoot);
    181                                         pEvRoot = NULL;
    182                                     }
    183                                     else
    184                                         rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
    185 
    186                                     if (RT_FAILURE(rc))
    187                                         break;
    188                                 }
    189                             }
    190                             else
    191                                 rc = VERR_NO_MEMORY;
    192                         }
    193 
     141                        PSHCLCLIENTMSG pMsgEntry = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
     142                                                                   VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
     143
     144                        PSHCLEVENT pEventRootEntry;
     145                        rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEventRootEntry);
    194146                        if (RT_SUCCESS(rc))
    195147                        {
    196                             pRootList->Hdr.cRoots = pSrcRootListHdr->cRoots;
    197                             pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
    198 
    199                             *ppRootList = pRootList;
     148                            HGCMSvcSetU64(&pMsgEntry->aParms[0],
     149                                          VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID,
     150                                                                   pCtx->pTransfer->State.uID, pEventRootEntry->idEvent));
     151                            HGCMSvcSetU32(&pMsgEntry->aParms[1], 0 /* fFeatures */);
     152                            HGCMSvcSetU32(&pMsgEntry->aParms[2], i /* uIndex */);
     153
     154                            shClSvcClientLock(pClient);
     155                            shClSvcMsgAdd(pClient, pMsgEntry, true /* fAppend */);
     156                            shClSvcClientUnlock(pClient);
     157
     158                            PSHCLEVENTPAYLOAD pPayloadEntry;
     159                            rc = ShClEventWait(pEventRootEntry, pCtx->pTransfer->uTimeoutMs, &pPayloadEntry);
     160                            if (RT_FAILURE(rc))
     161                                break;
     162
     163                            PSHCLLISTENTRY pRootListEntry = (PSHCLLISTENTRY)pPayloadEntry->pvData;
     164                            Assert(pPayloadEntry->cbData == sizeof(SHCLLISTENTRY));
     165
     166                            rc = ShClTransferListAddEntry(&pCtx->pTransfer->lstRoots, pRootListEntry, true /* fAppend */);
     167                            if (RT_FAILURE(rc))
     168                                ShClPayloadFree(pPayloadEntry);
     169                            /* else don't call ShClPayloadFree() here, as pRootList own the data now. */
     170                            pPayloadEntry = NULL;
     171
     172                            ShClEventRelease(pEventRootEntry);
     173                            pEventRootEntry = NULL;
    200174                        }
    201175                        else
    202                             ShClTransferRootListFree(pRootList);
    203 
    204                         ShClPayloadFree(pPayloadHdr);
     176                        {
     177                            shClSvcMsgFree(pClient, pMsgEntry);
     178                            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     179                        }
     180
     181                        if (RT_FAILURE(rc))
     182                            break;
    205183                    }
    206                     else
    207                         rc = VERR_NO_MEMORY;
     184
     185                    ShClPayloadFree(pPayloadHdr);
    208186                }
    209187            }
     
    212190        }
    213191        else
     192        {
     193            shClSvcMsgFree(pClient, pMsgHdr);
    214194            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     195        }
    215196    }
    216197    else
     
    246227            if (RT_SUCCESS(rc))
    247228            {
     229                shClSvcClientLock(pClient);
     230
    248231                shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    249 
    250232                rc = shClSvcClientWakeup(pClient);
     233
     234                shClSvcClientUnlock(pClient);
     235
    251236                if (RT_SUCCESS(rc))
    252237                {
     
    274259        }
    275260        else
     261        {
     262            shClSvcMsgFree(pClient, pMsg);
    276263            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     264        }
    277265    }
    278266    else
     
    307295            if (RT_SUCCESS(rc))
    308296            {
     297                shClSvcClientLock(pClient);
     298
    309299                shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    310 
    311300                rc = shClSvcClientWakeup(pClient);
     301
     302                shClSvcClientUnlock(pClient);
     303
    312304                if (RT_SUCCESS(rc))
    313305                {
     
    322314        }
    323315        else
     316        {
     317            shClSvcMsgFree(pClient, pMsg);
    324318            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     319        }
    325320    }
    326321    else
     
    355350            HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fFlags */);
    356351
     352            shClSvcClientLock(pClient);
     353
    357354            shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    358 
    359355            rc = shClSvcClientWakeup(pClient);
     356
     357            shClSvcClientUnlock(pClient);
     358
    360359            if (RT_SUCCESS(rc))
    361360            {
     
    375374        }
    376375        else
     376        {
     377            shClSvcMsgFree(pClient, pMsg);
    377378            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     379        }
    378380    }
    379381    else
     
    419421            HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fInfo */);
    420422
     423            shClSvcClientLock(pClient);
     424
    421425            shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    422 
    423426            rc = shClSvcClientWakeup(pClient);
     427
     428            shClSvcClientUnlock(pClient);
     429
    424430            if (RT_SUCCESS(rc))
    425431            {
     
    439445        }
    440446        else
     447        {
     448            shClSvcMsgFree(pClient, pMsg);
    441449            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     450        }
    442451    }
    443452    else
     
    460469
    461470/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
    462 int shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
    463                                 PSHCLOBJHANDLE phObj)
     471DECLCALLBACK(int) shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
    464472{
    465473    LogFlowFuncEnter();
     
    485493                                                                     pCtx->pTransfer->State.uID, pEvent->idEvent));
    486494            HGCMSvcSetU64(&pMsg->aParms[1], 0); /* uHandle */
    487             HGCMSvcSetU32(&pMsg->aParms[2], cbPath);
    488             HGCMSvcSetPv (&pMsg->aParms[3], pCreateParms->pszPath, cbPath);
    489             HGCMSvcSetU32(&pMsg->aParms[4], pCreateParms->fCreate);
     495            HGCMSvcSetPv (&pMsg->aParms[2], pCreateParms->pszPath, cbPath);
     496            HGCMSvcSetU32(&pMsg->aParms[3], pCreateParms->fCreate);
     497
     498            shClSvcClientLock(pClient);
    490499
    491500            shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    492 
    493501            rc = shClSvcClientWakeup(pClient);
     502
     503            shClSvcClientUnlock(pClient);
     504
    494505            if (RT_SUCCESS(rc))
    495506            {
     
    516527        }
    517528        else
     529        {
     530            shClSvcMsgFree(pClient, pMsg);
    518531            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     532        }
    519533    }
    520534    else
     
    526540
    527541/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
    528 int shClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
     542DECLCALLBACK(int) shClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
    529543{
    530544    LogFlowFuncEnter();
     
    547561            HGCMSvcSetU64(&pMsg->aParms[1], hObj);
    548562
     563            shClSvcClientLock(pClient);
     564
    549565            shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    550 
    551566            rc = shClSvcClientWakeup(pClient);
     567
     568            shClSvcClientUnlock(pClient);
     569
    552570            if (RT_SUCCESS(rc))
    553571            {
     
    572590        }
    573591        else
     592        {
     593            shClSvcMsgFree(pClient, pMsg);
    574594            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     595        }
    575596    }
    576597    else
     
    582603
    583604/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
    584 int shClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
    585                                 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
     605DECLCALLBACK(int) shClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
     606                                              void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
    586607{
    587608    LogFlowFuncEnter();
     
    606627            HGCMSvcSetU32(&pMsg->aParms[3], fFlags);
    607628
     629            shClSvcClientLock(pClient);
     630
    608631            shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    609 
    610632            rc = shClSvcClientWakeup(pClient);
     633
     634            shClSvcClientUnlock(pClient);
     635
    611636            if (RT_SUCCESS(rc))
    612637            {
     
    634659        }
    635660        else
     661        {
     662            shClSvcMsgFree(pClient, pMsg);
    636663            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     664        }
    637665    }
    638666    else
     
    644672
    645673/** @copydoc SHCLTXPROVIDERIFACE::pfnObjWrite */
    646 int shClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
    647                                  void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
     674DECLCALLBACK(int) shClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
     675                                               void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
    648676{
    649677    LogFlowFuncEnter();
     
    668696            HGCMSvcSetU64(&pMsg->aParms[3], fFlags);
    669697
     698            shClSvcClientLock(pClient);
     699
    670700            shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    671 
    672701            rc = shClSvcClientWakeup(pClient);
     702
     703            shClSvcClientUnlock(pClient);
     704
    673705            if (RT_SUCCESS(rc))
    674706            {
     
    691723        }
    692724        else
     725        {
     726            shClSvcMsgFree(pClient, pMsg);
    693727            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     728        }
    694729    }
    695730    else
     
    883918 */
    884919static int shClSvcTransferGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
    885                                          PSHCLROOTLISTHDR pRootLstHdr)
     920                                         PSHCLLISTHDR pRootLstHdr)
    886921{
    887922    int rc;
     
    889924    if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE)
    890925    {
    891         rc = HGCMSvcGetU32(&aParms[1], &pRootLstHdr->fRoots);
    892         if (RT_SUCCESS(rc))
    893             rc = HGCMSvcGetU32(&aParms[2], &pRootLstHdr->cRoots);
     926        rc = HGCMSvcGetU32(&aParms[1], &pRootLstHdr->fFeatures);
     927        if (RT_SUCCESS(rc))
     928            rc = HGCMSvcGetU64(&aParms[2], &pRootLstHdr->cEntries);
    894929    }
    895930    else
     
    909944 */
    910945static int shClSvcTransferGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
    911                                            PSHCLROOTLISTENTRY pListEntry)
     946                                           PSHCLLISTENTRY pListEntry)
    912947{
    913948    int rc;
     
    10471082            rc = HGCMSvcGetU32(&aParms[3], &pListHdr->fFeatures);
    10481083        if (RT_SUCCESS(rc))
    1049             rc = HGCMSvcGetU64(&aParms[4], &pListHdr->cTotalObjects);
     1084            rc = HGCMSvcGetU64(&aParms[4], &pListHdr->cEntries);
    10501085        if (RT_SUCCESS(rc))
    10511086            rc = HGCMSvcGetU64(&aParms[5], &pListHdr->cbTotalSize);
     
    10821117
    10831118        HGCMSvcSetU32(&aParms[3], pListHdr->fFeatures);
    1084         HGCMSvcSetU64(&aParms[4], pListHdr->cTotalObjects);
     1119        HGCMSvcSetU64(&aParms[4], pListHdr->cEntries);
    10851120        HGCMSvcSetU64(&aParms[5], pListHdr->cbTotalSize);
    10861121
     
    11901225        if (RT_SUCCESS(rc))
    11911226        {
    1192             uint32_t cbData;
    1193             rc = HGCMSvcGetU32(&aParms[2], &cbData);
     1227            uint32_t cbToRead;
     1228            rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
    11941229            if (RT_SUCCESS(rc))
    11951230            {
    11961231                rc = HGCMSvcGetPv(&aParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
    1197                 AssertReturn(cbData == pDataChunk->cbData, VERR_INVALID_PARAMETER);
    1198 
    1199                 /** @todo Implement checksum handling. */
    1200             }
     1232                if (RT_SUCCESS(rc))
     1233                    rc = cbToRead == pDataChunk->cbData ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
     1234            }
     1235
     1236            /** @todo Implement checksum handling. */
    12011237        }
    12021238    }
     
    12411277                {
    12421278                    case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
     1279                    {
     1280                        LogRel(("Shared Clipboard: Guest reported status %s for transfer %RU32\n",
     1281                                ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus), pTransfer->State.uID));
     1282
     1283                        switch (pReply->u.TransferStatus.uStatus)
     1284                        {
     1285                            case SHCLTRANSFERSTATUS_INITIALIZED: /* Initialized -> Started */
     1286                                rc = shClSvcTransferStart(pClient, pTransfer);
     1287                                break;
     1288
     1289                            case SHCLTRANSFERSTATUS_STARTED:
     1290                                break;
     1291
     1292                            case SHCLTRANSFERSTATUS_ERROR:
     1293                            {
     1294                                LogRel(("Shared Clipboard: Guest reported error %Rrc for transfer %RU32\n",
     1295                                        pReply->rc, pTransfer->State.uID));
     1296
     1297                                rc = shClSvcTransferStop(pClient, pTransfer, false /* fWaitForGuest */);
     1298                                break;
     1299                            }
     1300
     1301                            default:
     1302                                rc = shClSvcTransferStop(pClient, pTransfer, true /* fWaitForGuest */);
     1303                                break;
     1304                        }
     1305
    12431306                        RT_FALL_THROUGH();
     1307                    }
    12441308                    case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
    12451309                        RT_FALL_THROUGH();
     
    13331397    PSHCLTRANSFER pTransfer = NULL;
    13341398
     1399    shClSvcClientLock(pClient);
     1400    ASSERT_GUEST_MSG_RETURN(pClient->Pending.uType == 0, ("Already pending! (idClient=%RU32)\n",
     1401                                                          pClient->State.uClientID), VERR_RESOURCE_BUSY);
     1402    shClSvcClientUnlock(pClient);
     1403
    13351404    switch (u32Function)
    13361405    {
     
    13471416                break;
    13481417
     1418            ASSERT_GUEST_RETURN(aParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
     1419
    13491420            rc = HGCMSvcGetU64(&aParms[0], &uCID);
    13501421            if (RT_FAILURE(rc))
     
    13811452                break;
    13821453
     1454            ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Features */
     1455            ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* # Entries  */
     1456
    13831457            if (   ShClTransferGetSource(pTransfer) == SHCLSOURCE_LOCAL
    13841458                && ShClTransferGetDir(pTransfer)    == SHCLTRANSFERDIR_TO_REMOTE)
     
    13881462            }
    13891463            else
    1390             {
    1391                 rc = VERR_INVALID_PARAMETER;
    13921464                break;
    1393             }
    1394 
    1395             SHCLROOTLISTHDR rootListHdr;
     1465
     1466            SHCLLISTHDR rootListHdr;
    13961467            RT_ZERO(rootListHdr);
    13971468
    1398             rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
     1469            rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
     1470            /** @todo BUGBUG What about the features? */
    13991471
    14001472            HGCMSvcSetU64(&aParms[0], 0 /* Context ID */);
    1401             HGCMSvcSetU32(&aParms[1], rootListHdr.fRoots);
    1402             HGCMSvcSetU32(&aParms[2], rootListHdr.cRoots);
     1473            HGCMSvcSetU32(&aParms[1], rootListHdr.fFeatures);
     1474            HGCMSvcSetU64(&aParms[2], rootListHdr.cEntries);
    14031475
    14041476            rc = VINF_SUCCESS;
     
    14081480        case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
    14091481        {
    1410             SHCLROOTLISTHDR lstHdr;
     1482            SHCLLISTHDR lstHdr;
    14111483            rc = shClSvcTransferGetRootListHdr(cParms, aParms, &lstHdr);
    14121484            if (RT_SUCCESS(rc))
    14131485            {
    1414                 void    *pvData = ShClTransferRootListHdrDup(&lstHdr);
    1415                 uint32_t cbData = sizeof(SHCLROOTLISTHDR);
     1486                void    *pvData = ShClTransferListHdrDup(&lstHdr);
     1487                uint32_t cbData = sizeof(SHCLLISTHDR);
    14161488
    14171489                const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
     
    14381510                break;
    14391511
    1440             /* aParms[1] contains fInfo flags, currently unused. */
    1441             uint32_t uIndex;
    1442             rc = HGCMSvcGetU32(&aParms[2], &uIndex);
    1443             if (RT_SUCCESS(rc))
    1444             {
    1445                 SHCLROOTLISTENTRY rootListEntry;
    1446                 rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
    1447                 if (RT_SUCCESS(rc))
    1448                 {
    1449                     HGCMSvcSetPv (&aParms[3], rootListEntry.pszName, rootListEntry.cbName);
    1450                     HGCMSvcSetU32(&aParms[4], rootListEntry.cbInfo);
    1451                     HGCMSvcSetPv (&aParms[5], rootListEntry.pvInfo, rootListEntry.cbInfo);
    1452                 }
    1453             }
     1512            ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Info flags */
     1513            ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* Entry index # */
     1514            ASSERT_GUEST_RETURN(aParms[3].type == VBOX_HGCM_SVC_PARM_PTR,   VERR_WRONG_PARAMETER_TYPE); /* Entry name */
     1515            ASSERT_GUEST_RETURN(aParms[4].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Info size */
     1516            ASSERT_GUEST_RETURN(aParms[5].type == VBOX_HGCM_SVC_PARM_PTR,   VERR_WRONG_PARAMETER_TYPE); /* Info data */
     1517
     1518            uint32_t fInfo;
     1519            rc = HGCMSvcGetU32(&aParms[1], &fInfo);
     1520            AssertRCBreak(rc);
     1521
     1522            ASSERT_GUEST_RETURN(fInfo & VBOX_SHCL_INFO_F_FSOBJINFO, VERR_WRONG_PARAMETER_TYPE); /* Validate info flags.  */
     1523
     1524            uint64_t uIdx;
     1525            rc = HGCMSvcGetU64(&aParms[2], &uIdx);
     1526            AssertRCBreak(rc);
     1527
     1528            PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIdx);
     1529            if (pEntry)
     1530            {
     1531                /* Entry name */
     1532                void  *pvDst = aParms[3].u.pointer.addr;
     1533                size_t cbDst = aParms[3].u.pointer.size;
     1534                memcpy(pvDst, pEntry->pszName, RT_MIN(pEntry->cbName, cbDst));
     1535
     1536                /* Info size */
     1537                HGCMSvcSetU32(&aParms[4], pEntry->cbInfo);
     1538
     1539                /* Info data */
     1540                pvDst = aParms[5].u.pointer.addr;
     1541                cbDst = aParms[5].u.pointer.size;
     1542                memcpy(pvDst, pEntry->pvInfo, RT_MIN(pEntry->cbInfo, cbDst));
     1543            }
     1544            else
     1545                rc = VERR_NOT_FOUND;
     1546
    14541547            break;
    14551548        }
     
    14571550        case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
    14581551        {
    1459             SHCLROOTLISTENTRY lstEntry;
     1552            SHCLLISTENTRY lstEntry;
    14601553            rc = shClSvcTransferGetRootListEntry(cParms, aParms, &lstEntry);
    14611554            if (RT_SUCCESS(rc))
    14621555            {
    1463                 void    *pvData = ShClTransferRootListEntryDup(&lstEntry);
    1464                 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
     1556                void    *pvData = ShClTransferListEntryDup(&lstEntry);
     1557                uint32_t cbData = sizeof(SHCLLISTENTRY);
    14651558
    14661559                const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID));
     
    16581751                break;
    16591752
     1753            ASSERT_GUEST_RETURN(aParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); /* Object handle */
     1754            ASSERT_GUEST_RETURN(aParms[2].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Bytes to read */
     1755            ASSERT_GUEST_RETURN(aParms[3].type == VBOX_HGCM_SVC_PARM_PTR,   VERR_WRONG_PARAMETER_TYPE); /* Data buffer */
     1756            ASSERT_GUEST_RETURN(aParms[4].type == VBOX_HGCM_SVC_PARM_32BIT, VERR_WRONG_PARAMETER_TYPE); /* Checksum data size */
     1757            ASSERT_GUEST_RETURN(aParms[5].type == VBOX_HGCM_SVC_PARM_PTR,   VERR_WRONG_PARAMETER_TYPE); /* Checksum data buffer*/
     1758
    16601759            SHCLOBJHANDLE hObj;
    16611760            rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */
     1761            AssertRCBreak(rc);
    16621762
    16631763            uint32_t cbToRead = 0;
    1664             if (RT_SUCCESS(rc))
    1665                 rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
     1764            rc = HGCMSvcGetU32(&aParms[2], &cbToRead);
     1765            AssertRCBreak(rc);
    16661766
    16671767            void    *pvBuf = NULL;
    16681768            uint32_t cbBuf = 0;
    1669             if (RT_SUCCESS(rc))
    1670                 rc = HGCMSvcGetPv(&aParms[3], &pvBuf, &cbBuf);
     1769            rc = HGCMSvcGetPv(&aParms[3], &pvBuf, &cbBuf);
     1770            AssertRCBreak(rc);
    16711771
    16721772            LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, cbToRead=%RU32, rc=%Rrc\n", hObj, cbBuf, cbToRead, rc));
     
    16881788                if (RT_SUCCESS(rc))
    16891789                {
    1690                     HGCMSvcSetU32(&aParms[3], cbRead);
     1790                    HGCMSvcSetU32(&aParms[2], cbRead);
    16911791
    16921792                    /** @todo Implement checksum support. */
     
    16991799        {
    17001800            SHCLOBJDATACHUNK dataChunk;
     1801
    17011802            rc = shClSvcTransferGetObjDataChunk(cParms, aParms, &dataChunk);
    17021803            if (RT_SUCCESS(rc))
     
    17511852    switch (u32Function)
    17521853    {
    1753         case VBOX_SHCL_HOST_FN_CANCEL: /** @todo Implement this. */
    1754             break;
    1755 
    1756         case VBOX_SHCL_HOST_FN_ERROR: /** @todo Implement this. */
     1854        case VBOX_SHCL_HOST_FN_CANCEL: /** @todo BUGBUG Implement this. */
     1855            break;
     1856
     1857        case VBOX_SHCL_HOST_FN_ERROR: /** @todo BUGBUG Implement this. */
    17571858            break;
    17581859
     
    17931894 * @param   ppEvent             Where to return the wait event on success. Optional.
    17941895 *                              Must be released by the caller with ShClEventRelease().
     1896 *
     1897 * @note    Caller must enter critical section.
    17951898 */
    17961899int shClSvcTransferSendStatus(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
     
    18381941        rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
    18391942
     1943    if (RT_FAILURE(rc))
     1944        LogRel(("Shared Clipboard: Reporting status %s (%Rrc) for transfer %RU32 to guest failed with %Rrc\n",
     1945                ShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID, rc));
     1946
    18401947    LogFlowFuncLeaveRC(rc);
    18411948    return rc;
     
    18431950
    18441951/**
    1845  * Starts a new transfer, waiting for acknowledgement by the guest side.
     1952 * Cleans up (unregisters and destroys) all transfers not in the 'started' state (anymore).
     1953 *
     1954 * @param   pClient             Client to clean up transfers for.
     1955 *
     1956 * @note    Caller needs to take the critical section.
     1957 */
     1958void shClSvcTransferCleanupAllUnused(PSHCLCLIENT pClient)
     1959{
     1960    LogFlowFuncEnter();
     1961
     1962    PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
     1963
     1964    /* Remove all transfers which are not in a running state (e.g. only announced). */
     1965    PSHCLTRANSFER pTransfer, pTransferNext;
     1966    RTListForEachSafe(&pTxCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
     1967    {
     1968        if (ShClTransferGetStatus(pTransfer) != SHCLTRANSFERSTATUS_STARTED)
     1969        {
     1970            /* Let the guest know. */
     1971            int rc2 = shClSvcTransferSendStatus(pClient, pTransfer,
     1972                                                SHCLTRANSFERSTATUS_UNINITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
     1973            AssertRC(rc2);
     1974
     1975            ShClTransferCtxTransferUnregister(pTxCtx, pTransfer->State.uID);
     1976
     1977            ShClTransferDestroy(pTransfer);
     1978
     1979            RTMemFree(pTransfer);
     1980            pTransfer = NULL;
     1981        }
     1982    }
     1983}
     1984
     1985/**
     1986 * Initializes a new transfer and sends the status to the guest.
    18461987 *
    18471988 * @note Assumes that the client's critical section is taken.
     
    18531994 * @param   ppTransfer          Where to return the created transfer on success. Optional.
    18541995 */
    1855 int shClSvcTransferStart(PSHCLCLIENT pClient,
    1856                          SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
    1857                          PSHCLTRANSFER *ppTransfer)
    1858 {
     1996int shClSvcTransferInit(PSHCLCLIENT pClient,
     1997                        SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
     1998                        PSHCLTRANSFER *ppTransfer)
     1999{
     2000    Assert(RTCritSectIsOwner(&pClient->CritSect));
     2001
    18592002    AssertPtrReturn(pClient, VERR_INVALID_POINTER);
    18602003    /* ppTransfer is optional. */
     
    18622005    LogFlowFuncEnter();
    18632006
     2007    shClSvcTransferCleanupAllUnused(pClient);
     2008
    18642009    PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
    18652010
    1866     ShClTransferCtxCleanup(pTxCtx);
    1867 
    18682011    int rc;
    18692012
    18702013    if (!ShClTransferCtxTransfersMaximumReached(pTxCtx))
    18712014    {
    1872         LogRel2(("Shared Clipboard: Starting %s transfer ...\n", enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "read" : "write"));
     2015        LogRel2(("Shared Clipboard: Initializing %s transfer ...\n",
     2016                 enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "guest -> host" : "host -> guest"));
    18732017
    18742018        PSHCLTRANSFER pTransfer;
     
    18762020        if (RT_SUCCESS(rc))
    18772021        {
    1878             SHCLTXPROVIDERCREATIONCTX creationCtx;
    1879             RT_ZERO(creationCtx);
     2022            SHCLTXPROVIDER Provider;
     2023            RT_ZERO(Provider);
    18802024
    18812025            /* Assign local provider first and overwrite interface methods below if needed. */
    1882             VBClTransferQueryIfaceLocal(&creationCtx.Interface);
     2026            VBClTransferProviderLocalQueryInterface(&Provider);
    18832027
    18842028            if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host. */
    18852029            {
    1886                 creationCtx.Interface.pfnRootsGet      = shClSvcTransferIfaceRootsGet;
    1887 
    1888                 creationCtx.Interface.pfnListOpen      = shClSvcTransferIfaceListOpen;
    1889                 creationCtx.Interface.pfnListClose     = shClSvcTransferIfaceListClose;
    1890                 creationCtx.Interface.pfnListHdrRead   = shClSvcTransferIfaceListHdrRead;
    1891                 creationCtx.Interface.pfnListEntryRead = shClSvcTransferIfaceListEntryRead;
    1892 
    1893                 creationCtx.Interface.pfnObjOpen       = shClSvcTransferIfaceObjOpen;
    1894                 creationCtx.Interface.pfnObjClose      = shClSvcTransferIfaceObjClose;
    1895                 creationCtx.Interface.pfnObjRead       = shClSvcTransferIfaceObjRead;
     2030                Provider.Interface.pfnRootListRead  = shClSvcTransferIfaceRootListRead;
     2031
     2032                Provider.Interface.pfnListOpen      = shClSvcTransferIfaceListOpen;
     2033                Provider.Interface.pfnListClose     = shClSvcTransferIfaceListClose;
     2034                Provider.Interface.pfnListHdrRead   = shClSvcTransferIfaceListHdrRead;
     2035                Provider.Interface.pfnListEntryRead = shClSvcTransferIfaceListEntryRead;
     2036
     2037                Provider.Interface.pfnObjOpen       = shClSvcTransferIfaceObjOpen;
     2038                Provider.Interface.pfnObjClose      = shClSvcTransferIfaceObjClose;
     2039                Provider.Interface.pfnObjRead       = shClSvcTransferIfaceObjRead;
    18962040            }
    18972041            else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Host -> Guest. */
    18982042            {
    1899                 creationCtx.Interface.pfnListHdrWrite   = shClSvcTransferIfaceListHdrWrite;
    1900                 creationCtx.Interface.pfnListEntryWrite = shClSvcTransferIfaceListEntryWrite;
    1901                 creationCtx.Interface.pfnObjWrite       = shClSvcTransferIfaceObjWrite;
     2043                Provider.Interface.pfnListHdrWrite   = shClSvcTransferIfaceListHdrWrite;
     2044                Provider.Interface.pfnListEntryWrite = shClSvcTransferIfaceListEntryWrite;
     2045                Provider.Interface.pfnObjWrite       = shClSvcTransferIfaceObjWrite;
    19022046            }
    19032047            else
    19042048                AssertFailed();
    19052049
    1906             creationCtx.enmSource = pClient->State.enmSource;
    1907             creationCtx.pvUser    = pClient;
    1908 
    1909             rc = ShClTransferSetProviderIface(pTransfer, &creationCtx);
    1910             if (RT_SUCCESS(rc))
    1911             {
     2050            Provider.enmSource = pClient->State.enmSource;
     2051            Provider.pvUser    = pClient;
     2052
     2053            rc = ShClTransferSetProvider(pTransfer, &Provider);
     2054            if (RT_SUCCESS(rc))
     2055            {
     2056                ShClTransferSetCallbacks(pTransfer, &pClient->Transfers.Callbacks);
     2057
    19122058                rc = ShClTransferInit(pTransfer, enmDir, enmSource);
    19132059                if (RT_SUCCESS(rc))
     
    19202066                        if (RT_SUCCESS(rc))
    19212067                        {
    1922                             if (RT_SUCCESS(rc))
    1923                                 rc = ShClTransferStart(pTransfer);
    1924 
    1925                             if (RT_SUCCESS(rc))
    1926                             {
    1927                                 PSHCLEVENT pEvent;
    1928                                 rc = shClSvcTransferSendStatus(pClient, pTransfer,
    1929                                                                SHCLTRANSFERSTATUS_INITIALIZED, VINF_SUCCESS, &pEvent);
    1930                                 if (RT_SUCCESS(rc))
    1931                                 {
    1932                                     LogRel2(("Shared Clipboard: Waiting for start of transfer %RU32 on guest ...\n",
    1933                                              pTransfer->State.uID));
    1934 
    1935                                     /* Leave the client's critical section before waiting. */
    1936                                     RTCritSectLeave(&pClient->CritSect);
    1937 
    1938                                     PSHCLEVENTPAYLOAD pPayload = NULL;
    1939                                     rc = ShClEventWait(pEvent, pTransfer->uTimeoutMs, &pPayload);
    1940                                     if (RT_SUCCESS(rc))
    1941                                     {
    1942                                         Assert(pPayload->cbData == sizeof(SHCLREPLY));
    1943                                         PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
    1944                                         AssertPtr(pReply);
    1945 
    1946                                         Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
    1947 
    1948                                         if (pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_STARTED)
    1949                                         {
    1950                                             LogRel2(("Shared Clipboard: Started transfer %RU32 on guest\n", pTransfer->State.uID));
    1951                                         }
    1952                                         else
    1953                                             LogRel(("Shared Clipboard: Guest reported status %s (error %Rrc) while starting transfer %RU32\n",
    1954                                                     ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus),
    1955                                                     pReply->rc, pTransfer->State.uID));
    1956 
    1957                                         rc = pReply->rc; /* Set guest rc. */
    1958                                     }
    1959                                     else
    1960                                     {
    1961                                         if (rc == VERR_NOT_SUPPORTED)
    1962                                             LogRelMax(3, ("Shared Clipboard: File transfers are not supported by the installed Guest Additions.\n"));
    1963                                         else
    1964                                             LogRel(("Shared Clipboard: Unable to start transfer %RU32 on guest, rc=%Rrc\n",
    1965                                                     pTransfer->State.uID, rc));
    1966                                     }
    1967 
    1968                                     ShClPayloadFree(pPayload);
    1969                                     ShClEventRelease(pEvent);
    1970 
    1971                                     /* Re-enter the client's critical section again. */
    1972                                     RTCritSectEnter(&pClient->CritSect);
    1973                                 }
    1974                             }
     2068                            /* Tell the guest that we've initialized the transfer locally. */
     2069                            rc = shClSvcTransferSendStatus(pClient, pTransfer,
     2070                                                           SHCLTRANSFERSTATUS_INITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
    19752071                        }
    19762072                    }
     
    20072103
    20082104/**
    2009  * Stops (and destroys) a transfer, communicating the status to the guest side.
     2105 * Starts a transfer, communicating the status to the guest side.
    20102106 *
    20112107 * @returns VBox status code.
     
    20132109 * @param   pTransfer           Transfer to stop.
    20142110 */
    2015 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    2016 {
     2111int shClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
     2112{
     2113    LogRel2(("Shared Clipboard: Starting transfer %RU32 ...\n", pTransfer->State.uID));
     2114
     2115    shClSvcClientLock(pClient);
     2116
     2117    int rc = ShClTransferStart(pTransfer);
     2118
     2119    /* Let the guest know in any case
     2120     * (so that it can tear down the transfer on error as well). */
     2121    int rc2 = shClSvcTransferSendStatus(pClient, pTransfer,
     2122                                        RT_SUCCESS(rc) ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc, NULL /* ppEvent */);
     2123    if (RT_SUCCESS(rc))
     2124        rc = rc2;
     2125
     2126    shClSvcClientUnlock(pClient);
     2127    return rc;
     2128}
     2129
     2130/**
     2131 * Stops (and destroys) a transfer, communicating the status to the guest side.
     2132 *
     2133 * @returns VBox status code.
     2134 * @param   pClient             Client that owns the transfer.
     2135 * @param   pTransfer           Transfer to stop. The pointer will be invalid on success.
     2136 * @param   fWaitForGuest       Set to \c true to wait for acknowledgement from guest, or \c false to skip waiting.
     2137 */
     2138int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest)
     2139{
     2140    LogRel2(("Shared Clipboard: Stopping transfer %RU32 ...\n", pTransfer->State.uID));
     2141
     2142    shClSvcClientLock(pClient);
     2143
    20172144    PSHCLEVENT pEvent;
    20182145    int rc = shClSvcTransferSendStatus(pClient, pTransfer,
    20192146                                       SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS, &pEvent);
    2020     if (RT_SUCCESS(rc))
     2147    if (   RT_SUCCESS(rc)
     2148        && fWaitForGuest)
    20212149    {
    20222150        LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID));
    20232151
     2152        shClSvcClientUnlock(pClient);
     2153
    20242154        rc = ShClEventWait(pEvent, pTransfer->uTimeoutMs, NULL /* ppPayload */);
    20252155        if (RT_SUCCESS(rc))
     
    20272157
    20282158        ShClEventRelease(pEvent);
     2159
     2160        shClSvcClientLock(pClient);
    20292161    }
    20302162
     
    20432175    }
    20442176
     2177    if (RT_SUCCESS(rc))
     2178        rc = rc2;
     2179
     2180    if (RT_FAILURE(rc))
     2181        LogRel(("Shared Clipboard: Stopping transfer %RU32 failed with rc=%Rrc\n",
     2182                pTransfer->State.uID, rc));
     2183
     2184    shClSvcClientUnlock(pClient);
     2185
    20452186    LogFlowFuncLeaveRC(rc);
    20462187    return rc;
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp

    r99967 r100204  
    6868{
    6969    /** Handle for window message handling thread. */
    70     RTTHREAD    hThread;
     70    RTTHREAD                   hThread;
    7171    /** Structure for keeping and communicating with service client. */
    72     PSHCLCLIENT pClient;
     72    PSHCLCLIENT                pClient;
    7373    /** Windows-specific context data. */
    74     SHCLWINCTX  Win;
     74    SHCLWINCTX                 Win;
    7575};
    7676
     
    9393 *          (specified in @a pcbActualDst output parameter).
    9494 * @param   u32Format           VBox clipboard format (VBOX_SHCL_FMT_XXX) of copied data.
     95 *                              VBOX_SHCL_FMT_NONE returns 0 data.
    9596 * @param   pvSrc               Pointer to host clipboard data.
    9697 * @param   cbSrc               Size (in bytes) of actual clipboard data to copy.
     
    102103 *                              function returns VINF_BUFFER_OVERFLOW.
    103104 */
    104 static int vboxClipboardSvcWinDataGet(uint32_t u32Format, const void *pvSrc, uint32_t cbSrc,
     105static int vboxClipboardSvcWinDataGet(SHCLFORMAT u32Format, const void *pvSrc, uint32_t cbSrc,
    105106                                      void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
    106107{
    107     AssertPtrReturn(pvSrc,        VERR_INVALID_POINTER);
    108     AssertReturn   (cbSrc,        VERR_INVALID_PARAMETER);
    109     AssertPtrReturn(pvDst,        VERR_INVALID_POINTER);
    110     AssertReturn   (cbDst,        VERR_INVALID_PARAMETER);
    111108    AssertPtrReturn(pcbActualDst, VERR_INVALID_POINTER);
     109    if (u32Format == VBOX_SHCL_FMT_NONE)
     110    {
     111        *pcbActualDst = 0;
     112        return VINF_SUCCESS;
     113    }
     114
     115    AssertPtrReturn(pvSrc, VERR_INVALID_POINTER);
     116    AssertReturn   (cbSrc, VERR_INVALID_PARAMETER);
     117    AssertPtrReturn(pvDst, VERR_INVALID_POINTER);
     118    AssertReturn   (cbDst, VERR_INVALID_PARAMETER);
    112119
    113120    LogFlowFunc(("cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
     
    152159}
    153160
    154 static int vboxClipboardSvcWinDataRead(PSHCLCONTEXT pCtx, UINT uFormat, void **ppvData, uint32_t *pcbData)
    155 {
    156     SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(uFormat);
    157     LogFlowFunc(("uFormat=%u -> uFmt=0x%x\n", uFormat, fFormat));
    158 
    159     if (fFormat == VBOX_SHCL_FMT_NONE)
    160     {
    161         LogRel2(("Shared Clipboard: Windows format %u not supported, ignoring\n", uFormat));
    162         return VERR_NOT_SUPPORTED;
    163     }
     161/**
     162 * Worker for a reading clipboard from the guest.
     163 */
     164static int vboxClipboardSvcWinReadDataFromGuestWorker(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppvData, uint32_t *pcbData)
     165{
     166    LogFlowFunc(("uFmt=%#x\n", uFmt));
     167
     168    int rc;
    164169
    165170    PSHCLEVENT pEvent;
    166     int rc = ShClSvcGuestDataRequest(pCtx->pClient, fFormat, &pEvent);
     171    rc = ShClSvcReadDataFromGuestAsync(pCtx->pClient, uFmt, &pEvent);
    167172    if (RT_SUCCESS(rc))
    168173    {
     
    171176        if (RT_SUCCESS(rc))
    172177        {
    173             *ppvData = pPayload ? pPayload->pvData : NULL;
    174             *pcbData = pPayload ? pPayload->cbData : 0;
     178            if (ppvData)
     179                *ppvData = pPayload ? pPayload->pvData : NULL;
     180            if (pcbData)
     181                *pcbData = pPayload ? pPayload->cbData : 0;
    175182        }
    176183
     
    183190    LogFlowFuncLeaveRC(rc);
    184191    return rc;
     192}
     193
     194static int vboxClipboardSvcWinReadDataFromGuest(PSHCLCONTEXT pCtx, UINT uWinFormat, void **ppvData, uint32_t *pcbData)
     195{
     196    SHCLFORMAT uVBoxFmt = SharedClipboardWinClipboardFormatToVBox(uWinFormat);
     197    if (uVBoxFmt == VBOX_SHCL_FMT_NONE)
     198    {
     199        LogRel2(("Shared Clipboard: Windows format %u not supported, ignoring\n", uWinFormat));
     200        return VERR_NOT_SUPPORTED;
     201    }
     202
     203    int rc = vboxClipboardSvcWinReadDataFromGuestWorker(pCtx, uVBoxFmt, ppvData, pcbData);
     204
     205    LogFlowFuncLeaveRC(rc);
     206    return rc;
     207}
     208
     209/**
     210 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
     211 *
     212 * Called from the IDataObject implementation to request data from the guest.
     213 *
     214 * @thread  Windows event thread.
     215 */
     216static DECLCALLBACK(int) vboxClipboardSvcWinRequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
     217                                                                          SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
     218{
     219    RT_NOREF(pvUser);
     220
     221    LogFlowFuncEnter();
     222
     223    int rc = vboxClipboardSvcWinReadDataFromGuestWorker(pCtx, uFmt, ppv, pcb);
     224
     225    LogFlowFuncLeaveRC(rc);
     226
     227    return rc;
     228}
     229
     230/**
     231 * @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnStart
     232 *
     233 * Called on transfer start to notify the "in-flight" IDataObject about a started transfer.
     234 *
     235 * @thread  Service main thread.
     236 */
     237static DECLCALLBACK(void) vboxClipboardSvcWinTransferStartedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     238{
     239    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     240    AssertPtr(pCtx);
     241
     242    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     243    AssertPtr(pTransfer);
     244
     245    const SHCLTRANSFERDIR enmDir = ShClTransferGetDir(pTransfer);
     246
     247    int rc = VINF_SUCCESS;
     248
     249    LogFlowFunc(("pCtx=%p, idTransfer=%RU32, enmDir=%RU32\n", pCtx, ShClTransferGetID(pTransfer), enmDir));
     250
     251    /* The host wants to transfer data from the guest. */
     252    if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
     253    {
     254        rc = RTCritSectEnter(&pCtx->Win.CritSect);
     255        if (RT_SUCCESS(rc))
     256        {
     257            SharedClipboardWinDataObject *pObj = pCtx->Win.pDataObjInFlight;
     258            AssertPtrReturnVoid(pObj);
     259            rc = pObj->SetAndStartTransfer(pTransfer);
     260
     261            pCtx->Win.pDataObjInFlight = NULL; /* Hand off to Windows. */
     262
     263            int rc2 = RTCritSectLeave(&pCtx->Win.CritSect);
     264            AssertRC(rc2);
     265        }
     266    }
     267
     268    if (RT_FAILURE(rc))
     269        LogRel(("Shared Clipboard: Starting transfer failed, rc=%Rrc\n", rc));
     270
     271    LogFlowFunc(("LEAVE: idTransfer=%RU32, rc=%Rrc\n", ShClTransferGetID(pTransfer), rc));
    185272}
    186273
     
    295382                void    *pvData = NULL;
    296383                uint32_t cbData = 0;
    297                 int rc = vboxClipboardSvcWinDataRead(pCtx, uFormat, &pvData, &cbData);
     384                int rc = vboxClipboardSvcWinReadDataFromGuest(pCtx, uFormat, &pvData, &cbData);
    298385                if (   RT_SUCCESS(rc)
    299386                    && pvData
     
    343430        }
    344431
    345         case SHCL_WIN_WM_REPORT_FORMATS:
     432        case SHCL_WIN_WM_REPORT_FORMATS: /* Guest reported clipboard formats. */
    346433        {
    347434            /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT (or via IDataObject). */
     
    349436            LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: fFormats=%#xn", fFormats));
    350437
     438            int rc = SharedClipboardWinClearAndAnnounceFormats(pWinCtx, fFormats, hWnd);
    351439#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    352             if (fFormats & VBOX_SHCL_FMT_URI_LIST)
    353             {
    354                 PSHCLTRANSFER pTransfer;
    355                 int rc = shClSvcTransferStart(pCtx->pClient,
    356                                               SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
    357                                               &pTransfer);
    358                 if (RT_SUCCESS(rc))
    359                 {
    360                     /* Create the IDataObject implementation the host OS needs and assign
    361                      * the newly created transfer to this object. */
    362                     rc = SharedClipboardWinTransferCreate(&pCtx->Win, pTransfer);
    363 
    364                     /*  Note: The actual requesting + retrieving of data will be done in the IDataObject implementation
    365                               (ClipboardDataObjectImpl::GetData()). */
    366                 }
    367                 else
    368                     LogRel(("Shared Clipboard: Initializing read transfer failed with %Rrc\n", rc));
    369             }
    370             else
    371             {
     440            if (   RT_SUCCESS(rc)
     441                && fFormats & VBOX_SHCL_FMT_URI_LIST)
     442            {
     443                /*
     444                 * The host requested data from the guest as URI list.
     445                 *
     446                 * This means on Windows we
     447                 * - need to first create an own IDataObject and push it on the clipboard
     448                 * - register a transfer locally so that we have a valid ID for it
     449                 *
     450                 * That way Windows will recognize that there is a data transfer "in flight".
     451                 *
     452                 * As soon as the user requests to "paste" the data (transfer), the IDataObject will try to read data via
     453                 * the pfnOnRequestDataFromSource callback.
     454                 */
     455                SHCLCALLBACKS Callbacks;
     456                RT_ZERO(Callbacks);
     457                Callbacks.pfnOnRequestDataFromSource = vboxClipboardSvcWinRequestDataFromSourceCallback;
     458
     459                rc = SharedClipboardWinTransferCreateAndSetDataObject(pWinCtx, pCtx, &Callbacks);
     460            }
    372461#endif
    373                 int rc = SharedClipboardWinClearAndAnnounceFormats(pWinCtx, fFormats, hWnd);
    374                 if (RT_FAILURE(rc))
    375                     LogRel(("Shared Clipboard: Reporting clipboard formats %#x to Windows host failed with %Rrc\n", fFormats, rc));
    376 
    377 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    378             }
    379 #endif
     462            if (RT_FAILURE(rc))
     463                LogRel(("Shared Clipboard: Reporting clipboard formats %#x to Windows host failed with %Rrc\n", fFormats, rc));
     464
    380465            LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: lastErr=%ld\n", GetLastError()));
    381466            break;
     
    605690    else
    606691        LogRel(("Shared Clipboard: Initialized OLE\n"));
    607 #endif
     692#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    608693
    609694    return VINF_SUCCESS;
     
    635720        {
    636721            rc = RTThreadCreate(&pCtx->hThread, vboxClipboardSvcWinThread, pCtx /* pvUser */, _64K /* Stack size */,
    637                                 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
     722                                RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "ShClWin");
    638723            if (RT_SUCCESS(rc))
    639724            {
     
    645730        pClient->State.pCtx = pCtx;
    646731        pClient->State.pCtx->pClient = pClient;
     732
     733#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     734        /*
     735         * Init transfer callbacks.
     736         */
     737        RT_ZERO(pClient->Transfers.Callbacks);
     738        pClient->Transfers.Callbacks.pfnOnStarted = vboxClipboardSvcWinTransferStartedCallback;
     739
     740        pClient->Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
     741        pClient->Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
     742#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    647743    }
    648744    else
     
    718814     * The guest announced formats. Forward to the window thread.
    719815     */
    720     PostMessage(pCtx->Win.hWnd, SHCL_WIN_WM_REPORT_FORMATS,
    721                 0 /* wParam */, fFormats /* lParam */);
    722 
     816    PostMessage(pCtx->Win.hWnd, SHCL_WIN_WM_REPORT_FORMATS, 0 /* wParam */, fFormats /* lParam */);
    723817
    724818    LogFlowFuncLeaveRC(VINF_SUCCESS);
     
    821915        else if (uFmt & VBOX_SHCL_FMT_URI_LIST)
    822916        {
    823             AssertFailed(); /** @todo */
     917            hClip = hClip = GetClipboardData(CF_HDROP);
     918            if (hClip)
     919            {
     920                HDROP hDrop = (HDROP)GlobalLock(hClip);
     921                if (hDrop)
     922                {
     923                    char    *pszList = NULL;
     924                    uint32_t cbList;
     925                    rc = SharedClipboardWinTransferDropFilesToStringList((DROPFILES *)hDrop, &pszList, &cbList);
     926
     927                    GlobalUnlock(hClip);
     928
     929                    if (RT_SUCCESS(rc))
     930                    {
     931                        if (cbList <= cbData)
     932                        {
     933                            memcpy(pvData, pszList, cbList);
     934                            *pcbActual = cbList;
     935                        }
     936
     937                        RTStrFree(pszList);
     938                    }
     939                }
     940                else
     941                    LogRel(("Shared Clipboard: Unable to lock clipboard data, last error: %ld\n", GetLastError()));
     942            }
     943            else
     944                LogRel(("Shared Clipboard: Unable to retrieve clipboard data from clipboard (CF_HDROP), last error: %ld\n",
     945                        GetLastError()));
    824946        }
    825947#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     
    827949    }
    828950
    829     if (hClip == NULL) /* Empty data is not fatal. */
    830     {
    831         /* Reply with empty data. */
    832         vboxClipboardSvcWinDataGet(0, NULL, 0, pvData, cbData, pcbActual);
    833     }
    834 
    835951    if (RT_FAILURE(rc))
    836952        LogRel(("Shared Clipboard: Error reading host clipboard data in format %#x from Windows, rc=%Rrc\n", uFmt, rc));
     
    882998    const PSHCLWINCTX pWinCtx = &pClient->State.pCtx->Win;
    883999
    884     int rc = SharedClipboardWinGetRoots(pWinCtx, pTransfer);
     1000    int rc = SharedClipboardWinTransferGetRootsFromClipboard(pWinCtx, pTransfer);
    8851001
    8861002    LogFlowFuncLeaveRC(rc);
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp

    r100018 r100204  
    4444#include <iprt/errcore.h>
    4545
     46#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     47# include <VBox/GuestHost/SharedClipboard-transfers.h>
     48#endif
     49
    4650#include "VBoxSharedClipboardSvc-internal.h"
    4751
     
    7478*   Prototypes                                                                                                                   *
    7579*********************************************************************************************************************************/
    76 static DECLCALLBACK(int) shClReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser);
    77 static DECLCALLBACK(int) shClSendDataToDestCallback(PSHCLCONTEXT pCtx, void *pv, uint32_t cb, void *pvUser);
    78 static DECLCALLBACK(int) shClRequestDataFromSourceCallback(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser);
     80static DECLCALLBACK(int) shClSvcX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser);
     81static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser);
    7982
    8083
     
    9194    RT_ZERO(pBackend->Callbacks);
    9295    /* Use internal callbacks by default. */
    93     pBackend->Callbacks.pfnReportFormats           = shClReportFormatsCallback;
    94     pBackend->Callbacks.pfnOnRequestDataFromSource = shClRequestDataFromSourceCallback;
    95     pBackend->Callbacks.pfnOnSendDataToDest        = shClSendDataToDestCallback;
     96    pBackend->Callbacks.pfnReportFormats           = shClSvcX11ReportFormatsCallback;
     97    pBackend->Callbacks.pfnOnRequestDataFromSource = shClSvcX11RequestDataFromSourceCallback;
    9698
    9799    return VINF_SUCCESS;
     
    112114
    113115    SET_FN_IF_NOT_NULL(ReportFormats);
    114     SET_FN_IF_NOT_NULL(OnClipboardRead);
    115     SET_FN_IF_NOT_NULL(OnClipboardWrite);
    116116    SET_FN_IF_NOT_NULL(OnRequestDataFromSource);
    117     SET_FN_IF_NOT_NULL(OnSendDataToDest);
    118117
    119118#undef SET_FN_IF_NOT_NULL
     
    190189}
    191190
    192 /*
    193  * Shut down the shared clipboard service and "disconnect" the guest.
     191/**
     192 * Shuts down the shared clipboard service and "disconnect" the guest.
    194193 * Note!  Host glue code
    195194 */
     
    225224}
    226225
     226/**
     227 * Reports clipboard formats to the host clipboard.
     228 */
    227229int ShClBackendReportFormats(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, SHCLFORMATS fFormats)
    228230{
    229231    RT_NOREF(pBackend);
    230232
    231     int rc = ShClX11ReportFormatsToX11(&pClient->State.pCtx->X11, fFormats);
    232 
    233     LogFlowFuncLeaveRC(rc);
    234     return rc;
    235 }
    236 
    237 /** Structure describing a request for clipoard data from the guest. */
    238 struct CLIPREADCBREQ
    239 {
    240     /** User-supplied data pointer, based on the request type. */
    241     void                *pv;
    242     /** The size (in bytes) of the the user-supplied pointer in pv. */
    243     uint32_t             cb;
    244     /** The actual size of the data written. */
    245     uint32_t            *pcbActual;
    246     /** The request's event ID. */
    247     SHCLEVENTID          idEvent;
    248 };
    249 
    250 /**
     233    int rc = ShClX11ReportFormatsToX11Async(&pClient->State.pCtx->X11, fFormats);
     234
     235    LogFlowFuncLeaveRC(rc);
     236    return rc;
     237}
     238
     239/**
     240 * Reads data from the host clipboard.
     241 *
     242 * Schedules a request to the X11 event thread.
     243 *
    251244 * @note   We always fail or complete asynchronously.
    252  * @note   On success allocates a CLIPREADCBREQ structure which must be
    253  *         freed in ClipCompleteDataRequestFromX11 when it is called back from
    254  *         the backend code.
    255245 */
    256246int ShClBackendReadData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat,
     
    269259                 pClient, uFormat, pvData, cbData, pcbActual));
    270260
    271     int rc;
    272 
    273     CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
    274     if (pReq)
    275     {
    276         PSHCLEVENT pEvent;
    277         rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
     261    PSHCLEVENT pEvent;
     262    int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
     263    if (RT_SUCCESS(rc))
     264    {
     265        rc = ShClX11ReadDataFromX11Async(&pClient->State.pCtx->X11, uFormat, cbData, pEvent);
    278266        if (RT_SUCCESS(rc))
    279267        {
    280             pReq->pv        = pvData;
    281             pReq->cb        = cbData;
    282             pReq->pcbActual = pcbActual;
    283             pReq->idEvent   = pEvent->idEvent;
    284 
    285             /* Note: ShClX11ReadDataFromX11() will consume pReq on success. */
    286             rc = ShClX11ReadDataFromX11(&pClient->State.pCtx->X11, uFormat, pReq);
     268            PSHCLEVENTPAYLOAD pPayload;
     269            rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
    287270            if (RT_SUCCESS(rc))
    288271            {
    289                 PSHCLEVENTPAYLOAD pPayload;
    290                 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
    291                 if (RT_SUCCESS(rc))
     272                if (pPayload)
    292273                {
    293                     if (pPayload)
    294                     {
    295                         memcpy(pvData, pPayload->pvData, RT_MIN(cbData, pPayload->cbData));
    296 
    297                         *pcbActual = (uint32_t)pPayload->cbData;
    298 
    299                         ShClPayloadFree(pPayload);
    300                     }
    301                     else /* No payload given; could happen on invalid / not-expected formats. */
    302                         *pcbActual = 0;
     274                    Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
     275                    PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
     276
     277                    size_t const cbToCopy = RT_MIN(cbData, pPayload->cbData);
     278                    if (cbToCopy) /* memcpy doesn't like 0 byte inputs. */
     279                        memcpy(pvData, pResp->Read.pvData, RT_MIN(cbData, pPayload->cbData));
     280
     281                    LogRel2(("Shared Clipboard: Read %RU32 bytes host X11 clipboard data\n", pResp->Read.cbData));
     282
     283                    *pcbActual = pResp->Read.cbData;
     284
     285                    RTMemFree(pResp->Read.pvData);
     286                    pResp->Read.cbData = 0;
     287
     288                    ShClPayloadFree(pPayload);
    303289                }
     290                else /* No payload given; could happen on invalid / not-expected formats. */
     291                    *pcbActual = 0;
    304292            }
    305 
    306             ShClEventRelease(pEvent);
    307         }
    308 
    309         if (RT_FAILURE(rc))
    310             RTMemFree(pReq);
    311     }
    312     else
    313         rc = VERR_NO_MEMORY;
     293        }
     294
     295        ShClEventRelease(pEvent);
     296    }
    314297
    315298    if (RT_FAILURE(rc))
     
    320303}
    321304
    322 int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData)
     305int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
     306                         SHCLFORMAT uFormat, void *pvData, uint32_t cbData)
    323307{
    324308    RT_NOREF(pBackend, pClient, pCmdCtx, uFormat, pvData, cbData);
     
    332316}
    333317
    334 /** @copydoc SHCLCALLBACKS::pfnReportFormats */
    335 static DECLCALLBACK(int) shClReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
     318/**
     319 * @copydoc SHCLCALLBACKS::pfnReportFormats
     320 *
     321 * Reports clipboard formats to the guest.
     322 */
     323static DECLCALLBACK(int) shClSvcX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
    336324{
    337325    RT_NOREF(pvUser);
     
    362350}
    363351
    364 /** @copydoc SHCLCALLBACKS::pfnOnSendDataToDest */
    365 static DECLCALLBACK(int) shClSendDataToDestCallback(PSHCLCONTEXT pCtx, void *pv, uint32_t cb, void *pvUser)
    366 {
    367     AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
    368     AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
    369 
    370     PSHCLX11READDATAREQ pData = (PSHCLX11READDATAREQ)pvUser;
    371     CLIPREADCBREQ      *pReq  = pData->pReq;
    372 
    373     LogFlowFunc(("rcCompletion=%Rrc, pReq=%p, pv=%p, cb=%RU32, idEvent=%RU32\n",
    374                  pData->rcCompletion, pReq, pv, cb, pReq->idEvent));
    375 
    376     if (pReq->idEvent != NIL_SHCLEVENTID)
    377     {
    378         int rc2;
    379 
    380         PSHCLEVENTPAYLOAD pPayload = NULL;
    381         if (   RT_SUCCESS(pData->rcCompletion)
    382             && pv
    383             && cb)
    384         {
    385             rc2 = ShClPayloadAlloc(pReq->idEvent, pv, cb, &pPayload);
    386             AssertRC(rc2);
    387         }
    388 
    389         rc2 = RTCritSectEnter(&pCtx->pClient->CritSect);
    390         if (RT_SUCCESS(rc2))
    391         {
    392             const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pCtx->pClient->EventSrc, pReq->idEvent);
    393             if (pEvent)
    394                 rc2 = ShClEventSignal(pEvent, pPayload);
    395 
    396             RTCritSectLeave(&pCtx->pClient->CritSect);
    397 
    398             if (RT_SUCCESS(rc2))
    399                 pPayload = NULL;
    400         }
    401 
    402         if (pPayload)
    403             ShClPayloadFree(pPayload);
    404     }
    405 
    406     if (pReq)
    407         RTMemFree(pReq);
    408 
    409     LogRel2(("Shared Clipboard: Reading X11 clipboard data from host completed with %Rrc\n", pData->rcCompletion));
    410 
    411     return VINF_SUCCESS;
    412 }
    413 
    414 /** @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource */
    415 static DECLCALLBACK(int) shClRequestDataFromSourceCallback(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
     352/**
     353 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
     354 *
     355 * Requests clipboard data from the guest.
     356 *
     357 * @thread  Called from X11 event thread.
     358 */
     359static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
     360                                                                 SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
    416361{
    417362    RT_NOREF(pvUser);
     
    426371    }
    427372
    428     PSHCLCLIENT pClient = pCtx->pClient;
    429     AssertPtr(pClient);
    430 
    431     RTCritSectEnter(&pClient->CritSect);
    432 
    433373    int rc = VINF_SUCCESS;
    434374
    435 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     375#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
    436376    /*
    437377     * Note: We always return a generic URI list here.
     
    441381    if (uFmt == VBOX_SHCL_FMT_URI_LIST)
    442382    {
    443         PSHCLTRANSFER pTransfer;
    444         rc = shClSvcTransferStart(pCtx->pClient,
    445                                   SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
    446                                   &pTransfer);
    447         if (RT_SUCCESS(rc))
    448         {
    449 
    450         }
    451         else
    452             LogRel(("Shared Clipboard: Initializing read transfer from guest failed with %Rrc\n", rc));
     383        PSHCLTRANSFER pTransfer = ShClTransferHttpServerGetTransferFirst(&pCtx->X11.HttpCtx.HttpServer);
     384        if (pTransfer)
     385        {
     386            if (RT_SUCCESS(rc))
     387                rc = ShClTransferRootListRead(pTransfer);
     388        }
     389
     390        /** @todo BUGBUG IMPLEMENT THIS! */
    453391
    454392        *ppv = NULL;
     
    461399    if (RT_SUCCESS(rc))
    462400    {
    463         /* Request data from the guest. */
     401        /* Request data from the guest and for data to arrive. */
    464402        PSHCLEVENT pEvent;
    465         rc = ShClSvcGuestDataRequest(pCtx->pClient, uFmt, &pEvent);
     403        rc = ShClSvcReadDataFromGuestAsync(pCtx->pClient, uFmt, &pEvent);
    466404        if (RT_SUCCESS(rc))
    467405        {
    468             RTCritSectLeave(&pClient->CritSect);
    469 
    470406            PSHCLEVENTPAYLOAD pPayload;
    471407            rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     
    484420            }
    485421
    486             RTCritSectEnter(&pClient->CritSect);
    487 
    488422            ShClEventRelease(pEvent);
    489423        }
    490424    }
    491 
    492     RTCritSectLeave(&pClient->CritSect);
    493425
    494426    if (RT_FAILURE(rc))
     
    507439    /* We only need to start the HTTP server (and register the transfer to it) when we actually receive data from the guest. */
    508440    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    509         return ShClHttpTransferRegisterAndMaybeStart(&pClient->State.pCtx->X11.HttpCtx, pTransfer);
     441        return ShClTransferHttpServerMaybeStart(&pClient->State.pCtx->X11.HttpCtx);
    510442#else
    511443    RT_NOREF(pClient, pTransfer);
     
    520452    /* See comment in ShClBackendTransferCreate(). */
    521453    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    522         return ShClHttpTransferUnregisterAndMaybeStop(&pClient->State.pCtx->X11.HttpCtx, pTransfer);
     454        return ShClTransferHttpServerMaybeStop(&pClient->State.pCtx->X11.HttpCtx);
    523455#else
    524456    RT_NOREF(pClient, pTransfer);
     
    537469    if (RT_SUCCESS(rc))
    538470    {
    539         CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
    540         if (pReq)
    541         {
    542             pReq->idEvent = pEvent->idEvent;
    543 
    544             rc = ShClX11ReadDataFromX11(&pClient->State.pCtx->X11, VBOX_SHCL_FMT_URI_LIST, pReq);
     471        rc = ShClX11ReadDataFromX11Async(&pClient->State.pCtx->X11, VBOX_SHCL_FMT_URI_LIST, UINT32_MAX, pEvent);
     472        if (RT_SUCCESS(rc))
     473        {
     474            /* X supplies the data asynchronously, so we need to wait for data to arrive first. */
     475            PSHCLEVENTPAYLOAD pPayload;
     476            rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
    545477            if (RT_SUCCESS(rc))
    546478            {
    547                 /* X supplies the data asynchronously, so we need to wait for data to arrive first. */
    548                 PSHCLEVENTPAYLOAD pPayload;
    549                 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
    550                 if (RT_SUCCESS(rc))
     479                if (pPayload)
    551480                {
    552                     if (pPayload)
    553                     {
    554                         rc = ShClTransferRootsSet(pTransfer,
    555                                                   (char *)pPayload->pvData, pPayload->cbData + 1 /* Include termination */);
    556                     }
    557                     else
    558                         rc = VERR_NO_DATA; /* No payload. */
     481                    Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
     482                    AssertPtr(pPayload->pvData);
     483                    PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
     484
     485                    rc = ShClTransferRootsInitFromStringList(pTransfer,
     486                                              (char *)pResp->Read.pvData, pResp->Read.cbData + 1 /* Include zero terminator */);
     487                    if (RT_SUCCESS(rc))
     488                        rc = ShClTransferRootListRead(pTransfer);
     489
     490                    if (RT_SUCCESS(rc))
     491                        LogRel2(("Shared Clipboard: Host reported %RU64 X11 root entries for transfer to guest\n", ShClTransferRootsCount(pTransfer)));
     492
     493                    RTMemFree(pResp->Read.pvData);
     494                    pResp->Read.cbData = 0;
     495
     496                    ShClPayloadFree(pPayload);
     497                    pPayload = NULL;
    559498                }
     499                else
     500                    rc = VERR_NO_DATA; /* No payload. */
    560501            }
    561502        }
    562         else
    563             rc = VERR_NO_MEMORY;
    564503
    565504        ShClEventRelease(pEvent);
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp

    r100017 r100204  
    552552
    553553    RTListAppend(&pClient->MsgQueue, &pMsg->ListEntry);
    554     return shClSvcClientWakeup(pClient);
     554    return shClSvcClientWakeup(pClient); /** @todo r=andy Remove message if waking up failed? */
    555555}
    556556
     
    11731173 * @returns VBox status code.
    11741174 * @retval  VINF_NO_CHANGE if the client is not in pending mode.
    1175  *
    11761175 * @param   pClient             Client to wake up.
    1177  * @note    Caller must enter pClient->CritSect.
     1176 *
     1177 * @note    Caller must enter critical section.
    11781178 */
    11791179int shClSvcClientWakeup(PSHCLCLIENT pClient)
     
    12251225 * @param   pClient             Client to request to read data form.
    12261226 * @param   fFormats            The formats being requested, OR'ed together (VBOX_SHCL_FMT_XXX).
    1227  * @param   ppEvent             Where to return the event for waiting for new data on success. Optional.
    1228  *                              Must be released by the caller with ShClEventRelease().
    1229  */
    1230 int ShClSvcGuestDataRequest(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent)
     1227 * @param   ppEvent             Where to return the event for waiting for new data on success.
     1228 *                              Must be released by the caller with ShClEventRelease(). Optional.
     1229 *
     1230 * @thread  On X11: Called from the X11 event thread.
     1231 * @thread  On Windows: Called from the Windows event thread.
     1232 *
     1233 * @note    This will locally initialize a transfer if VBOX_SHCL_FMT_URI_LIST is being requested from the guest.
     1234 */
     1235int ShClSvcReadDataFromGuestAsync(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent)
    12311236{
    12321237    AssertPtrReturn(pClient, VERR_INVALID_POINTER);
     
    12481253        else if (fFormats & VBOX_SHCL_FMT_HTML)
    12491254            fFormat = VBOX_SHCL_FMT_HTML;
     1255#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1256        else if (fFormats & VBOX_SHCL_FMT_URI_LIST)
     1257            fFormat = VBOX_SHCL_FMT_URI_LIST;
     1258#endif
    12501259        else
    12511260            AssertMsgFailedBreak(("%#x\n", fFormats));
     
    12691278        if (pMsg)
    12701279        {
    1271             /*
    1272              * Enter the critical section and generate an event.
    1273              */
    1274             RTCritSectEnter(&pClient->CritSect);
     1280            shClSvcClientLock(pClient);
    12751281
    12761282            PSHCLEVENT pEvent;
     
    13161322
    13171323                    shClSvcMsgAdd(pClient, pMsg, true /* fAppend */);
    1318 
    1319                     /* Return event handle to the caller if requested. */
     1324                    /* Wake up the client to let it know that there are new messages. */
     1325                    shClSvcClientWakeup(pClient);
     1326
     1327                    /* Return event to caller. */
    13201328                    if (ppEvent)
    1321                     {
    13221329                        *ppEvent = pEvent;
    1323                     }
    1324 
    1325                     shClSvcClientWakeup(pClient);
    13261330                }
    13271331
     1332#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1333                /*
     1334                 * When the host wants to read URI data from the guest:
     1335                 *   - Initialize a transfer locally.
     1336                 *   - Request URI data from the guest; this tells the guest to initialize a transfer on the guest side.
     1337                 *   - Start the transfer locally once we receive the transfer STARTED status from the guest via VBOX_SHCL_GUEST_FN_REPLY.
     1338                 */
     1339                if (   RT_SUCCESS(rc)
     1340                    && fFormat == VBOX_SHCL_FMT_URI_LIST)
     1341                {
     1342                    rc = shClSvcTransferInit(pClient, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
     1343                                             NULL /* pTransfer */);
     1344                    if (RT_SUCCESS(rc))
     1345                        rc = shClSvcSetSource(pClient, SHCLSOURCE_REMOTE);
     1346
     1347                    if (RT_FAILURE(rc))
     1348                        LogRel(("Shared Clipboard: Initializing guest -> host transfer failed with %Rrc\n", rc));
     1349                }
     1350#endif
    13281351                /* Remove event from list if caller did not request event handle or in case
    13291352                 * of failure (in this case caller should not release event). */
     
    13321355                {
    13331356                    ShClEventRelease(pEvent);
     1357                    pEvent = NULL;
    13341358                }
    13351359            }
     
    13371361                rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
    13381362
    1339             RTCritSectLeave(&pClient->CritSect);
    1340 
    13411363            if (RT_FAILURE(rc))
    13421364                shClSvcMsgFree(pClient, pMsg);
     1365
     1366            shClSvcClientUnlock(pClient);
    13431367        }
    13441368        else
     
    13501374
    13511375    if (RT_FAILURE(rc))
    1352         LogRel(("Shared Clipboard: Requesting data in formats %#x from guest failed with %Rrc\n", fFormats, rc));
     1376        LogRel(("Shared Clipboard: Requesting guest clipboard data failed with %Rrc\n", rc));
    13531377
    13541378    LogFlowFuncLeaveRC(rc);
     
    13671391 * @param   cbData              Size (in bytes) of clipboard data received.
    13681392 *                              This can be zero.
     1393 *
     1394 * @thread  Backend thread.
    13691395 */
    13701396int ShClSvcGuestDataSignal(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData)
     
    14141440
    14151441/**
    1416  * Reports available VBox clipboard formats to the guest.
     1442 * Reports clipboard formats to the guest.
    14171443 *
    14181444 * @note    Host backend callers must check if it's active (use
     
    14241450 * @param   fFormats            The formats to report (VBOX_SHCL_FMT_XXX), zero
    14251451 *                              is okay (empty the clipboard).
     1452 *
     1453 * @thread  Backend thread.
    14261454 */
    14271455int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats)
    14281456{
     1457    LogFlowFuncEnter();
     1458
    14291459    /*
    14301460     * Check if the service mode allows this operation and whether the guest is
     
    14791509
    14801510        RTCritSectEnter(&pClient->CritSect);
    1481         shClSvcMsgAddAndWakeupClient(pClient, pMsg);
     1511        rc = shClSvcMsgAddAndWakeupClient(pClient, pMsg);
    14821512        RTCritSectLeave(&pClient->CritSect);
    1483 
    1484 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1485         /* Create a transfer locally and also tell the guest to create a transfer on the guest side. */
    1486         if (   !fSkipTransfers
    1487             && fFormats & VBOX_SHCL_FMT_URI_LIST) /* Only start a transfer if we supply an URI list. */
    1488         {
    1489             rc = shClSvcTransferStart(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
    1490                                       NULL /* pTransfer */);
    1491             if (RT_SUCCESS(rc))
    1492                 rc = shClSvcSetSource(pClient, SHCLSOURCE_LOCAL);
    1493 
    1494             if (RT_FAILURE(rc))
    1495                 LogRel(("Shared Clipboard: Initializing host write transfer failed with %Rrc\n", rc));
    1496         }
    1497         else
    1498 #endif
    1499             rc = VINF_SUCCESS;
    15001513    }
    15011514    else
     
    17491762        else
    17501763            LogRel(("Shared Clipboard: Reading host clipboard data failed with %Rrc\n", rc));
     1764
     1765#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1766        /*
     1767         * When we receive a read request for URI data:
     1768         *   - Initialize a transfer locally.
     1769         *   - Tell the guest to initialize a transfer on the guest side.
     1770         *   - Start the transfer locally once we receive the transfer STARTED status from the guest via VBOX_SHCL_GUEST_FN_REPLY.
     1771         */
     1772        if (uFormat == VBOX_SHCL_FMT_URI_LIST) /* Only init a transfer if we supply an URI list. */
     1773        {
     1774            shClSvcClientLock(pClient);
     1775
     1776            rc = shClSvcTransferInit(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
     1777                                     NULL /* pTransfer */);
     1778            if (RT_SUCCESS(rc))
     1779                rc = shClSvcSetSource(pClient, SHCLSOURCE_LOCAL);
     1780
     1781            if (RT_FAILURE(rc))
     1782                LogRel(("Shared Clipboard: Initializing host -> guest transfer failed with %Rrc\n", rc));
     1783
     1784            shClSvcClientUnlock(pClient);
     1785        }
     1786#endif
    17511787    }
    17521788
     
    19762012    int rc = VINF_SUCCESS;
    19772013
    1978     if (ShClSvcLock())
    1979     {
    1980         pClient->State.enmSource = enmSource;
    1981 
    1982         LogFlowFunc(("Source of client %RU32 is now %RU32\n", pClient->State.uClientID, pClient->State.enmSource));
    1983 
    1984         ShClSvcUnlock();
    1985     }
     2014    pClient->State.enmSource = enmSource;
     2015
     2016    LogFlowFunc(("Source of client %RU32 is now %RU32\n", pClient->State.uClientID, pClient->State.enmSource));
    19862017
    19872018    LogFlowFuncLeaveRC(rc);
     
    27252756            /* The service extension wants read data from the guest. */
    27262757            case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
    2727                 rc = ShClSvcGuestDataRequest(pClient, u32Format, NULL /* pidEvent */);
     2758            {
     2759                PSHCLEVENT pEvent;
     2760                rc = ShClSvcReadDataFromGuestAsync(pClient, u32Format, &pEvent);
     2761                if (RT_SUCCESS(rc))
     2762                {
     2763                    PSHCLEVENTPAYLOAD pPayload;
     2764                    rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     2765                    if (RT_SUCCESS(rc))
     2766                    {
     2767                        if (pPayload)
     2768                        {
     2769                            memcpy(pvData, pPayload->pvData, RT_MIN(cbData, pPayload->cbData));
     2770                            /** @todo r=andy How is this supposed to work wrt returning number of bytes read? */
     2771
     2772                            ShClPayloadFree(pPayload);
     2773                            pPayload = NULL;
     2774                        }
     2775                        else
     2776                        {
     2777                            pvData = NULL;
     2778                        }
     2779                    }
     2780
     2781                    ShClEventRelease(pEvent);
     2782                }
    27282783                break;
     2784            }
     2785
     2786            /** @todo BUGBUG Why no VBOX_CLIPBOARD_EXT_FN_DATA_WRITE here? */
    27292787
    27302788            default:
  • trunk/src/VBox/HostServices/SharedClipboard/testcase/Makefile.kmk

    r100011 r100204  
    7878        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp \
    7979        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-transfers-provider-local.cpp
     80  tstClipboardMockHGCM_SOURCES.win += \
     81        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp \
     82        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardEnumFormatEtcImpl-win.cpp \
     83        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp
    8084 endif
    8185
  • trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp

    r99968 r100204  
    140140static void testMsgAddReadData(PSHCLCLIENT pClient, SHCLFORMATS fFormats)
    141141{
    142     int rc = ShClSvcGuestDataRequest(pClient, fFormats, NULL /* pidEvent */);
     142    int rc = ShClSvcReadDataFromGuestAsync(pClient, fFormats, NULL /* ppEvent */);
    143143    RTTESTI_CHECK_RC_OK(rc);
    144144}
  • trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardTransfers.cpp

    r98103 r100204  
    215215    RTTESTI_CHECK_RC_OK(rc);
    216216
     217    SHCLTXPROVIDER Provider;
     218    RTTESTI_CHECK(VBClTransferProviderLocalQueryInterface(&Provider) != NULL);
     219    RTTESTI_CHECK_RC_OK(ShClTransferSetProvider(pTransfer, &Provider));
     220
    217221    char szTestTransferRootsSetDir[RTPATH_MAX];
    218222    rc = testCreateTempDir(hTest, "testTransferRootsSet", szTestTransferRootsSetDir, sizeof(szTestTransferRootsSetDir));
     
    227231    RTTESTI_CHECK_RC_OK_RETV(rc);
    228232
    229     rc = ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1);
     233    rc = ShClTransferRootsInitFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1);
    230234    RTTESTI_CHECK_RC(rc, rcExpected);
    231235
     
    243247    PSHCLTRANSFER pTransfer;
    244248    int rc = ShClTransferCreate(&pTransfer);
     249    RTTESTI_CHECK_RC_OK(rc);
     250
     251    SHCLTXPROVIDER Provider;
     252    VBClTransferProviderLocalQueryInterface(&Provider);
     253
     254    rc = ShClTransferSetProvider(pTransfer, &Provider);
    245255    RTTESTI_CHECK_RC_OK(rc);
    246256
     
    262272    RTTESTI_CHECK_RC_OK_RETV(rc);
    263273
    264     rc = ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1);
     274    rc = ShClTransferRootsInitFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1);
    265275    RTTESTI_CHECK_RC_OK(rc);
    266276
     
    303313    rc = ShClTransferDestroy(pTransfer);
    304314    RTTESTI_CHECK_RC_OK(rc);
     315    rc = ShClTransferDestroy(pTransfer); /* Second time, intentional. */
     316    RTTESTI_CHECK_RC_OK(rc);
     317
     318    PSHCLLIST pList = ShClTransferListAlloc();
     319    RTTESTI_CHECK(pList != NULL);
     320    rc = ShClTransferCreate(&pTransfer);
     321    RTTESTI_CHECK_RC_OK(rc);
     322    ShClTransferListFree(pList);
     323    pList = NULL;
     324    ShClTransferListFree(pList); /* Second time, intentional. */
     325
     326    SHCLLISTENTRY Entry;
     327    RTTESTI_CHECK_RC_OK(ShClTransferListEntryInit(&Entry));
     328    ShClTransferListEntryDestroy(&Entry);
     329    ShClTransferListEntryDestroy(&Entry); /* Second time, intentional. */
    305330}
    306331
     
    387412    return RTTestSummaryAndDestroy(hTest);
    388413}
    389 
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