VirtualBox

Changeset 100204 in vbox for trunk


Ignore:
Timestamp:
Jun 19, 2023 9:11:37 AM (18 months ago)
Author:
vboxsync
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
Files:
33 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/GuestHost/SharedClipboard-transfers.h

    r99966 r100204  
    4040# pragma once
    4141#endif
    42 
    43 #include <map>
    4442
    4543#include <iprt/assert.h>
     
    6765 */
    6866
    69 /** No Shared Clipboard listing feature flags defined. */
     67/** No Shared Clipboard list feature flags defined. */
    7068#define SHCL_TRANSFER_LIST_FEATURE_F_NONE            UINT32_C(0)
     69/** Is a root list. */
     70#define SHCL_TRANSFER_LIST_FEATURE_F_ROOT            RT_BIT(0)
    7171/** Shared Clipboard feature flags valid mask. */
    72 #define SHCL_TRANSFER_LIST_FEATURE_F_VALID_MASK      0x0
     72#define SHCL_TRANSFER_LIST_FEATURE_F_VALID_MASK      0x1
    7373
    7474/** Defines the maximum length (in chars) a Shared Clipboard transfer path can have. */
     
    8080/** Defines the default maximum object handles a Shared Clipboard transfer can have. */
    8181#define SHCL_TRANSFER_DEFAULT_MAX_OBJ_HANDLES   _4K
    82 /** Defines the default timeout (in ms) to use for clipboard operations. */
    83 #define SHCL_TIMEOUT_DEFAULT_MS                 RT_MS_30SEC
     82/** Defines the separator for the entries of an URI list (as a string). */
     83#define SHCL_TRANSFER_URI_LIST_SEP_STR          "\r\n"
    8484
    8585/**
     
    9292    /** The transfer has been initialized but is not running yet. */
    9393    SHCLTRANSFERSTATUS_INITIALIZED,
     94    /** The transfer has been uninitialized and is not usable anymore. */
     95    SHCLTRANSFERSTATUS_UNINITIALIZED,
    9496    /** The transfer is active and running. */
    9597    SHCLTRANSFERSTATUS_STARTED,
     
    100102    /** The transfer has been killed. */
    101103    SHCLTRANSFERSTATUS_KILLED,
    102     /** The transfer ran into an unrecoverable error. */
     104    /** The transfer ran into an unrecoverable error.
     105     *  This results in completely aborting the operation. */
    103106    SHCLTRANSFERSTATUS_ERROR,
    104107    /** The usual 32-bit hack. */
     
    401404typedef _SHCLLISTENTRY SHCLLISTENTRY;
    402405
    403 /** Defines a single root list entry. Currently the same as a regular list entry. */
    404 typedef SHCLLISTENTRY SHCLROOTLISTENTRY;
    405 /** Defines a pointer to a single root list entry. Currently the same as a regular list entry pointer. */
    406 typedef SHCLROOTLISTENTRY *PSHCLROOTLISTENTRY;
    407 
    408 /**
    409  * Structure for keeping Shared Clipboard root list headers.
    410  */
    411 typedef struct _SHCLROOTLISTHDR
    412 {
    413     /** Roots listing flags; unused at the moment. */
    414     uint32_t                fRoots;
    415     /** Number of root list entries. */
    416     uint32_t                cRoots;
    417 } SHCLROOTLISTHDR;
    418 /** Pointer to a Shared Clipboard root list header. */
    419 typedef SHCLROOTLISTHDR *PSHCLROOTLISTHDR;
    420 
    421 /**
    422  * Structure for maintaining a Shared Clipboard root list.
    423  */
    424 typedef struct _SHCLROOTLIST
    425 {
    426     /** Root list header. */
    427     SHCLROOTLISTHDR    Hdr;
    428     /** Root list entries. */
    429     SHCLROOTLISTENTRY *paEntries;
    430 } SHCLROOTLIST;
    431 /** Pointer to a Shared Clipboard root list. */
    432 typedef SHCLROOTLIST *PSHCLROOTLIST;
    433 
    434406/**
    435407 * Structure for maintaining Shared Clipboard list open parameters.
     
    458430    /** Feature flag(s) of type SHCL_TRANSFER_LIST_FEATURE_F_XXX. */
    459431    uint32_t fFeatures;
    460     /** Total objects returned. */
    461     uint64_t cTotalObjects;
     432    /** Total entries of the list. */
     433    uint64_t cEntries;
    462434    /** Total size (in bytes) returned. */
    463435    uint64_t cbTotalSize;
     
    467439
    468440/**
    469  * Structure for a Shared Clipboard list entry.
     441 * Structure for a generic Shared Clipboard list entry.
    470442 */
    471443typedef struct _SHCLLISTENTRY
    472444{
     445    /** List node. */
     446    RTLISTNODE Node;
    473447    /** Entry name. */
    474     char    *pszName;
     448    char      *pszName;
    475449    /** Size (in bytes) of entry name.
    476450     *  Includes terminator. */
    477     uint32_t cbName;
    478     /** Information flag(s). */
    479     uint32_t fInfo;
     451    uint32_t   cbName;
     452    /** Information flag(s). Of type VBOX_SHCL_INFO_FLAG_XXX. */
     453    uint32_t   fInfo;
    480454    /** Size (in bytes) of the actual list entry. */
    481     uint32_t cbInfo;
     455    uint32_t   cbInfo;
    482456    /** Data of the actual list entry. */
    483     void    *pvInfo;
     457    void      *pvInfo;
    484458} SHCLLISTENTRY;
    485459/** Pointer to a Shared Clipboard list entry. */
    486460typedef SHCLLISTENTRY *PSHCLLISTENTRY;
     461/** Pointer to a const Shared Clipboard list entry. */
     462typedef SHCLLISTENTRY *PCSHCLLISTENTRY;
    487463
    488464/** Maximum length (in UTF-8 characters) of a list entry name. Includes terminator. */
    489 #define SHCLLISTENTRY_MAX_NAME     RTPATH_MAX /** @todo Improve this to be more dynamic. */
    490 
    491 /**
    492  * Structure for maintaining a generic Shared Clipboard list.
     465#define SHCLLISTENTRY_MAX_NAME     1024
     466
     467/**
     468 * Structure for a generic Shared Clipboard list.
    493469 */
    494470typedef struct _SHCLLIST
    495471{
    496472    /** List header. */
    497     SHCLLISTHDR        Hdr;
    498     /** List entries. */
    499     SHCLROOTLISTENTRY *paEntries;
     473    SHCLLISTHDR    Hdr;
     474    /** List entries of type PSHCLLISTENTRY. */
     475    RTLISTANCHOR   lstEntries;
    500476} SHCLLIST;
    501 /** Pointer to a Shared Clipboard transfer transfer list. */
     477/** Pointer to a generic Shared Clipboard transfer transfer list. */
    502478typedef SHCLLIST *PSHCLLIST;
    503479
     
    637613
    638614/**
    639  * Structure for keeping a single transfer root list entry.
    640  */
    641 typedef struct _SHCLLISTROOT
    642 {
    643     /** The list node. */
    644     RTLISTNODE          Node;
    645     /** Absolute path of entry. */
    646     char               *pszPathAbs;
    647 } SHCLLISTROOT;
    648 /** Pointer to a Shared Clipboard transfer root list entry. */
    649 typedef SHCLLISTROOT *PSHCLLISTROOT;
    650 
    651 /**
    652615 * Structure for maintaining an Shared Clipboard transfer state.
    653616 * Everything in here will be part of a saved state (later).
     
    696659{
    697660    /**
    698      * Returns the root entries of a clipboard transfer.
     661     * Reads the clipboard transfer root list.
     662     *
     663     * Depending on the provider, this queries information for the root entries.
    699664     *
    700665     * @returns VBox status code.
    701666     * @param   pCtx                Provider context to use.
    702      * @param   ppRootList          Where to store the root list on success.
    703      */
    704     DECLCALLBACKMEMBER(int, pfnRootsGet,(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList));
     667     * @param   pRootList           Where to store the root list on success.
     668     */
     669    DECLCALLBACKMEMBER(int, pfnRootListRead,(PSHCLTXPROVIDERCTX pCtx));
    705670    /**
    706671     * Opens a transfer list.
     
    805770/** Queries (assigns) a Shared Clipboard provider interface. */
    806771#define SHCLTXPROVIDERIFACE_QUERY(a_Iface, a_Name) \
    807     a_Iface->pfnRootsGet       = a_Name ## RootsGet; \
     772    a_Iface->pfnRootListRead   = a_Name ## RootListRead; \
    808773    a_Iface->pfnListOpen       = a_Name ## ListOpen; \
    809774    a_Iface->pfnListClose      = a_Name ## ListClose; \
     
    822787
    823788/**
    824  * Structure for the Shared Clipboard transfer provider creation context.
    825  */
    826 typedef struct _SHCLTXPROVIDERCREATIONCTX
     789 * Structure for Shared Clipboard transfer provider.
     790 */
     791typedef struct _SHCLTXPROVIDER
    827792{
    828793    /** Specifies what the source of the provider is. */
    829794    SHCLSOURCE           enmSource;
    830     /** The provider interface table. */
     795    /** The provider interface table to use. */
    831796    SHCLTXPROVIDERIFACE  Interface;
    832797    /** User-provided callback data. */
     
    834799    /** Size (in bytes) of data at user pointer. */
    835800    size_t               cbUser;
    836 } SHCLTXPROVIDERCREATIONCTX;
    837 /** Pointer to a Shared Clipboard transfer provider creation context. */
    838 typedef SHCLTXPROVIDERCREATIONCTX *PSHCLTXPROVIDERCREATIONCTX;
     801} SHCLTXPROVIDER;
     802/** Pointer to Shared Clipboard transfer provider. */
     803typedef SHCLTXPROVIDER *PSHCLTXPROVIDER;
    839804
    840805/**
     
    856821 * Shared Clipboard transfer callback table.
    857822 *
    858  * All callbacks are optional and can provide additional information / feedback to a frontend.
     823 * All callbacks are optional (hence all returning void).
    859824 */
    860825typedef struct _SHCLTRANSFERCALLBACKTABLE
    861826{
    862827    /**
    863      * Called when the transfer gets initialized.
     828     * Called after the transfer got initialized.
    864829     *
    865830     * @param   pCbCtx              Pointer to callback context to use.
    866831     */
    867     DECLCALLBACKMEMBER(int,  pfnOnInitialize,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
    868     /**
    869      * Called before the transfer will be started.
     832    DECLCALLBACKMEMBER(void,  pfnOnInitialized,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
     833    /**
     834     * Called before the transfer gets destroys.
    870835     *
    871836     * @param   pCbCtx              Pointer to callback context to use.
    872837     */
    873     DECLCALLBACKMEMBER(int,  pfnOnStart,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
     838    DECLCALLBACKMEMBER(void,  pfnOnDestroy,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
     839    /**
     840     * Called after the transfer entered the started state.
     841     *
     842     * @param   pCbCtx              Pointer to callback context to use.
     843     */
     844    DECLCALLBACKMEMBER(void,  pfnOnStarted,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
    874845    /**
    875846     * Called when the transfer has been complete.
     
    888859    DECLCALLBACKMEMBER(void, pfnOnError,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError));
    889860    /**
    890      * Called when transfer got registered to a transfer context.
     861     * Called after a transfer got registered to a transfer context.
    891862     *
    892863     * @param   pCbCtx              Pointer to callback context to use.
     
    895866    DECLCALLBACKMEMBER(void, pfnOnRegistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx));
    896867    /**
    897      * Called when transfer got unregistered from a transfer context.
     868     * Called after a transfer got unregistered from a transfer context.
    898869     *
    899870     * @param   pCbCtx              Pointer to callback context to use.
     
    908879} SHCLTRANSFERCALLBACKTABLE;
    909880/** Pointer to a Shared Clipboard transfer callback table. */
    910 typedef SHCLTRANSFERCALLBACKTABLE *PSHCLTRANSFERCALLBACKTABLE;
     881typedef SHCLTRANSFERCALLBACKTABLE *PSHCLTRANSFERCALLBACKS;
    911882
    912883/**
     
    949920    /** The transfer's own event source. */
    950921    SHCLEVENTSOURCE           Events;
    951     /** Current number of concurrent list handles. */
     922    /** Current number of concurrent list handles in \a lstHandles. */
    952923    uint32_t                  cListHandles;
    953     /** Maximum number of concurrent list handles. */
     924    /** Maximum number of concurrent list handles allowed. */
    954925    uint32_t                  cMaxListHandles;
    955     /** Next upcoming list handle. */
     926    /** Next upcoming list handle. For book keeping. */
    956927    SHCLLISTHANDLE            uListHandleNext;
    957     /** List of all list handles elated to this transfer. */
    958     RTLISTANCHOR              lstList;
    959     /** Number of root entries in list. */
    960     uint64_t                  cRoots;
     928    /** List of all list handles related to this transfer. */
     929    RTLISTANCHOR              lstHandles;
    961930    /** List of root entries of this transfer. */
    962     RTLISTANCHOR              lstRoots;
    963     /** Current number of concurrent object handles. */
     931    SHCLLIST                  lstRoots;
     932    /** Current number of concurrent object handles. in \a lstObj. */
    964933    uint32_t                  cObjHandles;
    965934    /** Maximum number of concurrent object handles. */
    966935    uint32_t                  cMaxObjHandles;
    967     /** Next upcoming object handle. */
     936    /** Next upcoming object handle. For book keeping. */
    968937    SHCLOBJHANDLE             uObjHandleNext;
    969938    /** Map of all objects handles related to this transfer. */
     
    1006975#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
    1007976/**
     977 * Enumeration for HTTP server status changes.
     978 *
     979 * Keep those as flags, so that we can wait for multiple statuses, if needed.
     980 */
     981typedef enum _SHCLHTTPSERVERSTATUS
     982{
     983    /** No status set yet. */
     984    SHCLHTTPSERVERSTATUS_NONE                  = 0x0,
     985    /** A new transfer got registered. */
     986    SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED   = 0x1,
     987    /** A new transfer got registered. */
     988    SHCLHTTPSERVERSTATUS_TRANSFER_UNREGISTERED = 0x2
     989} SHCLHTTPSERVERSTATUS;
     990
     991/**
    1008992 * Structure for keeping a Shared Clipboard HTTP server instance.
    1009993 */
     
    1011995{
    1012996    /** Critical section for serializing access. */
    1013     RTCRITSECT          CritSect;
     997    RTCRITSECT           CritSect;
     998    /** Status event for callers to wait for.
     999     *  Updates \a enmStatus. */
     1000    RTSEMEVENT           StatusEvent;
     1001    /** Current status. */
     1002    SHCLHTTPSERVERSTATUS enmStatus;
    10141003    /** Handle of the HTTP server instance. */
    1015     RTHTTPSERVER        hHTTPServer;
     1004    RTHTTPSERVER         hHTTPServer;
    10161005    /** Port number the HTTP server is running on. 0 if not running. */
    1017     uint16_t            uPort;
     1006    uint16_t             uPort;
    10181007    /** List of registered HTTP transfers. */
    1019     RTLISTANCHOR        lstTransfers;
     1008    RTLISTANCHOR         lstTransfers;
    10201009    /** Number of registered HTTP transfers. */
    1021     uint32_t            cTransfers;
     1010    uint32_t             cTransfers;
    10221011    /** Number of files served (via GET) so far.
    10231012     *  Only complete downloads count (i.e. no aborted). */
    1024     uint32_t            cDownloaded;
     1013    uint32_t             cDownloaded;
    10251014    /** Cached response data. */
    1026     RTHTTPSERVERRESP    Resp;
     1015    RTHTTPSERVERRESP     Resp;
    10271016} SHCLHTTPSERVER;
    10281017/** Pointer to Shared Clipboard HTTP server. */
     
    10681057 *  @{
    10691058 */
    1070 PSHCLTXPROVIDERIFACE VBClTransferQueryIfaceLocal(PSHCLTXPROVIDERIFACE pIface);
     1059PSHCLTXPROVIDERIFACE VBClTransferProviderLocalQueryInterface(PSHCLTXPROVIDER pProvider);
    10711060/** @} */
    10721061
     
    11041093int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource);
    11051094int ShClTransferDestroy(PSHCLTRANSFER pTransfer);
     1095void ShClTransferReset(PSHCLTRANSFER pTransfer);
    11061096
    11071097int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser);
     
    11261116bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList);
    11271117
    1128 int ShClPathSanitizeFilename(char *pszPath, size_t cbPath);
    1129 int ShClPathSanitize(char *pszPath, size_t cbPath);
    1130 
    1131 PSHCLROOTLIST ShClTransferRootListAlloc(void);
    1132 void ShClTransferRootListFree(PSHCLROOTLIST pRootList);
    1133 
    1134 PSHCLROOTLISTHDR ShClTransferRootListHdrDup(PSHCLROOTLISTHDR pRoots);
    1135 int ShClTransferRootListHdrInit(PSHCLROOTLISTHDR pRoots);
    1136 void ShClTransferRootListHdrDestroy(PSHCLROOTLISTHDR pRoots);
    1137 
    1138 int ShClTransferRootListEntryCopy(PSHCLROOTLISTENTRY pDst, PSHCLROOTLISTENTRY pSrc);
    1139 int ShClTransferRootListEntryInit(PSHCLROOTLISTENTRY pRootListEntry);
    1140 void ShClTransferRootListEntryDestroy(PSHCLROOTLISTENTRY pRootListEntry);
    1141 PSHCLROOTLISTENTRY ShClTransferRootListEntryDup(PSHCLROOTLISTENTRY pRootListEntry);
     1118PSHCLLIST ShClTransferListAlloc(void);
     1119void ShClTransferListFree(PSHCLLIST pList);
     1120void ShClTransferListInit(PSHCLLIST pList);
     1121void ShClTransferListDestroy(PSHCLLIST pList);
     1122int ShClTransferListAddEntry(PSHCLLIST pList, PSHCLLISTENTRY pEntry, bool fAppend);
    11421123
    11431124int ShClTransferListHandleInfoInit(PSHCLLISTHANDLEINFO pInfo);
     
    11591140int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry);
    11601141void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry);
    1161 int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc);
    1162 PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry);
     1142int ShClTransferListEntryInitEx(PSHCLLISTENTRY pListEntry, uint32_t fInfo, const char *pszName, void *pvInfo, uint32_t cbInfo);
    11631143int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry);
    11641144void ShClTransferListEntryDestroy(PSHCLLISTENTRY pListEntry);
    11651145bool ShClTransferListEntryIsValid(PSHCLLISTENTRY pListEntry);
    1166 
    1167 void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst, PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc);
    1168 void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKTABLE pCallbacks);
    1169 int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDERCREATIONCTX pCreationCtx);
    1170 int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots);
    1171 int ShClTransferRootsSetAsFile(PSHCLTRANSFER pTransfer, const char *pszFile);
    1172 void ShClTransferReset(PSHCLTRANSFER pTransfer);
    1173 
    1174 uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer);
    1175 int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer, uint64_t uIndex, PSHCLROOTLISTENTRY pEntry);
    1176 int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList);
     1146int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc);
     1147PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry);
     1148
     1149void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKS pCallbacksDst, PSHCLTRANSFERCALLBACKS pCallbacksSrc);
     1150void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKS pCallbacks);
     1151int ShClTransferSetProvider(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDER pProvider);
     1152
     1153int ShClTransferRootsInitFromStringList(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots);
     1154int ShClTransferRootsInitFromFile(PSHCLTRANSFER pTransfer, const char *pszFile);
     1155uint64_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer);
     1156PCSHCLLISTENTRY ShClTransferRootsEntryGet(PSHCLTRANSFER pTransfer, uint64_t uIndex);
     1157int ShClTransferRootListRead(PSHCLTRANSFER pTransfer);
    11771158/** @} */
    11781159
     
    12011182 *  @{
    12021183 */
    1203 int ShClHttpTransferRegisterAndMaybeStart(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer);
    1204 int ShClHttpTransferUnregisterAndMaybeStop(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer);
     1184int ShClTransferHttpServerMaybeStart(PSHCLHTTPCONTEXT pCtx);
     1185int ShClTransferHttpServerMaybeStop(PSHCLHTTPCONTEXT pCtx);
    12051186/** @} */
    12061187
     
    12081189 *  @{
    12091190 */
    1210 int ShClTransferHttpServerCreate(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort);
    1211 int ShClTransferHttpServerCreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort);
     1191int ShClTransferHttpServerStart(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort);
     1192int ShClTransferHttpServerStartEx(PSHCLHTTPSERVER pSrv, uint16_t uPort);
    12121193int ShClTransferHttpServerDestroy(PSHCLHTTPSERVER pSrv);
    1213 void ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv);
     1194int ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv);
    12141195int ShClTransferHttpServerRegisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer);
    12151196int ShClTransferHttpServerUnregisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer);
    1216 bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer);
     1197PSHCLTRANSFER ShClTransferHttpServerGetTransferFirst(PSHCLHTTPSERVER pSrv);
     1198bool ShClTransferHttpServerGetTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer);
    12171199uint16_t ShClTransferHttpServerGetPort(PSHCLHTTPSERVER pSrv);
    12181200uint32_t ShClTransferHttpServerGetTransferCount(PSHCLHTTPSERVER pSrv);
     
    12201202char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer);
    12211203bool ShClTransferHttpServerIsRunning(PSHCLHTTPSERVER pSrv);
     1204int ShClTransferHttpServerWaitForStatusChange(PSHCLHTTPSERVER pSrv, SHCLHTTPSERVERSTATUS fStatus, RTMSINTERVAL msTimeout);
    12221205/** @} */
    12231206#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
     
    12261209 *  @{
    12271210 */
     1211int ShClPathSanitizeFilename(char *pszPath, size_t cbPath);
     1212int ShClPathSanitize(char *pszPath, size_t cbPath);
    12281213const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus);
    12291214int ShClTransferValidatePath(const char *pcszPath, bool fMustExist);
    1230 void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc);
     1215int ShClFsObjInfoQuery(const char *pszPath, PSHCLFSOBJINFO pObjInfo);
     1216int ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc);
    12311217/** @} */
    12321218
  • trunk/include/VBox/GuestHost/SharedClipboard-win.h

    r98103 r100204  
    4242#include <iprt/critsect.h>
    4343#include <iprt/types.h>
     44#include <iprt/req.h>
    4445#include <iprt/win/windows.h>
    4546
     
    109110    bool                   fCBChainPingInProcess;
    110111} SHCLWINAPIOLD, *PSHCLWINAPIOLD;
     112
     113/** Forward declaration for the Windows data object. */
     114class SharedClipboardWinDataObject;
    111115
    112116/**
     
    131135    /** Structure for maintaining the old clipboard API. */
    132136    SHCLWINAPIOLD      oldAPI;
     137    /** The "in-flight" data object for file transfers.
     138     *  This is the current data object which has been created and sent to the Windows clipboard.
     139     *  That way Windows knows that a potential file transfer is available, but the actual transfer
     140     *  hasn't been started yet.
     141     *  Can be NULL if currently not being used / no current "in-flight" transfer present. */
     142    SharedClipboardWinDataObject
     143                      *pDataObjInFlight;
     144    /** Request queue.
     145     *  Needed for processing HGCM requests within the HGCM (main) thread from the Windows event thread. */
     146    RTREQQUEUE         hReqQ;
    133147} SHCLWINCTX, *PSHCLWINCTX;
    134148
     
    154168
    155169#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    156 int SharedClipboardWinGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
    157 int SharedClipboardWinDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList);
     170int SharedClipboardWinTransferGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
     171int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList);
     172int SharedClipboardWinTransferGetRootsFromClipboard(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
     173int SharedClipboardWinTransferCreateAndSetDataObject(PSHCLWINCTX pWinCtx, PSHCLCONTEXT pCtx, PSHCLCALLBACKS pCallbacks);
    158174#endif
    159175
     
    188204        /** The object is uninitialized (not ready). */
    189205        Uninitialized = 0,
    190         /** The object is initialized and ready to use. */
     206        /** The object is initialized and ready to use.
     207         *  A transfer is *not* running yet! */
    191208        Initialized,
     209        /** Transfer is running. */
     210        Running,
    192211        /** The operation has been successfully completed. */
    193212        Completed,
     
    200219public:
    201220
    202     SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer,
    203                                  LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0);
     221    SharedClipboardWinDataObject(void);
    204222    virtual ~SharedClipboardWinDataObject(void);
     223
     224public:
     225
     226    int Init(PSHCLCONTEXT pCtx, LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0);
     227    void Destroy(void);
     228
     229    void SetCallbacks(PSHCLCALLBACKS pCallbacks);
    205230
    206231public: /* IUnknown methods. */
     
    234259public:
    235260
    236     int Init(void);
    237     void OnTransferComplete(int rc = VINF_SUCCESS);
    238     void OnTransferCanceled();
     261    int SetAndStartTransfer(PSHCLTRANSFER pTransfer);
     262    int SetStatus(Status enmStatus, int rc = VINF_SUCCESS);
    239263
    240264public:
     
    257281    void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
    258282                        LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
     283    int setStatusLocked(Status enmStatus, int rc = VINF_SUCCESS);
     284
    259285protected:
    260286
     
    265291    {
    266292        /** Relative path of the object. */
    267         Utf8Str       strPath;
     293        char         *pszPath;
    268294        /** Related (cached) object information. */
    269295        SHCLFSOBJINFO objInfo;
     
    273299    typedef std::vector<FSOBJENTRY> FsObjEntryList;
    274300
     301    /** Shared Clipboard context to use. */
     302    PSHCLCONTEXT                m_pCtx;
     303    /** Callbacks table to use. */
     304    SHCLCALLBACKS               m_Callbacks;
    275305    /** The object's current status. */
    276306    Status                      m_enmStatus;
     
    290320    /** List of (cached) file system objects. */
    291321    FsObjEntryList              m_lstEntries;
     322    /** Critical section to serialize access. */
     323    RTCRITSECT                  m_CritSect;
    292324    /** Whether the transfer thread is running. */
    293     bool                        m_fRunning;
     325    bool                        m_fThreadRunning;
    294326    /** Event being triggered when reading the transfer list been completed. */
    295327    RTSEMEVENT                  m_EventListComplete;
    296     /** Event being triggered when the transfer has been completed. */
    297     RTSEMEVENT                  m_EventTransferComplete;
     328    /** Event being triggered when the transfer status has been changed. */
     329    RTSEMEVENT                  m_EventStatusChanged;
    298330    /** Registered format for CFSTR_FILEDESCRIPTORA. */
    299331    UINT                        m_cfFileDescriptorA;
     
    310342public:
    311343
    312     SharedClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats);
     344    SharedClipboardWinEnumFormatEtc(void);
    313345    virtual ~SharedClipboardWinEnumFormatEtc(void);
     346
     347public:
     348
     349    int Init(LPFORMATETC pFormatEtc, ULONG cFormats);
     350    void Destroy(void);
    314351
    315352public: /* IUnknown methods. */
  • trunk/include/VBox/GuestHost/SharedClipboard-x11.h

    r98103 r100204  
    4242#include <X11/Intrinsic.h>
    4343
     44#include <iprt/req.h>
    4445#include <iprt/thread.h>
    4546
     
    113114    /** Flag indicating that the thread is in a started state. */
    114115    bool             fThreadStarted;
     116    /** Request queue.
     117     *  Needed for processing HGCM requests within the HGCM (main) thread from
     118     *  the X11 event thread. */
     119    RTREQQUEUE       hReqQ;
    115120    /** The X Toolkit widget which we use as our clipboard client.  It is never made visible. */
    116121    Widget           pWidget;
     
    159164
    160165/**
    161  * Structure for keeping a X11 read data request.
    162  */
    163 typedef struct _SHCLX11READDATAREQ
    164 {
    165     /** Actual read request to handle. */
    166     CLIPREADCBREQ *pReq;
    167     /** Result code of the operation on completion. */
    168     int            rcCompletion;
    169 } SHCLX11READDATAREQ;
    170 /** Pointer to a send data request. */
    171 typedef SHCLX11READDATAREQ *PSHCLX11READDATAREQ;
     166 * Structure describing an X11 clipboard request.
     167 */
     168typedef struct _SHCLX11REQUEST
     169{
     170    /** The clipboard context this request is associated with. */
     171    SHCLX11CTX      *pCtx;
     172    /** Event associated to this request. */
     173    PSHCLEVENT       pEvent;
     174    union
     175    {
     176        /** Format announcement to X. */
     177        struct
     178        {
     179            /** VBox formats to announce. */
     180            SHCLFORMATS      fFormats;
     181        } Formats;
     182        /** Read request. */
     183        struct
     184        {
     185            /** The format VBox would like the data in. */
     186            SHCLFORMAT       uFmtVBox;
     187            /** The format we requested from X11. */
     188            SHCLX11FMTIDX    idxFmtX11;
     189            /** How much bytes to read at max. */
     190            uint32_t         cbMax;
     191        } Read;
     192    };
     193} SHCLX11REQUEST;
     194/** Pointer to an X11 clipboard request. */
     195typedef SHCLX11REQUEST *PSHCLX11REQUEST;
     196
     197/**
     198 * Structure describing an X11 clipboard response to an X11 clipboard request.
     199 */
     200typedef struct _SHCLX11RESPONSE
     201{
     202    int rc;
     203    struct
     204    {
     205        void    *pvData;
     206        uint32_t cbData;
     207    } Read;
     208} SHCLX11RESPONSE;
     209/** Pointer to an X11 clipboard response. */
     210typedef SHCLX11RESPONSE *PSHCLX11RESPONSE;
    172211
    173212/** @name Shared Clipboard APIs for X11.
     
    179218int ShClX11ThreadStartEx(PSHCLX11CTX pCtx, const char *pszName, bool fGrab);
    180219int ShClX11ThreadStop(PSHCLX11CTX pCtx);
    181 int ShClX11ReportFormatsToX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats);
    182 int ShClX11ReadDataFromX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormat, CLIPREADCBREQ *pReq);
     220int ShClX11ReportFormatsToX11Async(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats);
     221int ShClX11ReadDataFromX11Async(PSHCLX11CTX pCtx, SHCLFORMAT uFmt, uint32_t cbData, PSHCLEVENT pEvent);
    183222void ShClX11SetCallbacks(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks);
    184223/** @} */
  • trunk/include/VBox/GuestHost/SharedClipboard.h

    r98103 r100204  
    5555/** Shared Clipboard format is HTML. */
    5656#define VBOX_SHCL_FMT_HTML          RT_BIT(2)
    57 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    58 /** Shared Clipboard format is a transfer list. */
     57/** Shared Clipboard format is a transfer list.
     58 *
     59 *  When requesting (reading) data with this format, the following happens:
     60 *  - Acts as a beacon for transfer negotiation / handshake.
     61 *  - The receiving side (source) initializes a transfer locally.
     62 *  - The receiving side reports the transfer status (INIT) to the sending side (target).
     63 *  - The sending side proceeds initializing the transfer locally.
     64 *  - The sending side reports its transfer status (INIT) to the receiving side.
     65 *
     66 *  Note: When receiving an error via a transfer status, the transfer must be destroyed and
     67 *  is considered as being failed wholesale.
     68 *
     69 *  @since 7.1
     70 */
    5971# define VBOX_SHCL_FMT_URI_LIST     RT_BIT(3)
    60 #endif
    6172/** @}  */
    6273
     
    7182/** Pointer to a bit map of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */
    7283typedef SHCLFORMATS *PSHCLFORMATS;
     84
     85/** Defines the default timeout (in ms) to use for clipboard operations. */
     86#define SHCL_TIMEOUT_DEFAULT_MS                 RT_MS_30SEC
    7387
    7488
     
    193207 *  @{
    194208 */
     209int ShClPayloadInit(uint32_t uID, void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload);
    195210int ShClPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload);
    196211void ShClPayloadFree(PSHCLEVENTPAYLOAD pPayload);
     
    316331     *         Runs in Xt event thread for the X11 code.
    317332     *
    318      * @returns VBox status code. VERR_NO_DATA if no data available.
     333     * @returns VBox status code.
     334     * @retval  VERR_NO_DATA if no data available.
    319335     * @param   pCtx            Opaque context pointer for the glue code.
    320336     * @param   uFmt            The format in which the data should be transferred
     
    345361/** @} */
    346362
    347 /** Opaque request structure for X11 clipboard data.
    348  * @{ */
    349 struct CLIPREADCBREQ;
    350 typedef struct CLIPREADCBREQ CLIPREADCBREQ;
    351 /** @} */
    352 
    353363#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_h */
    354364
  • trunk/include/VBox/HostServices/VBoxClipboardSvc.h

    r100021 r100204  
    798798
    799799/** No listing flags specified. */
    800 #define VBOX_SHCL_LIST_FLAG_NONE          0
     800#define VBOX_SHCL_LIST_F_NONE               0
    801801/** Only returns one entry per read. */
    802 #define VBOX_SHCL_LIST_FLAG_RETURN_ONE    RT_BIT(0)
     802#define VBOX_SHCL_LIST_F_RETURN_ONE         RT_BIT(0)
    803803/** Restarts reading a list from the beginning. */
    804 #define VBOX_SHCL_LIST_FLAG_RESTART       RT_BIT(1)
    805 
    806 #define VBOX_SHCL_LISTHDR_FLAG_NONE       0
     804#define VBOX_SHCL_LIST_F_RESTART            RT_BIT(1)
     805/** Listing flags valid mask. */
     806#define VBOX_SHCL_LIST_F_VALID_MASK         0x3
     807
     808/** No list header flags specified. */
     809#define VBOX_SHCL_LISTHDR_F_NONE            0
     810/** List header flags valid mask. */
     811#define VBOX_SHCL_LISTHDR_F_VALID_MASK      0x0
    807812
    808813/** No additional information provided. */
    809 #define VBOX_SHCL_INFO_FLAG_NONE          0
     814#define VBOX_SHCL_INFO_F_NONE               0
    810815/** Get object information of type SHCLFSOBJINFO. */
    811 #define VBOX_SHCL_INFO_FLAG_FSOBJINFO     RT_BIT(0)
     816#define VBOX_SHCL_INFO_F_FSOBJINFO          RT_BIT(0)
     817/** Info flags valid mask. */
     818#define VBOX_SHCL_INFO_F_VALID_MASK         0x1
    812819
    813820/**
     
    929936    /** uint32_t, in: VBOX_SHCL_INFO_FLAG_XXX. */
    930937    HGCMFunctionParameter fInfo;
    931     /** uint32_t, in: Index of root list entry to get (zero-based). */
     938    /** uint64_t, in: Index of root list entry to get (zero-based). */
    932939    HGCMFunctionParameter uIndex;
    933940} VBoxShClRootListEntryParms;
     
    957964    /** in/out: Request parameters. */
    958965    VBoxShClRootListEntryParms Parms;
    959     /** pointer, in/out: Entry name. */
     966    /** pointer, in/out: Entry name.
     967     *  Up to SHCLLISTENTRY_MAX_NAME. */
    960968    HGCMFunctionParameter      szName;
    961969    /** uint32_t, out: Bytes to be used for information/How many bytes were used.  */
  • trunk/include/VBox/VBoxGuestLib.h

    r99739 r100204  
    688688        struct
    689689        {
    690             /** ID of the trnasfer. */
     690            /** ID of the transfer. */
    691691            SHCLTRANSFERID     uID;
    692692            /** Transfer direction. */
    693693            SHCLTRANSFERDIR    enmDir;
    694             /** Additional reproting information. */
     694            /** Additional reporting information. */
    695695            SHCLTRANSFERREPORT Report;
    696696        } TransferStatus;
     
    717717VBGLR3DECL(int)     VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures);
    718718VBGLR3DECL(int)     VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures);
     719VBGLR3DECL(int)     VbglR3ClipboardMsgPeek(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck);
    719720VBGLR3DECL(int)     VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck);
    720721VBGLR3DECL(int)     VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent);
     
    724725
    725726#  ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    726 VBGLR3DECL(void)    VbglR3ClipboardTransferSetCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacks);
     727VBGLR3DECL(void)    VbglR3ClipboardTransferSetCallbacks(PSHCLTRANSFERCALLBACKS pCallbacks);
    727728VBGLR3DECL(int)     VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFERCTX pTransferCtx, PVBGLR3CLIPBOARDEVENT pEvent);
    728729
    729730VBGLR3DECL(int)     VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus);
    730731
    731 VBGLR3DECL(int)     VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST *ppRootList);
     732VBGLR3DECL(int)     VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLLIST *ppRootList);
    732733
    733734VBGLR3DECL(int)     VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots);
    734 VBGLR3DECL(int)     VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST pRootList);
    735 VBGLR3DECL(int)     VbglR3ClipboardRootsWrite(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRoots);
     735VBGLR3DECL(int)     VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLIST pRootList);
     736VBGLR3DECL(int)     VbglR3ClipboardRootsWrite(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRoots);
    736737
    737738VBGLR3DECL(int)     VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList);
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp

    r100090 r100204  
    9393*********************************************************************************************************************************/
    9494#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    95 static DECLCALLBACK(int)  vboxClipboardOnTransferInitCallback(PSHCLTXPROVIDERCTX pCtx);
    96 static DECLCALLBACK(int)  vboxClipboardOnTransferStartCallback(PSHCLTXPROVIDERCTX pCtx);
    97 static DECLCALLBACK(void) vboxClipboardOnTransferCompleteCallback(PSHCLTXPROVIDERCTX pCtx, int rc);
    98 static DECLCALLBACK(void) vboxClipboardOnTransferErrorCallback(PSHCLTXPROVIDERCTX pCtx, int rc);
     95static DECLCALLBACK(void) vbtrShClTransferInitializedCallback(PSHCLTXPROVIDERCTX pCtx);
     96static DECLCALLBACK(void) vbtrShClTransferStartedCallback(PSHCLTXPROVIDERCTX pCtx);
     97static DECLCALLBACK(void) vbtrShClTransferErrorCallback(PSHCLTXPROVIDERCTX pCtx, int rc);
    9998#endif
    10099
     
    108107 * @param   pTransfer           Pointer to transfer to cleanup.
    109108 */
    110 static void vboxClipboardTransferCallbackCleanup(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer)
     109static void vbtrShClTransferCallbackCleanup(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer)
    111110{
    112111    LogFlowFuncEnter();
     
    130129}
    131130
    132 /** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnInitialize */
    133 static DECLCALLBACK(int) vboxClipboardOnTransferInitCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     131/**
     132 * Worker for a reading clipboard from the host.
     133 *
     134 * @thread  Main clipboard thread.
     135 */
     136static DECLCALLBACK(int) vbtrShClRequestDataFromSourceCallbackWorker(PSHCLCONTEXT pCtx,
     137                                                                     SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
     138{
     139    RT_NOREF(pvUser);
     140
     141    LogFlowFuncEnter();
     142
     143    int rc = VERR_NO_DATA; /* Play safe. */
     144
     145    uint32_t cbRead = 0;
     146
     147    uint32_t cbData = _4K; /** @todo Make this dynamic. */
     148    void    *pvData = RTMemAlloc(cbData);
     149    if (pvData)
     150    {
     151        rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
     152    }
     153    else
     154        rc = VERR_NO_MEMORY;
     155
     156    /*
     157     * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
     158     * larger buffer.  The size of the buffer needed is placed in *pcb.
     159     * So we start all over again.
     160     */
     161    if (rc == VINF_BUFFER_OVERFLOW)
     162    {
     163        /* cbRead contains the size required. */
     164
     165        cbData = cbRead;
     166        pvData = RTMemRealloc(pvData, cbRead);
     167        if (pvData)
     168        {
     169            rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
     170            if (rc == VINF_BUFFER_OVERFLOW)
     171                rc = VERR_BUFFER_OVERFLOW;
     172        }
     173        else
     174            rc = VERR_NO_MEMORY;
     175    }
     176
     177    if (!cbRead)
     178        rc = VERR_NO_DATA;
     179
     180    if (RT_SUCCESS(rc))
     181    {
     182        if (ppv)
     183            *ppv = pvData;
     184        if (pcb)
     185            *pcb = cbRead; /* Actual bytes read. */
     186    }
     187    else
     188    {
     189        /*
     190         * Catch other errors. This also catches the case in which the buffer was
     191         * too small a second time, possibly because the clipboard contents
     192         * changed half-way through the operation.  Since we can't say whether or
     193         * not this is actually an error, we just return size 0.
     194         */
     195        RTMemFree(pvData);
     196    }
     197
     198    LogFlowFuncLeaveRC(rc);
     199    return rc;
     200}
     201
     202/**
     203 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
     204 *
     205 * Called from the IDataObject implementation to request data from the host.
     206 *
     207 * @thread  shclwnd thread.
     208 */
     209DECLCALLBACK(int) vbtrShClRequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
     210                                                        SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
     211{
     212    PRTREQ pReq = NULL;
     213    int rc = RTReqQueueCallEx(pCtx->Win.hReqQ, &pReq, SHCL_TIMEOUT_DEFAULT_MS, RTREQFLAGS_IPRT_STATUS,
     214                              (PFNRT)vbtrShClRequestDataFromSourceCallbackWorker, 5, pCtx, uFmt, ppv, pcb, pvUser);
     215    RTReqRelease(pReq);
     216    return rc;
     217}
     218
     219/**
     220 * @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnStart
     221 *
     222 * Called from VbglR3 (main thread) to notify the IDataObject.
     223 *
     224 * @thread  Clipboard main thread.
     225 */
     226static DECLCALLBACK(void) vbtrShClTransferStartedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
    134227{
    135228    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
    136229    AssertPtr(pCtx);
    137230
    138     LogFlowFunc(("pCtx=%p\n", pCtx));
    139 
    140     RT_NOREF(pCtx);
    141 
    142     return VINF_SUCCESS;
    143 }
    144 
    145 /** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnStart */
    146 static DECLCALLBACK(int) vboxClipboardOnTransferStartCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     231    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     232    AssertPtr(pTransfer);
     233
     234    const SHCLTRANSFERDIR enmDir = ShClTransferGetDir(pTransfer);
     235
     236    LogFlowFunc(("pCtx=%p, idTransfer=%RU32, enmDir=%RU32\n", pCtx, ShClTransferGetID(pTransfer), enmDir));
     237
     238    int rc;
     239
     240    /* The guest wants to transfer data to the host. */
     241    if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
     242    {
     243        rc = SharedClipboardWinTransferGetRootsFromClipboard(&pCtx->Win, pTransfer);
     244    }
     245    /* The guest wants to transfer data from the host. */
     246    else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
     247    {
     248        rc = RTCritSectEnter(&pCtx->Win.CritSect);
     249        if (RT_SUCCESS(rc))
     250        {
     251            SharedClipboardWinDataObject *pObj = pCtx->Win.pDataObjInFlight;
     252            AssertPtrReturnVoid(pObj);
     253            rc = pObj->SetAndStartTransfer(pTransfer);
     254
     255            pCtx->Win.pDataObjInFlight = NULL; /* Hand off to Windows. */
     256
     257            int rc2 = RTCritSectLeave(&pCtx->Win.CritSect);
     258            AssertRC(rc2);
     259        }
     260    }
     261    else
     262        AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
     263
     264    if (RT_FAILURE(rc))
     265        LogRel(("Shared Clipboard: Starting transfer failed, rc=%Rrc\n", rc));
     266
     267    LogFlowFunc(("LEAVE: idTransfer=%RU32, rc=%Rrc\n", ShClTransferGetID(pTransfer), rc));
     268}
     269
     270/** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnCompleted */
     271static DECLCALLBACK(void) vbtrShClTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion)
    147272{
    148273    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
    149274    AssertPtr(pCtx);
    150275
    151     PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
    152     AssertPtr(pTransfer);
    153 
    154     const SHCLTRANSFERDIR enmDir = ShClTransferGetDir(pTransfer);
    155 
    156     LogFlowFunc(("pCtx=%p, idTransfer=%RU32, enmDir=%RU32\n", pCtx, ShClTransferGetID(pTransfer), enmDir));
    157 
    158     int rc;
    159 
    160     /* The guest wants to write local data to the host? */
    161     if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
    162     {
    163         rc = SharedClipboardWinGetRoots(&pCtx->Win, pTransfer);
    164     }
    165     /* The guest wants to read data from a remote source. */
    166     else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
    167     {
    168         /* The IDataObject *must* be created on the same thread as our (proxy) window, so post a message to it
    169          * to do the stuff for us. */
    170         PSHCLEVENT pEvent;
    171         rc = ShClEventSourceGenerateAndRegisterEvent(&pTransfer->Events, &pEvent);
    172         if (RT_SUCCESS(rc))
    173         {
    174             /* Don't want to rely on SendMessage (synchronous) here, so just post and wait the event getting signalled. */
    175             ::PostMessage(pCtx->Win.hWnd, SHCL_WIN_WM_TRANSFER_START, (WPARAM)pTransfer, (LPARAM)pEvent->idEvent);
    176 
    177             PSHCLEVENTPAYLOAD pPayload;
    178             rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
    179             if (RT_SUCCESS(rc))
    180             {
    181                 Assert(pPayload->cbData == sizeof(int));
    182                 rc = *(int *)pPayload->pvData;
    183 
    184                 ShClPayloadFree(pPayload);
    185             }
    186 
    187             ShClEventRelease(pEvent);
    188         }
    189         else
    190             AssertFailedStmt(rc = VERR_SHCLPB_MAX_EVENTS_REACHED);
    191     }
    192     else
    193         AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
    194 
    195     if (RT_FAILURE(rc))
    196         LogRel(("Shared Clipboard: Starting transfer failed, rc=%Rrc\n", rc));
    197 
    198     LogFlowFunc(("LEAVE: idTransfer=%RU32, rc=%Rrc\n", ShClTransferGetID(pTransfer), rc));
    199     return rc;
    200 }
    201 
    202 /** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnCompleted */
    203 static DECLCALLBACK(void) vboxClipboardOnTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion)
     276    LogRel2(("Shared Clipboard: Transfer to destination %s\n",
     277             rcCompletion == VERR_CANCELLED ? "canceled" : "complete"));
     278
     279    vbtrShClTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer);
     280}
     281
     282/** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnError */
     283static DECLCALLBACK(void) vbtrShClTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError)
    204284{
    205285    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
    206286    AssertPtr(pCtx);
    207287
    208     LogRel2(("Shared Clipboard: Transfer to destination %s\n",
    209              rcCompletion == VERR_CANCELLED ? "canceled" : "complete"));
    210 
    211     vboxClipboardTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer);
    212 }
    213 
    214 /** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnError */
    215 static DECLCALLBACK(void) vboxClipboardOnTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError)
    216 {
    217     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
    218     AssertPtr(pCtx);
    219 
    220288    LogRel(("Shared Clipboard: Transfer to destination failed with %Rrc\n", rcError));
    221289
    222     vboxClipboardTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer);
     290    vbtrShClTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer);
    223291}
    224292
    225293#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    226294
    227 static LRESULT vboxClipboardWinProcessMsg(PSHCLCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     295static LRESULT vbtrShClWndProcWorker(PSHCLCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    228296{
    229297    AssertPtr(pCtx);
     
    335403        }
    336404
    337         case WM_RENDERFORMAT:
     405        case WM_RENDERFORMAT: /* Guest wants to render the clipboard data. */
    338406        {
    339407            LogFunc(("WM_RENDERFORMAT\n"));
     
    346414            LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat));
    347415
     416#ifdef LOG_ENABLED
     417            char *pszFmts = ShClFormatsToStrA(fFormat);
     418            AssertPtrReturn(pszFmts, 0);
     419            LogRel(("Shared Clipboard: Rendering Windows format %#x as VBox format '%s'\n", cfFormat, pszFmts));
     420            RTStrFree(pszFmts);
     421#endif
    348422            if (fFormat == VBOX_SHCL_FMT_NONE)
    349423            {
    350                 LogFunc(("WM_RENDERFORMAT: Unsupported format requested\n"));
     424                LogRel(("Shared Clipboard: Unsupported format (%#x) requested\n", cfFormat));
    351425                SharedClipboardWinClear();
    352426            }
     
    535609        }
    536610
    537         case SHCL_WIN_WM_REPORT_FORMATS:
     611        case SHCL_WIN_WM_REPORT_FORMATS: /* Host reported clipboard formats. */
    538612        {
    539613            LogFunc(("SHCL_WIN_WM_REPORT_FORMATS\n"));
     
    546620            const SHCLFORMATS fFormats = pEvent->u.fReportedFormats;
    547621
     622#ifdef LOG_ENABLED
     623            char *pszFmts = ShClFormatsToStrA(fFormats);
     624            AssertPtrReturn(pszFmts, 0);
     625            LogRel(("Shared Clipboard: Host reported formats '%s'\n", pszFmts));
     626            RTStrFree(pszFmts);
     627#endif
    548628            if (fFormats != VBOX_SHCL_FMT_NONE) /* Could arrive with some older GA versions. */
    549629            {
    550 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    551                 if (fFormats & VBOX_SHCL_FMT_URI_LIST)
    552                 {
    553                     LogFunc(("VBOX_SHCL_FMT_URI_LIST\n"));
    554 
     630                int rc = SharedClipboardWinClearAndAnnounceFormats(pWinCtx, fFormats, hwnd);
     631#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     632                if (   RT_SUCCESS(rc)
     633                    && fFormats & VBOX_SHCL_FMT_URI_LIST)
     634                {
    555635                    /*
    556636                     * Creating and starting the actual transfer will be done in vbglR3ClipboardTransferStart() as soon
     
    558638                     * Transfers always are controlled and initiated on the host side!
    559639                     *
    560                      * So don't announce the transfer to the OS here yet. Don't touch the clipboard in any way here; otherwise
    561                      * this will trigger a WM_DRAWCLIPBOARD or friends, which will result in fun bugs coming up.
     640                     * What we need to do here, however, is, that we create our IDataObject implementation and push it to the
     641                     * Windows clibpoard. That way Windows will recognize that there is a data transfer "in flight".
    562642                     */
    563                 }
    564                 else
    565                 {
    566 #endif
    567                     SharedClipboardWinClearAndAnnounceFormats(pWinCtx, fFormats, hwnd);
    568 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     643                    SHCLCALLBACKS Callbacks;
     644                    RT_ZERO(Callbacks);
     645                    Callbacks.pfnOnRequestDataFromSource = vbtrShClRequestDataFromSourceCallback;
     646
     647                    rc = SharedClipboardWinTransferCreateAndSetDataObject(pWinCtx, pCtx, &Callbacks);
    569648                }
    570649#endif
     
    575654        }
    576655
    577         case SHCL_WIN_WM_READ_DATA:
     656        case SHCL_WIN_WM_READ_DATA: /* Host wants to read clipboard data from the guest. */
    578657        {
    579658            /* Send data in the specified format to the host. */
     
    585664
    586665            LogFlowFunc(("SHCL_WIN_WM_READ_DATA: fFormat=%#x\n", fFormat));
    587 
     666#ifdef LOG_ENABLED
     667            char *pszFmts = ShClFormatsToStrA(fFormat);
     668            AssertPtrReturn(pszFmts, 0);
     669            LogRel(("Shared Clipboard: Sending data to host as '%s'\n", pszFmts));
     670            RTStrFree(pszFmts);
     671#endif
    588672            int rc = SharedClipboardWinOpen(hwnd);
    589673            HANDLE hClip = NULL;
     
    673757        }
    674758
    675 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    676         case SHCL_WIN_WM_TRANSFER_START:
    677         {
    678             LogFunc(("SHCL_WIN_WM_TRANSFER_START\n"));
    679 
    680             PSHCLTRANSFER pTransfer  = (PSHCLTRANSFER)wParam;
    681             AssertPtr(pTransfer);
    682 
    683             const SHCLEVENTID idEvent = (SHCLEVENTID)lParam;
    684 
    685             Assert(ShClTransferGetSource(pTransfer) == SHCLSOURCE_REMOTE); /* Sanity. */
    686 
    687             int rcTransfer = SharedClipboardWinTransferCreate(pWinCtx, pTransfer);
    688 
    689             PSHCLEVENTPAYLOAD pPayload = NULL;
    690             int rc = ShClPayloadAlloc(idEvent, &rcTransfer, sizeof(rcTransfer), &pPayload);
    691             if (RT_SUCCESS(rc))
    692             {
    693                 rc = ShClEventSignal(&pTransfer->Events, idEvent, pPayload);
    694                 if (RT_FAILURE(rc))
    695                     ShClPayloadFree(pPayload);
    696             }
    697 
    698             break;
    699         }
    700 #endif
    701759        case WM_DESTROY:
    702760        {
     
    726784}
    727785
    728 static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    729 
    730 static int vboxClipboardCreateWindow(PSHCLCONTEXT pCtx)
     786static LRESULT CALLBACK vbtrShClWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
     787
     788static int vbtrShClCreateWindow(PSHCLCONTEXT pCtx)
    731789{
    732790    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     
    747805    {
    748806        wc.style         = CS_NOCLOSE;
    749         wc.lpfnWndProc   = vboxClipboardWinWndProc;
     807        wc.lpfnWndProc   = vbtrShClWndProc;
    750808        wc.hInstance     = pCtx->pEnv->hInstance;
    751809        wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
     
    788846}
    789847
    790 static DECLCALLBACK(int) vboxClipboardWindowThread(RTTHREAD hThread, void *pvUser)
     848static DECLCALLBACK(int) vbtrShClWindowThread(RTTHREAD hThread, void *pvUser)
    791849{
    792850    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pvUser;
     
    802860    else
    803861        LogRel(("Shared Clipboard: Initialized OLE in window thread\n"));
    804 #endif
    805 
    806     int rc = vboxClipboardCreateWindow(pCtx);
     862#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     863
     864    int rc = vbtrShClCreateWindow(pCtx);
    807865    if (RT_FAILURE(rc))
    808866    {
     
    855913}
    856914
    857 static void vboxClipboardDestroy(PSHCLCONTEXT pCtx)
    858 {
     915static LRESULT CALLBACK vbtrShClWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     916{
     917    PSHCLCONTEXT pCtx = &g_Ctx; /** @todo r=andy Make pCtx available through SetWindowLongPtr() / GWL_USERDATA. */
     918    AssertPtr(pCtx);
     919
     920    /* Forward with proper context. */
     921    return vbtrShClWndProcWorker(pCtx, hWnd, uMsg, wParam, lParam);
     922}
     923
     924DECLCALLBACK(int) vbtrShClInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
     925{
     926    LogFlowFuncEnter();
     927
     928    PSHCLCONTEXT pCtx = &g_Ctx; /* Only one instance for now. */
     929    AssertPtr(pCtx);
     930
     931    if (pCtx->pEnv)
     932    {
     933        /* Clipboard was already initialized. 2 or more instances are not supported. */
     934        return VERR_NOT_SUPPORTED;
     935    }
     936
     937    if (VbglR3AutoLogonIsRemoteSession())
     938    {
     939        /* Do not use clipboard for remote sessions. */
     940        LogRel(("Shared Clipboard: Clipboard has been disabled for a remote session\n"));
     941        return VERR_NOT_SUPPORTED;
     942    }
     943
     944    pCtx->pEnv      = pEnv;
     945    pCtx->hThread   = NIL_RTTHREAD;
     946    pCtx->fStarted  = false;
     947    pCtx->fShutdown = false;
     948
     949    int rc = RTReqQueueCreate(&pCtx->Win.hReqQ);
     950    AssertRCReturn(rc, rc);
     951
     952    rc = SharedClipboardWinCtxInit(&pCtx->Win);
     953    if (RT_SUCCESS(rc))
     954        rc = VbglR3ClipboardConnectEx(&pCtx->CmdCtx, VBOX_SHCL_GF_0_CONTEXT_ID);
     955    if (RT_SUCCESS(rc))
     956    {
     957#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     958        rc = ShClTransferCtxInit(&pCtx->TransferCtx);
     959#endif
     960        if (RT_SUCCESS(rc))
     961        {
     962            /* Message pump thread for our proxy window. */
     963            rc = RTThreadCreate(&pCtx->hThread, vbtrShClWindowThread, pCtx /* pvUser */,
     964                                0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
     965                                "shclwnd");
     966            if (RT_SUCCESS(rc))
     967            {
     968                int rc2 = RTThreadUserWait(pCtx->hThread, RT_MS_30SEC /* Timeout in ms */);
     969                AssertRC(rc2);
     970
     971                if (!pCtx->fStarted) /* Did the thread fail to start? */
     972                    rc = VERR_NOT_SUPPORTED; /* Report back Shared Clipboard as not being supported. */
     973            }
     974        }
     975
     976        if (RT_SUCCESS(rc))
     977        {
     978            *ppInstance = pCtx;
     979        }
     980        else
     981            VbglR3ClipboardDisconnectEx(&pCtx->CmdCtx);
     982    }
     983
     984    if (RT_FAILURE(rc))
     985        LogRel(("Shared Clipboard: Unable to initialize, rc=%Rrc\n", rc));
     986
     987    LogFlowFuncLeaveRC(rc);
     988    return rc;
     989}
     990
     991DECLCALLBACK(int) vbtrShClWorker(void *pInstance, bool volatile *pfShutdown)
     992{
     993    AssertPtr(pInstance);
     994    LogFlowFunc(("pInstance=%p\n", pInstance));
     995
     996    /*
     997     * Tell the control thread that it can continue
     998     * spawning services.
     999     */
     1000    RTThreadUserSignal(RTThreadSelf());
     1001
     1002    const PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
     1003    AssertPtr(pCtx);
     1004
     1005    const PSHCLWINCTX pWinCtx = &pCtx->Win;
     1006
     1007    LogRel2(("Shared Clipboard: Worker loop running\n"));
     1008
     1009#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1010    HRESULT hr = OleInitialize(NULL);
     1011    if (FAILED(hr))
     1012    {
     1013        LogRel(("Shared Clipboard: Initializing OLE in worker thread failed (%Rhrc) -- file transfers unavailable\n", hr));
     1014        /* Not critical, the rest of the clipboard might work. */
     1015    }
     1016    else
     1017        LogRel(("Shared Clipboard: Initialized OLE in worker thread\n"));
     1018
     1019    /*
     1020     * Init callbacks.
     1021     * Those will be registered within VbglR3 when a new transfer gets initialized.
     1022     */
     1023    RT_ZERO(pCtx->CmdCtx.Transfers.Callbacks);
     1024
     1025    pCtx->CmdCtx.Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
     1026    pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
     1027
     1028    pCtx->CmdCtx.Transfers.Callbacks.pfnOnStarted     = vbtrShClTransferStartedCallback;
     1029    pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted   = vbtrShClTransferCompletedCallback;
     1030    pCtx->CmdCtx.Transfers.Callbacks.pfnOnError       = vbtrShClTransferErrorCallback;
     1031#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     1032
     1033    int rc;
     1034
     1035    /* The thread waits for incoming messages from the host. */
     1036    PVBGLR3CLIPBOARDEVENT pEvent = NULL;
     1037    for (;;)
     1038    {
     1039        LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n",
     1040                     pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
     1041
     1042        if (!pEvent)
     1043            pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
     1044        AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
     1045
     1046        uint32_t idMsg  = 0;
     1047        uint32_t cParms = 0;
     1048        rc = VbglR3ClipboardMsgPeek(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
     1049        if (RT_SUCCESS(rc))
     1050        {
     1051#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1052            rc = VbglR3ClipboardEventGetNextEx(idMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
     1053#else
     1054            rc = VbglR3ClipboardEventGetNext(idMsg, cParms, &pCtx->CmdCtx, pEvent);
     1055#endif
     1056        }
     1057        else if (rc == VERR_TRY_AGAIN) /* No new message (yet). */
     1058        {
     1059            RTReqQueueProcess(pCtx->Win.hReqQ, RT_MS_1SEC);
     1060            continue;
     1061        }
     1062
     1063        if (RT_FAILURE(rc))
     1064        {
     1065            LogFlowFunc(("Getting next event failed with %Rrc\n", rc));
     1066
     1067            VbglR3ClipboardEventFree(pEvent);
     1068            pEvent = NULL;
     1069
     1070            if (*pfShutdown)
     1071                break;
     1072
     1073            /* Wait a bit before retrying. */
     1074            RTThreadSleep(1000);
     1075            continue;
     1076        }
     1077        else
     1078        {
     1079            AssertPtr(pEvent);
     1080            LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType));
     1081
     1082            switch (pEvent->enmType)
     1083            {
     1084                case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS:
     1085                {
     1086                    /* The host has announced available clipboard formats.
     1087                     * Forward the information to the window, so it can later
     1088                     * respond to WM_RENDERFORMAT message. */
     1089                    ::PostMessage(pWinCtx->hWnd, SHCL_WIN_WM_REPORT_FORMATS,
     1090                                  0 /* wParam */, (LPARAM)pEvent /* lParam */);
     1091
     1092                    pEvent = NULL; /* Consume pointer. */
     1093                    break;
     1094                }
     1095
     1096                case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA:
     1097                {
     1098                    /* The host needs data in the specified format. */
     1099                    ::PostMessage(pWinCtx->hWnd, SHCL_WIN_WM_READ_DATA,
     1100                                  0 /* wParam */, (LPARAM)pEvent /* lParam */);
     1101
     1102                    pEvent = NULL; /* Consume pointer. */
     1103                    break;
     1104                }
     1105
     1106                case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
     1107                {
     1108                    LogRel2(("Shared Clipboard: Host requested termination\n"));
     1109                    ASMAtomicXchgBool(pfShutdown, true);
     1110                    break;
     1111                }
     1112
     1113#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1114                case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:
     1115                {
     1116                    /* Nothing to do here. */
     1117                    rc = VINF_SUCCESS;
     1118                    break;
     1119                }
     1120#endif
     1121                case VBGLR3CLIPBOARDEVENTTYPE_NONE:
     1122                {
     1123                    /* Nothing to do here. */
     1124                    rc = VINF_SUCCESS;
     1125                    break;
     1126                }
     1127
     1128                default:
     1129                {
     1130                    AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED);
     1131                }
     1132            }
     1133
     1134            if (pEvent)
     1135            {
     1136                VbglR3ClipboardEventFree(pEvent);
     1137                pEvent = NULL;
     1138            }
     1139        }
     1140
     1141        if (*pfShutdown)
     1142            break;
     1143    }
     1144
     1145    LogRel2(("Shared Clipboard: Worker loop ended\n"));
     1146
     1147#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1148    OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
     1149    OleUninitialize();
     1150#endif
     1151
     1152    LogFlowFuncLeaveRC(rc);
     1153    return rc;
     1154}
     1155
     1156DECLCALLBACK(int) vbtrShClStop(void *pInstance)
     1157{
     1158    AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
     1159
     1160    LogFunc(("Stopping pInstance=%p\n", pInstance));
     1161
     1162    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
     1163    AssertPtr(pCtx);
     1164
     1165    /* Set shutdown indicator. */
     1166    ASMAtomicWriteBool(&pCtx->fShutdown, true);
     1167
     1168    /* Let our clipboard know that we're going to shut down. */
     1169    PostMessage(pCtx->Win.hWnd, WM_QUIT, 0, 0);
     1170
     1171    /* Disconnect from the host service.
     1172     * This will also send a VBOX_SHCL_HOST_MSG_QUIT from the host so that we can break out from our message worker. */
     1173    VbglR3ClipboardDisconnect(pCtx->CmdCtx.idClient);
     1174    pCtx->CmdCtx.idClient = 0;
     1175
     1176    LogFlowFuncLeaveRC(VINF_SUCCESS);
     1177    return VINF_SUCCESS;
     1178}
     1179
     1180DECLCALLBACK(void) vbtrShClDestroy(void *pInstance)
     1181{
     1182    AssertPtrReturnVoid(pInstance);
     1183
     1184    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
    8591185    AssertPtrReturnVoid(pCtx);
     1186
     1187    /* Make sure that we are disconnected. */
     1188    Assert(pCtx->CmdCtx.idClient == 0);
    8601189
    8611190    LogFlowFunc(("pCtx=%p\n", pCtx));
     
    8841213    SharedClipboardWinCtxDestroy(&pCtx->Win);
    8851214
     1215#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1216    ShClTransferCtxDestroy(&pCtx->TransferCtx);
     1217#endif
     1218
     1219    RTReqQueueDestroy(pCtx->Win.hReqQ);
     1220
    8861221    LogRel2(("Shared Clipboard: Destroyed\n"));
    887 }
    888 
    889 static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    890 {
    891     PSHCLCONTEXT pCtx = &g_Ctx; /** @todo r=andy Make pCtx available through SetWindowLongPtr() / GWL_USERDATA. */
    892     AssertPtr(pCtx);
    893 
    894     /* Forward with proper context. */
    895     return vboxClipboardWinProcessMsg(pCtx, hWnd, uMsg, wParam, lParam);
    896 }
    897 
    898 DECLCALLBACK(int) VBoxShClInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
    899 {
    900     LogFlowFuncEnter();
    901 
    902     PSHCLCONTEXT pCtx = &g_Ctx; /* Only one instance for now. */
    903     AssertPtr(pCtx);
    904 
    905     if (pCtx->pEnv)
    906     {
    907         /* Clipboard was already initialized. 2 or more instances are not supported. */
    908         return VERR_NOT_SUPPORTED;
    909     }
    910 
    911     if (VbglR3AutoLogonIsRemoteSession())
    912     {
    913         /* Do not use clipboard for remote sessions. */
    914         LogRel(("Shared Clipboard: Clipboard has been disabled for a remote session\n"));
    915         return VERR_NOT_SUPPORTED;
    916     }
    917 
    918     pCtx->pEnv      = pEnv;
    919     pCtx->hThread   = NIL_RTTHREAD;
    920     pCtx->fStarted  = false;
    921     pCtx->fShutdown = false;
    922 
    923     int rc = VINF_SUCCESS;
    924 
    925 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    926     /*
    927      * Set callbacks.
    928      * Those will be registered within VbglR3 when a new transfer gets initialized.
    929      */
    930     RT_ZERO(pCtx->CmdCtx.Transfers.Callbacks);
    931 
    932     pCtx->CmdCtx.Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
    933     pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
    934 
    935     pCtx->CmdCtx.Transfers.Callbacks.pfnOnInitialize = vboxClipboardOnTransferInitCallback;
    936     pCtx->CmdCtx.Transfers.Callbacks.pfnOnStart      = vboxClipboardOnTransferStartCallback;
    937     pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted  = vboxClipboardOnTransferCompletedCallback;
    938     pCtx->CmdCtx.Transfers.Callbacks.pfnOnError      = vboxClipboardOnTransferErrorCallback;
    939 #endif
    940 
    941     if (RT_SUCCESS(rc))
    942     {
    943         rc = SharedClipboardWinCtxInit(&pCtx->Win);
    944         if (RT_SUCCESS(rc))
    945             rc = VbglR3ClipboardConnectEx(&pCtx->CmdCtx, VBOX_SHCL_GF_0_CONTEXT_ID);
    946         if (RT_SUCCESS(rc))
    947         {
    948 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    949             rc = ShClTransferCtxInit(&pCtx->TransferCtx);
    950 #endif
    951             if (RT_SUCCESS(rc))
    952             {
    953                 /* Message pump thread for our proxy window. */
    954                 rc = RTThreadCreate(&pCtx->hThread, vboxClipboardWindowThread, pCtx /* pvUser */,
    955                                     0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
    956                                     "shclwnd");
    957                 if (RT_SUCCESS(rc))
    958                 {
    959                     int rc2 = RTThreadUserWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */);
    960                     AssertRC(rc2);
    961 
    962                     if (!pCtx->fStarted) /* Did the thread fail to start? */
    963                         rc = VERR_NOT_SUPPORTED; /* Report back Shared Clipboard as not being supported. */
    964                 }
    965             }
    966 
    967             if (RT_SUCCESS(rc))
    968             {
    969                 *ppInstance = pCtx;
    970             }
    971             else
    972                 VbglR3ClipboardDisconnectEx(&pCtx->CmdCtx);
    973         }
    974     }
    975 
    976     if (RT_FAILURE(rc))
    977         LogRel(("Shared Clipboard: Unable to initialize, rc=%Rrc\n", rc));
    978 
    979     LogFlowFuncLeaveRC(rc);
    980     return rc;
    981 }
    982 
    983 DECLCALLBACK(int) VBoxShClWorker(void *pInstance, bool volatile *pfShutdown)
    984 {
    985     AssertPtr(pInstance);
    986     LogFlowFunc(("pInstance=%p\n", pInstance));
    987 
    988     /*
    989      * Tell the control thread that it can continue
    990      * spawning services.
    991      */
    992     RTThreadUserSignal(RTThreadSelf());
    993 
    994     const PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
    995     AssertPtr(pCtx);
    996 
    997     const PSHCLWINCTX pWinCtx = &pCtx->Win;
    998 
    999     LogRel2(("Shared Clipboard: Worker loop running\n"));
    1000 
    1001 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1002     HRESULT hr = OleInitialize(NULL);
    1003     if (FAILED(hr))
    1004     {
    1005         LogRel(("Shared Clipboard: Initializing OLE in worker thread failed (%Rhrc) -- file transfers unavailable\n", hr));
    1006         /* Not critical, the rest of the clipboard might work. */
    1007     }
    1008     else
    1009         LogRel(("Shared Clipboard: Initialized OLE in worker thread\n"));
    1010 #endif
    1011 
    1012     int rc;
    1013 
    1014     /* The thread waits for incoming messages from the host. */
    1015     for (;;)
    1016     {
    1017         LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n",
    1018                      pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
    1019 
    1020         PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
    1021         AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
    1022 
    1023         uint32_t idMsg  = 0;
    1024         uint32_t cParms = 0;
    1025         rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
    1026         if (RT_SUCCESS(rc))
    1027         {
    1028 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1029             rc = VbglR3ClipboardEventGetNextEx(idMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
    1030 #else
    1031             rc = VbglR3ClipboardEventGetNext(idMsg, cParms, &pCtx->CmdCtx, pEvent);
    1032 #endif
    1033         }
    1034 
    1035         if (RT_FAILURE(rc))
    1036         {
    1037             LogFlowFunc(("Getting next event failed with %Rrc\n", rc));
    1038 
    1039             VbglR3ClipboardEventFree(pEvent);
    1040             pEvent = NULL;
    1041 
    1042             if (*pfShutdown)
    1043                 break;
    1044 
    1045             /* Wait a bit before retrying. */
    1046             RTThreadSleep(1000);
    1047             continue;
    1048         }
    1049         else
    1050         {
    1051             AssertPtr(pEvent);
    1052             LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType));
    1053 
    1054             switch (pEvent->enmType)
    1055             {
    1056                 case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS:
    1057                 {
    1058                     /* The host has announced available clipboard formats.
    1059                      * Forward the information to the window, so it can later
    1060                      * respond to WM_RENDERFORMAT message. */
    1061                     ::PostMessage(pWinCtx->hWnd, SHCL_WIN_WM_REPORT_FORMATS,
    1062                                   0 /* wParam */, (LPARAM)pEvent /* lParam */);
    1063 
    1064                     pEvent = NULL; /* Consume pointer. */
    1065                     break;
    1066                 }
    1067 
    1068                 case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA:
    1069                 {
    1070                     /* The host needs data in the specified format. */
    1071                     ::PostMessage(pWinCtx->hWnd, SHCL_WIN_WM_READ_DATA,
    1072                                   0 /* wParam */, (LPARAM)pEvent /* lParam */);
    1073 
    1074                     pEvent = NULL; /* Consume pointer. */
    1075                     break;
    1076                 }
    1077 
    1078                 case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
    1079                 {
    1080                     LogRel2(("Shared Clipboard: Host requested termination\n"));
    1081                     ASMAtomicXchgBool(pfShutdown, true);
    1082                     break;
    1083                 }
    1084 
    1085 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1086                 case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:
    1087                 {
    1088                     /* Nothing to do here. */
    1089                     rc = VINF_SUCCESS;
    1090                     break;
    1091                 }
    1092 #endif
    1093                 case VBGLR3CLIPBOARDEVENTTYPE_NONE:
    1094                 {
    1095                     /* Nothing to do here. */
    1096                     rc = VINF_SUCCESS;
    1097                     break;
    1098                 }
    1099 
    1100                 default:
    1101                 {
    1102                     AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED);
    1103                 }
    1104             }
    1105 
    1106             if (pEvent)
    1107             {
    1108                 VbglR3ClipboardEventFree(pEvent);
    1109                 pEvent = NULL;
    1110             }
    1111         }
    1112 
    1113         if (*pfShutdown)
    1114             break;
    1115     }
    1116 
    1117     LogRel2(("Shared Clipboard: Worker loop ended\n"));
    1118 
    1119 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1120     OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
    1121     OleUninitialize();
    1122 #endif
    1123 
    1124     LogFlowFuncLeaveRC(rc);
    1125     return rc;
    1126 }
    1127 
    1128 DECLCALLBACK(int) VBoxShClStop(void *pInstance)
    1129 {
    1130     AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
    1131 
    1132     LogFunc(("Stopping pInstance=%p\n", pInstance));
    1133 
    1134     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
    1135     AssertPtr(pCtx);
    1136 
    1137     /* Set shutdown indicator. */
    1138     ASMAtomicWriteBool(&pCtx->fShutdown, true);
    1139 
    1140     /* Let our clipboard know that we're going to shut down. */
    1141     PostMessage(pCtx->Win.hWnd, WM_QUIT, 0, 0);
    1142 
    1143     /* Disconnect from the host service.
    1144      * This will also send a VBOX_SHCL_HOST_MSG_QUIT from the host so that we can break out from our message worker. */
    1145     VbglR3ClipboardDisconnect(pCtx->CmdCtx.idClient);
    1146     pCtx->CmdCtx.idClient = 0;
    1147 
    1148     LogFlowFuncLeaveRC(VINF_SUCCESS);
    1149     return VINF_SUCCESS;
    1150 }
    1151 
    1152 DECLCALLBACK(void) VBoxShClDestroy(void *pInstance)
    1153 {
    1154     AssertPtrReturnVoid(pInstance);
    1155 
    1156     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
    1157     AssertPtr(pCtx);
    1158 
    1159     /* Make sure that we are disconnected. */
    1160     Assert(pCtx->CmdCtx.idClient == 0);
    1161 
    1162     vboxClipboardDestroy(pCtx);
    1163 
    1164 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1165     ShClTransferCtxDestroy(&pCtx->TransferCtx);
    1166 #endif
    11671222
    11681223    return;
     
    11791234    "Shared Clipboard",
    11801235    /* methods */
    1181     VBoxShClInit,
    1182     VBoxShClWorker,
    1183     VBoxShClStop,
    1184     VBoxShClDestroy
     1236    vbtrShClInit,
     1237    vbtrShClWorker,
     1238    vbtrShClStop,
     1239    vbtrShClDestroy
    11851240};
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp

    r99739 r100204  
    9898static VBOXSERVICEINFO g_aServices[] =
    9999{
    100     {&g_SvcDescDnD,      NIL_RTTHREAD, NULL, false, false, false, false, true }
     100    { &g_SvcDescClipboard,      NIL_RTTHREAD, NULL, false, false, false, false, true }
    101101};
    102102#else
     
    533533        RTLogSetDefaultInstance(g_pLoggerRelease);
    534534
    535         const char *apszGroups[] = { "all", "guest_dnd" }; /* All groups we want to enable logging for VBoxTray. */
     535        /* All groups we want to enable logging for VBoxTray. */
     536        const char *apszGroups[] = { "guest_dnd", "shared_clipboard" };
    536537        char        szGroupSettings[_1K];
    537538
  • trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp

    r100015 r100204  
    5454#include <iprt/string.h>
    5555#include <iprt/cpp/ministring.h>
     56
     57#ifdef LOG_GROUP
     58 #undef LOG_GROUP
     59#endif
     60#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
     61#include <VBox/log.h>
    5662
    5763#include "VBoxGuestR3LibInternal.h"
     
    176182                {
    177183                    if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS))
    178                         LogRel2(("Shared Clipboard: Host does not support transfers\n"));
     184                        LogRel(("Shared Clipboard: Host does not support transfers\n"));
    179185                }
    180186#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     
    424430 * Reads data from the host clipboard.
    425431 *
    426  * Legacy function, do not use anymore.
    427  *
    428432 * @returns VBox status code.
    429433 * @retval  VINF_BUFFER_OVERFLOW    If there is more data available than the caller provided buffer space for.
     
    433437 * @param   pvData          Where to store the data.
    434438 * @param   cbData          The size of the buffer pointed to by \a pvData.
     439 *                          This also indicates the maximum size to read.
    435440 * @param   pcbRead         The actual size of the host clipboard data. May be larger than \a cbData.
    436441 */
     
    438443                                        uint32_t *pcbRead)
    439444{
    440     LogFlowFuncEnter();
     445    LogFlowFunc(("fFormat=%#x, pvData=%p, cbData=%RU32\n", fFormat, pvData, cbData));
    441446
    442447    struct
     
    532537
    533538/**
     539 * Peeks at the next host message, extended version.
     540 *
     541 * This glosses over the difference between new (6.1) and old (1.3.2) host
     542 * service versions, however it does so by abusing @a pcParameters, so don't use
     543 * it directly when in legacy mode, always pass it on to
     544 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
     545 *
     546 * @returns VBox status code.
     547 * @retval  VERR_INTERRUPTED if interrupted.  Does the necessary cleanup, so
     548 *          caller just have to repeat this call.
     549 * @retval  VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
     550 * @retval  VERR_TRY_AGAIN if no new message is available.
     551 *
     552 * @param   pCtx            Shared Clipboard command context to use for the connection.
     553 * @param   fWait           Wait for new messages to arrive if \c true, return immediately if \c false.
     554 * @param   pidMsg          Where to store the message id.
     555 * @param   pcParameters    Where to store the number  of parameters which will
     556 *                          be received in a second call to the host.
     557 * @param   pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
     558 *                          for the VM restore check.  Optional.
     559 *
     560 * @note    Restore check is only performed optimally with a 6.0 host.
     561 */
     562static int vbglR3ClipboardMsgPeekEx(PVBGLR3SHCLCMDCTX pCtx, bool fWait, uint32_t *pidMsg,
     563                                    uint32_t *pcParameters, uint64_t *pidRestoreCheck)
     564{
     565    AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
     566    AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
     567
     568    struct
     569    {
     570        VBGLIOCHGCMCALL Hdr;
     571        HGCMFunctionParameter idMsg;       /* Doubles as restore check on input. */
     572        HGCMFunctionParameter cParameters;
     573    } Msg;
     574    int rc;
     575    if (!pCtx->fUseLegacyProtocol)
     576    {
     577        VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient,
     578                           fWait ? VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT
     579                                 : VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT, 2);
     580        VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
     581        VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
     582        rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
     583        Log4Func(("VbglR3HGCMCall -> %Rrc\n", rc));
     584        if (RT_SUCCESS(rc))
     585        {
     586            AssertMsgReturn(   Msg.idMsg.type       == VMMDevHGCMParmType_64bit
     587                            && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
     588                            ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
     589                            VERR_INTERNAL_ERROR_3);
     590
     591            *pidMsg       = (uint32_t)Msg.idMsg.u.value64;
     592            *pcParameters = Msg.cParameters.u.value32;
     593            return rc;
     594        }
     595
     596        /*
     597         * If restored, update pidRestoreCheck.
     598         */
     599        if (rc == VERR_VM_RESTORED && pidRestoreCheck)
     600            *pidRestoreCheck = Msg.idMsg.u.value64;
     601    }
     602    else
     603    {
     604        /*
     605         * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
     606         * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
     607         * VbglR3ClipboardEventGetNextEx, so that's fine...
     608         */
     609        rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
     610        if (RT_SUCCESS(rc))
     611            return rc;
     612    }
     613
     614    /*
     615     * If interrupted we must cancel the call so it doesn't prevent us from making another one.
     616     */
     617    if (rc == VERR_INTERRUPTED)
     618    {
     619        VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_CANCEL, 0);
     620        int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
     621        AssertRC(rc2);
     622    }
     623
     624    *pidMsg       = UINT32_MAX - 1;
     625    *pcParameters = UINT32_MAX - 2;
     626    return rc;
     627}
     628
     629/**
    534630 * Peeks at the next host message, waiting for one to turn up.
    535631 *
     
    556652                                           uint32_t *pcParameters, uint64_t *pidRestoreCheck)
    557653{
    558     AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
    559     AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
    560 
    561     struct
    562     {
    563         VBGLIOCHGCMCALL Hdr;
    564         HGCMFunctionParameter idMsg;       /* Doubles as restore check on input. */
    565         HGCMFunctionParameter cParameters;
    566     } Msg;
    567     int rc;
    568     if (!pCtx->fUseLegacyProtocol)
    569     {
    570         VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, 2);
    571         VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
    572         VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
    573         rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
    574         LogFlowFunc(("VbglR3HGCMCall -> %Rrc\n", rc));
    575         if (RT_SUCCESS(rc))
    576         {
    577             AssertMsgReturn(   Msg.idMsg.type       == VMMDevHGCMParmType_64bit
    578                             && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
    579                             ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
    580                             VERR_INTERNAL_ERROR_3);
    581 
    582             *pidMsg       = (uint32_t)Msg.idMsg.u.value64;
    583             *pcParameters = Msg.cParameters.u.value32;
    584             return rc;
    585         }
    586 
    587         /*
    588          * If restored, update pidRestoreCheck.
    589          */
    590         if (rc == VERR_VM_RESTORED && pidRestoreCheck)
    591             *pidRestoreCheck = Msg.idMsg.u.value64;
    592     }
    593     else
    594     {
    595         /*
    596          * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
    597          * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
    598          * VbglR3ClipboardEventGetNextEx, so that's fine...
    599          */
    600         rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
    601         if (RT_SUCCESS(rc))
    602             return rc;
    603     }
    604 
    605     /*
    606      * If interrupted we must cancel the call so it doesn't prevent us from making another one.
    607      */
    608     if (rc == VERR_INTERRUPTED)
    609     {
    610         VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_CANCEL, 0);
    611         int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
    612         AssertRC(rc2);
    613     }
    614 
    615     *pidMsg       = UINT32_MAX - 1;
    616     *pcParameters = UINT32_MAX - 2;
    617     return rc;
     654    return vbglR3ClipboardMsgPeekEx(pCtx, true /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
     655}
     656
     657/**
     658 * Peeks at the next host message, returning immediately.
     659 *
     660 * This glosses over the difference between new (6.1) and old (1.3.2) host
     661 * service versions, however it does so by abusing @a pcParameters, so don't use
     662 * it directly when in legacy mode, always pass it on to
     663 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
     664 *
     665 * @returns VBox status code.
     666 * @retval  VERR_INTERRUPTED if interrupted.  Does the necessary cleanup, so
     667 *          caller just have to repeat this call.
     668 * @retval  VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
     669 * @retval  VERR_TRY_AGAIN if no new message is available.
     670 *
     671 * @param   pCtx            Shared Clipboard command context to use for the connection.
     672 * @param   pidMsg          Where to store the message id.
     673 * @param   pcParameters    Where to store the number  of parameters which will
     674 *                          be received in a second call to the host.
     675 * @param   pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
     676 *                          for the VM restore check.  Optional.
     677 *
     678 * @note    Restore check is only performed optimally with a 6.0 host.
     679 */
     680VBGLR3DECL(int) VbglR3ClipboardMsgPeek(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
     681                                       uint32_t *pcParameters, uint64_t *pidRestoreCheck)
     682{
     683    return vbglR3ClipboardMsgPeekEx(pCtx, false /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
    618684}
    619685
     
    627693 * @param   pRootListHdr        Where to store the received root list header.
    628694 */
    629 static int vbglR3ClipboardRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
     695static int vbglR3ClipboardRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
    630696{
    631697    AssertPtrReturn(pCtx,         VERR_INVALID_POINTER);
     
    645711    if (RT_SUCCESS(rc))
    646712    {
    647         rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fRoots); AssertRC(rc);
    648         if (RT_SUCCESS(rc))
    649         {
    650             rc = Msg.cRoots.GetUInt64(&pRootListHdr->cRoots);
     713        rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fFeatures); AssertRC(rc);
     714        if (RT_SUCCESS(rc))
     715        {
     716            rc = Msg.cRoots.GetUInt64(&pRootListHdr->cEntries);
    651717            AssertRC(rc);
     718
     719            pRootListHdr->cbTotalSize = 0; /* Unused for the root list header. */
    652720        }
    653721    }
     
    665733 * @param   pRootListEntry      Where to store the root list entry read from the host.
    666734 */
    667 static int vbglR3ClipboardRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pRootListEntry)
     735static int vbglR3ClipboardRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint64_t uIndex, PSHCLLISTENTRY pRootListEntry)
    668736{
    669737    AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
     
    675743                       VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ);
    676744
     745    uint32_t const fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; /* For now the only info we have. */
     746
    677747    Msg.Parms.uContext.SetUInt64(pCtx->idContext);
    678     Msg.Parms.fInfo.SetUInt32(pRootListEntry->fInfo);
    679     Msg.Parms.uIndex.SetUInt32(uIndex);
    680 
    681     Msg.szName.SetPtr(pRootListEntry->pszName, pRootListEntry->cbName);
    682     Msg.cbInfo.SetUInt32(pRootListEntry->cbInfo);
    683     Msg.pvInfo.SetPtr(pRootListEntry->pvInfo, pRootListEntry->cbInfo);
    684 
    685     int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
    686     if (RT_SUCCESS(rc))
    687     {
    688         rc = Msg.Parms.fInfo.GetUInt32(&pRootListEntry->fInfo); AssertRC(rc);
    689         if (RT_SUCCESS(rc))
    690         {
    691             uint32_t cbInfo = 0;
    692             rc = Msg.cbInfo.GetUInt32(&cbInfo); AssertRC(rc);
    693             if (pRootListEntry->cbInfo != cbInfo)
    694                 rc = VERR_INVALID_PARAMETER;
    695         }
    696     }
     748    Msg.Parms.fInfo.SetUInt32(fInfo);
     749    Msg.Parms.uIndex.SetUInt64(uIndex);
     750
     751    char szName[SHCLLISTENTRY_MAX_NAME];
     752    Msg.szName.SetPtr(szName, sizeof(szName));
     753
     754    void    *pvInfo = NULL;
     755    uint32_t cbInfo = 0;
     756
     757    int rc = VINF_SUCCESS;
     758
     759    if ((fInfo & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO)
     760    {
     761        cbInfo = sizeof(SHCLFSOBJINFO);
     762        pvInfo = RTMemAlloc(cbInfo);
     763        if (!pvInfo)
     764            rc = VERR_NO_MEMORY;
     765    }
     766
     767    if (RT_SUCCESS(rc))
     768    {
     769        Msg.cbInfo.SetUInt32(cbInfo);
     770        Msg.pvInfo.SetPtr(pvInfo, cbInfo);
     771
     772        rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
     773        if (RT_SUCCESS(rc))
     774        {
     775            uint32_t fInfoRet;
     776            rc = Msg.Parms.fInfo.GetUInt32(&fInfoRet);
     777            AssertRCReturn(rc, rc);
     778            AssertMsgStmt((fInfoRet & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO,
     779                          ("Host returned unknown entry info flags (%#x)\n", fInfoRet), rc = VERR_INVALID_PARAMETER);
     780            if (RT_SUCCESS(rc))
     781            {
     782                uint32_t cbInfoRet = 0;
     783                Msg.cbInfo.GetUInt32(&cbInfoRet);
     784
     785                AssertMsgStmt(cbInfo == cbInfoRet,
     786                              ("Host reported cbInfo %RU32, expected %RU32\n", cbInfoRet, cbInfo), rc = VERR_INVALID_PARAMETER);
     787
     788                rc = ShClTransferListEntryInitEx(pRootListEntry, fInfo, szName, pvInfo, cbInfo);
     789                if (RT_SUCCESS(rc))
     790                {
     791                    pvInfo = NULL;  /* Entry took ownership of pvInfo now. */
     792                    cbInfo = 0;
     793                }
     794            }
     795        }
     796    }
     797
     798    RTMemFree(pvInfo);
    697799
    698800    LogFlowFuncLeaveRC(rc);
     
    705807 * @returns VBox status code.
    706808 * @param   pCtx                Shared Clipboard command context to use for the connection.
    707  * @param   ppRootList          Where to store the (allocated) root list. Must be free'd by the caller with
    708  *                              SharedClipboardTransferRootListFree().
    709  */
    710 VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST *ppRootList)
    711 {
    712     AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
    713     AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
    714 
    715     int rc;
    716 
    717     PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
    718     if (pRootList)
    719     {
    720         rc = vbglR3ClipboardRootListHdrRead(pCtx, &pRootList->Hdr);
    721         if (RT_SUCCESS(rc))
    722         {
    723             if (pRootList->Hdr.cRoots)
     809 * @param   pRootList           Where to store the read root list.
     810 *
     811 */
     812VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer)
     813{
     814    AssertPtrReturn(pCtx,      VERR_INVALID_POINTER);
     815    AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
     816
     817    SHCLLISTHDR Hdr;
     818    int rc = vbglR3ClipboardRootListHdrRead(pCtx, &Hdr);
     819    if (RT_SUCCESS(rc))
     820    {
     821        LogFlowFunc(("cEntries=%RU64, cTotalSize=%RU64\n", Hdr.cEntries, Hdr.cbTotalSize));
     822
     823        for (uint64_t i = 0; i < Hdr.cEntries; i++)
     824        {
     825            PSHCLLISTENTRY pEntry = NULL;
     826            rc = ShClTransferListEntryAlloc(&pEntry);
     827            if (RT_SUCCESS(rc))
    724828            {
    725                 pRootList->paEntries =
    726                     (PSHCLROOTLISTENTRY)RTMemAllocZ(pRootList->Hdr.cRoots * sizeof(SHCLROOTLISTENTRY));
    727                 if (pRootList->paEntries)
    728                 {
    729                     for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++)
    730                     {
    731                         SHCLROOTLISTENTRY *pEntry = &pRootList->paEntries[i];
    732                         AssertPtr(pEntry);
    733 
    734                         rc = ShClTransferRootListEntryInit(pEntry);
    735                         if (RT_SUCCESS(rc))
    736                             rc = vbglR3ClipboardRootListEntryRead(pCtx, i, pEntry);
    737 
    738                         if (RT_FAILURE(rc))
    739                             break;
    740                     }
    741                 }
    742                 else
    743                     rc = VERR_NO_MEMORY;
     829                rc = vbglR3ClipboardRootListEntryRead(pCtx, i, pEntry);
     830                if (RT_SUCCESS(rc))
     831                    rc = ShClTransferListAddEntry(&pTransfer->lstRoots, pEntry, true /* fAppend */);
    744832            }
    745         }
    746 
    747         if (RT_SUCCESS(rc))
    748         {
    749             *ppRootList = pRootList;
    750         }
    751         else
    752             ShClTransferRootListFree(pRootList);
    753     }
    754     else
    755         rc = VERR_NO_MEMORY;
     833
     834            if (RT_FAILURE(rc))
     835            {
     836                ShClTransferListEntryFree(pEntry);
     837                break;
     838            }
     839        }
     840    }
    756841
    757842    LogFlowFuncLeaveRC(rc);
     
    891976 * @param   pRootListHdr        Root lsit header to reply to the host.
    892977 */
    893 VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
     978VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
    894979{
    895980    AssertPtrReturn(pCtx,         VERR_INVALID_POINTER);
     
    901986
    902987    Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
    903     Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fRoots);
    904 
    905     Msg.cRoots.SetUInt64(pRootListHdr->cRoots);
     988    Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fFeatures);
     989
     990    Msg.cRoots.SetUInt64(pRootListHdr->cEntries);
    906991
    907992    int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
     
    9611046 * @param   pEntry              Actual root list entry to reply.
    9621047 */
    963 VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pEntry)
     1048VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLLISTENTRY pEntry)
    9641049{
    9651050    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
     
    12021287        rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
    12031288        if (RT_SUCCESS(rc))
    1204             rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cTotalObjects);
     1289            rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cEntries);
    12051290        if (RT_SUCCESS(rc))
    12061291            rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
     
    12711356    Msg.fFeatures.SetUInt32(0);
    12721357    Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
    1273     Msg.cTotalObjects.SetUInt64(pListHdr->cTotalObjects);
     1358    Msg.cTotalObjects.SetUInt64(pListHdr->cEntries);
    12741359    Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
    12751360
     
    16811766    Msg.uContext.SetUInt64(pCtx->idContext);
    16821767    Msg.uHandle.SetUInt64(hObj);
     1768    Msg.cbData.SetUInt32(cbData);
    16831769    Msg.pvData.SetPtr(pvData, cbData);
     1770    Msg.cbChecksum.SetUInt32(0);
    16841771    Msg.pvChecksum.SetPtr(NULL, 0);
    16851772
     
    17021789*********************************************************************************************************************************/
    17031790
    1704 /** @copydoc SHCLTXPROVIDERIFACE::pfnRootsGet */
    1705 static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
     1791/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
     1792static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx)
    17061793{
    17071794    LogFlowFuncEnter();
     
    17101797    AssertPtr(pCmdCtx);
    17111798
    1712     int rc = VbglR3ClipboardRootListRead(pCmdCtx, ppRootList);
     1799    int rc = VbglR3ClipboardRootListRead(pCmdCtx, pCtx->pTransfer);
    17131800
    17141801    LogFlowFuncLeaveRC(rc);
     
    18321919
    18331920/**
    1834  * Starts a transfer on the guest side.
     1921 * Initializes a transfer on the guest side.
    18351922 *
    18361923 * @returns VBox status code.
    18371924 * @param   pCmdCtx             Command context to use.
    1838  * @param   pTransferCtx        Transfer context to create transfer for.
    1839  * @param   uTransferID         ID to use for transfer to start.
    1840  * @param   enmDir              Direction of transfer to start.
    1841  * @param   enmSource           Source of transfer to start.
     1925 * @param   pTransferCtx        Transfer context to init transfer for.
     1926 * @param   uTransferID         ID to use for transfer to init.
     1927 * @param   enmDir              Direction of transfer to init.
     1928 * @param   enmSource           Source of transfer to init.
    18421929 * @param   ppTransfer          Where to return the transfer object on success. Optional.
    18431930 */
    1844 static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
    1845                                         SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
    1846                                         PSHCLTRANSFER *ppTransfer)
    1847 {
     1931static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
     1932                                       SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
     1933                                       PSHCLTRANSFER *ppTransfer)
     1934{
     1935    LogFlowFuncEnter();
     1936
    18481937    PSHCLTRANSFER pTransfer;
    18491938    int rc = ShClTransferCreate(&pTransfer);
    18501939    if (RT_SUCCESS(rc))
    18511940    {
     1941        /* Set the callbacks the (OS-dependent) implementation relies on. Optional. */
    18521942        ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
    18531943
     
    18551945        if (RT_SUCCESS(rc))
    18561946        {
    1857             rc = ShClTransferCtxTransferRegisterById(pTransferCtx, pTransfer, uTransferID);
     1947            SHCLTXPROVIDER Provider;
     1948            RT_ZERO(Provider);
     1949
     1950            /* Assign local provider first and overwrite interface methods below if needed. */
     1951            VBClTransferProviderLocalQueryInterface(&Provider);
     1952
     1953            /* If this is a read transfer (reading data from host), set the interface to use
     1954             * our VbglR3 routines here. */
     1955            if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Host -> Guest */
     1956            {
     1957                Provider.Interface.pfnRootListRead  = vbglR3ClipboardTransferIfaceRootListRead;
     1958
     1959                Provider.Interface.pfnListOpen      = vbglR3ClipboardTransferIfaceListOpen;
     1960                Provider.Interface.pfnListClose     = vbglR3ClipboardTransferIfaceListClose;
     1961                Provider.Interface.pfnListHdrRead   = vbglR3ClipboardTransferIfaceListHdrRead;
     1962                Provider.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
     1963
     1964                Provider.Interface.pfnObjOpen       = vbglR3ClipboardTransferIfaceObjOpen;
     1965                Provider.Interface.pfnObjClose      = vbglR3ClipboardTransferIfaceObjClose;
     1966                Provider.Interface.pfnObjRead       = vbglR3ClipboardTransferIfaceObjRead;
     1967            }
     1968
     1969            Provider.pvUser = pCmdCtx;
     1970
     1971            rc = ShClTransferSetProvider(pTransfer, &Provider);
     1972
     1973            /* As a last step, register the transfer with our transfer context. */
    18581974            if (RT_SUCCESS(rc))
    1859             {
    1860                 SHCLTXPROVIDERCREATIONCTX creationCtx;
    1861                 RT_ZERO(creationCtx);
    1862 
    1863                 /* Assign local provider first and overwrite interface methods below if needed. */
    1864                 VBClTransferQueryIfaceLocal(&creationCtx.Interface);
    1865 
    1866                 /* If this is a read transfer (reading data from host), set the interface to use
    1867                  * our VbglR3 routines here. */
    1868                 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
    1869                 {
    1870                     creationCtx.Interface.pfnRootsGet      = vbglR3ClipboardTransferIfaceRootsGet;
    1871 
    1872                     creationCtx.Interface.pfnListOpen      = vbglR3ClipboardTransferIfaceListOpen;
    1873                     creationCtx.Interface.pfnListClose     = vbglR3ClipboardTransferIfaceListClose;
    1874                     creationCtx.Interface.pfnListHdrRead   = vbglR3ClipboardTransferIfaceListHdrRead;
    1875                     creationCtx.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
    1876 
    1877                     creationCtx.Interface.pfnObjOpen       = vbglR3ClipboardTransferIfaceObjOpen;
    1878                     creationCtx.Interface.pfnObjClose      = vbglR3ClipboardTransferIfaceObjClose;
    1879                     creationCtx.Interface.pfnObjRead       = vbglR3ClipboardTransferIfaceObjRead;
    1880 
    1881                     creationCtx.pvUser = pCmdCtx;
    1882 
    1883                     rc = ShClTransferSetProviderIface(pTransfer, &creationCtx);
    1884                 }
    1885 
    1886                 if (RT_SUCCESS(rc))
    1887                     rc = ShClTransferStart(pTransfer);
    1888             }
     1975                rc = ShClTransferCtxTransferRegisterById(pTransferCtx, pTransfer, uTransferID);
    18891976
    18901977            if (RT_FAILURE(rc))
     
    18981985            *ppTransfer = pTransfer;
    18991986
    1900         LogRel2(("Shared Clipboard: Transfer ID=%RU32 (%s %s) successfully started\n",
    1901                  uTransferID,
    1902                  enmDir    == SHCLTRANSFERDIR_FROM_REMOTE ? "reading from" : "writing to",
    1903                  enmSource == SHCLSOURCE_LOCAL            ? "local"        : "remote"));
     1987        LogRel(("Shared Clipboard: Transfer %RU32 (%s) successfully initialized\n",
     1988                uTransferID,
     1989                enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "host -> guest" : "guest -> host"));
    19041990    }
    19051991    else
    1906         LogRel(("Shared Clipboard: Unable to start transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
     1992        LogRel(("Shared Clipboard: Unable to initialize transfer %RU32, rc=%Rrc\n", uTransferID, rc));
     1993
     1994    /* Send a reply in any case. */
     1995    int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
     1996                                                   RT_SUCCESS(rc)
     1997                                                 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
     1998    if (RT_SUCCESS(rc))
     1999        rc = rc2;
     2000
     2001    if (RT_FAILURE(rc))
     2002    {
     2003        ShClTransferDestroy(pTransfer);
     2004        pTransfer = NULL;
     2005    }
     2006
     2007    LogFlowFuncLeaveRC(rc);
     2008    return rc;
     2009}
     2010
     2011/**
     2012 * Uninitializes a transfer on the guest side.
     2013 *
     2014 * @returns VBox status code.
     2015 * @param   pCmdCtx             Command context to use.
     2016 * @param   pTransferCtx        Transfer context to uninit transfer for.
     2017 * @param   uTransferID         ID to use for transfer to uninit.
     2018 */
     2019static int vbglR3ClipboardTransferUninit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID uTransferID)
     2020{
     2021    RT_NOREF(pCmdCtx);
     2022
     2023    LogFlowFuncEnter();
     2024
     2025    int rc;
     2026
     2027    PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
     2028    if (pTransfer)
     2029    {
     2030        rc = ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
     2031        if (RT_SUCCESS(rc))
     2032            rc = ShClTransferDestroy(pTransfer);
     2033
     2034        if (RT_SUCCESS(rc))
     2035        {
     2036            LogRel(("Shared Clipboard: Transfer %RU32 successfully uninitialized\n", uTransferID));
     2037        }
     2038        else
     2039            LogRel(("Shared Clipboard: Unable to uninitialized transfer %RU32, rc=%Rrc\n", uTransferID, rc));
     2040    }
     2041    else
     2042        rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
     2043
     2044    /* Send a reply in any case. */
     2045    int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
     2046                                                   RT_SUCCESS(rc)
     2047                                                 ? SHCLTRANSFERSTATUS_UNINITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
     2048
     2049    /* The host might not have the transfer around anymore at this time, so simply ignore this error. */
     2050    if (rc2 == VERR_SHCLPB_TRANSFER_ID_NOT_FOUND)
     2051        rc2 = VINF_SUCCESS;
     2052
     2053    if (RT_SUCCESS(rc))
     2054        rc = rc2;
     2055
     2056    LogFlowFuncLeaveRC(rc);
     2057    return rc;
     2058}
     2059
     2060/**
     2061 * Starts a transfer on the guest side.
     2062 *
     2063 * @returns VBox status code.
     2064 * @param   pCmdCtx             Command context to use.
     2065 * @param   pTransferCtx        Transfer context to start transfer for.
     2066 * @param   uTransferID         ID to use for transfer to start.
     2067 */
     2068static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
     2069                                        SHCLTRANSFERID uTransferID)
     2070{
     2071    RT_NOREF(pCmdCtx);
     2072
     2073    LogFlowFuncEnter();
     2074
     2075    int rc;
     2076
     2077    PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
     2078    if (pTransfer)
     2079    {
     2080        rc = ShClTransferStart(pTransfer);
     2081        if (RT_SUCCESS(rc))
     2082        {
     2083            LogRel(("Shared Clipboard: Transfer %RU32 successfully started\n", uTransferID));
     2084        }
     2085        else
     2086            LogRel(("Shared Clipboard: Unable to start transfer %RU32, rc=%Rrc\n", uTransferID, rc));
     2087    }
     2088    else
     2089        rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
    19072090
    19082091    /* Send a reply in any case. */
     
    19132096        rc = rc2;
    19142097
    1915     if (RT_FAILURE(rc))
    1916     {
    1917         ShClTransferDestroy(pTransfer);
    1918         pTransfer = NULL;
    1919     }
    1920 
    19212098    LogFlowFuncLeaveRC(rc);
    19222099    return rc;
     
    19342111                                       SHCLTRANSFERID uTransferID)
    19352112{
     2113    LogFlowFuncEnter();
     2114
    19362115    int rc;
    19372116
     
    19422121        if (RT_SUCCESS(rc))
    19432122        {
    1944             LogRel2(("Shared Clipboard: Transfer ID=%RU32 successfully stopped\n", uTransferID));
     2123            LogRel(("Shared Clipboard: Transfer %RU32 successfully stopped\n", uTransferID));
    19452124        }
    19462125        else
    1947             LogRel(("Shared Clipboard: Unable to stop transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
    1948 
    1949         /* Send a reply in any case. */
    1950         int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
    1951                                                        RT_SUCCESS(rc)
    1952                                                      ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
    1953         AssertRC(rc2);
     2126            LogRel(("Shared Clipboard: Unable to stop transfer %RU32, rc=%Rrc\n", uTransferID, rc));
    19542127    }
    19552128    else
    1956         rc = VERR_NOT_FOUND;
     2129        rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
     2130
     2131    /* Send a reply in any case. */
     2132    int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
     2133                                                   RT_SUCCESS(rc)
     2134                                                 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
     2135    if (RT_SUCCESS(rc))
     2136        rc = rc2;
    19572137
    19582138    LogFlowFuncLeaveRC(rc);
     
    19662146 * @param   pCallbacks          Pointer to callback table to set.
    19672147 */
    1968 VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx,  PSHCLTRANSFERCALLBACKTABLE pCallbacks)
     2148VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx,  PSHCLTRANSFERCALLBACKS pCallbacks)
    19692149{
    19702150    AssertPtrReturnVoid(pCmdCtx);
     
    20002180                    const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
    20012181
    2002                     LogFlowFunc(("[Transfer %RU32] enmDir=%RU32, status=%s\n",
    2003                                  uTransferID, enmDir, ShClTransferStatusToStr(transferReport.uStatus)));
     2182                    LogRel(("Shared Clipboard: Received status %s (%Rrc) for transfer %RU32\n",
     2183                            ShClTransferStatusToStr(transferReport.uStatus), transferReport.rc, uTransferID));
    20042184
    20052185                    switch (transferReport.uStatus)
    20062186                    {
     2187                        case SHCLTRANSFERSTATUS_NONE:
     2188                            AssertFailed(); /* Should never happen. */
     2189                            break;
     2190
    20072191                        case SHCLTRANSFERSTATUS_INITIALIZED:
    2008                             RT_FALL_THROUGH();
    2009                         case SHCLTRANSFERSTATUS_STARTED:
    20102192                        {
    20112193                            SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
    20122194
    20132195                            /* The host announces the transfer direction from its point of view, so inverse the direction here. */
    2014                             if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
     2196                            if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Host -> Guest */
    20152197                            {
    20162198                                enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
    20172199                                enmSource = SHCLSOURCE_REMOTE;
     2200
     2201                                rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransferCtx, uTransferID,
     2202                                                                 enmDir, enmSource, NULL /* ppTransfer */);
    20182203                            }
    2019                             else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
     2204                            else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host */
    20202205                            {
     2206                                /* Already initialized when remote (host) was reading the URI data. */
    20212207                                enmDir = SHCLTRANSFERDIR_TO_REMOTE;
    20222208                                enmSource = SHCLSOURCE_LOCAL;
     2209
     2210                                rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransferCtx, uTransferID,
     2211                                                                 enmDir, enmSource, NULL /* ppTransfer */);
    20232212                            }
    20242213                            else
    20252214                                AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
    20262215
    2027                             rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
    2028                                                               enmDir, enmSource, NULL /* ppTransfer */);
     2216                            break;
     2217                        }
     2218
     2219                        case SHCLTRANSFERSTATUS_UNINITIALIZED:
     2220                        {
     2221                            rc = vbglR3ClipboardTransferUninit(pCmdCtx, pTransferCtx, uTransferID);
     2222                            break;
     2223                        }
     2224
     2225                        case SHCLTRANSFERSTATUS_STARTED:
     2226                        {
     2227                            rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID);
    20292228                            break;
    20302229                        }
     
    20442243
    20452244                        default:
     2245                            LogRel(("Shared Clipboard: Received unknown status %#x (%Rrc) for transfer %RU32\n",
     2246                                    pEvent->u.TransferStatus.Report.uStatus, pEvent->u.TransferStatus.Report.rc,
     2247                                    pEvent->u.TransferStatus.uID));
    20462248                            rc = VERR_NOT_SUPPORTED;
    20472249                            break;
     
    20552257
    20562258                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
    2057 
    2058                         LogRel2(("Shared Clipboard: Received status %s (rc=%Rrc) for transfer ID=%RU32\n",
    2059                                  ShClTransferStatusToStr(pEvent->u.TransferStatus.Report.uStatus), pEvent->u.TransferStatus.Report.rc,
    2060                                  pEvent->u.TransferStatus.uID));
    20612259                    }
    20622260                }
     
    20772275                    AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
    20782276
    2079                     SHCLROOTLISTHDR rootListHdr;
    2080                     RT_ZERO(rootListHdr);
    2081 
    2082                     rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
    2083 
    2084                     LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
     2277                    SHCLLISTHDR rootListHdr;
     2278                    ShClTransferListHdrInit(&rootListHdr);
     2279
     2280                    rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
     2281
     2282                    LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries));
    20852283
    20862284                    rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
     
    21002298                    AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
    21012299
    2102                     SHCLROOTLISTENTRY rootListEntry;
    2103                     rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
    2104                     if (RT_SUCCESS(rc))
    2105                         rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
     2300                    PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIndex);
     2301                    if (pEntry)
     2302                    {
     2303                        rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, pEntry);
     2304                    }
     2305                    else
     2306                        rc = VERR_NOT_FOUND;
    21062307                }
    21072308                break;
     
    25532754VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
    25542755{
    2555     LogFlowFunc(("ENTER: fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
    25562756    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    2557     if (cbData > 0)
    2558         AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     2757    AssertReturn(cbData == 0 || RT_VALID_PTR(pvData), VERR_INVALID_PARAMETER);
     2758
     2759    LogFlowFunc(("fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
    25592760
    25602761    int rc;
  • trunk/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h

    r98103 r100204  
    7171
    7272/* The shared clipboard service prototypes. */
    73 int VBoxShClInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
     73int vbtrShClInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
    7474unsigned __stdcall VBoxShClThread(void *pInstance);
    75 void VBoxShClDestroy(const VBOXSERVICEENV *pEnv, void *pInstance);
     75void vbtrShClDestroy(const VBOXSERVICEENV *pEnv, void *pInstance);
    7676
    7777#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h */
  • trunk/src/VBox/Additions/x11/VBoxClient/clipboard-x11.cpp

    r99987 r100204  
    4040#include <iprt/semaphore.h>
    4141
    42 #include <VBox/log.h>
     42#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
     43#include <iprt/log.h>
     44
    4345#include <VBox/VBoxGuestLib.h>
    4446#include <VBox/HostServices/VBoxClipboardSvc.h>
     
    5052#include "clipboard.h"
    5153
    52 
     54#include <iprt/req.h>
     55
     56
     57#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     58#if 0
     59/**
     60 * Worker for reading the transfer root list from the host.
     61 */
     62static DECLCALLBACK(int) vbclX11ReqTransferReadRootListWorker(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
     63{
     64    RT_NOREF(pCtx);
     65
     66    LogFlowFuncEnter();
     67
     68    int rc = ShClTransferRootListRead(pTransfer);
     69
     70    LogFlowFuncLeaveRC(rc);
     71    return rc;
     72}
     73#endif
     74
     75/**
     76 * Worker for waiting for a transfer status change.
     77 */
     78static DECLCALLBACK(int) vbclX11TransferWaitForStatusWorker(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS enmSts,
     79                                                            RTMSINTERVAL msTimeout)
     80{
     81    RT_NOREF(pCtx);
     82
     83    LogFlowFuncEnter();
     84
     85    int rc = VERR_TIMEOUT;
     86
     87    ShClTransferAcquire(pTransfer);
     88
     89    uint64_t const tsStartMs = RTTimeMilliTS();
     90
     91    while (RTTimeMilliTS() - tsStartMs <= msTimeout)
     92    {
     93        if (ShClTransferGetStatus(pTransfer) == enmSts) /* Currently we only have busy waiting here. */
     94        {
     95            rc = VINF_SUCCESS;
     96            break;
     97        }
     98        RTThreadSleep(100);
     99    }
     100
     101    ShClTransferRelease(pTransfer);
     102
     103    return rc;
     104}
     105
     106/**
     107 * @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnRegistered
     108 *
     109 * This starts the HTTP server if not done yet and registers the transfer with it.
     110 *
     111 * @thread Clipbpoard main thread.
     112 */
     113static DECLCALLBACK(void) vbclX11OnHttpTransferRegisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
     114{
     115    RT_NOREF(pTransferCtx);
     116
     117    LogFlowFuncEnter();
     118
     119    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     120    AssertPtr(pCtx);
     121
     122    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     123    AssertPtr(pTransfer);
     124
     125    ShClTransferAcquire(pTransfer);
     126
     127    /* We only need to start the HTTP server when we actually receive data from the remote (host). */
     128    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
     129    {
     130        /* Retrieve the root entries as a first action, so that the transfer is ready to go
     131         * once it gets registered to HTTP server below. */
     132        int rc2 = ShClTransferRootListRead(pTransfer);
     133        if (RT_SUCCESS(rc2))
     134        {
     135            ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
     136            rc2 = ShClTransferHttpServerRegisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
     137        }
     138
     139        if (RT_FAILURE(rc2))
     140            LogRel(("Shared Clipboard: Registering HTTP transfer failed: %Rrc\n", rc2));
     141    }
     142
     143    LogFlowFuncLeave();
     144}
     145
     146/**
     147 * Unregisters a transfer from a HTTP server.
     148 *
     149 * This also stops the HTTP server if no active transfers are found anymore.
     150 *
     151 * @param   pCtx                Shared clipboard context to unregister transfer for.
     152 * @param   pTransfer           Transfer to unregister.
     153 *
     154 * @thread Clipbpoard main thread.
     155 */
     156static void vbclX11HttpTransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
     157{
     158    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
     159    {
     160        ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
     161        ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
     162    }
     163
     164    ShClTransferRelease(pTransfer);
     165}
     166
     167/**
     168 * @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnUnregistered
     169 *
     170 * Unregisters a (now) unregistered transfer from the HTTP server.
     171 *
     172 * @thread Clipbpoard main thread.
     173 */
     174static DECLCALLBACK(void) vbclX11OnHttpTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
     175{
     176    RT_NOREF(pTransferCtx);
     177    vbclX11HttpTransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
     178}
     179
     180/**
     181 * @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnCompleted
     182 *
     183 * Unregisters a complete transfer from the HTTP server.
     184 *
     185 * @thread Clipbpoard main thread.
     186 */
     187static DECLCALLBACK(void) vbclX11OnHttpTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rc)
     188{
     189    RT_NOREF(rc);
     190    vbclX11HttpTransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
     191}
     192
     193/** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnError
     194 *
     195 * Unregisters a failed transfer from the HTTP server.
     196 *
     197 * @thread Clipbpoard main thread.
     198 */
     199static DECLCALLBACK(void) vbclX11OnHttpTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCtx, int rc)
     200{
     201    return vbclX11OnHttpTransferCompletedCallback(pCtx, rc);
     202}
     203#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
     204
     205/**
     206 * Worker for a reading clipboard from the host.
     207 */
     208static DECLCALLBACK(int) vbclX11ReqReadDataWorker(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
     209{
     210    RT_NOREF(pvUser);
     211
     212    LogFlowFuncEnter();
     213
     214    int rc = VERR_NO_DATA; /* Play safe. */
     215
     216    uint32_t cbRead = 0;
     217
     218    uint32_t cbData = _4K; /** @todo Make this dynamic. */
     219    void    *pvData = RTMemAlloc(cbData);
     220    if (pvData)
     221    {
     222        rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
     223    }
     224    else
     225        rc = VERR_NO_MEMORY;
     226
     227    /*
     228     * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
     229     * larger buffer.  The size of the buffer needed is placed in *pcb.
     230     * So we start all over again.
     231     */
     232    if (rc == VINF_BUFFER_OVERFLOW)
     233    {
     234        /* cbRead contains the size required. */
     235
     236        cbData = cbRead;
     237        pvData = RTMemRealloc(pvData, cbRead);
     238        if (pvData)
     239        {
     240            rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
     241            if (rc == VINF_BUFFER_OVERFLOW)
     242                rc = VERR_BUFFER_OVERFLOW;
     243        }
     244        else
     245            rc = VERR_NO_MEMORY;
     246    }
     247
     248    if (!cbRead)
     249        rc = VERR_NO_DATA;
     250
     251    if (RT_SUCCESS(rc))
     252    {
     253        if (ppv)
     254            *ppv = pvData;
     255        if (pcb)
     256            *pcb = cbRead; /* Actual bytes read. */
     257    }
     258    else
     259    {
     260        /*
     261         * Catch other errors. This also catches the case in which the buffer was
     262         * too small a second time, possibly because the clipboard contents
     263         * changed half-way through the operation.  Since we can't say whether or
     264         * not this is actually an error, we just return size 0.
     265         */
     266        RTMemFree(pvData);
     267    }
     268
     269    LogFlowFuncLeaveRC(rc);
     270    return rc;
     271}
     272
     273/**
     274 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
     275 *
     276 * Requests URI data from the host.
     277 * This initiates a transfer on the host. Most of the handling will be done VbglR3 then.
     278 *
     279 * @thread  X11 event thread.
     280 */
    53281static DECLCALLBACK(int) vbclX11OnRequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
    54282                                                                SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
     
    58286    LogFlowFunc(("pCtx=%p, uFmt=%#x\n", pCtx, uFmt));
    59287
    60     int rc = VINF_SUCCESS;
    61 
    62 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     288    /* Request reading host clipboard data. */
     289    PRTREQ pReq = NULL;
     290    int rc = RTReqQueueCallEx(pCtx->X11.hReqQ, &pReq, SHCL_TIMEOUT_DEFAULT_MS, RTREQFLAGS_IPRT_STATUS,
     291                              (PFNRT)vbclX11ReqReadDataWorker, 5, pCtx, uFmt, ppv, pcb, pvUser);
     292    RTReqRelease(pReq);
     293
     294#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
    63295    if (uFmt == VBOX_SHCL_FMT_URI_LIST)
    64296    {
    65         //rc = VbglR3ClipboardRootListRead()
    66         rc = VERR_NO_DATA;
    67     }
    68     else
    69 #endif
    70     {
    71         uint32_t cbRead = 0;
    72 
    73         uint32_t cbData = _4K; /** @todo Make this dynamic. */
    74         void    *pvData = RTMemAlloc(cbData);
    75         if (pvData)
    76         {
    77             rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
    78         }
    79         else
    80             rc = VERR_NO_MEMORY;
    81 
    82         /*
    83          * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
    84          * larger buffer.  The size of the buffer needed is placed in *pcb.
    85          * So we start all over again.
    86          */
    87         if (rc == VINF_BUFFER_OVERFLOW)
    88         {
    89             /* cbRead contains the size required. */
    90 
    91             cbData = cbRead;
    92             pvData = RTMemRealloc(pvData, cbRead);
    93             if (pvData)
     297        PSHCLHTTPSERVER pSrv = &pCtx->X11.HttpCtx.HttpServer;
     298
     299        rc = ShClTransferHttpServerWaitForStatusChange(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED, SHCL_TIMEOUT_DEFAULT_MS);
     300        if (RT_SUCCESS(rc))
     301        {
     302            PSHCLTRANSFER pTransfer = ShClTransferHttpServerGetTransferFirst(pSrv);
     303            if (pTransfer)
    94304            {
    95                 rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
    96                 if (rc == VINF_BUFFER_OVERFLOW)
    97                     rc = VERR_BUFFER_OVERFLOW;
     305                rc = vbclX11TransferWaitForStatusWorker(pCtx, pTransfer, SHCLTRANSFERSTATUS_STARTED, SHCL_TIMEOUT_DEFAULT_MS);
     306                if (RT_SUCCESS(rc))
     307                {
     308                    char *pszURL = ShClTransferHttpServerGetUrlA(pSrv, pTransfer->State.uID);
     309                    char *pszData = NULL;
     310                    RTStrAPrintf(&pszData, "copy\n%s", pszURL);
     311
     312                    *ppv = pszData;
     313                    *pcb = strlen(pszData) + 1 /* Include terminator */;
     314
     315                    RTStrFree(pszURL);
     316
     317                    rc = VINF_SUCCESS;
     318
     319                    LogFlowFunc(("pszURL=%s\n", pszURL));
     320                }
    98321            }
    99322            else
    100                 rc = VERR_NO_MEMORY;
    101         }
    102 
    103         if (!cbRead)
    104             rc = VERR_NO_DATA;
    105 
    106         if (RT_SUCCESS(rc))
    107         {
    108             *pcb = cbRead; /* Actual bytes read. */
    109             *ppv = pvData;
     323                AssertMsgFailed(("No registered transfer found for HTTP server\n"));
    110324        }
    111325        else
    112         {
    113             /*
    114              * Catch other errors. This also catches the case in which the buffer was
    115              * too small a second time, possibly because the clipboard contents
    116              * changed half-way through the operation.  Since we can't say whether or
    117              * not this is actually an error, we just return size 0.
    118              */
    119             RTMemFree(pvData);
    120         }
    121     }
     326            LogRel(("Shared Clipboard: Could not start transfer, as the HTTP server is not running\n"));
     327    }
     328#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
    122329
    123330    if (RT_FAILURE(rc))
     
    129336
    130337/**
    131  * Opaque data structure describing a request from the host for clipboard
    132  * data, passed in when the request is forwarded to the X11 backend so that
    133  * it can be completed correctly.
    134  */
    135 struct CLIPREADCBREQ
    136 {
    137     /** The data format that was requested. */
    138     SHCLFORMAT uFmt;
    139 };
    140 
     338 * Worker for reporting clipboard formats to the host.
     339 */
     340static DECLCALLBACK(int) vbclX11ReqReportFormatsWorker(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
     341{
     342    RT_NOREF(pvUser);
     343
     344    LogFlowFunc(("fFormats=%#x\n", fFormats));
     345
     346    int rc = VbglR3ClipboardReportFormats(pCtx->CmdCtx.idClient, fFormats);
     347
     348    LogFlowFuncLeaveRC(rc);
     349    return rc;
     350}
     351
     352/**
     353 * @copydoc SHCLCALLBACKS::pfnReportFormats
     354 *
     355 * Reports clipboard formats to the host.
     356 *
     357 * @thread  X11 event thread.
     358 */
    141359static DECLCALLBACK(int) vbclX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
    142360{
    143     RT_NOREF(pvUser);
    144 
    145     LogFlowFunc(("fFormats=%#x\n", fFormats));
    146 
    147     int rc = VbglR3ClipboardReportFormats(pCtx->CmdCtx.idClient, fFormats);
    148     LogFlowFuncLeaveRC(rc);
    149 
    150     return rc;
    151 }
    152 
    153 static DECLCALLBACK(int) vbclX11OnSendDataToDestCallback(PSHCLCONTEXT pCtx, void *pv, uint32_t cb, void *pvUser)
    154 {
    155     PSHCLX11READDATAREQ pData = (PSHCLX11READDATAREQ)pvUser;
    156     AssertPtrReturn(pData, VERR_INVALID_POINTER);
    157 
    158     LogFlowFunc(("rcCompletion=%Rrc, Format=0x%x, pv=%p, cb=%RU32\n", pData->rcCompletion, pData->pReq->uFmt, pv, cb));
    159 
    160     Assert((cb == 0 && pv == NULL) || (cb != 0 && pv != NULL));
    161     pData->rcCompletion = VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pData->pReq->uFmt, pv, cb);
    162 
    163     RTMemFree(pData->pReq);
    164 
    165     LogFlowFuncLeaveRC(pData->rcCompletion);
    166 
    167     return VINF_SUCCESS;
     361    /* Request reading host clipboard data. */
     362    PRTREQ pReq = NULL;
     363    int rc = RTReqQueueCallEx(pCtx->X11.hReqQ, &pReq, SHCL_TIMEOUT_DEFAULT_MS, RTREQFLAGS_IPRT_STATUS,
     364                              (PFNRT)vbclX11ReqReportFormatsWorker, 3, pCtx, fFormats, pvUser);
     365    RTReqRelease(pReq);
     366
     367    LogFlowFuncLeaveRC(rc);
     368    return rc;
    168369}
    169370
     
    181382    Callbacks.pfnReportFormats           = vbclX11ReportFormatsCallback;
    182383    Callbacks.pfnOnRequestDataFromSource = vbclX11OnRequestDataFromSourceCallback;
    183     Callbacks.pfnOnSendDataToDest        = vbclX11OnSendDataToDestCallback;
    184384
    185385    int rc = ShClX11Init(&g_Ctx.X11, &Callbacks, &g_Ctx, false /* fHeadless */);
     
    220420}
    221421
    222 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
    223 /** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnStart */
    224 static DECLCALLBACK(int) vboxClipboardOnTransferStartCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
    225 {
    226     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
    227     AssertPtr(pCtx);
    228 
    229     PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
    230     AssertPtr(pTransfer);
    231 
    232     /* We only need to start the HTTP server (and register the transfer to it) when we actually receive data from the host. */
    233     if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    234         return ShClHttpTransferRegisterAndMaybeStart(&pCtx->X11.HttpCtx, pTransfer);
    235 
    236     return VINF_SUCCESS;
    237 }
    238 
    239 /** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnCompleted */
    240 static DECLCALLBACK(void) vboxClipboardOnTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rc)
    241 {
    242     RT_NOREF(rc);
    243 
    244     PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
    245     AssertPtr(pCtx);
    246 
    247     PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
    248     AssertPtr(pTransfer);
    249 
    250     /* See comment in vboxClipboardOnTransferInitCallback(). */
    251     if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    252         ShClHttpTransferUnregisterAndMaybeStop(&pCtx->X11.HttpCtx, pTransfer);
    253 }
    254 
    255 /** @copydoc SHCLTRANSFERCALLBACKTABLE::pfnOnError */
    256 static DECLCALLBACK(void) vboxClipboardOnTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCtx, int rc)
    257 {
    258     return vboxClipboardOnTransferCompletedCallback(pCtx, rc);
    259 }
    260 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
    261 
    262422/**
    263423 * The main loop of the X11-specifc Shared Clipboard code.
    264424 *
    265425 * @returns VBox status code.
     426 *
     427 * @thread  Clipboard service worker thread.
    266428 */
    267429int VBClX11ClipboardMain(void)
    268430{
    269     int rc;
    270 
    271431    PSHCLCONTEXT pCtx = &g_Ctx;
     432
     433    int rc = RTReqQueueCreate(&pCtx->X11.hReqQ);
     434    AssertRCReturn(rc, rc);
    272435
    273436    bool fShutdown = false;
     
    286449    pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
    287450
    288     pCtx->CmdCtx.Transfers.Callbacks.pfnOnStart      = vboxClipboardOnTransferStartCallback;
    289     pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted  = vboxClipboardOnTransferCompletedCallback;
    290     pCtx->CmdCtx.Transfers.Callbacks.pfnOnError      = vboxClipboardOnTransferErrorCallback;
     451    pCtx->CmdCtx.Transfers.Callbacks.pfnOnRegistered   = vbclX11OnHttpTransferRegisteredCallback;
     452    pCtx->CmdCtx.Transfers.Callbacks.pfnOnUnregistered = vbclX11OnHttpTransferUnregisteredCallback;
     453    pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted    = vbclX11OnHttpTransferCompletedCallback;
     454    pCtx->CmdCtx.Transfers.Callbacks.pfnOnError        = vbclX11OnHttpTransferErrorCallback;
    291455# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
    292456#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    293457
    294     /* The thread waits for incoming messages from the host. */
     458    LogFlowFunc(("fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64 ...\n",
     459                 pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
     460
     461    /* The thread processes incoming messages from the host and the worker queue. */
     462    PVBGLR3CLIPBOARDEVENT pEvent = NULL;
    295463    for (;;)
    296464    {
    297         PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
     465        if (!pEvent)
     466            pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
    298467        AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
    299 
    300         LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n",
    301                      pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
    302468
    303469        uint32_t idMsg  = 0;
    304470        uint32_t cParms = 0;
    305         rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
     471        rc = VbglR3ClipboardMsgPeek(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
    306472        if (RT_SUCCESS(rc))
    307473        {
     
    312478#endif
    313479        }
     480        else if (rc == VERR_TRY_AGAIN) /* No new message (yet). */
     481        {
     482            RTReqQueueProcess(pCtx->X11.hReqQ, RT_MS_1SEC);
     483            continue;
     484        }
    314485
    315486        if (RT_FAILURE(rc))
     
    324495
    325496            /* Wait a bit before retrying. */
    326             RTThreadSleep(1000);
     497            RTThreadSleep(RT_MS_1SEC);
    327498            continue;
    328499        }
     
    336507                case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS:
    337508                {
    338                     ShClX11ReportFormatsToX11(&g_Ctx.X11, pEvent->u.fReportedFormats);
     509                    ShClX11ReportFormatsToX11Async(&g_Ctx.X11, pEvent->u.fReportedFormats);
    339510                    break;
    340511                }
     
    342513                case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA:
    343514                {
    344                     /* The host needs data in the specified format. */
    345                     CLIPREADCBREQ *pReq;
    346                     pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
    347                     if (pReq)
     515                    PSHCLEVENT pReadDataEvent;
     516                    rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->EventSrc, &pReadDataEvent);
     517                    if (RT_SUCCESS(rc))
    348518                    {
    349                         pReq->uFmt = pEvent->u.fReadData;
    350                         ShClX11ReadDataFromX11(&g_Ctx.X11, pReq->uFmt, pReq);
     519                        rc = ShClX11ReadDataFromX11Async(&g_Ctx.X11, pEvent->u.fReadData, UINT32_MAX, pReadDataEvent);
     520                        if (RT_SUCCESS(rc))
     521                        {
     522                            PSHCLEVENTPAYLOAD pPayload;
     523                            rc = ShClEventWait(pReadDataEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     524                            if (RT_SUCCESS(rc))
     525                            {
     526                                if (pPayload)
     527                                {
     528                                    Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
     529                                    PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
     530
     531                                    rc = VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pEvent->u.fReadData,
     532                                                                    pResp->Read.pvData, pResp->Read.cbData);
     533
     534                                    RTMemFree(pResp->Read.pvData);
     535                                    pResp->Read.cbData = 0;
     536
     537                                    ShClPayloadFree(pPayload);
     538                                }
     539                            }
     540                        }
     541
     542                        ShClEventRelease(pReadDataEvent);
     543                        pReadDataEvent = NULL;
    351544                    }
    352                     else
    353                         rc = VERR_NO_MEMORY;
     545
     546                    if (RT_FAILURE(rc))
     547                        VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pEvent->u.fReadData, NULL, 0);
     548
    354549                    break;
    355550                }
     
    365560                case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:
    366561                {
    367                     /* Nothing to do here. */
     562                    if (pEvent->u.TransferStatus.Report.uStatus == SHCLTRANSFERSTATUS_STARTED)
     563                    {
     564
     565                    }
    368566                    rc = VINF_SUCCESS;
    369567                    break;
     
    394592    }
    395593
    396     LogFlowFuncLeaveRC(rc);
    397     return rc;
    398 }
    399 
     594    RTReqQueueDestroy(pCtx->X11.hReqQ);
     595
     596    LogFlowFuncLeaveRC(rc);
     597    return rc;
     598}
  • trunk/src/VBox/Additions/x11/VBoxClient/clipboard.h

    r99590 r100204  
    3333
    3434/**
    35  * Struct keeping a Shared Clipboard context.
     35 * Struct keeping am X11 Shared Clipboard context.
    3636 */
    3737struct SHCLCONTEXT
     
    4545    union
    4646    {
     47        /** Event source for waiting for request responses. */
     48        SHCLEVENTSOURCE  EventSrc;
    4749        /** X11 clipboard context. */
    4850        SHCLX11CTX       X11;
  • trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp

    r99967 r100204  
    3838#include <iprt/win/shlwapi.h>
    3939
     40#include <iprt/thread.h> // REMOVE
     41
    4042#include <iprt/asm.h>
    4143#include <iprt/err.h>
     
    5254//#define VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 1
    5355
    54 SharedClipboardWinDataObject::SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer,
    55                                                            LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
    56     : m_enmStatus(Uninitialized)
     56SharedClipboardWinDataObject::SharedClipboardWinDataObject(void)
     57    : m_pCtx(NULL)
     58    , m_enmStatus(Uninitialized)
    5759    , m_lRefCount(0)
    5860    , m_cFormats(0)
    59     , m_pTransfer(pTransfer)
     61    , m_pTransfer(NULL)
    6062    , m_pStream(NULL)
    6163    , m_uObjIdx(0)
    62     , m_fRunning(false)
     64    , m_fThreadRunning(false)
    6365    , m_EventListComplete(NIL_RTSEMEVENT)
    64     , m_EventTransferComplete(NIL_RTSEMEVENT)
    65 {
    66     AssertPtr(m_pTransfer);
    67 
    68     HRESULT hr;
     66    , m_EventStatusChanged(NIL_RTSEMEVENT)
     67{
     68}
     69
     70SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void)
     71{
     72    Destroy();
     73
     74    LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount));
     75}
     76
     77/**
     78 * Initializes a data object instance.
     79 *
     80 * @returns VBox status code.
     81 * @param   pFormatEtc          FormatETC to use.
     82 * @param   pStgMed             Storage medium to use.
     83 * @param   cFormats            Number of formats in \a pFormatEtc and \a pStgMed.
     84 */
     85int SharedClipboardWinDataObject::Init(PSHCLCONTEXT pCtx,
     86                                       LPFORMATETC pFormatEtc /* = NULL */, LPSTGMEDIUM pStgMed /* = NULL */,
     87                                       ULONG cFormats /* = 0 */)
     88{
     89    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     90    AssertReturn(cFormats == 0 || (RT_VALID_PTR(pFormatEtc) && RT_VALID_PTR(pStgMed)), VERR_INVALID_POINTER);
     91
     92    int rc = VINF_SUCCESS;
     93
     94    m_pCtx = pCtx; /* Save opaque context. */
    6995
    7096    ULONG cFixedFormats = 3; /* CFSTR_FILEDESCRIPTORA + CFSTR_FILECONTENTS + CFSTR_PERFORMEDDROPEFFECT */
     
    74100    const ULONG cAllFormats   = cFormats + cFixedFormats;
    75101
    76     try
    77     {
    78         m_pFormatEtc = new FORMATETC[cAllFormats];
    79         RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats);
    80         m_pStgMedium = new STGMEDIUM[cAllFormats];
    81         RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cAllFormats);
    82 
    83         /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */
    84 
    85         /*
    86          * Register fixed formats.
    87          */
    88         unsigned uIdx = 0;
    89 
    90         LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n"));
    91         m_cfFileDescriptorA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
    92         registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorA);
     102    m_pFormatEtc = new FORMATETC[cAllFormats];
     103    AssertPtrReturn(m_pFormatEtc, VERR_NO_MEMORY);
     104    RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats);
     105    m_pStgMedium = new STGMEDIUM[cAllFormats];
     106    AssertPtrReturn(m_pStgMedium, VERR_NO_MEMORY);
     107    RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cAllFormats);
     108
     109    /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */
     110
     111    /*
     112     * Register fixed formats.
     113     */
     114    unsigned uIdx = 0;
     115
     116    LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n"));
     117    m_cfFileDescriptorA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
     118    registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorA);
    93119#ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
    94         LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n"));
    95         m_cfFileDescriptorW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
    96         registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorW);
     120    LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n"));
     121    m_cfFileDescriptorW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
     122    registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorW);
    97123#endif
    98124
    99         /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */
    100         LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n"));
    101         m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
    102         registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */);
    103 
    104         /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */
    105         LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n"));
    106         m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
    107         registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT);
    108 
    109         /*
    110          * Registration of dynamic formats needed?
    111          */
    112         LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
    113         if (cFormats)
    114         {
    115             AssertPtr(pFormatEtc);
    116             AssertPtr(pStgMed);
    117 
    118             for (ULONG i = 0; i < cFormats; i++)
    119             {
    120                 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
    121                              i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
    122                 m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i];
    123                 m_pStgMedium[cFixedFormats + i] = pStgMed[i];
    124             }
    125         }
    126 
    127         hr = S_OK;
    128     }
    129     catch (std::bad_alloc &)
    130     {
    131         hr = E_OUTOFMEMORY;
    132     }
    133 
    134     if (SUCCEEDED(hr))
     125    /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */
     126    LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n"));
     127    m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
     128    registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */);
     129
     130    /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */
     131    LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n"));
     132    m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
     133    registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT);
     134
     135    /*
     136     * Registration of dynamic formats needed?
     137     */
     138    LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
     139    if (cFormats)
     140    {
     141        for (ULONG i = 0; i < cFormats; i++)
     142        {
     143            LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
     144                         i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
     145            m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i];
     146            m_pStgMedium[cFixedFormats + i] = pStgMed[i];
     147        }
     148    }
     149
     150    if (RT_SUCCESS(rc))
    135151    {
    136152        m_cFormats  = cAllFormats;
    137153        m_enmStatus = Initialized;
    138154
    139         int rc2 = RTSemEventCreate(&m_EventListComplete);
    140         AssertRC(rc2);
    141         rc2 = RTSemEventCreate(&m_EventTransferComplete);
    142         AssertRC(rc2);
    143     }
    144 
    145     LogFlowFunc(("cAllFormats=%RU32, hr=%Rhrc\n", cAllFormats, hr));
    146 }
    147 
    148 SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void)
     155        rc = RTCritSectInit(&m_CritSect);
     156        if (RT_SUCCESS(rc))
     157        {
     158            rc = RTSemEventCreate(&m_EventListComplete);
     159            if (RT_SUCCESS(rc))
     160                rc = RTSemEventCreate(&m_EventStatusChanged);
     161        }
     162    }
     163
     164    LogFlowFunc(("cAllFormats=%RU32, rc=%Rrc\n", cAllFormats, rc));
     165    return rc;
     166}
     167
     168/**
     169 * Destroys a data object instance.
     170 */
     171void SharedClipboardWinDataObject::Destroy(void)
    149172{
    150173    LogFlowFuncEnter();
    151174
    152     RTSemEventDestroy(m_EventListComplete);
    153     m_EventListComplete = NIL_RTSEMEVENT;
    154 
    155     RTSemEventDestroy(m_EventTransferComplete);
    156     m_EventTransferComplete = NIL_RTSEMEVENT;
     175    AssertReturnVoid(m_lRefCount == 0);
     176
     177    int rc = RTCritSectDelete(&m_CritSect);
     178    AssertRC(rc);
     179
     180    if (m_EventListComplete != NIL_RTSEMEVENT)
     181    {
     182        rc = RTSemEventDestroy(m_EventListComplete);
     183        AssertRC(rc);
     184        m_EventListComplete = NIL_RTSEMEVENT;
     185    }
     186
     187    if (m_EventStatusChanged != NIL_RTSEMEVENT)
     188    {
     189        rc = RTSemEventDestroy(m_EventStatusChanged);
     190        AssertRC(rc);
     191        m_EventStatusChanged = NIL_RTSEMEVENT;
     192    }
    157193
    158194    if (m_pStream)
     195    {
    159196        m_pStream->Release();
     197        m_pStream = NULL;
     198    }
    160199
    161200    if (m_pFormatEtc)
     201    {
    162202        delete[] m_pFormatEtc;
     203        m_pFormatEtc = NULL;
     204    }
    163205
    164206    if (m_pStgMedium)
     207    {
    165208        delete[] m_pStgMedium;
    166 
    167     LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount));
    168 }
    169 
    170 /*
     209        m_pStgMedium = NULL;
     210    }
     211
     212    if (m_pTransfer)
     213        ShClTransferRelease(m_pTransfer);
     214
     215    FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin();
     216    while (itRoot != m_lstEntries.end())
     217    {
     218        RTStrFree(itRoot->pszPath);
     219        ++itRoot;
     220    }
     221    m_lstEntries.clear();
     222
     223    m_enmStatus = Uninitialized;
     224    m_fThreadRunning = false;
     225    m_pTransfer = NULL;
     226}
     227
     228/**
     229 * Sets the callbacks for this object.
     230 *
     231 * @param   pCallbacks          Pointer to callbacks table to use.
     232 */
     233void SharedClipboardWinDataObject::SetCallbacks(PSHCLCALLBACKS pCallbacks)
     234{
     235    AssertPtrReturnVoid(pCallbacks);
     236
     237    RT_ZERO(m_Callbacks);
     238
     239    m_Callbacks.pfnOnRequestDataFromSource = pCallbacks->pfnOnRequestDataFromSource;
     240}
     241
     242
     243/*********************************************************************************************************************************
    171244 * IUnknown methods.
    172  */
     245 ********************************************************************************************************************************/
    173246
    174247STDMETHODIMP_(ULONG) SharedClipboardWinDataObject::AddRef(void)
     
    270343                {
    271344                    LogFlowFunc(("cTotalObjects=%RU64, cbTotalSize=%RU64\n\n",
    272                                  hdrList.cTotalObjects, hdrList.cbTotalSize));
    273 
    274                     for (uint64_t o = 0; o < hdrList.cTotalObjects; o++)
     345                                 hdrList.cEntries, hdrList.cbTotalSize));
     346
     347                    for (uint64_t o = 0; o < hdrList.cEntries; o++)
    275348                    {
    276349                        SHCLLISTENTRY entryList;
     
    291364                                                 entryList.pszName, pFsObjInfo->cbObject, strPath.c_str()));
    292365
    293                                     if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode))
     366                                    if (   RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode)
     367                                        || RTFS_IS_FILE     (pFsObjInfo->Attr.fMode))
    294368                                    {
    295                                         FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo };
    296 
    297                                         m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
    298 
    299                                         rc = readDir(pTransfer, strPath.c_str());
    300                                     }
    301                                     else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode))
    302                                     {
    303                                         FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo };
     369                                        FSOBJENTRY objEntry;
     370                                        objEntry.pszPath = RTStrDup(strPath.c_str());
     371                                        AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY);
     372                                        objEntry.objInfo = *pFsObjInfo;
    304373
    305374                                        m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
    306375                                    }
    307                                     else
    308                                         rc = VERR_NOT_SUPPORTED;
     376                                    else /* Not fatal, just skip. */
     377                                        LogRel(("Shared Clipboard: Warning: File system object '%s' of type %#x not supported, skipping\n",
     378                                                strPath.c_str(), pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK));
    309379
    310380                                    /** @todo Handle symlinks. */
     
    330400    }
    331401
     402    if (RT_FAILURE(rc))
     403        LogRel(("Shared Clipboard: Reading directory '%s' failed with %Rrc\n", strDir.c_str(), rc));
     404
    332405    LogFlowFuncLeaveRC(rc);
    333406    return rc;
     
    362435    LogRel2(("Shared Clipboard: Calculating transfer ...\n"));
    363436
    364     PSHCLROOTLIST pRootList;
    365     int rc = ShClTransferRootsGet(pTransfer, &pRootList);
     437    int rc = ShClTransferRootListRead(pTransfer);
    366438    if (RT_SUCCESS(rc))
    367439    {
    368         LogFlowFunc(("cRoots=%RU32\n\n", pRootList->Hdr.cRoots));
    369 
    370         for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++)
    371         {
    372             PSHCLLISTENTRY pRootEntry = &pRootList->paEntries[i];
    373             AssertPtr(pRootEntry);
    374 
    375             Assert(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO));
    376             PSHCLFSOBJINFO pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo;
    377 
    378             LogFlowFunc(("pszRoot=%s, fMode=0x%x\n", pRootEntry->pszName, pFsObjInfo->Attr.fMode));
     440        uint64_t const cRoots = ShClTransferRootsCount(pTransfer);
     441
     442        LogFlowFunc(("cRoots=%RU64\n\n", cRoots));
     443
     444        for (uint32_t i = 0; i < cRoots; i++)
     445        {
     446            PCSHCLLISTENTRY pRootEntry = ShClTransferRootsEntryGet(pTransfer, i);
     447
     448            AssertBreakStmt(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO), rc = VERR_INVALID_PARAMETER);
     449            PSHCLFSOBJINFO const pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo;
     450
     451            LogFlowFunc(("pszRoot=%s, fMode=0x%x (type %#x)\n",
     452                         pRootEntry->pszName, pFsObjInfo->Attr.fMode, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK)));
    379453
    380454            if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode))
    381455            {
    382                 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo };
     456                FSOBJENTRY objEntry;
     457                objEntry.pszPath = RTStrDup(pRootEntry->pszName);
     458                AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY);
     459                objEntry.objInfo = *pFsObjInfo;
    383460
    384461                pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
     
    388465            else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode))
    389466            {
    390                 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo };
     467                FSOBJENTRY objEntry;
     468                objEntry.pszPath = RTStrDup(pRootEntry->pszName);
     469                AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY);
     470                objEntry.objInfo = *pFsObjInfo;
    391471
    392472                pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
    393473            }
    394474            else
     475            {
     476                LogRel(("Shared Clipboard: Root entry '%s': File type %#x not supported\n",
     477                        pRootEntry->pszName, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK)));
    395478                rc = VERR_NOT_SUPPORTED;
     479            }
    396480
    397481            if (ASMAtomicReadBool(&pTransfer->Thread.fStop))
     
    404488                break;
    405489        }
    406 
    407         ShClTransferRootListFree(pRootList);
    408         pRootList = NULL;
    409490
    410491        if (   RT_SUCCESS(rc)
     
    424505                LogRel2(("Shared Clipboard: Waiting for transfer to complete ...\n"));
    425506
    426                 LogFlowFunc(("Waiting for transfer to complete ...\n"));
    427 
    428507                /* Transferring stuff can take a while, so don't use any timeout here. */
    429                 rc2 = RTSemEventWait(pThis->m_EventTransferComplete, RT_INDEFINITE_WAIT);
     508                rc2 = RTSemEventWait(pThis->m_EventStatusChanged, RT_INDEFINITE_WAIT);
    430509                AssertRC(rc2);
    431510
     
    499578    char *pszFileSpec = NULL;
    500579
    501     FsObjEntryList::const_iterator itRoot = m_lstEntries.begin();
     580    FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin();
    502581    while (itRoot != m_lstEntries.end())
    503582    {
     
    505584        RT_BZERO(pFD, cbFileDescriptor);
    506585
    507         const char *pszFile = itRoot->strPath.c_str();
     586        const char *pszFile = itRoot->pszPath;
    508587        AssertPtr(pszFile);
    509588
     
    584663
    585664/**
    586  * Retrieves the data stored in this object and store the result in
    587  * pMedium.
    588  *
    589  * @return  IPRT status code.
     665 * Retrieves the data stored in this object and store the result in pMedium.
     666 *
    590667 * @return  HRESULT
    591  * @param   pFormatEtc
    592  * @param   pMedium
     668 * @param   pFormatEtc          Format to retrieve.
     669 * @param   pMedium             Where to store the data on success.
     670 *
     671 * @thread  Windows event thread.
    593672 */
    594673STDMETHODIMP SharedClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
     
    597676    AssertPtrReturn(pMedium, DV_E_FORMATETC);
    598677
    599     LogFlowFuncEnter();
    600 
    601     LogFlowFunc(("lIndex=%RI32\n", pFormatEtc->lindex));
     678    int rc2 = RTCritSectEnter(&m_CritSect);
     679    AssertRCReturn(rc2, E_UNEXPECTED);
     680
     681    LogFlowFunc(("lIndex=%RI32, enmStatus=%#x\n", pFormatEtc->lindex, m_enmStatus));
    602682
    603683    /*
     
    607687
    608688    HRESULT hr = DV_E_FORMATETC; /* Play safe. */
     689
     690    int rc = VINF_SUCCESS;
    609691
    610692    if (   pFormatEtc->cfFormat == m_cfFileDescriptorA
     
    614696       )
    615697    {
    616         const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW;
    617 
    618         const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer);
    619         RT_NOREF(enmTransferStatus);
    620 
    621         LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n",
    622                      fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fRunning));
    623 
    624         int rc;
    625 
    626         /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
    627         if (!m_fRunning)
    628         {
    629             /* Start the transfer asynchronously in a separate thread. */
    630             rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this);
    631             if (RT_SUCCESS(rc))
     698        switch (m_enmStatus)
     699        {
     700            case Initialized:
    632701            {
    633                 m_fRunning = true;
    634 
    635                 /* Don't block for too long here, as this also will screw other apps running on the OS. */
    636                 LogFunc(("Waiting for listing to arrive ...\n"));
    637                 rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS);
     702                LogRel2(("Shared Clipboard: Requesting data for IDataObject ...\n"));
     703
     704                /* Leave lock while requesting + waiting. */
     705                rc2 = RTCritSectLeave(&m_CritSect);
     706                AssertRCReturn(rc2, E_UNEXPECTED);
     707
     708                /* Request the transfer from the source.
     709                 * This will generate a transfer status message which we're waiting for here. */
     710                AssertPtr(m_Callbacks.pfnOnRequestDataFromSource);
     711                rc = m_Callbacks.pfnOnRequestDataFromSource(m_pCtx,
     712                                                            VBOX_SHCL_FMT_URI_LIST, NULL /* ppv */, NULL /* pv */,
     713                                                            this /* pvUser */);
     714                AssertRCBreak(rc);
     715
     716                LogRel2(("Shared Clipboard: Waiting for IDataObject started status ...\n"));
     717
     718                rc = RTSemEventWait(m_EventStatusChanged, SHCL_TIMEOUT_DEFAULT_MS);
     719
     720                /* Re-acquire lock. */
     721                rc2 = RTCritSectEnter(&m_CritSect);
     722                AssertRCReturn(rc2, E_UNEXPECTED);
     723
    638724                if (RT_SUCCESS(rc))
    639725                {
    640                     LogFunc(("Listing complete\n"));
     726                    if (m_enmStatus != Running)
     727                    {
     728                        LogRel(("Shared Clipboard: Received wrong IDataObject status (%#x)\n", m_enmStatus));
     729                        rc = VERR_WRONG_ORDER;
     730                        break;
     731                    }
     732
     733                    /* There now must be a transfer assigned. */
     734                    AssertPtrBreakStmt(m_pTransfer, rc = VERR_WRONG_ORDER);
     735                }
     736                else /* Bail out on failure. */
     737                    break;
     738
     739                RT_FALL_THROUGH();
     740            }
     741
     742            case Running:
     743            {
     744                const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW;
     745
     746                const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer);
     747                RT_NOREF(enmTransferStatus);
     748
     749                LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n",
     750                             fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fThreadRunning));
     751
     752                /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
     753                if (!m_fThreadRunning)
     754                {
     755                    /* Start the transfer asynchronously in a separate thread. */
     756                    rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this /* pvUser */);
     757                    if (RT_SUCCESS(rc))
     758                    {
     759                        m_fThreadRunning = true;
     760
     761                        /* Leave lock while waiting. */
     762                        rc2 = RTCritSectLeave(&m_CritSect);
     763                        AssertRCReturn(rc2, E_UNEXPECTED);
     764
     765                        /* Don't block for too long here, as this also will screw other apps running on the OS. */
     766                        LogRel2(("Shared Clipboard: Waiting for IDataObject listing to arrive ...\n"));
     767                        rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS);
     768
     769                        /* Re-acquire lock. */
     770                        rc2 = RTCritSectEnter(&m_CritSect);
     771                        AssertRCReturn(rc2, E_UNEXPECTED);
     772                    }
     773                }
     774
     775                if (RT_SUCCESS(rc))
     776                {
     777                    HGLOBAL hGlobal;
     778                    rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
     779                    if (RT_SUCCESS(rc))
     780                    {
     781                        pMedium->tymed   = TYMED_HGLOBAL;
     782                        pMedium->hGlobal = hGlobal;
     783                        /* Note: hGlobal now is being owned by pMedium / the caller. */
     784
     785                        hr = S_OK;
     786                    }
     787                }
     788
     789                break;
     790            }
     791
     792            default:
     793                break;
     794        }
     795
     796        if (RT_FAILURE(rc))
     797        {
     798            LogRel(("Shared Clipboard: Error getting data for IDataObject, rc=%Rrc\n", rc));
     799            hr = E_UNEXPECTED; /* We can't tell any better to the caller, unfortunately. */
     800        }
     801    }
     802
     803    if (RT_SUCCESS(rc))
     804    {
     805        if (pFormatEtc->cfFormat == m_cfFileContents)
     806        {
     807            if (          pFormatEtc->lindex >= 0
     808                && (ULONG)pFormatEtc->lindex <  m_lstEntries.size())
     809            {
     810                m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */
     811
     812                FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx);
     813
     814                LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.pszPath));
     815
     816                LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.pszPath));
     817
     818                /* Hand-in the provider so that our IStream implementation can continue working with it. */
     819                hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer,
     820                                                          fsObjEntry.pszPath /* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */,
     821                                                          &m_pStream);
     822                if (SUCCEEDED(hr))
     823                {
     824                    /* Hand over the stream to the caller. */
     825                    pMedium->tymed = TYMED_ISTREAM;
     826                    pMedium->pstm  = m_pStream;
    641827                }
    642828            }
    643829        }
    644         else
    645             rc = VINF_SUCCESS;
    646 
    647         if (RT_SUCCESS(rc))
    648         {
    649             HGLOBAL hGlobal;
    650             rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
    651             if (RT_SUCCESS(rc))
    652             {
    653                 pMedium->tymed   = TYMED_HGLOBAL;
    654                 pMedium->hGlobal = hGlobal;
    655                 /* Note: hGlobal now is being owned by pMedium / the caller. */
    656 
    657                 hr = S_OK;
    658             }
    659             else /* We can't tell any better to the caller, unfortunately. */
    660                 hr = E_UNEXPECTED;
    661         }
    662 
    663         if (RT_FAILURE(rc))
    664             LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc));
    665     }
    666 
    667     if (pFormatEtc->cfFormat == m_cfFileContents)
    668     {
    669         if (          pFormatEtc->lindex >= 0
    670             && (ULONG)pFormatEtc->lindex <  m_lstEntries.size())
    671         {
    672             m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */
    673 
    674             FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx);
    675 
    676             LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.strPath.c_str()));
    677 
    678             LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.strPath.c_str()));
    679 
    680             /* Hand-in the provider so that our IStream implementation can continue working with it. */
    681             hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer,
    682                                                       fsObjEntry.strPath.c_str()/* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */,
    683                                                       &m_pStream);
    684             if (SUCCEEDED(hr))
    685             {
    686                 /* Hand over the stream to the caller. */
    687                 pMedium->tymed = TYMED_ISTREAM;
    688                 pMedium->pstm  = m_pStream;
    689             }
    690         }
    691     }
    692     else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect)
    693     {
    694         HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD));
    695 
    696         DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal);
    697         *pdwDropEffect = DROPEFFECT_COPY;
    698 
    699         GlobalUnlock(hGlobal);
    700 
    701         pMedium->tymed          = TYMED_HGLOBAL;
    702         pMedium->hGlobal        = hGlobal;
    703         pMedium->pUnkForRelease = NULL;
    704     }
    705 
    706     if (   FAILED(hr)
    707         && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */
    708     {
    709         LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr));
    710     }
     830        else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect)
     831        {
     832            HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD));
     833
     834            DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal);
     835            *pdwDropEffect = DROPEFFECT_COPY;
     836
     837            GlobalUnlock(hGlobal);
     838
     839            pMedium->tymed          = TYMED_HGLOBAL;
     840            pMedium->hGlobal        = hGlobal;
     841            pMedium->pUnkForRelease = NULL;
     842        }
     843
     844        if (   FAILED(hr)
     845            && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */
     846        {
     847            LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr));
     848        }
     849    }
     850
     851    rc2 = RTCritSectLeave(&m_CritSect);
     852    AssertRCReturn(rc2, E_UNEXPECTED);
    711853
    712854    LogFlowFunc(("hr=%Rhrc\n", hr));
     
    786928            LogRel2(("Shared Clipboard: Transfer canceled by user interaction\n"));
    787929
    788             OnTransferCanceled();
     930            SetStatus(Canceled);
    789931        }
    790932        /** @todo Detect move / overwrite actions here. */
     
    8711013 */
    8721014
    873 int SharedClipboardWinDataObject::Init(void)
    874 {
    875     LogFlowFuncLeaveRC(VINF_SUCCESS);
    876     return VINF_SUCCESS;
    877 }
    878 
    879 void SharedClipboardWinDataObject::OnTransferComplete(int rc /* = VINF_SUCESS */)
    880 {
    881     RT_NOREF(rc);
    882 
    883     LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size()));
    884 
     1015/**
     1016 * Assigns a transfer object and starts the transfer for the data object.
     1017 *
     1018 * @returns VBox status code.
     1019 * @param   pTransfer           Transfer to assign.
     1020 */
     1021int SharedClipboardWinDataObject::SetAndStartTransfer(PSHCLTRANSFER pTransfer)
     1022{
     1023    AssertReturn(m_pTransfer == NULL, VERR_WRONG_ORDER); /* Transfer already set? */
     1024
     1025    int rc = RTCritSectEnter(&m_CritSect);
    8851026    if (RT_SUCCESS(rc))
    8861027    {
    887         const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */;
    888         if (fComplete)
    889         {
    890             m_enmStatus = Completed;
    891         }
    892     }
    893     else
    894         m_enmStatus = Error;
    895 
    896     if (m_enmStatus != Initialized)
    897     {
    898         if (m_EventTransferComplete != NIL_RTSEMEVENT)
    899         {
    900             int rc2 = RTSemEventSignal(m_EventTransferComplete);
    901             AssertRC(rc2);
    902         }
    903     }
    904 
    905     LogFlowFuncLeaveRC(rc);
    906 }
    907 
    908 void SharedClipboardWinDataObject::OnTransferCanceled(void)
    909 {
    910     LogFlowFuncEnter();
    911 
    912     m_enmStatus = Canceled;
    913 
    914     if (m_EventTransferComplete != NIL_RTSEMEVENT)
    915     {
    916         int rc2 = RTSemEventSignal(m_EventTransferComplete);
    917         AssertRC(rc2);
    918     }
    919 
    920     LogFlowFuncLeave();
     1028        if (m_enmStatus == Initialized)
     1029        {
     1030            m_pTransfer = pTransfer;
     1031
     1032            ShClTransferAcquire(pTransfer);
     1033
     1034            rc = setStatusLocked(Running);
     1035        }
     1036        else
     1037            AssertFailedStmt(rc = VERR_WRONG_ORDER);
     1038
     1039        RTCritSectLeave(&m_CritSect);
     1040    }
     1041
     1042    return rc;
     1043}
     1044
     1045/**
     1046 * Sets a new status to the data object and signals its waiter.
     1047 *
     1048 * @returns VBox status code.
     1049 * @param   enmStatus           New status to signal.
     1050 * @param   rc                  Result code. Optional.
     1051 *
     1052 * @note    Called by the main clipboard thread + SharedClipboardWinStreamImpl.
     1053 */
     1054int SharedClipboardWinDataObject::SetStatus(Status enmStatus, int rc /* = VINF_SUCCESS */)
     1055{
     1056    int rc2 = RTCritSectEnter(&m_CritSect);
     1057    if (RT_SUCCESS(rc2))
     1058    {
     1059        setStatusLocked(enmStatus, rc);
     1060
     1061        RTCritSectLeave(&m_CritSect);
     1062    }
     1063
     1064    return rc2;
    9211065}
    9221066
     
    9771121    logFormat(pFormatEtc->cfFormat);
    9781122}
     1123
     1124/**
     1125 * Sets a new status to the data object and signals its waiter.
     1126 *
     1127 * @returns VBox status code.
     1128 * @param   enmStatus           New status to signal.
     1129 * @param   rc                  Result code. Optional.
     1130 *
     1131 * @note    Caller must have taken the critical section.
     1132 */
     1133int SharedClipboardWinDataObject::setStatusLocked(Status enmStatus, int rc /* = VINF_SUCCESS */)
     1134{
     1135    AssertReturn(enmStatus == Error || RT_SUCCESS(rc), VERR_INVALID_PARAMETER);
     1136    AssertReturn(RTCritSectIsOwned(&m_CritSect), VERR_WRONG_ORDER);
     1137
     1138    RT_NOREF(rc);
     1139
     1140    int rc2 = RTCritSectEnter(&m_CritSect);
     1141    if (RT_SUCCESS(rc2))
     1142    {
     1143        LogFlowFunc(("enmStatus=%#x (current is: %#x)\n", enmStatus, m_enmStatus));
     1144
     1145        switch (enmStatus)
     1146        {
     1147            case Completed:
     1148            {
     1149                LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size()));
     1150
     1151                const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */;
     1152                if (fComplete)
     1153                    m_enmStatus = Completed;
     1154                break;
     1155            }
     1156
     1157            default:
     1158            {
     1159                m_enmStatus = enmStatus;
     1160                break;
     1161            }
     1162        }
     1163
     1164        if (RT_FAILURE(rc))
     1165            LogRel(("Shared Clipboard: Data object received error %Rrc (status %#x)\n", rc, enmStatus));
     1166
     1167        if (m_EventStatusChanged != NIL_RTSEMEVENT)
     1168            rc2 = RTSemEventSignal(m_EventStatusChanged);
     1169
     1170        RTCritSectLeave(&m_CritSect);
     1171    }
     1172
     1173    return rc2;
     1174}
     1175
  • trunk/src/VBox/GuestHost/SharedClipboard/ClipboardEnumFormatEtcImpl-win.cpp

    r98103 r100204  
    4141
    4242
    43 SharedClipboardWinEnumFormatEtc::SharedClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats)
     43SharedClipboardWinEnumFormatEtc::SharedClipboardWinEnumFormatEtc(void)
    4444    : m_lRefCount(1),
    4545      m_nIndex(0)
    4646{
    47     HRESULT hr;
    48 
    49     try
    50     {
    51         LogFlowFunc(("pFormatEtc=%p, cFormats=%RU32\n", pFormatEtc, cFormats));
    52         m_pFormatEtc  = new FORMATETC[cFormats];
    53 
    54         for (ULONG i = 0; i < cFormats; i++)
    55         {
    56             LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
    57                          i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
    58 
    59             SharedClipboardWinDataObject::logFormat(pFormatEtc[i].cfFormat);
    60 
    61             SharedClipboardWinEnumFormatEtc::CopyFormat(&m_pFormatEtc[i], &pFormatEtc[i]);
    62         }
    63 
    64         m_nNumFormats = cFormats;
    65         hr = S_OK;
    66     }
    67     catch (std::bad_alloc &)
    68     {
    69         hr = E_OUTOFMEMORY;
    70     }
    71 
    72     LogFlowFunc(("hr=%Rhrc\n", hr));
    7347}
    7448
    7549SharedClipboardWinEnumFormatEtc::~SharedClipboardWinEnumFormatEtc(void)
     50{
     51    Destroy();
     52
     53    LogFlowFunc(("m_lRefCount=%RI32\n", m_lRefCount));
     54}
     55
     56/**
     57 * Initializes an IEnumFORMATETC instance.
     58 *
     59 * @returns VBox status code.
     60 * @param   pFormatEtc          Array of formats to use for initialization.
     61 * @param   cFormats            Number of formats in \a pFormatEtc.
     62 */
     63int SharedClipboardWinEnumFormatEtc::Init(LPFORMATETC pFormatEtc, ULONG cFormats)
     64{
     65    LogFlowFunc(("pFormatEtc=%p, cFormats=%RU32\n", pFormatEtc, cFormats));
     66    m_pFormatEtc = new FORMATETC[cFormats];
     67    AssertPtrReturn(m_pFormatEtc, VERR_NO_MEMORY);
     68
     69    for (ULONG i = 0; i < cFormats; i++)
     70    {
     71        LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
     72                     i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
     73
     74        SharedClipboardWinDataObject::logFormat(pFormatEtc[i].cfFormat);
     75
     76        SharedClipboardWinEnumFormatEtc::CopyFormat(&m_pFormatEtc[i], &pFormatEtc[i]);
     77    }
     78
     79    m_nNumFormats = cFormats;
     80
     81    return VINF_SUCCESS;
     82}
     83
     84/**
     85 * Destroys an IEnumFORMATETC instance.
     86 */
     87void SharedClipboardWinEnumFormatEtc::Destroy(void)
    7688{
    7789    if (m_pFormatEtc)
     
    8799    }
    88100
    89     LogFlowFunc(("m_lRefCount=%RI32\n", m_lRefCount));
     101    m_nNumFormats = 0;
    90102}
    91103
     
    191203
    192204    HRESULT hr;
    193     try
    194     {
    195         *ppEnumFormatEtc = new SharedClipboardWinEnumFormatEtc(pFormatEtc, nNumFormats);
    196         hr = S_OK;
    197     }
    198     catch(std::bad_alloc &)
    199     {
     205
     206    SharedClipboardWinEnumFormatEtc *pEnumFormatEtc = new SharedClipboardWinEnumFormatEtc();
     207    if (pEnumFormatEtc)
     208    {
     209        hr = pEnumFormatEtc->Init(pFormatEtc, nNumFormats);
     210        if (SUCCEEDED(hr))
     211            *ppEnumFormatEtc = pEnumFormatEtc;
     212    }
     213    else
    200214        hr = E_OUTOFMEMORY;
    201     }
    202215
    203216    return hr;
  • trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp

    r98103 r100204  
    3939#include <VBox/GuestHost/SharedClipboard.h>
    4040#include <VBox/GuestHost/SharedClipboard-win.h>
    41 #include <strsafe.h>
    4241
    4342#include <VBox/log.h>
     
    6160    , m_lRefCount(1) /* Our IDataObjct *always* holds the last reference to this object; needed for the callbacks. */
    6261    , m_pTransfer(pTransfer)
    63     , m_hObj(SHCLOBJHANDLE_INVALID)
     62    , m_hObj(NIL_SHCLOBJHANDLE)
    6463    , m_strPath(strPath)
    6564    , m_objInfo(*pObjInfo)
     
    187186    int rc;
    188187
    189     try
    190     {
    191         if (   m_hObj == SHCLOBJHANDLE_INVALID
    192             && m_pTransfer->ProviderIface.pfnObjOpen)
    193         {
    194             SHCLOBJOPENCREATEPARMS openParms;
    195             rc = ShClTransferObjOpenParmsInit(&openParms);
     188    if (   m_hObj == NIL_SHCLOBJHANDLE
     189        && m_pTransfer->ProviderIface.pfnObjOpen)
     190    {
     191        SHCLOBJOPENCREATEPARMS openParms;
     192        rc = ShClTransferObjOpenParmsInit(&openParms);
     193        if (RT_SUCCESS(rc))
     194        {
     195            openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
     196                              | SHCL_OBJ_CF_ACCESS_DENYWRITE;
     197
     198            rc = RTStrCopy(openParms.pszPath, openParms.cbPath, m_strPath.c_str());
    196199            if (RT_SUCCESS(rc))
    197200            {
    198                 openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
    199                                   | SHCL_OBJ_CF_ACCESS_DENYWRITE;
    200 
    201                 rc = RTStrCopy(openParms.pszPath, openParms.cbPath, m_strPath.c_str());
    202                 if (RT_SUCCESS(rc))
    203                 {
    204                     rc = m_pTransfer->ProviderIface.pfnObjOpen(&m_pTransfer->ProviderCtx, &openParms, &m_hObj);
    205                 }
    206 
    207                 ShClTransferObjOpenParmsDestroy(&openParms);
     201                rc = m_pTransfer->ProviderIface.pfnObjOpen(&m_pTransfer->ProviderCtx, &openParms, &m_hObj);
    208202            }
    209         }
    210         else
    211             rc = VINF_SUCCESS;
    212 
    213         uint32_t cbRead = 0;
    214 
    215         const uint64_t cbSize   = (uint64_t)m_objInfo.cbObject;
    216         const uint32_t cbToRead = RT_MIN(cbSize - m_cbProcessed, nBytesToRead);
    217 
    218         if (RT_SUCCESS(rc))
    219         {
    220             if (cbToRead)
     203
     204            ShClTransferObjOpenParmsDestroy(&openParms);
     205        }
     206    }
     207    else
     208        rc = VINF_SUCCESS;
     209
     210    uint32_t cbRead = 0;
     211
     212    const uint64_t cbSize   = (uint64_t)m_objInfo.cbObject;
     213    const uint32_t cbToRead = RT_MIN(cbSize - m_cbProcessed, nBytesToRead);
     214
     215    if (RT_SUCCESS(rc))
     216    {
     217        if (cbToRead)
     218        {
     219            rc = m_pTransfer->ProviderIface.pfnObjRead(&m_pTransfer->ProviderCtx, m_hObj,
     220                                                       pvBuffer, cbToRead, 0 /* fFlags */, &cbRead);
     221            if (RT_SUCCESS(rc))
    221222            {
    222                 rc = m_pTransfer->ProviderIface.pfnObjRead(&m_pTransfer->ProviderCtx, m_hObj,
    223                                                            pvBuffer, cbToRead, 0 /* fFlags */, &cbRead);
    224                 if (RT_SUCCESS(rc))
    225                 {
    226                     m_cbProcessed += cbRead;
    227                     Assert(m_cbProcessed <= cbSize);
    228                 }
     223                m_cbProcessed += cbRead;
     224                Assert(m_cbProcessed <= cbSize);
    229225            }
    230 
    231             /* Transfer complete? Make sure to close the object again. */
    232             m_fIsComplete = m_cbProcessed == cbSize;
    233 
    234             if (m_fIsComplete)
     226        }
     227
     228        /* Transfer complete? Make sure to close the object again. */
     229        m_fIsComplete = m_cbProcessed == cbSize;
     230
     231        if (m_fIsComplete)
     232        {
     233            if (m_pTransfer->ProviderIface.pfnObjClose)
    235234            {
    236                 if (m_pTransfer->ProviderIface.pfnObjClose)
    237                 {
    238                     int rc2 = m_pTransfer->ProviderIface.pfnObjClose(&m_pTransfer->ProviderCtx, m_hObj);
    239                     AssertRC(rc2);
    240                 }
    241 
    242                 if (m_pParent)
    243                     m_pParent->OnTransferComplete();
     235                int rc2 = m_pTransfer->ProviderIface.pfnObjClose(&m_pTransfer->ProviderCtx, m_hObj);
     236                AssertRC(rc2);
    244237            }
    245         }
    246 
    247         LogFlowThisFunc(("Leave: rc=%Rrc, cbSize=%RU64, cbProcessed=%RU64 -> nBytesToRead=%RU32, cbToRead=%RU32, cbRead=%RU32\n",
    248                          rc, cbSize, m_cbProcessed, nBytesToRead, cbToRead, cbRead));
    249 
    250         if (nBytesRead)
    251             *nBytesRead = (ULONG)cbRead;
    252 
    253         if (nBytesToRead != cbRead)
    254             return S_FALSE;
    255 
    256         return S_OK;
    257     }
    258     catch (...)
    259     {
    260         LogFunc(("Caught exception\n"));
    261     }
    262 
    263     return E_FAIL;
     238
     239            if (m_pParent)
     240                m_pParent->SetStatus(SharedClipboardWinDataObject::Completed);
     241        }
     242    }
     243
     244    LogFlowThisFunc(("Leave: rc=%Rrc, cbSize=%RU64, cbProcessed=%RU64 -> nBytesToRead=%RU32, cbToRead=%RU32, cbRead=%RU32\n",
     245                     rc, cbSize, m_cbProcessed, nBytesToRead, cbToRead, cbRead));
     246
     247    if (nBytesRead)
     248        *nBytesRead = (ULONG)cbRead;
     249
     250    if (nBytesToRead != cbRead)
     251        return S_FALSE;
     252
     253    return S_OK;
    264254}
    265255
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp

    r99974 r100204  
    6363 * @returns VBox status code.
    6464 * @param   uID                 Payload ID to set for this payload. Useful for consequtive payloads.
    65  * @param   pvData              Data block to associate to this payload.
    66  * @param   cbData              Size (in bytes) of data block to associate.
     65 * @param   pvData              Data to associate to this payload.
     66 *                              The payload owns the data then.
     67 * @param   cbData              Size (in bytes) of data to associate.
     68 * @param   ppPayload           Where to store the allocated event payload on success.
     69 */
     70int ShClPayloadInit(uint32_t uID, void *pvData, uint32_t cbData,
     71                    PSHCLEVENTPAYLOAD *ppPayload)
     72{
     73    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     74    AssertReturn(cbData > 0, VERR_INVALID_PARAMETER);
     75
     76    PSHCLEVENTPAYLOAD pPayload = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
     77    if (pPayload)
     78    {
     79        pPayload->pvData = pvData;
     80        pPayload->cbData = cbData;
     81        pPayload->uID    = uID;
     82
     83        *ppPayload = pPayload;
     84        return VINF_SUCCESS;
     85    }
     86
     87    return VERR_NO_MEMORY;
     88}
     89
     90/**
     91 * Allocates a new event payload.
     92 *
     93 * @returns VBox status code.
     94 * @param   uID                 Payload ID to set for this payload. Useful for consequtive payloads.
     95 * @param   pvData              Data block to allocate (duplicate) to this payload.
     96 * @param   cbData              Size (in bytes) of data block to allocate.
    6797 * @param   ppPayload           Where to store the allocated event payload on success.
    6898 */
     
    73103    AssertReturn(cbData > 0, VERR_INVALID_PARAMETER);
    74104
    75     PSHCLEVENTPAYLOAD pPayload = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
    76     if (pPayload)
    77     {
    78         pPayload->pvData = RTMemDup(pvData, cbData);
    79         if (pPayload->pvData)
    80         {
    81             pPayload->cbData = cbData;
    82             pPayload->uID    = uID;
    83 
    84             *ppPayload = pPayload;
    85             return VINF_SUCCESS;
    86         }
    87 
    88         RTMemFree(pPayload);
    89     }
     105    void *pvDataDup = RTMemDup(pvData, cbData);
     106    if (pvDataDup)
     107        return ShClPayloadInit(uID, pvDataDup, cbData, ppPayload);
     108
    90109    return VERR_NO_MEMORY;
    91110}
     
    418437 * Detaches a payload from an event, internal version.
    419438 *
    420  * @returns Pointer to the detached payload. Can be NULL if the payload has no payload.
     439 * @returns Pointer to the detached payload. Can be NULL if the event has no payload.
    421440 * @param   pEvent              Event to detach payload for.
    422441 */
     
    480499
    481500/**
    482  * Releases an event by decreasing its reference count.
     501 * Releases event by decreasing its reference count. Will be destroys once the reference count reaches 0.
    483502 *
    484503 * @returns New reference count, or UINT32_MAX if failed.
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers-http.cpp

    r99937 r100204  
    4949#include <iprt/path.h>
    5050#include <iprt/rand.h>
     51#include <iprt/semaphore.h>
    5152#include <iprt/stream.h>
    5253#include <iprt/string.h>
     
    7475    PSHCLTRANSFER       pTransfer;
    7576    /** The (cached) root list of the transfer. NULL if not cached yet. */
    76     PSHCLROOTLIST       pRootList;
     77    PSHCLLIST           pRootList;
    7778    /** Critical section for serializing access. */
    7879    RTCRITSECT          CritSect;
     
    9293static const char *shClTransferHttpServerGetHost(PSHCLHTTPSERVER pSrv);
    9394static int shClTransferHttpServerDestroyTransfer(PSHCLHTTPSERVER pSrv, PSHCLHTTPSERVERTRANSFER pSrvTx);
     95static SHCLHTTPSERVERSTATUS shclTransferHttpServerSetStatusLocked(PSHCLHTTPSERVER pSrv, SHCLHTTPSERVERSTATUS enmStatus);
    9496
    9597
     
    188190
    189191    return NULL;
    190 }
    191 
    192 static int shClTransferHttpGetTransferRoots(PSHCLHTTPSERVER pThis, PSHCLHTTPSERVERTRANSFER pSrvTx)
    193 {
    194     RT_NOREF(pThis);
    195 
    196     int rc = VINF_SUCCESS;
    197 
    198     if (pSrvTx->pRootList == NULL)
    199     {
    200         AssertMsgReturn(ShClTransferRootsCount(pSrvTx->pTransfer) == 1,
    201                         ("At the moment only single files are supported!\n"), VERR_NOT_SUPPORTED);
    202 
    203         rc = ShClTransferRootsGet(pSrvTx->pTransfer, &pSrvTx->pRootList);
    204     }
    205 
    206     return rc;
    207192}
    208193
     
    350335                                                   PRTHTTPSERVERREQ pReq, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint)
    351336{
     337    RT_NOREF(pData);
    352338    RT_NOREF(ppszMIMEHint);
    353 
    354     PSHCLHTTPSERVER pThis = (PSHCLHTTPSERVER)pData->pvUser;
    355     Assert(pData->cbUser == sizeof(SHCLHTTPSERVER));
    356339
    357340    int rc;
     
    360343    if (pSrvTx)
    361344    {
    362         rc = shClTransferHttpGetTransferRoots(pThis, pSrvTx);
     345        SHCLOBJOPENCREATEPARMS openParms;
     346        rc = ShClTransferObjOpenParmsInit(&openParms);
    363347        if (RT_SUCCESS(rc))
    364348        {
    365             SHCLOBJOPENCREATEPARMS openParms;
    366             rc = ShClTransferObjOpenParmsInit(&openParms);
    367             if (RT_SUCCESS(rc))
     349            openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
     350                              | SHCL_OBJ_CF_ACCESS_DENYWRITE;
     351
     352            PSHCLTRANSFER pTx = pSrvTx->pTransfer;
     353            AssertPtr(pTx);
     354
     355            /* For now we only serve single files, hence index 0 below. */
     356            PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTx, 0 /* First file */);
     357            if (pEntry)
    368358            {
    369                 openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
    370                                   | SHCL_OBJ_CF_ACCESS_DENYWRITE;
    371 
    372                 PSHCLTRANSFER pTx = pSrvTx->pTransfer;
    373                 AssertPtr(pTx);
    374 
    375                 /* For now we only serve single files, hence index 0 below. */
    376                 SHCLROOTLISTENTRY ListEntry;
    377                 rc = ShClTransferRootsEntry(pTx, 0 /* First file */, &ListEntry);
     359                rc = RTStrCopy(openParms.pszPath, openParms.cbPath, pEntry->pszName);
    378360                if (RT_SUCCESS(rc))
    379361                {
    380                     rc = RTStrCopy(openParms.pszPath, openParms.cbPath, ListEntry.pszName);
     362                    rc = ShClTransferObjOpen(pTx, &openParms, &pSrvTx->hObj);
    381363                    if (RT_SUCCESS(rc))
    382364                    {
    383                         rc = ShClTransferObjOpen(pTx, &openParms, &pSrvTx->hObj);
     365                        char szPath[RTPATH_MAX];
     366                        rc = ShClTransferGetRootPathAbs(pTx, szPath, sizeof(szPath));
    384367                        if (RT_SUCCESS(rc))
    385368                        {
    386                             char szPath[RTPATH_MAX];
    387                             rc = ShClTransferGetRootPathAbs(pTx, szPath, sizeof(szPath));
     369                            rc = RTPathAppend(szPath, sizeof(szPath), openParms.pszPath);
    388370                            if (RT_SUCCESS(rc))
    389371                            {
    390                                 rc = RTPathAppend(szPath, sizeof(szPath), openParms.pszPath);
    391                                 if (RT_SUCCESS(rc))
    392                                 {
    393                                     /* Now that the object is locked, query information that we can return. */
    394                                     rc = RTPathQueryInfo(szPath, pObjInfo, RTFSOBJATTRADD_NOTHING);
    395                                 }
     372                                /* Now that the object is locked, query information that we can return. */
     373                                rc = RTPathQueryInfo(szPath, pObjInfo, RTFSOBJATTRADD_NOTHING);
    396374                            }
    397375                        }
    398376                    }
    399377                }
    400 
    401                 ShClTransferObjOpenParmsDestroy(&openParms);
    402378            }
     379            else
     380                rc = VERR_NOT_FOUND;
     381
     382            ShClTransferObjOpenParmsDestroy(&openParms);
    403383        }
    404384    }
     
    453433    }
    454434
     435    rc = RTSemEventDestroy(pSrv->StatusEvent);
     436    pSrv->StatusEvent = NIL_RTSEMEVENT;
     437
    455438    return rc;
    456439}
     
    481464 * Initializes a new Shared Clipboard HTTP server instance.
    482465 *
     466 * @return  VBox status code.
    483467 * @param   pSrv                HTTP server instance to initialize.
    484468 */
    485 static void shClTransferHttpServerInitInternal(PSHCLHTTPSERVER pSrv)
    486 {
     469static int shClTransferHttpServerInitInternal(PSHCLHTTPSERVER pSrv)
     470{
     471    int rc = RTCritSectInit(&pSrv->CritSect);
     472    AssertRCReturn(rc, rc);
     473
     474    rc = RTSemEventCreate(&pSrv->StatusEvent);
     475    AssertRCReturn(rc, rc);
     476
    487477    pSrv->hHTTPServer = NIL_RTHTTPSERVER;
    488478    pSrv->uPort       = 0;
    489479    RTListInit(&pSrv->lstTransfers);
    490480    pSrv->cTransfers  = 0;
    491     int rc2 = RTHttpServerResponseInit(&pSrv->Resp);
    492     AssertRC(rc2);
     481
     482    rc = RTHttpServerResponseInit(&pSrv->Resp);
     483    AssertRCReturn(rc, rc);
     484
     485    return rc;
    493486}
    494487
     
    501494 * Initializes a new Shared Clipboard HTTP server instance.
    502495 *
     496 * @return  VBox status code.
    503497 * @param   pSrv                HTTP server instance to initialize.
    504498 */
    505 void ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv)
    506 {
    507     AssertPtrReturnVoid(pSrv);
    508 
    509     shClTransferHttpServerInitInternal(pSrv);
     499int ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv)
     500{
     501    AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
     502
     503    return shClTransferHttpServerInitInternal(pSrv);
    510504}
    511505
     
    534528
    535529/**
    536  * Creates a new Shared Clipboard HTTP server instance, extended version.
     530 * Starts the Shared Clipboard HTTP server instance, extended version.
    537531 *
    538532 * @returns VBox status code.
     
    541535 * @param   uPort               TCP port number to use.
    542536 */
    543 int ShClTransferHttpServerCreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort)
     537int ShClTransferHttpServerStartEx(PSHCLHTTPSERVER pSrv, uint16_t uPort)
    544538{
    545539    AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
     
    564558    if (RT_SUCCESS(rc))
    565559    {
    566         rc = RTCritSectInit(&pSrv->CritSect);
    567         AssertRCReturn(rc, rc);
    568 
    569560        pSrv->uPort = uPort;
    570561
     
    584575
    585576/**
    586  * Creates a new Shared Clipboard HTTP server instance using a random port (>= 1024).
     577 * Starts the Shared Clipboard HTTP server instance using a random port (>= 1024).
    587578 *
    588579 * This does automatic probing of TCP ports if a port already is being used.
     
    593584 * @param   puPort              Where to return the TCP port number being used on success. Optional.
    594585 */
    595 int ShClTransferHttpServerCreate(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort)
     586int ShClTransferHttpServerStart(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort)
    596587{
    597588    AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
     
    615606                continue;
    616607
    617             rc = ShClTransferHttpServerCreateEx(pSrv, (uint32_t)uPort);
     608            rc = ShClTransferHttpServerStartEx(pSrv, (uint32_t)uPort);
    618609            if (RT_SUCCESS(rc))
    619610            {
     
    723714                    VERR_INVALID_PARAMETER);
    724715
    725     uint32_t const cRoots = ShClTransferRootsCount(pTransfer);
     716    uint64_t const cRoots = ShClTransferRootsCount(pTransfer);
    726717    AssertMsgReturn(cRoots  > 0, ("Transfer has no root entries\n"), VERR_INVALID_PARAMETER);
    727718    AssertMsgReturn(cRoots == 1, ("Only single files are supported for now\n"), VERR_NOT_SUPPORTED);
     
    744735            AssertRC(rc);
    745736
    746             SHCLROOTLISTENTRY ListEntry;
    747             rc = ShClTransferRootsEntry(pTransfer, 0 /* First file */, &ListEntry);
    748             if (RT_SUCCESS(rc))
     737            PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, 0 /* First file */);
     738            if (pEntry)
    749739            {
    750740#ifdef DEBUG_andy
     
    752742                 * Every transfer has a dedicated HTTP path (but live in the same URL namespace). */
    753743                ssize_t cch = RTStrPrintf2(pSrvTx->szPathVirtual, sizeof(pSrvTx->szPathVirtual), "/%s/uuid/%RU32/%s",
    754                                            SHCL_HTTPT_URL_NAMESPACE, pSrv->cTransfers, ListEntry.pszName);
     744                                           SHCL_HTTPT_URL_NAMESPACE, pSrv->cTransfers, pEntry->pszName);
    755745#else
    756746                /* Create the virtual HTTP path for the transfer.
    757747                 * Every transfer has a dedicated HTTP path (but live in the same URL namespace). */
    758748                ssize_t cch = RTStrPrintf2(pSrvTx->szPathVirtual, sizeof(pSrvTx->szPathVirtual), "/%s/%s/%RU16/%s",
    759                                            SHCL_HTTPT_URL_NAMESPACE, szUuid, pTransfer->State.uID, ListEntry.pszName);
     749                                           SHCL_HTTPT_URL_NAMESPACE, szUuid, pTransfer->State.uID, pEntry->pszName);
    760750#endif
    761751                AssertReturn(cch, VERR_BUFFER_OVERFLOW);
     
    767757                RTListAppend(&pSrv->lstTransfers, &pSrvTx->Node);
    768758                pSrv->cTransfers++;
     759
     760                shclTransferHttpServerSetStatusLocked(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED);
    769761
    770762                LogFunc(("pTransfer=%p, idTransfer=%RU16, szPath=%s -> %RU32 transfers\n",
     
    811803        {
    812804            rc = shClTransferHttpServerDestroyTransfer(pSrv, pSrvTx);
     805            if (RT_SUCCESS(rc))
     806                shclTransferHttpServerSetStatusLocked(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_UNREGISTERED);
    813807            break;
    814808        }
     
    822816
    823817/**
    824  * Returns whether a specific transfer ID is registered with a HTTP server instance or not.
    825  *
    826  * @returns \c true if the transfer ID is registered, \c false if not.
     818 * Sets a new status.
     819 *
     820 * @returns New status set.
     821 * @param   pSrv                HTTP server instance to set status for.
     822 * @param   enmStatus           New status to set.
     823 *
     824 * @note    Caller needs to take critical section.
     825 */
     826static SHCLHTTPSERVERSTATUS shclTransferHttpServerSetStatusLocked(PSHCLHTTPSERVER pSrv, SHCLHTTPSERVERSTATUS enmStatus)
     827{
     828    Assert(RTCritSectIsOwner(&pSrv->CritSect));
     829
     830    /* Bogus checks. */
     831    Assert(   !(enmStatus & SHCLHTTPSERVERSTATUS_NONE) || enmStatus == SHCLHTTPSERVERSTATUS_NONE);
     832    Assert(     enmStatus & SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED
     833           && !(enmStatus & SHCLHTTPSERVERSTATUS_TRANSFER_UNREGISTERED));
     834
     835    pSrv->enmStatus = enmStatus;
     836    LogFlowFunc(("fStatus=%#x\n", pSrv->enmStatus));
     837
     838    int rc2 = RTSemEventSignal(pSrv->StatusEvent);
     839    AssertRC(rc2);
     840
     841    return pSrv->enmStatus;
     842}
     843
     844/**
     845 * Returns the first transfer in the list.
     846 *
     847 * @returns Pointer to first transfer if found, or NULL if not found.
    827848 * @param   pSrv                HTTP server instance.
    828  * @param   idTransfer          Transfer ID to check for.
    829  */
    830 bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer)
     849 */
     850PSHCLTRANSFER ShClTransferHttpServerGetTransferFirst(PSHCLHTTPSERVER pSrv)
     851{
     852    shClTransferHttpServerLock(pSrv);
     853
     854    PSHCLHTTPSERVERTRANSFER pHttpTransfer = RTListGetFirst(&pSrv->lstTransfers, SHCLHTTPSERVERTRANSFER, Node);
     855
     856    shClTransferHttpServerUnlock(pSrv);
     857
     858    return pHttpTransfer ? pHttpTransfer->pTransfer : NULL;
     859}
     860
     861/**
     862 * Returns a transfer for a specific ID.
     863 *
     864 * @returns Pointer to the transfer if found, or NULL if not found.
     865 * @param   pSrv                HTTP server instance.
     866 * @param   idTransfer          Transfer ID of transfer to return..
     867 */
     868bool ShClTransferHttpServerGetTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer)
    831869{
    832870    AssertPtrReturn(pSrv, false);
     
    834872    shClTransferHttpServerLock(pSrv);
    835873
    836     const bool fRc = shClTransferHttpServerGetTransferById(pSrv, idTransfer) != NULL;
     874    PSHCLHTTPSERVERTRANSFER pTransfer = shClTransferHttpServerGetTransferById(pSrv, idTransfer);
    837875
    838876    shClTransferHttpServerUnlock(pSrv);
    839877
    840     return fRc;
     878    return pTransfer;
    841879}
    842880
     
    945983}
    946984
     985/**
     986 * Waits for a status change.
     987 *
     988 * @returns VBox status code.
     989 * @param   pSrv                HTTP server instance to wait for.
     990 * @param   fStatus             Status to wait for.
     991 *                              Multiple statuses are possible, @sa SHCLHTTPSERVERSTATUS.
     992 * @param   msTimeout           Timeout (in ms) to wait.
     993 */
     994int ShClTransferHttpServerWaitForStatusChange(PSHCLHTTPSERVER pSrv, SHCLHTTPSERVERSTATUS fStatus, RTMSINTERVAL msTimeout)
     995{
     996    AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
     997
     998    shClTransferHttpServerLock(pSrv);
     999
     1000    uint64_t const tsStartMs = RTTimeMilliTS();
     1001
     1002    int rc = VERR_TIMEOUT;
     1003
     1004    LogFlowFunc(("fStatus=%#x, msTimeout=%RU32\n", fStatus, msTimeout));
     1005
     1006    while (RTTimeMilliTS() - tsStartMs <= msTimeout)
     1007    {
     1008        shClTransferHttpServerUnlock(pSrv); /* Leave lock before waiting. */
     1009
     1010        rc = RTSemEventWait(pSrv->StatusEvent, msTimeout);
     1011
     1012        shClTransferHttpServerLock(pSrv);
     1013
     1014        if (RT_SUCCESS(rc))
     1015        {
     1016            if (pSrv->enmStatus & fStatus)
     1017            {
     1018                rc = VINF_SUCCESS;
     1019                break;
     1020            }
     1021        }
     1022    }
     1023
     1024    shClTransferHttpServerUnlock(pSrv);
     1025    return rc;
     1026}
     1027
    9471028
    9481029/*********************************************************************************************************************************
     
    9511032
    9521033/**
    953  * Registers a Shared Clipboard transfer to a HTTP context and starts the HTTP server, if not started already.
     1034 * Starts the HTTP server, if not started already.
    9541035 *
    9551036 * @returns VBox status code.
    956  * @param   pCtx                HTTP context to register transfer for.
    957  * @param   pTransfer           Transfer to register.
    958  */
    959 int ShClHttpTransferRegisterAndMaybeStart(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer)
     1037 * @param   pCtx                HTTP context to start HTTP server for.
     1038 */
     1039int ShClTransferHttpServerMaybeStart(PSHCLHTTPCONTEXT pCtx)
    9601040{
    9611041    int rc = VINF_SUCCESS;
     
    9631043    /* Start the built-in HTTP server to serve file(s). */
    9641044    if (!ShClTransferHttpServerIsRunning(&pCtx->HttpServer)) /* Only one HTTP server per transfer context. */
    965         rc = ShClTransferHttpServerCreate(&pCtx->HttpServer, 32 /* cMaxAttempts */, NULL /* puPort */);
    966 
    967     if (RT_SUCCESS(rc))
    968         rc = ShClTransferHttpServerRegisterTransfer(&pCtx->HttpServer, pTransfer);
    969 
    970     return rc;
    971 }
    972 
    973 /**
    974  * Unregisters a formerly registered Shared Clipboard transfer and stops the HTTP server, if no transfers are left.
     1045        rc = ShClTransferHttpServerStart(&pCtx->HttpServer, 32 /* cMaxAttempts */, NULL /* puPort */);
     1046
     1047    return rc;
     1048}
     1049
     1050/**
     1051 * Stops the HTTP server, if no transfers are left.
    9751052 *
    9761053 * @returns VBox status code.
    977  * @param   pCtx                HTTP context to unregister transfer from.
    978  * @param   pTransfer           Transfer to unregister.
    979  */
    980 int ShClHttpTransferUnregisterAndMaybeStop(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer)
     1054 * @param   pCtx                HTTP context to stop HTTP server for.
     1055 */
     1056int ShClTransferHttpServerMaybeStop(PSHCLHTTPCONTEXT pCtx)
    9811057{
    9821058    int rc = VINF_SUCCESS;
     
    9841060    if (ShClTransferHttpServerIsRunning(&pCtx->HttpServer))
    9851061    {
    986         /* Try unregistering transfer (if it was registered before). */
    987         rc = ShClTransferHttpServerUnregisterTransfer(&pCtx->HttpServer, pTransfer);
    988         if (RT_SUCCESS(rc))
    989         {
    990             /* No more registered transfers left? Tear down the HTTP server instance then. */
    991             if (ShClTransferHttpServerGetTransferCount(&pCtx->HttpServer) == 0)
    992                 rc = ShClTransferHttpServerDestroy(&pCtx->HttpServer);
    993         }
    994         AssertRC(rc);
    995     }
    996 
    997     return rc;
    998 }
    999 
     1062        /* No more registered transfers left? Tear down the HTTP server instance then. */
     1063        if (ShClTransferHttpServerGetTransferCount(&pCtx->HttpServer) == 0)
     1064            rc = ShClTransferHttpServerDestroy(&pCtx->HttpServer);
     1065    }
     1066
     1067    return rc;
     1068}
     1069
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers-provider-local.cpp

    r99951 r100204  
    129129 * @returns VBox status code.
    130130 * @param   pTransfer           Clipboard transfer to resolve path for.
    131  * @param   pszPath             Path to resolve.
     131 * @param   pszPath             Relative path to resolve.
    132132 * @param   fFlags              Resolve flags. Currently not used and must be 0.
    133133 * @param   ppszResolved        Where to store the allocated resolved path. Must be free'd by the called using RTStrFree().
     
    145145    if (RT_SUCCESS(rc))
    146146    {
    147         char *pszPathAbs = RTPathJoinA(pTransfer->pszPathRootAbs, pszPath);
    148         if (pszPathAbs)
    149         {
    150             char   szResolved[RTPATH_MAX];
    151             size_t cbResolved = sizeof(szResolved);
    152             rc = RTPathAbsEx(pTransfer->pszPathRootAbs, pszPathAbs, RTPATH_STR_F_STYLE_HOST, szResolved, &cbResolved);
    153 
    154             RTStrFree(pszPathAbs);
    155 
    156             if (RT_SUCCESS(rc))
    157             {
    158                 LogFlowFunc(("pszResolved=%s\n", szResolved));
    159 
    160                 rc = VERR_PATH_NOT_FOUND; /* Play safe by default. */
    161 
    162                 /* Make sure the resolved path is part of the set of root entries. */
    163                 PSHCLLISTROOT pListRoot;
    164                 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)
    165                 {
    166                     if (RTPathStartsWith(szResolved, pListRoot->pszPathAbs))
    167                     {
    168                         rc = VINF_SUCCESS;
    169                         break;
    170                     }
    171                 }
     147        rc = VERR_PATH_NOT_FOUND; /* Play safe by default. */
     148
     149        /* Make sure the given path is part of the set of root entries. */
     150        PSHCLLISTENTRY pEntry;
     151        RTListForEach(&pTransfer->lstRoots.lstEntries, pEntry, SHCLLISTENTRY, Node)
     152        {
     153            LogFlowFunc(("\tpEntry->pszName=%s\n", pEntry->pszName));
     154
     155            if (!RTStrCmp(pszPath, pEntry->pszName)) /* Case-sensitive! */
     156            {
     157                rc = VINF_SUCCESS;
     158                break;
     159            }
     160        }
     161
     162        if (RT_SUCCESS(rc))
     163        {
     164            char *pszPathAbs = RTPathJoinA(pTransfer->pszPathRootAbs, pszPath);
     165            if (pszPathAbs)
     166            {
     167                char   szResolved[RTPATH_MAX];
     168                size_t cbResolved = sizeof(szResolved);
     169                rc = RTPathAbsEx(pTransfer->pszPathRootAbs, pszPathAbs, RTPATH_STR_F_STYLE_HOST, szResolved, &cbResolved);
     170
     171                RTStrFree(pszPathAbs);
     172                pszPathAbs = NULL;
    172173
    173174                if (RT_SUCCESS(rc))
    174                     *ppszResolved = RTStrDup(szResolved);
    175             }
    176         }
    177         else
    178             rc = VERR_NO_MEMORY;
     175                {
     176                    LogFlowFunc(("pszResolved=%s\n", szResolved));
     177
     178                    if (RT_SUCCESS(rc))
     179                        *ppszResolved = RTStrDup(szResolved);
     180                }
     181            }
     182            else
     183                rc = VERR_NO_MEMORY;
     184        }
    179185    }
    180186
    181187    if (RT_FAILURE(rc))
    182         LogRel(("Shared Clipboard: Resolving absolute path '%s' failed, rc=%Rrc\n", pszPath, rc));
     188        LogRel(("Shared Clipboard: Resolving absolute path for '%s' failed, rc=%Rrc\n", pszPath, rc));
    183189
    184190    LogFlowFuncLeaveRC(rc);
     
    202208    if (RT_SUCCESS(rc))
    203209    {
    204         pHdr->cbTotalSize  += cbSize;
    205         pHdr->cTotalObjects++;
     210        pHdr->cbTotalSize += cbSize;
     211        pHdr->cEntries++;
    206212    }
    207213
     
    254260                                break;
    255261
    256                             pHdr->cTotalObjects++;
     262                            pHdr->cEntries++;
    257263                            break;
    258264                        }
     
    303309 * Creates a new list handle (local only).
    304310 *
    305  * @returns New List handle on success, or SHCLLISTHANDLE_INVALID on error.
     311 * @returns New List handle on success, or NIL_SHCLLISTHANDLE on error.
    306312 * @param   pTransfer           Clipboard transfer to create new list handle for.
    307313 */
     
    311317}
    312318
    313 static DECLCALLBACK(int) vbclTransferIfaceLocalRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
     319static int shClTransferListEntryQueryFsInfo(PSHCLLISTENTRY pListEntry, PSHCLFSOBJINFO pFsObjInfo)
     320{
     321    AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
     322
     323    const char *pcszSrcPathAbs = pListEntry->pszName;
     324    AssertPtrReturn(pcszSrcPathAbs, VERR_INVALID_POINTER);
     325
     326    int rc;
     327
     328    /* Make sure that we only advertise relative source paths, not absolute ones. */
     329    char *pszFileName = RTPathFilename(pcszSrcPathAbs);
     330    if (pszFileName)
     331    {
     332        Assert(pszFileName >= pcszSrcPathAbs);
     333        size_t cchDstBase = pszFileName - pcszSrcPathAbs;
     334        const char *pszDstPath = &pcszSrcPathAbs[cchDstBase];
     335
     336        LogFlowFunc(("pcszSrcPathAbs=%s, pszDstPath=%s\n", pcszSrcPathAbs, pszDstPath));
     337
     338        RTFSOBJINFO fsObjInfo;
     339        rc = RTPathQueryInfo(pcszSrcPathAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING);
     340        if (RT_SUCCESS(rc))
     341            rc = ShClFsObjInfoFromIPRT(pFsObjInfo, &fsObjInfo);
     342    }
     343    else
     344        rc = VERR_INVALID_POINTER;
     345
     346    return rc;
     347}
     348
     349/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
     350static DECLCALLBACK(int) shclTransferIfaceLocalRootListRead(PSHCLTXPROVIDERCTX pCtx)
    314351{
    315352    LogFlowFuncEnter();
    316353
    317     PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
    318     if (!pRootList)
    319         return VERR_NO_MEMORY;
    320 
    321     AssertPtr(pCtx->pTransfer);
    322     const uint64_t cRoots = (uint32_t)pCtx->pTransfer->cRoots;
    323 
    324     LogFlowFunc(("cRoots=%RU64\n", cRoots));
    325 
    326354    int rc = VINF_SUCCESS;
    327355
    328     if (cRoots)
    329     {
    330         PSHCLROOTLISTENTRY paRootListEntries
    331             = (PSHCLROOTLISTENTRY)RTMemAllocZ(cRoots * sizeof(SHCLROOTLISTENTRY));
    332         if (paRootListEntries)
    333         {
    334             for (uint64_t i = 0; i < cRoots; ++i)
    335             {
    336                 rc = ShClTransferRootsEntry(pCtx->pTransfer, i, &paRootListEntries[i]);
    337                 if (RT_FAILURE(rc))
    338                     break;
    339             }
    340 
    341             if (RT_SUCCESS(rc))
    342                 pRootList->paEntries = paRootListEntries;
    343         }
    344         else
    345             rc = VERR_NO_MEMORY;
    346     }
    347     else
    348         rc = VERR_NOT_FOUND;
    349 
    350     if (RT_SUCCESS(rc))
    351     {
    352         pRootList->Hdr.cRoots = cRoots;
    353 
    354         *ppRootList = pRootList;
    355     }
    356 
    357     LogFlowFuncLeaveRC(rc);
    358     return rc;
    359 }
    360 
    361 static DECLCALLBACK(int) vbclTransferIfaceLocalListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
     356    PSHCLLISTENTRY pEntry;
     357    RTListForEach(&pCtx->pTransfer->lstRoots.lstEntries, pEntry, SHCLLISTENTRY, Node)
     358    {
     359        AssertBreakStmt(pEntry->cbInfo == sizeof(SHCLFSOBJINFO), rc = VERR_WRONG_ORDER);
     360        rc = shClTransferListEntryQueryFsInfo(pEntry, (PSHCLFSOBJINFO)pEntry->pvInfo);
     361        if (RT_FAILURE(rc)) /* Currently this is an all-or-nothing op. */
     362            break;
     363    }
     364
     365    LogFlowFuncLeaveRC(rc);
     366    return rc;
     367}
     368
     369/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
     370static DECLCALLBACK(int) shclTransferIfaceLocalListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
    362371                                                        PSHCLLISTHANDLE phList)
    363372{
     
    416425                        pInfo->hList = shClTransferListHandleNew(pTransfer);
    417426
    418                         RTListAppend(&pTransfer->lstList, &pInfo->Node);
     427                        RTListAppend(&pTransfer->lstHandles, &pInfo->Node);
    419428                        pTransfer->cListHandles++;
    420429
     
    457466}
    458467
    459 static DECLCALLBACK(int) vbclTransferIfaceLocalListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
     468/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
     469static DECLCALLBACK(int) shclTransferIfaceLocalListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
    460470{
    461471    LogFlowFuncEnter();
     
    500510}
    501511
    502 static DECLCALLBACK(int) vbclTransferIfaceLocalListHdrRead(PSHCLTXPROVIDERCTX pCtx,
     512/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
     513static DECLCALLBACK(int) shclTransferIfaceLocalListHdrRead(PSHCLTXPROVIDERCTX pCtx,
    503514                                                           SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
    504515{
     
    530541                    LogFlowFunc(("FileAbs: %s\n", pInfo->pszPathLocalAbs));
    531542
    532                     pListHdr->cTotalObjects = 1;
     543                    pListHdr->cEntries = 1;
    533544
    534545                    RTFSOBJINFO objInfo;
     
    549560        }
    550561
    551         LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pListHdr->cTotalObjects, pListHdr->cbTotalSize));
     562        LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pListHdr->cEntries, pListHdr->cbTotalSize));
    552563    }
    553564    else
     
    558569}
    559570
    560 static DECLCALLBACK(int) vbclTransferIfaceLocalListEntryRead(PSHCLTXPROVIDERCTX pCtx,
     571/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
     572static DECLCALLBACK(int) shclTransferIfaceLocalListEntryRead(PSHCLTXPROVIDERCTX pCtx,
    561573                                                             SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)
    562574{
     
    628640                                Assert   (pEntry->cbInfo == sizeof(SHCLFSOBJINFO));
    629641
    630                                 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);
     642                                ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);
    631643
    632644                                LogFlowFunc(("Entry pszName=%s, pvInfo=%p, cbInfo=%RU32\n",
     
    662674                        if (RT_SUCCESS(rc))
    663675                        {
    664                             ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo);
     676                            ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo);
    665677
    666678                            pEntry->cbInfo = sizeof(SHCLFSOBJINFO);
    667                             pEntry->fInfo  = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
     679                            pEntry->fInfo  = VBOX_SHCL_INFO_F_FSOBJINFO;
    668680                        }
    669681                    }
     
    687699}
    688700
    689 static DECLCALLBACK(int) vbclTransferIfaceLocalObjOpen(PSHCLTXPROVIDERCTX pCtx,
     701/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
     702static DECLCALLBACK(int) shclTransferIfaceLocalObjOpen(PSHCLTXPROVIDERCTX pCtx,
    690703                                                       PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
    691704{
     
    745758}
    746759
    747 static DECLCALLBACK(int) vbclTransferIfaceLocalObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
     760/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
     761static DECLCALLBACK(int) shclTransferIfaceLocalObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
    748762{
    749763    LogFlowFuncEnter();
     
    809823}
    810824
    811 static DECLCALLBACK(int) vbclTransferIfaceLocalObjRead(PSHCLTXPROVIDERCTX pCtx,
     825/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
     826static DECLCALLBACK(int) shclTransferIfaceLocalObjRead(PSHCLTXPROVIDERCTX pCtx,
    812827                                                       SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
    813828                                                       uint32_t fFlags, uint32_t *pcbRead)
     
    851866}
    852867
    853 static DECLCALLBACK(int) vbclTransferIfaceLocalObjWrite(PSHCLTXPROVIDERCTX pCtx,
     868static DECLCALLBACK(int) shclTransferIfaceLocalObjWrite(PSHCLTXPROVIDERCTX pCtx,
    854869                                                        SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, uint32_t fFlags,
    855870                                                        uint32_t *pcbWritten)
     
    892907 * The local provider is being used for accessing files on local file systems.
    893908 *
    894  * @returns Interface pointer the provider get assigned to.
    895  * @param   pIface              Interface to assign provider to.
     909 * @returns Interface pointer assigned to the provider.
     910 * @param   pProvider           Provider to assign interface to.
    896911 */
    897 PSHCLTXPROVIDERIFACE VBClTransferQueryIfaceLocal(PSHCLTXPROVIDERIFACE pIface)
    898 {
    899     pIface->pfnRootsGet       = vbclTransferIfaceLocalRootsGet;
    900     pIface->pfnListOpen       = vbclTransferIfaceLocalListOpen;
    901     pIface->pfnListClose      = vbclTransferIfaceLocalListClose;
    902     pIface->pfnListHdrRead    = vbclTransferIfaceLocalListHdrRead;
    903     pIface->pfnListEntryRead  = vbclTransferIfaceLocalListEntryRead;
    904     pIface->pfnObjOpen        = vbclTransferIfaceLocalObjOpen;
    905     pIface->pfnObjClose       = vbclTransferIfaceLocalObjClose;
    906     pIface->pfnObjRead        = vbclTransferIfaceLocalObjRead;
    907     pIface->pfnObjWrite       = vbclTransferIfaceLocalObjWrite;
    908 
    909     return pIface;
    910 }
    911 
     912PSHCLTXPROVIDERIFACE VBClTransferProviderLocalQueryInterface(PSHCLTXPROVIDER pProvider)
     913{
     914    pProvider->Interface.pfnRootListRead   = shclTransferIfaceLocalRootListRead;
     915    pProvider->Interface.pfnListOpen       = shclTransferIfaceLocalListOpen;
     916    pProvider->Interface.pfnListClose      = shclTransferIfaceLocalListClose;
     917    pProvider->Interface.pfnListHdrRead    = shclTransferIfaceLocalListHdrRead;
     918    pProvider->Interface.pfnListEntryRead  = shclTransferIfaceLocalListEntryRead;
     919    pProvider->Interface.pfnObjOpen        = shclTransferIfaceLocalObjOpen;
     920    pProvider->Interface.pfnObjClose       = shclTransferIfaceLocalObjClose;
     921    pProvider->Interface.pfnObjRead        = shclTransferIfaceLocalObjRead;
     922    pProvider->Interface.pfnObjWrite       = shclTransferIfaceLocalObjWrite;
     923
     924    return &pProvider->Interface;
     925}
     926
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp

    r99966 r100204  
    3535#include <iprt/rand.h>
    3636#include <iprt/semaphore.h>
     37#include <iprt/uri.h>
    3738
    3839#include <VBox/err.h>
     
    5051
    5152/**
    52  * Allocates a new transfer root list.
    53  *
    54  * @returns Allocated transfer root list on success, or NULL on failure.
    55  */
    56 PSHCLROOTLIST ShClTransferRootListAlloc(void)
    57 {
    58     PSHCLROOTLIST pRootList = (PSHCLROOTLIST)RTMemAllocZ(sizeof(SHCLROOTLIST));
    59 
    60     return pRootList;
    61 }
    62 
    63 /**
    64  * Frees a transfer root list.
    65  *
    66  * @param   pRootList           Transfer root list to free. The pointer will be
     53 * Initializes a transfer list.
     54 *
     55 * @param   pList               Transfer list to initialize.
     56 */
     57void ShClTransferListInit(PSHCLLIST pList)
     58{
     59    RT_ZERO(pList->Hdr);
     60    RTListInit(&pList->lstEntries);
     61}
     62
     63/**
     64 * Destroys a transfer list.
     65 *
     66 * @param   pList               Transfer list to destroy.
     67 */
     68void ShClTransferListDestroy(PSHCLLIST pList)
     69{
     70    if (!pList)
     71        return;
     72
     73    PSHCLLISTENTRY pEntry, pEntryNext;
     74    RTListForEachSafe(&pList->lstEntries, pEntry, pEntryNext, SHCLLISTENTRY, Node)
     75    {
     76        RTListNodeRemove(&pEntry->Node);
     77        ShClTransferListEntryDestroy(pEntry);
     78        RTMemFree(pEntry);
     79    }
     80
     81    RT_ZERO(pList->Hdr);
     82}
     83
     84/**
     85 * Adds a list entry to a transfer list.
     86 *
     87 * @returns VBox status code.
     88 * @param   pList               Transfer list to add entry to.
     89 * @param   pEntry              Entry to add.
     90 * @param   fAppend             \c true to append to a list, or \c false to prepend.
     91 */
     92int ShClTransferListAddEntry(PSHCLLIST pList, PSHCLLISTENTRY pEntry, bool fAppend)
     93{
     94    AssertReturn(ShClTransferListEntryIsValid(pEntry), VERR_INVALID_PARAMETER);
     95
     96    if (fAppend)
     97        RTListAppend(&pList->lstEntries, &pEntry->Node);
     98    else
     99        RTListPrepend(&pList->lstEntries, &pEntry->Node);
     100    pList->Hdr.cEntries++;
     101
     102    LogFlowFunc(("%p: '%s' (%RU32 bytes) + %RU32 bytes info -> now %RU32 entries\n",
     103                 pList, pEntry->pszName, pEntry->cbName, pEntry->cbInfo, pList->Hdr.cEntries));
     104
     105    return VINF_SUCCESS;
     106}
     107
     108/**
     109 * Allocates a new transfer list.
     110 *
     111 * @returns Allocated transfer list on success, or NULL on failure.
     112 */
     113PSHCLLIST ShClTransferListAlloc(void)
     114{
     115    PSHCLLIST pList = (PSHCLLIST)RTMemAllocZ(sizeof(SHCLLIST));
     116    if (pList)
     117    {
     118        ShClTransferListInit(pList);
     119        return pList;
     120    }
     121
     122    return NULL;
     123}
     124
     125/**
     126 * Frees a transfer list.
     127 *
     128 * @param   pList               Transfer list to free. The pointer will be
    67129 *                              invalid after returning from this function.
    68130 */
    69 void ShClTransferRootListFree(PSHCLROOTLIST pRootList)
    70 {
    71     if (!pRootList)
     131void ShClTransferListFree(PSHCLLIST pList)
     132{
     133    if (!pList)
    72134        return;
    73135
    74     for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++)
    75         ShClTransferListEntryDestroy(&pRootList->paEntries[i]);
    76 
    77     RTMemFree(pRootList);
    78     pRootList = NULL;
    79 }
    80 
    81 /**
    82  * Initializes a transfer root list header.
    83  *
    84  * @returns VBox status code.
    85  * @param   pRootLstHdr         Root list header to initialize.
    86  */
    87 int ShClTransferRootListHdrInit(PSHCLROOTLISTHDR pRootLstHdr)
    88 {
    89     AssertPtrReturn(pRootLstHdr, VERR_INVALID_POINTER);
    90 
    91     RT_BZERO(pRootLstHdr, sizeof(SHCLROOTLISTHDR));
    92 
    93     return VINF_SUCCESS;
    94 }
    95 
    96 /**
    97  * Destroys a transfer root list header.
    98  *
    99  * @param   pRootLstHdr         Root list header to destroy.
    100  */
    101 void ShClTransferRootListHdrDestroy(PSHCLROOTLISTHDR pRootLstHdr)
    102 {
    103     if (!pRootLstHdr)
    104         return;
    105 
    106     pRootLstHdr->cRoots = 0;
    107 }
    108 
    109 /**
    110  * Duplicates a transfer list header.
    111  *
    112  * @returns Duplicated transfer list header on success, or NULL on failure.
    113  * @param   pRootLstHdr         Root list header to duplicate.
    114  */
    115 PSHCLROOTLISTHDR ShClTransferRootListHdrDup(PSHCLROOTLISTHDR pRootLstHdr)
    116 {
    117     AssertPtrReturn(pRootLstHdr, NULL);
    118 
    119     int rc = VINF_SUCCESS;
    120 
    121     PSHCLROOTLISTHDR pRootsDup = (PSHCLROOTLISTHDR)RTMemAllocZ(sizeof(SHCLROOTLISTHDR));
    122     if (pRootsDup)
    123     {
    124         *pRootsDup = *pRootLstHdr;
    125     }
    126     else
    127         rc = VERR_NO_MEMORY;
    128 
    129     if (RT_FAILURE(rc))
    130     {
    131         ShClTransferRootListHdrDestroy(pRootsDup);
    132         pRootsDup = NULL;
    133     }
    134 
    135     return pRootsDup;
    136 }
    137 
    138 /**
    139  * (Deep) Copies a clipboard root list entry structure.
    140  *
    141  * @returns VBox status code.
    142  * @param   pDst                Where to copy the source root list entry to.
    143  * @param   pSrc                Source root list entry to copy.
    144  */
    145 int ShClTransferRootListEntryCopy(PSHCLROOTLISTENTRY pDst, PSHCLROOTLISTENTRY pSrc)
    146 {
    147     return ShClTransferListEntryCopy(pDst, pSrc);
    148 }
    149 
    150 /**
    151  * Initializes a clipboard root list entry structure.
    152  *
    153  * @param   pRootListEntry      Clipboard root list entry structure to destroy.
    154  */
    155 int ShClTransferRootListEntryInit(PSHCLROOTLISTENTRY pRootListEntry)
    156 {
    157     return ShClTransferListEntryInit(pRootListEntry);
    158 }
    159 
    160 /**
    161  * Destroys a clipboard root list entry structure.
    162  *
    163  * @param   pRootListEntry      Clipboard root list entry structure to destroy.
    164  */
    165 void ShClTransferRootListEntryDestroy(PSHCLROOTLISTENTRY pRootListEntry)
    166 {
    167     return ShClTransferListEntryDestroy(pRootListEntry);
    168 }
    169 
    170 /**
    171  * Duplicates (allocates) a clipboard root list entry structure.
    172  *
    173  * @returns Duplicated clipboard root list entry structure on success.
    174  * @param   pRootListEntry      Clipboard root list entry to duplicate.
    175  */
    176 PSHCLROOTLISTENTRY ShClTransferRootListEntryDup(PSHCLROOTLISTENTRY pRootListEntry)
    177 {
    178     return ShClTransferListEntryDup(pRootListEntry);
     136    ShClTransferListDestroy(pList);
     137
     138    RTMemFree(pList);
     139    pList = NULL;
     140}
     141
     142/**
     143 * Returns a specific list entry of a transfer list.
     144 *
     145 * @returns Pointer to list entry if found, or NULL if not found.
     146 * @param   pList               Clipboard transfer list to get list entry from.
     147 * @param   uIdx                Index of list entry to return.
     148 */
     149DECLINLINE(PSHCLLISTENTRY) shClTransferListGetEntryById(PSHCLLIST pList, uint32_t uIdx)
     150{
     151    if (uIdx >= pList->Hdr.cEntries)
     152        return NULL;
     153
     154    Assert(!RTListIsEmpty(&pList->lstEntries));
     155
     156    PSHCLLISTENTRY pIt = RTListGetFirst(&pList->lstEntries, SHCLLISTENTRY, Node);
     157    while (uIdx) /** @todo Slow, but works for now. */
     158    {
     159        pIt = RTListGetNext(&pList->lstEntries, pIt, SHCLLISTENTRY, Node);
     160        uIdx--;
     161    }
     162
     163    return pIt;
    179164}
    180165
     
    446431 *
    447432 * @returns VBox status code.
    448  * @param   ppDirData           Where to return the created clipboard list entry structure on success.
     433 * @param   ppListEntry         Where to return the created clipboard list entry structure on success.
     434 *                              Must be free'd with  ShClTransferListEntryFree().
    449435 */
    450436int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry)
     
    454440        return VERR_NO_MEMORY;
    455441
    456     int rc = ShClTransferListEntryInit(pListEntry);
    457     if (RT_SUCCESS(rc))
    458         *ppListEntry = pListEntry;
    459 
     442    int rc;
     443
     444    size_t cbInfo = sizeof(SHCLFSOBJINFO);
     445    void  *pvInfo = RTMemAlloc(cbInfo);
     446    if (pvInfo)
     447    {
     448        rc = ShClTransferListEntryInitEx(pListEntry, VBOX_SHCL_INFO_F_NONE, NULL /* pszName */, pvInfo, (uint32_t)cbInfo);
     449        if (RT_SUCCESS(rc))
     450            *ppListEntry = pListEntry;
     451
     452        return rc;
     453    }
     454    else
     455        rc = VERR_NO_MEMORY;
     456
     457    RTMemFree(pListEntry);
    460458    return rc;
    461459}
     
    464462 * Frees a clipboard list entry structure.
    465463 *
    466  * @param   pListEntry          Clipboard list entry structure to free.
     464 * @param   pEntry              Clipboard list entry structure to free.
    467465 *                              The pointer will be invalid on return.
    468466 */
    469 void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry)
    470 {
    471     if (!pListEntry)
     467void ShClTransferListEntryFree(PSHCLLISTENTRY pEntry)
     468{
     469    if (!pEntry)
    472470        return;
    473471
    474     ShClTransferListEntryDestroy(pListEntry);
    475     RTMemFree(pListEntry);
     472    /* Make sure to destroy the entry properly, in case the caller forgot this. */
     473    ShClTransferListEntryDestroy(pEntry);
     474
     475    RTMemFree(pEntry);
     476    pEntry = NULL;
    476477}
    477478
     
    528529 *
    529530 * @returns Duplicated clipboard list entry structure on success.
    530  * @param   pListEntry          Clipboard list entry to duplicate.
    531  */
    532 PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry)
    533 {
    534     AssertPtrReturn(pListEntry, NULL);
     531 * @param   pEntry              Clipboard list entry to duplicate.
     532 */
     533PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pEntry)
     534{
     535    AssertPtrReturn(pEntry, NULL);
    535536
    536537    int rc = VINF_SUCCESS;
     
    538539    PSHCLLISTENTRY pListEntryDup = (PSHCLLISTENTRY)RTMemAllocZ(sizeof(SHCLLISTENTRY));
    539540    if (pListEntryDup)
    540         rc = ShClTransferListEntryCopy(pListEntryDup, pListEntry);
     541        rc = ShClTransferListEntryCopy(pListEntryDup, pEntry);
    541542
    542543    if (RT_FAILURE(rc))
     
    586587 * @returns VBox status code.
    587588 * @param   pListEntry          Clipboard list entry structure to initialize.
     589 * @param   fInfo               Info flags (of type VBOX_SHCL_INFO_FLAG_XXX).
    588590 * @param   pszName             Name (e.g. filename) to use. Can be NULL if not being used.
    589591 *                              Up to SHCLLISTENTRY_MAX_NAME characters.
    590  */
    591 int ShClTransferListEntryInitEx(PSHCLLISTENTRY pListEntry, const char *pszName)
     592 * @param   pvInfo              Pointer to info data to assign. Must match \a fInfo.
     593 *                              The list entry takes the ownership of the data on success.
     594 * @param   cbInfo              Size (in bytes) of \a pvInfo data to assign.
     595 */
     596int ShClTransferListEntryInitEx(PSHCLLISTENTRY pListEntry, uint32_t fInfo, const char *pszName, void *pvInfo, uint32_t cbInfo)
    592597{
    593598    AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
    594599    AssertReturn   (   pszName == NULL
    595600                    || shclTransferListEntryNameIsValid(pszName, strlen(pszName) + 1), VERR_INVALID_PARAMETER);
     601    /* pvInfo + cbInfo depend on fInfo. See below. */
    596602
    597603    RT_BZERO(pListEntry, sizeof(SHCLLISTENTRY));
     
    599605    if (pszName)
    600606    {
    601         pListEntry->pszName = RTStrDup(pszName);
    602         if (!pListEntry->pszName)
    603             return VERR_NO_MEMORY;
    604         pListEntry->cbName = strlen(pszName) + 1 /* Include terminator */;
    605     }
    606 
    607     pListEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(sizeof(SHCLFSOBJINFO));
    608     if (pListEntry->pvInfo)
    609     {
    610         pListEntry->cbInfo = sizeof(SHCLFSOBJINFO);
    611         pListEntry->fInfo  = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
    612 
    613         return VINF_SUCCESS;
    614     }
    615 
    616     return VERR_NO_MEMORY;
     607        pListEntry->pszName = RTStrDupN(pszName, SHCLLISTENTRY_MAX_NAME);
     608        AssertPtrReturn(pListEntry->pszName, VERR_NO_MEMORY);
     609        pListEntry->cbName = (uint32_t)strlen(pListEntry->pszName) + 1 /* Include terminator */;
     610    }
     611
     612    pListEntry->pvInfo = pvInfo;
     613    pListEntry->cbInfo = cbInfo;
     614    pListEntry->fInfo  = fInfo;
     615
     616    return VINF_SUCCESS;
    617617}
    618618
     
    625625int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry)
    626626{
    627     return ShClTransferListEntryInitEx(pListEntry, NULL);
     627    return ShClTransferListEntryInitEx(pListEntry, VBOX_SHCL_INFO_F_NONE, NULL /* pszName */, NULL /* pvInfo */, 0 /* cbInfo */);
    628628}
    629629
     
    862862    AssertPtrReturn(phObj,            VERR_INVALID_POINTER);
    863863    AssertMsgReturn(pTransfer->pszPathRootAbs, ("Transfer has no root path set\n"), VERR_INVALID_PARAMETER);
     864    /** @todo Check pOpenCreateParms->fCreate flags. */
    864865    AssertMsgReturn(pOpenCreateParms->pszPath, ("No path in open/create params set\n"), VERR_INVALID_PARAMETER);
    865866
     
    10681069    pTransfer->cbUser = 0;
    10691070
    1070     RTListInit(&pTransfer->lstList);
     1071    RTListInit(&pTransfer->lstHandles);
    10711072    RTListInit(&pTransfer->lstObj);
    10721073
    1073     pTransfer->cRoots = 0;
    1074     RTListInit(&pTransfer->lstRoots);
     1074    /* The provider context + interface is NULL by default. */
     1075    RT_ZERO(pTransfer->ProviderCtx);
     1076    RT_ZERO(pTransfer->ProviderIface);
     1077
     1078    ShClTransferListInit(&pTransfer->lstRoots);
    10751079
    10761080    int rc = ShClEventSourceCreate(&pTransfer->Events, 0 /* uID */);
     
    11181122        return VINF_SUCCESS;
    11191123
     1124    /* Must come before the refcount check below, as the callback might release a reference. */
     1125    if (pTransfer->Callbacks.pfnOnDestroy)
     1126        pTransfer->Callbacks.pfnOnDestroy(&pTransfer->CallbackCtx);
     1127
    11201128    AssertMsgReturn(pTransfer->cRefs == 0, ("Number of references > 0 (%RU32)\n", pTransfer->cRefs), VERR_WRONG_ORDER);
    11211129
     
    11441152int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource)
    11451153{
     1154    AssertMsgReturn(pTransfer->State.enmStatus < SHCLTRANSFERSTATUS_INITIALIZED,
     1155                    ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),
     1156                    VERR_WRONG_ORDER);
     1157
    11461158    pTransfer->cRefs = 0;
    11471159
     
    11521164                 pTransfer->State.uID, pTransfer->State.enmDir, pTransfer->State.enmSource));
    11531165
    1154     pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_INITIALIZED; /* Now we're ready to run. */
    1155 
    11561166    pTransfer->cListHandles    = 0;
    11571167    pTransfer->uListHandleNext = 1;
     
    11601170    pTransfer->uObjHandleNext  = 1;
    11611171
     1172    /* Make sure that the callback context has all values set according to the callback table.
     1173     * This only needs to be done once, so do this here. */
     1174    pTransfer->CallbackCtx.pTransfer = pTransfer;
     1175    pTransfer->CallbackCtx.pvUser    = pTransfer->Callbacks.pvUser;
     1176    pTransfer->CallbackCtx.cbUser    = pTransfer->Callbacks.cbUser;
     1177
    11621178    int rc = VINF_SUCCESS;
    11631179
    1164     if (pTransfer->Callbacks.pfnOnInitialize)
    1165         rc = pTransfer->Callbacks.pfnOnInitialize(&pTransfer->CallbackCtx);
     1180    LogRelFunc(("pfnOnInitialized=%p\n", pTransfer->Callbacks.pfnOnInitialized));
     1181
     1182    if (pTransfer->Callbacks.pfnOnInitialized)
     1183        pTransfer->Callbacks.pfnOnInitialized(&pTransfer->CallbackCtx);
     1184
     1185    if (RT_SUCCESS(rc))
     1186    {
     1187        pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_INITIALIZED; /* Now we're ready to run. */
     1188    }
    11661189
    11671190    LogFlowFuncLeaveRC(rc);
     
    12791302{
    12801303    PSHCLLISTHANDLEINFO pIt;
    1281     RTListForEach(&pTransfer->lstList, pIt, SHCLLISTHANDLEINFO, Node) /** @todo Sloooow ... improve this. */
     1304    RTListForEach(&pTransfer->lstHandles, pIt, SHCLLISTHANDLEINFO, Node) /** @todo Sloooow ... improve this. */
    12821305    {
    12831306        if (pIt->hList == hList)
     
    13921415 *                              destination callback table will be unset.
    13931416 */
    1394 void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst,
    1395                                PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc)
     1417void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKS pCallbacksDst,
     1418                               PSHCLTRANSFERCALLBACKS pCallbacksSrc)
    13961419{
    13971420    AssertPtrReturnVoid(pCallbacksDst);
     
    14031426            pCallbacksDst->a_pfnCallback = pCallbacksSrc->a_pfnCallback
    14041427
    1405         SET_CALLBACK(pfnOnInitialize);
    1406         SET_CALLBACK(pfnOnStart);
     1428        SET_CALLBACK(pfnOnInitialized);
     1429        SET_CALLBACK(pfnOnDestroy);
     1430        SET_CALLBACK(pfnOnStarted);
    14071431        SET_CALLBACK(pfnOnCompleted);
    14081432        SET_CALLBACK(pfnOnError);
     
    14261450 * @param   pCallbacks          Pointer to callback table to set. If set to NULL,
    14271451 *                              existing callbacks for this transfer will be unset.
     1452 *
     1453 * @note    Must come before initializing the transfer via ShClTransferInit().
    14281454 */
    14291455void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer,
    1430                               PSHCLTRANSFERCALLBACKTABLE pCallbacks)
     1456                              PSHCLTRANSFERCALLBACKS pCallbacks)
    14311457{
    14321458    AssertPtrReturnVoid(pTransfer);
     
    14371463
    14381464/**
    1439  * Sets the transfer provider interface for a given transfer.
     1465 * Sets the transfer provider for a given transfer.
    14401466 *
    14411467 * @returns VBox status code.
    14421468 * @param   pTransfer           Transfer to create transfer provider for.
    1443  * @param   pCreationCtx        Provider creation context to use for provider creation.
    1444  */
    1445 int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer,
    1446                                  PSHCLTXPROVIDERCREATIONCTX pCreationCtx)
    1447 {
    1448     AssertPtrReturn(pTransfer,    VERR_INVALID_POINTER);
    1449     AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER);
     1469 * @param   pProvider           Provider to use.
     1470 */
     1471int ShClTransferSetProvider(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDER pProvider)
     1472{
     1473    AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
     1474    AssertPtrReturn(pProvider, VERR_INVALID_POINTER);
    14501475
    14511476    LogFlowFuncEnter();
     
    14531478    int rc = VINF_SUCCESS;
    14541479
    1455     pTransfer->ProviderIface         = pCreationCtx->Interface;
     1480    pTransfer->ProviderIface         = pProvider->Interface;
    14561481    pTransfer->ProviderCtx.pTransfer = pTransfer;
    1457     pTransfer->ProviderCtx.pvUser    = pCreationCtx->pvUser;
     1482    pTransfer->ProviderCtx.pvUser    = pProvider->pvUser;
     1483    pTransfer->ProviderCtx.cbUser    = pProvider->cbUser;
     1484
     1485    LogRelFunc(("pfnOnInitialized=%p\n", pTransfer->Callbacks.pfnOnInitialized));
    14581486
    14591487    LogFlowFuncLeaveRC(rc);
     
    14621490
    14631491/**
    1464  * Clears (resets) the root list of a clipboard transfer.
     1492 * Returns the number of transfer root list entries.
     1493 *
     1494 * @returns Root list entry count.
     1495 * @param   pTransfer           Clipboard transfer to return root entry count for.
     1496 */
     1497uint64_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer)
     1498{
     1499    AssertPtrReturn(pTransfer, 0);
     1500
     1501    LogFlowFunc(("[Transfer %RU32] cRoots=%RU64\n", pTransfer->State.uID, pTransfer->lstRoots.Hdr.cEntries));
     1502    return (uint32_t)pTransfer->lstRoots.Hdr.cEntries;
     1503}
     1504
     1505/**
     1506 * Resets the root list of a clipboard transfer.
    14651507 *
    14661508 * @param   pTransfer           Transfer to clear transfer root list for.
    14671509 */
    1468 static void shClTransferListRootsClear(PSHCLTRANSFER pTransfer)
     1510static void shClTransferRootsReset(PSHCLTRANSFER pTransfer)
    14691511{
    14701512    AssertPtrReturnVoid(pTransfer);
     
    14761518    }
    14771519
    1478     PSHCLLISTROOT pListRoot, pListRootNext;
    1479     RTListForEachSafe(&pTransfer->lstRoots, pListRoot, pListRootNext, SHCLLISTROOT, Node)
    1480     {
    1481         RTStrFree(pListRoot->pszPathAbs);
    1482 
    1483         RTListNodeRemove(&pListRoot->Node);
    1484 
    1485         RTMemFree(pListRoot);
    1486         pListRoot = NULL;
    1487     }
    1488 
    1489     pTransfer->cRoots = 0;
     1520    ShClTransferListDestroy(&pTransfer->lstRoots);
    14901521}
    14911522
     
    15011532    LogFlowFuncEnter();
    15021533
    1503     shClTransferListRootsClear(pTransfer);
     1534    shClTransferRootsReset(pTransfer);
    15041535
    15051536    PSHCLLISTHANDLEINFO pItList, pItListNext;
    1506     RTListForEachSafe(&pTransfer->lstList, pItList, pItListNext, SHCLLISTHANDLEINFO, Node)
     1537    RTListForEachSafe(&pTransfer->lstHandles, pItList, pItListNext, SHCLLISTHANDLEINFO, Node)
    15071538    {
    15081539        ShClTransferListHandleInfoDestroy(pItList);
     
    15251556
    15261557/**
    1527  * Returns the number of transfer root list entries.
    1528  *
    1529  * @returns Root list entry count.
    1530  * @param   pTransfer           Clipboard transfer to return root entry count for.
    1531  */
    1532 uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer)
    1533 {
    1534     AssertPtrReturn(pTransfer, 0);
    1535 
    1536     LogFlowFunc(("[Transfer %RU32] cRoots=%RU64\n", pTransfer->State.uID, pTransfer->cRoots));
    1537     return (uint32_t)pTransfer->cRoots;
    1538 }
    1539 
    1540 /**
    1541  * Returns a specific root list entry of a transfer.
    1542  *
    1543  * @returns Pointer to root list entry if found, or NULL if not found.
    1544  * @param   pTransfer           Clipboard transfer to get root list entry from.
    1545  * @param   uIdx                Index of root list entry to return.
    1546  */
    1547 DECLINLINE(PSHCLLISTROOT) shClTransferRootsGetInternal(PSHCLTRANSFER pTransfer, uint32_t uIdx)
    1548 {
    1549     if (uIdx >= pTransfer->cRoots)
    1550         return NULL;
    1551 
    1552     PSHCLLISTROOT pIt = RTListGetFirst(&pTransfer->lstRoots, SHCLLISTROOT, Node);
    1553     while (uIdx--) /** @todo Slow, but works for now. */
    1554         pIt = RTListGetNext(&pTransfer->lstRoots, pIt, SHCLLISTROOT, Node);
    1555 
    1556     return pIt;
    1557 }
    1558 
    1559 /**
    15601558 * Get a specific root list entry.
    15611559 *
    1562  * @returns VBox status code.
     1560 * @returns Const pointer to root list entry if found, or NULL if not found..
    15631561 * @param   pTransfer           Clipboard transfer to get root list entry of.
    15641562 * @param   uIndex              Index (zero-based) of entry to get.
    1565  * @param   pEntry              Where to store the returned entry on success.
    1566  */
    1567 int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer,
    1568                            uint64_t uIndex, PSHCLROOTLISTENTRY pEntry)
     1563 */
     1564PCSHCLLISTENTRY ShClTransferRootsEntryGet(PSHCLTRANSFER pTransfer, uint64_t uIndex)
     1565{
     1566    AssertPtrReturn(pTransfer, NULL);
     1567
     1568    if (uIndex >= pTransfer->lstRoots.Hdr.cEntries)
     1569        return NULL;
     1570
     1571    return shClTransferListGetEntryById(&pTransfer->lstRoots, uIndex);
     1572}
     1573
     1574/**
     1575 * Reads the root entries of a clipboard transfer.
     1576 *
     1577 * This gives the provider interface the chance of reading root entries information.
     1578 *
     1579 * @returns VBox status code.
     1580 * @param   pTransfer           Clipboard transfer to read root list for.
     1581 */
     1582int ShClTransferRootListRead(PSHCLTRANSFER pTransfer)
    15691583{
    15701584    AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
    1571     AssertPtrReturn(pEntry,    VERR_INVALID_POINTER);
    1572 
    1573     if (uIndex >= pTransfer->cRoots)
    1574         return VERR_INVALID_PARAMETER;
     1585
     1586    LogFlowFuncEnter();
    15751587
    15761588    int rc;
    1577 
    1578     PSHCLLISTROOT pRoot = shClTransferRootsGetInternal(pTransfer, uIndex);
    1579     AssertPtrReturn(pRoot, VERR_INVALID_PARAMETER);
    1580 
    1581     const char *pcszSrcPathAbs = pRoot->pszPathAbs;
    1582 
    1583     /* Make sure that we only advertise relative source paths, not absolute ones. */
    1584     char *pszFileName = RTPathFilename(pcszSrcPathAbs);
    1585     if (pszFileName)
    1586     {
    1587         Assert(pszFileName >= pcszSrcPathAbs);
    1588         size_t cchDstBase = pszFileName - pcszSrcPathAbs;
    1589         const char *pszDstPath = &pcszSrcPathAbs[cchDstBase];
    1590 
    1591         LogFlowFunc(("pcszSrcPathAbs=%s, pszDstPath=%s\n", pcszSrcPathAbs, pszDstPath));
    1592 
    1593         rc = ShClTransferListEntryInitEx(pEntry, pszFileName);
    1594         if (RT_SUCCESS(rc))
    1595         {
    1596             rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pszDstPath);
    1597             if (RT_SUCCESS(rc))
    1598             {
    1599                 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);
    1600                 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(pEntry->cbInfo);
    1601                 if (pEntry->pvInfo)
    1602                 {
    1603                     RTFSOBJINFO fsObjInfo;
    1604                     rc = RTPathQueryInfo(pcszSrcPathAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING);
    1605                     if (RT_SUCCESS(rc))
    1606                     {
    1607                         ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &fsObjInfo);
    1608 
    1609                         pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;
    1610                     }
    1611                 }
    1612                 else
    1613                     rc = VERR_NO_MEMORY;
    1614             }
    1615         }
    1616     }
    1617     else
    1618         rc = VERR_INVALID_POINTER;
    1619 
    1620     LogFlowFuncLeaveRC(rc);
    1621     return rc;
    1622 }
    1623 
    1624 /**
    1625  * Returns the root entries of a clipboard transfer.
    1626  *
    1627  * @returns VBox status code.
    1628  * @param   pTransfer           Clipboard transfer to return root entries for.
    1629  * @param   ppRootList          Where to store the root list on success.
    1630  */
    1631 int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList)
    1632 {
    1633     AssertPtrReturn(pTransfer,  VERR_INVALID_POINTER);
    1634     AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
    1635 
    1636     LogFlowFuncEnter();
    1637 
    1638     int rc;
    1639     if (pTransfer->ProviderIface.pfnRootsGet)
    1640         rc = pTransfer->ProviderIface.pfnRootsGet(&pTransfer->ProviderCtx, ppRootList);
     1589    if (pTransfer->ProviderIface.pfnRootListRead)
     1590        rc = pTransfer->ProviderIface.pfnRootListRead(&pTransfer->ProviderCtx);
    16411591    else
    16421592        rc = VERR_NOT_SUPPORTED;
    16431593
     1594    /* Make sure that we have at least an empty root path set. */
     1595    if (   RT_SUCCESS(rc)
     1596        && !pTransfer->pszPathRootAbs)
     1597    {
     1598        if (RTStrAPrintf(&pTransfer->pszPathRootAbs, "") < 0)
     1599            rc = VERR_NO_MEMORY;
     1600    }
     1601
    16441602    LogFlowFuncLeaveRC(rc);
    16451603    return rc;
     
    16471605
    16481606/**
    1649  * Sets root list entries for a given clipboard transfer.
     1607 * Initializes the root list entries for a given clipboard transfer.
    16501608 *
    16511609 * @returns VBox status code.
     
    16531611 * @param   pszRoots            String list (separated by CRLF) of root entries to set.
    16541612 *                              All entries must have the same root path.
    1655  * @param   cbRoots             Size (in bytes) of string list.
    1656  */
    1657 int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots)
     1613 * @param   cbRoots             Size (in bytes) of string list. Includes zero terminator.
     1614 *
     1615 * @note    Accepts local paths or URI string lists (absolute only).
     1616 */
     1617int ShClTransferRootsInitFromStringList(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots)
    16581618{
    16591619    AssertPtrReturn(pTransfer,      VERR_INVALID_POINTER);
     
    16611621    AssertReturn(cbRoots,           VERR_INVALID_PARAMETER);
    16621622
     1623    LogFlowFuncEnter();
     1624
    16631625    if (!RTStrIsValidEncoding(pszRoots))
    16641626        return VERR_INVALID_UTF8_ENCODING;
     
    16661628    int rc = VINF_SUCCESS;
    16671629
    1668     shClTransferListRootsClear(pTransfer);
    1669 
    1670     char  *pszPathRootAbs = NULL;
    1671 
    1672     RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split("\r\n");
     1630    shClTransferRootsReset(pTransfer);
     1631
     1632    PSHCLLIST pLstRoots      = &pTransfer->lstRoots;
     1633    char     *pszPathRootAbs = NULL;
     1634
     1635    RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split(SHCL_TRANSFER_URI_LIST_SEP_STR);
     1636    if (!lstRootEntries.size())
     1637        return VINF_SUCCESS;
     1638
    16731639    for (size_t i = 0; i < lstRootEntries.size(); ++i)
    16741640    {
    1675         PSHCLLISTROOT pListRoot = (PSHCLLISTROOT)RTMemAlloc(sizeof(SHCLLISTROOT));
    1676         AssertPtrBreakStmt(pListRoot, rc = VERR_NO_MEMORY);
    1677 
    1678         const char *pszPathCur = RTStrDup(lstRootEntries.at(i).c_str());
     1641        char *pszPathCur = NULL;
     1642
     1643        char *pszPath = NULL;
     1644        rc = RTUriFilePathEx(lstRootEntries.at(i).c_str(),
     1645                             RTPATH_STR_F_STYLE_UNIX, &pszPath, 0 /*cbPath*/, NULL /*pcchPath*/);
     1646        if (RT_SUCCESS(rc))
     1647        {
     1648            pszPathCur = pszPath;
     1649            pszPath    = NULL; /* pszPath has ownership now. */
     1650        }
     1651        else if (rc == VERR_URI_NOT_FILE_SCHEME) /* Local file path? */
     1652        {
     1653            pszPathCur = RTStrDup(lstRootEntries.at(i).c_str());
     1654            rc = VINF_SUCCESS;
     1655        }
    16791656
    16801657        LogFlowFunc(("pszPathCur=%s\n", pszPathCur));
     1658
     1659        rc = ShClTransferValidatePath(pszPathCur, false);
     1660        if (RT_FAILURE(rc))
     1661        {
     1662            RT_BREAKPOINT();
     1663            break;
     1664        }
    16811665
    16821666        /* No root path determined yet? */
     
    16961680                }
    16971681                else
    1698                     rc = VERR_INVALID_PARAMETER;
     1682                    rc = VERR_PATH_IS_RELATIVE;
    16991683            }
    17001684            else
     
    17021686        }
    17031687
    1704         if (RT_FAILURE(rc))
    1705             break;
    1706 
    1707         pListRoot->pszPathAbs = RTStrDup(pszPathCur);
    1708         if (!pListRoot->pszPathAbs)
     1688        if (RT_SUCCESS(rc))
    17091689        {
    1710             rc = VERR_NO_MEMORY;
    1711             break;
     1690            PSHCLLISTENTRY pEntry;
     1691            rc = ShClTransferListEntryAlloc(&pEntry);
     1692            if (RT_SUCCESS(rc))
     1693            {
     1694                PSHCLFSOBJINFO pFsObjInfo = (PSHCLFSOBJINFO )RTMemAlloc(sizeof(SHCLFSOBJINFO));
     1695                if (pFsObjInfo)
     1696                {
     1697                    rc = ShClFsObjInfoQuery(pszPathCur, pFsObjInfo);
     1698                    if (RT_SUCCESS(rc))
     1699                    {
     1700                        /* Calculate the relative path within the root path. */
     1701                        const char *pszPathRelToRoot = &pszPathRootAbs[strlen(pszPathRootAbs) + 1 /* Skip terminator or (back)slash. */];
     1702                        if (    pszPathRelToRoot
     1703                            && *pszPathRelToRoot != '\0')
     1704                        {
     1705                            LogFlowFunc(("pszPathRelToRoot=%s\n", pszPathRelToRoot));
     1706
     1707                            rc = ShClTransferListEntryInitEx(pEntry, VBOX_SHCL_INFO_F_FSOBJINFO, pszPathRelToRoot,
     1708                                                             pFsObjInfo, sizeof(SHCLFSOBJINFO));
     1709                            if (RT_SUCCESS(rc))
     1710                            {
     1711                                rc = ShClTransferListAddEntry(pLstRoots, pEntry, true /* fAppend */);
     1712                                if (RT_SUCCESS(rc))
     1713                                {
     1714                                    pFsObjInfo = NULL; /* pEntry has ownership now. */
     1715                                }
     1716                            }
     1717                        }
     1718                        else
     1719                            LogRel(("Shared Clipboard: Unable to construct relative path for '%s' (root is '%s')\n",
     1720                                    pszPathCur, pszPathRootAbs));
     1721                    }
     1722
     1723                    if (pFsObjInfo)
     1724                    {
     1725                        RTMemFree(pFsObjInfo);
     1726                        pFsObjInfo = NULL;
     1727                    }
     1728                }
     1729                else
     1730                    rc = VERR_NO_MEMORY;
     1731
     1732                if (RT_FAILURE(rc))
     1733                    ShClTransferListEntryFree(pEntry);
     1734            }
    17121735        }
    17131736
    1714         RTListAppend(&pTransfer->lstRoots, &pListRoot->Node);
    1715 
    1716         pTransfer->cRoots++;
     1737        RTStrFree(pszPathCur);
    17171738    }
    17181739
    17191740    /* No (valid) root directory found? Bail out early. */
    17201741    if (!pszPathRootAbs)
    1721         rc = VERR_PATH_NOT_FOUND;
     1742        rc = VERR_PATH_DOES_NOT_START_WITH_ROOT;
    17221743
    17231744    if (RT_SUCCESS(rc))
    17241745    {
    1725         /*
    1726          * Step 2:
    1727          * Go through the created list and make sure all entries have the same root path.
    1728          */
    1729         PSHCLLISTROOT pListRoot;
    1730         RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)
    1731         {
    1732             if (!RTStrStartsWith(pListRoot->pszPathAbs, pszPathRootAbs))
    1733             {
    1734                 rc = VERR_INVALID_PARAMETER;
    1735                 break;
    1736             }
    1737 
    1738             rc = ShClTransferValidatePath(pListRoot->pszPathAbs, true /* Path must exist */);
    1739             if (RT_FAILURE(rc))
    1740                 break;
    1741         }
    1742     }
    1743 
    1744     /** @todo Entry rollback on failure? */
    1745 
    1746     if (RT_SUCCESS(rc))
    1747     {
    17481746        pTransfer->pszPathRootAbs = pszPathRootAbs;
    1749         LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->cRoots));
     1747        LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->lstRoots.Hdr.cEntries));
    17501748
    17511749        LogRel2(("Shared Clipboard: Transfer uses root '%s'\n", pTransfer->pszPathRootAbs));
     
    17541752    {
    17551753        LogRel(("Shared Clipboard: Unable to set roots for transfer, rc=%Rrc\n", rc));
     1754        ShClTransferListDestroy(pLstRoots);
    17561755        RTStrFree(pszPathRootAbs);
    17571756    }
     
    17621761
    17631762/**
    1764  * Sets a single file as a transfer root.
     1763 * Initializes a single file as a transfer root.
    17651764 *
    17661765 * @returns VBox status code.
     
    17701769 * @note    Convenience function, uses ShClTransferRootsSet() internally.
    17711770 */
    1772 int ShClTransferRootsSetAsFile(PSHCLTRANSFER pTransfer, const char *pszFile)
     1771int ShClTransferRootsInitFromFile(PSHCLTRANSFER pTransfer, const char *pszFile)
    17731772{
    17741773    char *pszRoots = NULL;
     1774
     1775    LogFlowFuncEnter();
    17751776
    17761777    int rc = RTStrAAppend(&pszRoots, pszFile);
     
    17781779    rc = RTStrAAppend(&pszRoots, "\r\n");
    17791780    AssertRCReturn(rc, rc);
    1780     rc =  ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1);
     1781    rc =  ShClTransferRootsInitFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1 /* Include terminator */);
    17811782    RTStrFree(pszRoots);
    17821783    return rc;
     
    18211822{
    18221823    AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
     1824    AssertMsgReturn(pTransfer->pszPathRootAbs, ("Transfer has no root path set (yet)\n"), VERR_WRONG_ORDER);
    18231825
    18241826    return RTStrCopy(pszPath, cbPath, pTransfer->pszPathRootAbs);
     
    18491851    AssertPtrReturn(pTransfer, SHCLTRANSFERSTATUS_NONE);
    18501852
    1851     LogFlowFunc(("[Transfer %RU32] enmStatus=%RU32\n", pTransfer->State.uID, pTransfer->State.enmStatus));
    18521853    return pTransfer->State.enmStatus;
    18531854}
     
    18901891
    18911892    /* Ready to start? */
     1893    AssertMsgReturn(pTransfer->ProviderIface.pfnRootListRead != NULL,
     1894                    ("No provider interface set (yet)\n"),
     1895                    VERR_WRONG_ORDER);
    18921896    AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_INITIALIZED,
    18931897                    ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),
    18941898                    VERR_WRONG_ORDER);
    18951899
    1896     int rc;
    1897 
    1898     if (pTransfer->Callbacks.pfnOnStart)
    1899     {
    1900         rc = pTransfer->Callbacks.pfnOnStart(&pTransfer->CallbackCtx);
    1901     }
    1902     else
    1903         rc = VINF_SUCCESS;
    1904 
    1905     if (RT_SUCCESS(rc))
    1906     {
    1907         pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_STARTED;
    1908     }
     1900    int rc = VINF_SUCCESS;
     1901
     1902    pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_STARTED;
     1903
     1904    if (pTransfer->Callbacks.pfnOnStarted)
     1905        pTransfer->Callbacks.pfnOnStarted(&pTransfer->CallbackCtx);
    19091906
    19101907    LogFlowFuncLeaveRC(rc);
     
    19351932    int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc,
    19361933                            pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
    1937                             "shclp");
     1934                            "shclptx");
    19381935    if (RT_SUCCESS(rc))
    19391936    {
     
    21892186    }
    21902187
    2191     Log2Func(("pTransfer=%p, idTransfer=%RU32 (%RU16 transfers)\n", pTransfer, idTransfer, pTransferCtx->cTransfers));
    2192 
    21932188    pTransfer->State.uID = idTransfer;
    21942189
     
    21962191
    21972192    pTransferCtx->cTransfers++;
     2193
     2194    Log2Func(("pTransfer=%p, idTransfer=%RU32 -- now %RU16 transfer(s)\n", pTransfer, idTransfer, pTransferCtx->cTransfers));
    21982195
    21992196    if (pTransfer->Callbacks.pfnOnRegistered)
     
    23422339 * Copies file system objinfo from IPRT to Shared Clipboard format.
    23432340 *
    2344  * @param   pDst                The Shared Clipboard structure to convert data to.
    2345  * @param   pSrc                The IPRT structure to convert data from.
    2346  */
    2347 void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc)
    2348 {
     2341 * @return VBox status code.
     2342 * @param  pDst                 The Shared Clipboard structure to convert data to.
     2343 * @param  pSrc                 The IPRT structure to convert data from.
     2344 */
     2345int ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc)
     2346{
     2347    AssertPtrReturn(pDst, VERR_INVALID_POINTER);
     2348    AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
     2349
    23492350    pDst->cbObject          = pSrc->cbObject;
    23502351    pDst->cbAllocated       = pSrc->cbAllocated;
     
    23602361    {
    23612362        default:
     2363            RT_FALL_THROUGH();
    23622364        case RTFSOBJATTRADD_NOTHING:
    23632365            pDst->Attr.enmAdditional        = SHCLFSOBJATTRADD_NOTHING;
     
    23812383            break;
    23822384    }
     2385
     2386    return VINF_SUCCESS;
     2387}
     2388
     2389/**
     2390 * Queries Shared Clipboard file system information from a given path.
     2391 *
     2392 * @returns VBox status code.
     2393 * @param   pszPath             Path to query file system information for.
     2394 * @param   pObjInfo            Where to return the queried file system information on success.
     2395 */
     2396int ShClFsObjInfoQuery(const char *pszPath, PSHCLFSOBJINFO pObjInfo)
     2397{
     2398    RTFSOBJINFO objInfo;
     2399    int rc = RTPathQueryInfo(pszPath, &objInfo,
     2400#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     2401                            RTFSOBJATTRADD_NOTHING
     2402#else
     2403                            RTFSOBJATTRADD_UNIX
     2404#endif
     2405                            );
     2406    if (RT_SUCCESS(rc))
     2407        rc = ShClFsObjInfoFromIPRT(pObjInfo, &objInfo);
     2408
     2409    return rc;
    23832410}
    23842411
     
    23952422        RT_CASE_RET_STR(SHCLTRANSFERSTATUS_NONE);
    23962423        RT_CASE_RET_STR(SHCLTRANSFERSTATUS_INITIALIZED);
     2424        RT_CASE_RET_STR(SHCLTRANSFERSTATUS_UNINITIALIZED);
    23972425        RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STARTED);
    23982426        RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STOPPED);
     
    24492477            else /* Everything else (e.g. symbolic links) are not supported. */
    24502478            {
    2451                 LogRel2(("Shared Clipboard: Path '%s' contains a symbolic link or junktion, which are not supported\n", pcszPath));
     2479                LogRel2(("Shared Clipboard: Path '%s' contains a symbolic link or junction, which are not supported\n", pcszPath));
    24522480                rc = VERR_NOT_SUPPORTED;
    24532481            }
     
    24612489    return rc;
    24622490}
    2463 
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp

    r98103 r100204  
    2626 */
    2727
    28 #define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
    2928#include <VBox/GuestHost/SharedClipboard.h>
    3029
     
    4039#endif
    4140
     41#ifdef LOG_GROUP
     42# undef LOG_GROUP
     43#endif
     44#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
    4245#include <VBox/log.h>
    4346
     
    4851#include <VBox/GuestHost/SharedClipboard-win.h>
    4952#include <VBox/GuestHost/clipboard-helper.h>
     53
     54
     55#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     56int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **ppszList, uint32_t *pcbList);
     57#endif
    5058
    5159
     
    833841 * a separate WM_RENDERFORMAT message.
    834842 *
    835  * @returns VBox status code. VERR_NOT_SUPPORTED if the format is not supported / handled.
     843 * @returns VBox status code.
     844 * @retval  VERR_NOT_SUPPORTED if *all* format(s) is/are not supported / handled.
    836845 * @param   pWinCtx             Windows context to use.
    837846 * @param   fFormats            Clipboard format(s) to announce.
     
    841850    LogFunc(("fFormats=0x%x\n", fFormats));
    842851
     852    /* Make sure that if VBOX_SHCL_FMT_URI_LIST is announced, we don't announced anything else.
     853     * This otherwise this will trigger a WM_DRAWCLIPBOARD or friends, which will result in fun bugs coming up. */
     854    AssertReturn((  !(fFormats & VBOX_SHCL_FMT_URI_LIST)
     855                  || (fFormats & VBOX_SHCL_FMT_URI_LIST) == VBOX_SHCL_FMT_URI_LIST), VERR_INVALID_PARAMETER);
    843856    /*
    844857     * Set the clipboard formats.
     
    846859    static struct
    847860    {
     861        /** VBox format to handle. */
    848862        uint32_t        fVBoxFormat;
     863        /** Native Windows format to use.
     864         *  Set to 0 if unused / needs special handling. */
    849865        UINT            uWinFormat;
    850         const char     *pszWinFormat;
     866        /** Own registered format. Set to NULL if not used / applicable. */
     867        const char     *pszRegFormat;
    851868        const char     *pszLog;
    852869    } s_aFormats[] =
    853870    {
    854871        { VBOX_SHCL_FMT_UNICODETEXT,    CF_UNICODETEXT, NULL,                 "CF_UNICODETEXT" },
     872#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     873        /* We don't announce anything here for an URI list to the Windows clipboard, as we later have to
     874         * initialize our custom IDataObject and set it via OleSetClipboard(). */
     875        { VBOX_SHCL_FMT_URI_LIST,       0,              NULL,                 "SHCL_URI_LIST" },
     876#endif
    855877        { VBOX_SHCL_FMT_BITMAP,         CF_DIB,         NULL,                 "CF_DIB" },
    856         { VBOX_SHCL_FMT_HTML,           0,              SHCL_WIN_REGFMT_HTML, "SHCL_WIN_REGFMT_HTML" },
     878        { VBOX_SHCL_FMT_HTML,           0,              SHCL_WIN_REGFMT_HTML, "SHCL_WIN_REGFMT_HTML" }
    857879    };
     880
    858881    unsigned    cSuccessfullySet = 0;
    859882    SHCLFORMATS fFormatsLeft     = fFormats;
     
    863886        if (fFormatsLeft & s_aFormats[i].fVBoxFormat)
    864887        {
    865             LogFunc(("%s\n", s_aFormats[i].pszLog));
     888            LogRel2(("Shared Clipboard: Announcing format '%s' to clipboard\n", s_aFormats[i].pszLog));
    866889            fFormatsLeft &= ~s_aFormats[i].fVBoxFormat;
    867890
    868             /* Reg format if needed: */
    869             UINT uWinFormat = s_aFormats[i].uWinFormat;
     891            UINT uWinFormat = 0;
     892            if (s_aFormats[i].pszRegFormat) /* See if we have (special) registered format. */
     893            {
     894                uWinFormat = RegisterClipboardFormat(s_aFormats[i].pszRegFormat);
     895                AssertContinue(uWinFormat != 0);
     896            }
     897            else /* Native format. */
     898                uWinFormat = s_aFormats[i].uWinFormat;
     899
     900            /* Any native format set? If not, just skip it (as successful). */
    870901            if (!uWinFormat)
    871902            {
    872                 uWinFormat = RegisterClipboardFormat(s_aFormats[i].pszWinFormat);
    873                 AssertContinue(uWinFormat != 0);
     903                cSuccessfullySet++;
     904                continue;
    874905            }
    875906
     
    903934    else if (RT_SUCCESS(rc) && fFormatsLeft != 0)
    904935    {
    905         LogFunc(("Unsupported formats: %#x (%#x)\n", fFormatsLeft, fFormats));
     936        LogRel(("Shared Clipboard: Unable to announce unsupported/invalid formats: %#x (%#x)\n", fFormatsLeft, fFormats));
    906937        rc = VERR_NOT_SUPPORTED;
    907938    }
     
    917948 * a separate WM_RENDERFORMAT message.
    918949 *
    919  * @returns VBox status code. VERR_NOT_SUPPORTED if the format is not supported / handled.
     950 * @returns VBox status code.
    920951 * @param   pWinCtx     Windows context to use.
    921952 * @param   fFormats    Clipboard format(s) to announce.
     
    10031034
    10041035#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1005 
    1006 /**
    1007  * Creates an Shared Clipboard transfer by announcing transfer data  (via IDataObject) to Windows.
     1036/**
     1037 * Creates an Shared Clipboard transfer by announcing transfer data (via IDataObject) to Windows.
    10081038 *
    10091039 * This creates the necessary IDataObject + IStream implementations and initiates the actual transfers required for getting
     
    10121042 * @returns VBox status code.
    10131043 * @param   pWinCtx             Windows context to use.
    1014  * @param   pTransferCtxCtx     Transfer contextto use.
    1015  * @param   pTransfer           Shared Clipboard transfer to use.
    1016  */
    1017 int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)
    1018 {
    1019     AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
    1020 
    1021     LogFlowFunc(("pWinCtx=%p\n", pWinCtx));
    1022 
    1023     AssertReturn(pTransfer->pvUser == NULL, VERR_WRONG_ORDER);
     1044 * @param   pCtx                Shared Clipboard context to use.
     1045 *                              Needed for the data object to communicate with the main window thread.
     1046 * @param   pCallbacks          Callbacks table to use.
     1047 */
     1048int SharedClipboardWinTransferCreateAndSetDataObject(PSHCLWINCTX pWinCtx, PSHCLCONTEXT pCtx, PSHCLCALLBACKS pCallbacks)
     1049{
     1050    AssertPtrReturn(pWinCtx, VERR_INVALID_POINTER);
     1051    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1052    AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
    10241053
    10251054    /* Make sure to enter the critical section before setting the clipboard data, as otherwise WM_CLIPBOARDUPDATE
     
    10281057    if (RT_SUCCESS(rc))
    10291058    {
     1059        if (pWinCtx->pDataObjInFlight == NULL)
     1060        {
     1061            SharedClipboardWinDataObject *pObj = new SharedClipboardWinDataObject();
     1062            if (pObj)
     1063            {
     1064                rc = pObj->Init(pCtx);
     1065                if (RT_SUCCESS(rc))
     1066                {
     1067                    if (RT_SUCCESS(rc))
     1068                        pObj->SetCallbacks(pCallbacks);
     1069
     1070                    if (RT_SUCCESS(rc))
     1071                        pWinCtx->pDataObjInFlight = pObj;
     1072                }
     1073            }
     1074            else
     1075                rc = VERR_NO_MEMORY;
     1076        }
     1077
     1078        if (RT_SUCCESS(rc))
     1079        {
     1080            SharedClipboardWinClose();
     1081            /* Note: Clipboard must be closed first before calling OleSetClipboard(). */
     1082
     1083            /** @todo There is a potential race between SharedClipboardWinClose() and OleSetClipboard(),
     1084             *        where another application could own the clipboard (open), and thus the call to
     1085             *        OleSetClipboard() will fail. Needs (better) fixing. */
     1086            HRESULT hr = S_OK;
     1087
     1088            for (unsigned uTries = 0; uTries < 3; uTries++)
     1089            {
     1090                hr = OleSetClipboard(pWinCtx->pDataObjInFlight);
     1091                if (SUCCEEDED(hr))
     1092                {
     1093                    Assert(OleIsCurrentClipboard(pWinCtx->pDataObjInFlight) == S_OK); /* Sanity. */
     1094
     1095                    /*
     1096                     * Calling OleSetClipboard() changed the clipboard owner, which in turn will let us receive
     1097                     * a WM_CLIPBOARDUPDATE message. To not confuse ourselves with our own clipboard owner changes,
     1098                     * save a new window handle and deal with it in WM_CLIPBOARDUPDATE.
     1099                     */
     1100                    pWinCtx->hWndClipboardOwnerUs = GetClipboardOwner();
     1101
     1102                    LogFlowFunc(("hWndClipboardOwnerUs=%p\n", pWinCtx->hWndClipboardOwnerUs));
     1103                    break;
     1104                }
     1105
     1106                LogFlowFunc(("Failed with %Rhrc (try %u/3)\n", hr, uTries + 1));
     1107                RTThreadSleep(500); /* Wait a bit. */
     1108            }
     1109
     1110            if (FAILED(hr))
     1111            {
     1112                rc = VERR_ACCESS_DENIED; /** @todo Fudge; fix this. */
     1113                LogRel(("Shared Clipboard: Failed with %Rhrc when setting data object to clipboard\n", hr));
     1114            }
     1115        }
     1116
     1117        int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
     1118        AssertRC(rc2);
     1119    }
     1120
     1121    LogFlowFuncLeaveRC(rc);
     1122    return rc;
     1123}
     1124
     1125#if 0
     1126/**
     1127 * Creates an Shared Clipboard transfer by announcing transfer data  (via IDataObject) to Windows.
     1128 *
     1129 * This creates the necessary IDataObject + IStream implementations and initiates the actual transfers required for getting
     1130 * the meta data. Whether or not the actual (file++) transfer(s) are happening is up to the user (at some point) later then.
     1131 *
     1132 * @returns VBox status code.
     1133 * @param   pWinCtx             Windows context to use.
     1134 * @param   pTransferCtxCtx     Transfer contextto use.
     1135 * @param   pTransfer           Shared Clipboard transfer to use.
     1136 */
     1137int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)
     1138{
     1139    AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
     1140
     1141    LogFlowFunc(("pWinCtx=%p\n", pWinCtx));
     1142
     1143    AssertReturn(pTransfer->pvUser == NULL, VERR_WRONG_ORDER);
     1144
     1145    /* Make sure to enter the critical section before setting the clipboard data, as otherwise WM_CLIPBOARDUPDATE
     1146     * might get called *before* we had the opportunity to set pWinCtx->hWndClipboardOwnerUs below. */
     1147    int rc = RTCritSectEnter(&pWinCtx->CritSect);
     1148    if (RT_SUCCESS(rc))
     1149    {
    10301150        SharedClipboardWinTransferCtx *pWinURITransferCtx = new SharedClipboardWinTransferCtx();
    10311151        if (pWinURITransferCtx)
     
    10341154            pTransfer->cbUser = sizeof(SharedClipboardWinTransferCtx);
    10351155
    1036             pWinURITransferCtx->pDataObj = new SharedClipboardWinDataObject(pTransfer);
     1156            pWinURITransferCtx->pDataObj = new SharedClipboardWinDataObject();
    10371157            if (pWinURITransferCtx->pDataObj)
    10381158            {
    1039                 rc = pWinURITransferCtx->pDataObj->Init();
     1159                rc = pWinURITransferCtx->pDataObj->Init(pCtx);
    10401160                if (RT_SUCCESS(rc))
    10411161                {
     
    10901210    return rc;
    10911211}
     1212#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    10921213
    10931214/**
     
    11331254 * @param   pTransfer           Transfer to get roots for.
    11341255 */
    1135 int SharedClipboardWinGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)
     1256int SharedClipboardWinTransferGetRootsFromClipboard(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)
    11361257{
    11371258    AssertPtrReturn(pWinCtx,   VERR_INVALID_POINTER);
     
    11511272            if (hDrop)
    11521273            {
    1153                 char    *papszList = NULL;
     1274                char    *pszList = NULL;
    11541275                uint32_t cbList;
    1155                 rc = SharedClipboardWinDropFilesToStringList((DROPFILES *)hDrop, &papszList, &cbList);
     1276                rc = SharedClipboardWinTransferDropFilesToStringList((DROPFILES *)hDrop, &pszList, &cbList);
    11561277
    11571278                GlobalUnlock(hClip);
     
    11591280                if (RT_SUCCESS(rc))
    11601281                {
    1161                     rc = ShClTransferRootsSet(pTransfer,
    1162                                               papszList, cbList + 1 /* Include termination */);
    1163                     RTStrFree(papszList);
     1282                    rc = ShClTransferRootsInitFromStringList(pTransfer, pszList, cbList);
     1283                    RTStrFree(pszList);
    11641284                }
    11651285            }
     
    11791299
    11801300/**
    1181  * Converts a DROPFILES (HDROP) structure to a string list, separated by \r\n.
     1301 * Converts a DROPFILES (HDROP) structure to a string list, separated by SHCL_TRANSFER_URI_LIST_SEP_STR.
    11821302 * Does not do any locking on the input data.
    11831303 *
    11841304 * @returns VBox status code.
    11851305 * @param   pDropFiles          Pointer to DROPFILES structure to convert.
    1186  * @param   papszList           Where to store the allocated string list.
     1306 * @param   ppszList            Where to store the allocated string list on success.
     1307 *                              Needs to be free'd with RTStrFree().
    11871308 * @param   pcbList             Where to store the size (in bytes) of the allocated string list.
    1188  */
    1189 int SharedClipboardWinDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList)
     1309 *                              Includes zero terminator.
     1310 */
     1311int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **ppszList, uint32_t *pcbList)
    11901312{
    11911313    AssertPtrReturn(pDropFiles, VERR_INVALID_POINTER);
    1192     AssertPtrReturn(papszList,  VERR_INVALID_POINTER);
     1314    AssertPtrReturn(ppszList,   VERR_INVALID_POINTER);
    11931315    AssertPtrReturn(pcbList,    VERR_INVALID_POINTER);
    11941316
     
    12931415        /* Add separation between filenames.
    12941416         * Note: Also do this for the last element of the list. */
    1295         rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, "\r\n", 2 /* Bytes */);
     1417        rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, SHCL_TRANSFER_URI_LIST_SEP_STR, 2 /* Bytes */);
    12961418        if (RT_SUCCESS(rc))
    1297             cchFiles += 2; /* Include \r\n */
     1419            cchFiles += 2; /* Include SHCL_TRANSFER_URI_LIST_SEP_STR */
    12981420    }
    12991421
     
    13061428                     cFiles, cchFiles, cbFiles, pszFiles));
    13071429
    1308         *papszList = pszFiles;
     1430        *ppszList = pszFiles;
    13091431        *pcbList   = cbFiles;
    13101432    }
     
    13181440    return rc;
    13191441}
    1320 
    13211442#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    13221443
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp

    r99953 r100204  
    190190*   Internal structures                                                                                                          *
    191191*********************************************************************************************************************************/
    192 
    193 /**
    194  * A structure containing information about where to store a request
    195  * for the X11 clipboard contents.
    196  */
    197 typedef struct _CLIPREADX11CBREQ
    198 {
    199     /** The format VBox would like the data in. */
    200     SHCLFORMAT       uFmtVBox;
    201     /** The format we requested from X11. */
    202     SHCLX11FMTIDX    idxFmtX11;
    203     /** The clipboard context this request is associated with. */
    204     SHCLX11CTX      *pCtx;
    205     /** The request structure passed in from the backend. */
    206     CLIPREADCBREQ   *pReq;
    207 } CLIPREADX11CBREQ;
    208 
    209 
    210192
    211193#ifdef TESTCASE
     
    15001482 *                              Needs to be free'd with RTMemFree() by the caller.
    15011483 * @param   pcb                 Returns the amount of data read (in bytes) on success.
     1484 *
     1485 * @thread  X11 event thread.
    15021486 */
    15031487static int shClX11RequestDataForX11CallbackHelper(PSHCLX11CTX pCtx, SHCLFORMAT uFmt,
     
    15071491    AssertPtrReturn(ppv,  VERR_INVALID_POINTER);
    15081492    AssertPtrReturn(pcb,  VERR_INVALID_POINTER);
     1493
     1494    AssertPtrReturn(pCtx->Callbacks.pfnOnRequestDataFromSource, VERR_INVALID_POINTER);
     1495
     1496#ifdef LOG_ENABLED
     1497    char *pszFmts = ShClFormatsToStrA(uFmt);
     1498    AssertPtrReturn(pszFmts, VERR_NO_MEMORY);
     1499    LogRel2(("Shared Clipboard: Requesting data for X11 from source as '%s'\n", pszFmts));
     1500    RTStrFree(pszFmts);
     1501#endif
    15091502
    15101503    LogFlowFunc(("pCtx=%p, uFmt=%#x\n", pCtx, uFmt));
     
    15351528        rc = pCtx->Callbacks.pfnOnRequestDataFromSource(pCtx->pFrontend, uFmt, &pv, &cb, NULL /* pvUser */);
    15361529
    1537 
    15381530    /* Safey net in case the callbacks above misbehave
    15391531     * (must return VERR_NO_DATA if no data available). */
     
    15471539        *pcb = cb;
    15481540    }
     1541
     1542    if (RT_FAILURE(rc))
     1543        LogRel(("Shared Clipboard: Requesting data for X11 from source failed with %Rrc\n", rc));
    15491544
    15501545    LogFlowFunc(("Returning pv=%p, cb=%RU32, rc=%Rrc\n", pv, cb, rc));
     
    18801875
    18811876/**
    1882  * Structure used to pass information about formats that VBox supports.
    1883  */
    1884 typedef struct _CLIPNEWVBOXFORMATS
    1885 {
    1886     /** Context information for the X11 clipboard. */
    1887     PSHCLX11CTX pCtx;
    1888     /** Formats supported by VBox. */
    1889     SHCLFORMATS  Formats;
    1890 } CLIPNEWVBOXFORMATS, *PCLIPNEWVBOXFORMATS;
    1891 
    1892 
    1893 
    1894 /**
    18951877 * Invalidates the local cache of the data in the VBox clipboard.
    18961878 *
     
    19401922
    19411923/**
    1942  * Worker function for ShClX11ReportFormatsToX11 which runs on the
    1943  * event thread.
    1944  *
    1945  * @param pvUserData            Pointer to a CLIPNEWVBOXFORMATS structure containing
     1924 * Worker function for ShClX11ReportFormatsToX11Async.
     1925 *
     1926 * @param  pvUserData           Pointer to a CLIPNEWVBOXFORMATS structure containing
    19461927 *                              information about the VBox formats available and the
    19471928 *                              clipboard context data.  Must be freed by the worker.
     1929 *
     1930 * @thread X11 event thread.
    19481931 */
    19491932static void ShClX11ReportFormatsToX11Worker(void *pvUserData, void * /* interval */)
     
    19511934    AssertPtrReturnVoid(pvUserData);
    19521935
    1953     CLIPNEWVBOXFORMATS *pFormats = (CLIPNEWVBOXFORMATS *)pvUserData;
    1954 
    1955     PSHCLX11CTX pCtx     = pFormats->pCtx;
    1956     SHCLFORMATS fFormats = pFormats->Formats;
    1957 
    1958     RTMemFree(pFormats);
     1936    PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)pvUserData;
     1937
     1938    PSHCLX11CTX pCtx     = pReq->pCtx;
     1939    SHCLFORMATS fFormats = pReq->Formats.fFormats;
     1940
     1941    RTMemFree(pReq);
    19591942
    19601943#ifdef LOG_ENABLED
     
    19791962 * @param   uFormats            Clipboard formats offered.
    19801963 */
    1981 int ShClX11ReportFormatsToX11(PSHCLX11CTX pCtx, SHCLFORMATS uFormats)
     1964int ShClX11ReportFormatsToX11Async(PSHCLX11CTX pCtx, SHCLFORMATS uFormats)
    19821965{
    19831966    /*
     
    19891972    int rc;
    19901973
    1991     /* This must be free'd by the worker callback. */
    1992     PCLIPNEWVBOXFORMATS pFormats = (PCLIPNEWVBOXFORMATS)RTMemAlloc(sizeof(CLIPNEWVBOXFORMATS));
    1993     if (pFormats)
    1994     {
    1995         pFormats->pCtx    = pCtx;
    1996         pFormats->Formats = uFormats;
    1997         rc = clipThreadScheduleCall(pCtx, ShClX11ReportFormatsToX11Worker,
    1998                                     (XtPointer)pFormats);
     1974    PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)RTMemAllocZ(sizeof(SHCLX11REQUEST));
     1975    if (pReq)
     1976    {
     1977        pReq->pCtx             = pCtx;
     1978        pReq->Formats.fFormats = uFormats;
     1979
     1980        rc = clipThreadScheduleCall(pCtx, ShClX11ReportFormatsToX11Worker, (XtPointer)pReq);
    19991981        if (RT_FAILURE(rc))
    2000             RTMemFree(pFormats);
     1982            RTMemFree(pReq);
    20011983    }
    20021984    else
     
    20071989}
    20081990
    2009 /**
    2010  * Converts the data obtained from the X11 clipboard to the required format,
    2011  * place it in the buffer supplied and signal that data has arrived.
     1991#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1992/**
     1993 * Converts an X11 data blob to a string list.
     1994 *
     1995 * @returns VBox status code.
     1996 * @param   pvData              Data to conver to a string list.
     1997 * @param   cbData              Size (in bytes) of \a pvData.
     1998 * @param   ppszList            Where to return the allocated string list on success.
     1999 *                              Must be free'd with RTStrFree().
     2000 * @param   pcbList             Size (in  bytes) of the returned string list on success.
     2001 *                              Includes terminator.
     2002 */
     2003int ShClX11TransferConvertDataToStringList(const char *pvData, size_t cbData, char **ppszList, size_t *pcbList)
     2004{
     2005    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     2006    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     2007    AssertPtrNullReturn(ppszList, VERR_INVALID_POINTER);
     2008    AssertPtrReturn(pcbList, VERR_INVALID_POINTER);
     2009
     2010    /* For URI lists we only accept valid UTF-8 encodings. */
     2011    int rc = RTStrValidateEncodingEx((char *)pvData, cbData, 0 /* fFlags */);
     2012    if (RT_FAILURE(rc))
     2013        return rc;
     2014
     2015    /* We might need to skip some prefixes before actually reaching the file list. */
     2016    static const char *s_aszPrefixesToSkip[] =
     2017        { "copy\n" /* Nautilus / Nemo */ };
     2018    for (size_t i = 0; i < RT_ELEMENTS(s_aszPrefixesToSkip); i++)
     2019    {
     2020        const char *pszNeedle = RTStrStr(pvData, s_aszPrefixesToSkip[i]);
     2021        if (pszNeedle)
     2022        {
     2023            size_t const cbNeedle = strlen(s_aszPrefixesToSkip[i]);
     2024            pszNeedle += cbNeedle;
     2025            pvData     = pszNeedle;
     2026            Assert(cbData >= cbNeedle);
     2027            cbData    -= cbNeedle;
     2028        }
     2029    }
     2030
     2031    *pcbList = 0;
     2032
     2033    char **papszStrings;
     2034    size_t cStrings;
     2035    rc = RTStrSplit(pvData, cbData, SHCL_TRANSFER_URI_LIST_SEP_STR, &papszStrings, &cStrings);
     2036    if (RT_SUCCESS(rc))
     2037    {
     2038        for (size_t i = 0; i < cStrings; i++)
     2039        {
     2040            const char *pszString = papszStrings[i];
     2041            rc = RTStrAAppend(ppszList, pszString);
     2042            if (RT_FAILURE(rc))
     2043                break;
     2044            *pcbList += strlen(pszString);
     2045        }
     2046
     2047        *pcbList++; /* Include terminator. */
     2048    }
     2049
     2050    return rc;
     2051}
     2052#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     2053
     2054/**
     2055 * Worker function for clipConvertDataFromX11.
     2056 *
     2057 * Converts the data read from the X11 clipboard to the required format.
     2058 * Signals the wait event.
    20122059 *
    20132060 * Converts the text obtained UTF-16LE with Windows EOLs.
    20142061 * Converts full BMP data to DIB format.
     2062 *
     2063 * @thread X11 event thread.
    20152064 */
    20162065SHCL_X11_DECL(void) clipConvertDataFromX11Worker(void *pClient, void *pvSrc, unsigned cbSrc)
    20172066{
    2018     CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pClient;
     2067    PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)pClient;
    20192068    AssertPtrReturnVoid(pReq);
    20202069
    2021     LogFlowFunc(("uFmtVBox=%#x, idxFmtX11=%u, pvSrc=%p, cbSrc=%u\n", pReq->uFmtVBox, pReq->idxFmtX11, pvSrc, cbSrc));
    2022 
    2023     LogRel2(("Shared Clipboard: Converting X11 format '%s' to VBox format %#x\n",
    2024              g_aFormats[pReq->idxFmtX11].pcszAtom, pReq->uFmtVBox));
     2070    LogFlowFunc(("uFmtVBox=%#x, idxFmtX11=%u, pvSrc=%p, cbSrc=%u\n", pReq->Read.uFmtVBox, pReq->Read.idxFmtX11, pvSrc, cbSrc));
     2071
     2072    LogRel2(("Shared Clipboard: Converting X11 format '%s' to VBox format %#x (%RU32 bytes max)\n",
     2073             g_aFormats[pReq->Read.idxFmtX11].pcszAtom, pReq->Read.uFmtVBox, pReq->Read.cbMax));
    20252074
    20262075    AssertPtr(pReq->pCtx);
    2027     Assert(pReq->uFmtVBox != VBOX_SHCL_FMT_NONE); /* Sanity. */
     2076    Assert(pReq->Read.uFmtVBox != VBOX_SHCL_FMT_NONE); /* Sanity. */
    20282077
    20292078    int rc = VINF_SUCCESS;
     
    20482097        rc = VERR_NO_DATA;
    20492098    }
    2050     else if (pReq->uFmtVBox == VBOX_SHCL_FMT_UNICODETEXT)
     2099    else if (pReq->Read.uFmtVBox == VBOX_SHCL_FMT_UNICODETEXT)
    20512100    {
    20522101        /* In which format is the clipboard data? */
    2053         switch (clipRealFormatForX11Format(pReq->idxFmtX11))
     2102        switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11))
    20542103        {
    20552104            case SHCLX11FMT_UTF8:
     
    20692118                    cwDst += 1                        /* Include terminator */;
    20702119                    cbDst  = cwDst * sizeof(RTUTF16); /* Convert RTUTF16 units to bytes. */
     2120
     2121                    LogFlowFunc(("UTF-16 text (%zu bytes):\n%ls\n", cbDst, pvDst));
    20712122                }
    20722123                break;
     
    20802131        }
    20812132    }
    2082     else if (pReq->uFmtVBox == VBOX_SHCL_FMT_BITMAP)
     2133    else if (pReq->Read.uFmtVBox == VBOX_SHCL_FMT_BITMAP)
    20832134    {
    20842135        /* In which format is the clipboard data? */
    2085         switch (clipRealFormatForX11Format(pReq->idxFmtX11))
     2136        switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11))
    20862137        {
    20872138            case SHCLX11FMT_BMP:
     
    21122163        }
    21132164    }
    2114     else if (pReq->uFmtVBox == VBOX_SHCL_FMT_HTML)
     2165    else if (pReq->Read.uFmtVBox == VBOX_SHCL_FMT_HTML)
    21152166    {
    21162167        /* In which format is the clipboard data? */
    2117         switch (clipRealFormatForX11Format(pReq->idxFmtX11))
     2168        switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11))
    21182169        {
    21192170            case SHCLX11FMT_HTML:
     
    21752226    }
    21762227# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    2177     else if (pReq->uFmtVBox == VBOX_SHCL_FMT_URI_LIST)
     2228    else if (pReq->Read.uFmtVBox == VBOX_SHCL_FMT_URI_LIST)
    21782229    {
    21792230        /* In which format is the clipboard data? */
    2180         switch (clipRealFormatForX11Format(pReq->idxFmtX11))
     2231        switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11))
    21812232        {
    21822233            case SHCLX11FMT_URI_LIST:
    21832234            {
    2184                 /* For URI lists we only accept valid UTF-8 encodings. */
    2185                 if (RT_SUCCESS(RTStrValidateEncodingEx((char *)pvSrc, cbSrc, 0)))
     2235                RTCList<RTCString> lstRootEntries;
     2236                rc = ShClX11TransferConvertDataToStringList((const char *)pvSrc, cbSrc, (char **)&pvDst, &cbDst);
     2237                if (RT_SUCCESS(rc))
    21862238                {
    2187                     /* URI lists on X are strings separated with "\r\n". */
    2188                     RTCList<RTCString> lstRootEntries = RTCString((char *)pvSrc, cbSrc).split("\r\n");
     2239            #if 0
    21892240                    for (size_t i = 0; i < lstRootEntries.size(); ++i)
    21902241                    {
    2191                         char *pszEntry = RTUriFilePath(lstRootEntries.at(i).c_str());
     2242                        char *pszEntry = RTUriFilePath(lstRootEntries.at(i).c_str())
    21922243                        AssertPtrBreakStmt(pszEntry, VERR_INVALID_PARAMETER);
     2244
     2245                        LogFlowFunc(("Entry '%s' -> ", (char *)pszEntry));
    21932246
    21942247                        rc = RTStrAAppend((char **)&pvDst, "http://localhost");
     
    22052258                        cbDst += (uint32_t)strlen(pszEntry);
    22062259
    2207                         LogFlowFunc(("URI list entry '%s'\n", (char *)pvDst));
    2208 
    2209                         rc = RTStrAAppend((char **)&pvDst, "\r\n");
     2260                        LogFlowFunc(("'%s'\n", (char *)pvDst));
     2261
     2262                        rc = RTStrAAppend((char **)&pvDst, SHCL_TRANSFER_URI_LIST_SEP_STR);
    22102263                        AssertRCBreakStmt(rc, VERR_NO_MEMORY);
    2211                         cbDst += (uint32_t)strlen("\r\n");
     2264                        cbDst += (uint32_t)strlen(SHCL_TRANSFER_URI_LIST_SEP_STR);
    22122265
    22132266                        RTStrFree(pszEntry);
     
    22162269                    if (cbDst)
    22172270                        cbDst++; /* Include final (zero) termination. */
    2218 
    2219                     LogFlowFunc(("URI list: cbDst=%RU32\n", cbDst));
     2271            #endif
     2272
     2273
    22202274                }
    2221                 else
    2222                     rc = VERR_INVALID_PARAMETER;
    22232275                break;
    22242276            }
     
    22352287        rc = VERR_NOT_SUPPORTED;
    22362288
     2289    LogFlowFunc(("pvDst=%p, cbDst=%RU32\n", pvDst, cbDst));
     2290
    22372291    if (RT_FAILURE(rc))
    22382292        LogRel(("Shared Clipboard: Converting X11 format '%s' (idxFmtX11=%u) to VBox format %#x failed, rc=%Rrc\n",
    2239                 g_aFormats[pReq->idxFmtX11].pcszAtom, pReq->idxFmtX11, pReq->uFmtVBox, rc));
    2240 
    2241     SHCLX11READDATAREQ SendData;
    2242     RT_ZERO(SendData);
    2243     SendData.pReq         = pReq->pReq;
    2244     SendData.rcCompletion = rc;
    2245 
    2246     pCtx->Callbacks.pfnOnSendDataToDest(pReq->pCtx->pFrontend, pvDst, cbDst, &SendData);
    2247 
     2293                g_aFormats[pReq->Read.idxFmtX11].pcszAtom, pReq->Read.idxFmtX11, pReq->Read.uFmtVBox, rc));
     2294
     2295    int rc2;
     2296
     2297    PSHCLEVENTPAYLOAD pPayload = NULL;
     2298    size_t            cbResp   = sizeof(SHCLX11RESPONSE);
     2299    PSHCLX11RESPONSE  pResp    = (PSHCLX11RESPONSE)RTMemAlloc(cbResp);
     2300    if (pResp)
     2301    {
     2302        pResp->Read.pvData = pvDst;
     2303        pResp->Read.cbData = cbDst;
     2304
     2305        pvDst = NULL; /* The response owns the data now. */
     2306
     2307        if (   pResp->Read.pvData
     2308            && pResp->Read.cbData)
     2309        {
     2310            rc2 = ShClPayloadInit(0 /* ID, unused */, pResp, cbResp, &pPayload);
     2311            AssertRC(rc2);
     2312        }
     2313    }
     2314    else
     2315        rc = VERR_NO_MEMORY;
     2316
     2317    rc2 = ShClEventSignal(pReq->pEvent, pPayload);
     2318    if (RT_SUCCESS(rc2))
     2319        pPayload = NULL; /* The event owns the payload now. */
     2320
     2321    if (pPayload) /* Free payload on error. */
     2322    {
     2323        ShClPayloadFree(pPayload);
     2324        pPayload = NULL;
     2325    }
     2326
     2327    LogRel2(("Shared Clipboard: Reading X11 clipboard data completed with %Rrc\n", rc));
     2328
     2329    RTMemFree(pReq);
    22482330    RTMemFree(pvDst);
    2249     RTMemFree(pReq);
    22502331
    22512332    LogFlowFuncLeaveRC(rc);
     
    22532334
    22542335/**
    2255  * Converts the data obtained from the X11 clipboard to the required format,
    2256  * place it in the buffer supplied and signal that data has arrived.
    2257  *
    2258  * Converts the text obtained UTF-16LE with Windows EOLs.
    2259  * Converts full BMP data to DIB format.
     2336 * Converts the data read from the X11 clipboard to the required format.
     2337 *
     2338 * @thread X11 event thread.
    22602339 */
    22612340SHCL_X11_DECL(void) clipConvertDataFromX11(Widget widget, XtPointer pClient,
     
    22682347    int rc = VINF_SUCCESS;
    22692348
    2270     CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pClient;
    2271     if (pReq) /* Give some more clues, if available. */
    2272     {
    2273         char *pszFmts = ShClFormatsToStrA(pReq->uFmtVBox);
    2274         AssertPtrReturnVoid(pszFmts);
    2275         AssertReturnVoid(pReq->idxFmtX11 <= SHCL_MAX_X11_FORMATS); /* Paranoia, should be checked already by the caller. */
    2276         LogRel2(("Shared Clipboard: Converting X11 format '%s' -> VBox format(s) '%s'\n", g_aFormats[pReq->idxFmtX11].pcszAtom, pszFmts));
    2277         RTStrFree(pszFmts);
    2278     }
    2279 
    22802349    if (*atomType == XT_CONVERT_FAIL) /* Xt timeout */
    22812350    {
     
    22852354    else
    22862355    {
    2287         if (   pReq
    2288             && pReq->pCtx->Callbacks.pfnOnClipboardRead)
    2289         {
    2290             void  *pvData = NULL;
    2291             size_t cbData = 0;
    2292             rc = pReq->pCtx->Callbacks.pfnOnClipboardRead(pReq->pCtx->pFrontend, pReq->uFmtVBox, &pvData, &cbData, NULL);
    2293             if (RT_SUCCESS(rc))
     2356        PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)pClient;
     2357        if (pReq) /* Give some more clues, if available. */
     2358        {
     2359            char *pszFmts = ShClFormatsToStrA(pReq->Read.uFmtVBox);
     2360            AssertPtrReturnVoid(pszFmts);
     2361            AssertReturnVoid(pReq->Read.idxFmtX11 <= SHCL_MAX_X11_FORMATS); /* Paranoia, should be checked already by the caller. */
     2362            LogRel2(("Shared Clipboard: Converting X11 format '%s' -> VBox format(s) '%s'\n", g_aFormats[pReq->Read.idxFmtX11].pcszAtom, pszFmts));
     2363            RTStrFree(pszFmts);
     2364
     2365            if (pReq->pCtx->Callbacks.pfnOnClipboardRead) /* Usually only used for testcases. */
    22942366            {
    2295                 /* Feed to conversion worker. */
    2296                 clipConvertDataFromX11Worker(pClient, pvData, cbData);
    2297                 RTMemFree(pvData);
     2367                void  *pvData = NULL;
     2368                size_t cbData = 0;
     2369                rc = pReq->pCtx->Callbacks.pfnOnClipboardRead(pReq->pCtx->pFrontend, pReq->Read.uFmtVBox, &pvData, &cbData, NULL);
     2370                if (RT_SUCCESS(rc))
     2371                {
     2372                    /* Feed to conversion worker. */
     2373                    clipConvertDataFromX11Worker(pClient, pvData, cbData);
     2374                    RTMemFree(pvData);
     2375                }
    22982376            }
    2299         }
    2300         else /* Call with current data provided by X (default). */
    2301             clipConvertDataFromX11Worker(pClient, pvSrc, (*pcLen) * (*piFormat) / 8);
     2377            else /* Call conversion worker with current data provided by X (default). */
     2378                clipConvertDataFromX11Worker(pClient, pvSrc, (*pcLen) * (*piFormat) / 8);
     2379        }
     2380        else
     2381            rc = VERR_INVALID_POINTER;
    23022382    }
    23032383
     
    23052385    {
    23062386        LogRel(("Shared Clipboard: Reading clipboard data from X11 failed with %Rrc\n", rc));
    2307         /* Make sure to complete the request in any case. */
     2387
     2388        /* Make sure to complete the request in any case by calling the conversion worker. */
    23082389        clipConvertDataFromX11Worker(pClient, NULL, 0);
    23092390    }
     
    23222403 */
    23232404static int clipGetSelectionValueEx(PSHCLX11CTX pCtx, const char *pszWhere, SHCLX11FMTIDX idxFmt,
    2324                                    CLIPREADX11CBREQ *pReq)
     2405                                   PSHCLX11REQUEST pReq)
    23252406{
    23262407    AssertPtrReturn(pszWhere, VERR_INVALID_POINTER);
     
    23542435 * @sa clipGetSelectionValueEx() for requesting data for a specific selection.
    23552436 */
    2356 static int clipGetSelectionValue(PSHCLX11CTX pCtx, SHCLX11FMTIDX idxFmt, CLIPREADX11CBREQ *pReq)
     2437static int clipGetSelectionValue(PSHCLX11CTX pCtx, SHCLX11FMTIDX idxFmt, PSHCLX11REQUEST pReq)
    23572438{
    23582439    return clipGetSelectionValueEx(pCtx, "CLIPBOARD", idxFmt, pReq);
     
    23602441
    23612442/**
    2362  * Worker function for ShClX11ReadDataFromX11 which runs on the event thread.
    2363  *
    2364  * @param pvUserData            Pointer to a CLIPREADX11CBREQ structure containing
     2443 * Worker function for ShClX11ReadDataFromX11Async.
     2444 *
     2445 * @param  pvUserData           Pointer to a CLIPREADX11CBREQ structure containing
    23652446 *                              information about the clipboard read request.
    23662447 *                              Must be free'd by the worker.
     2448 * @thread X11 event thread.
    23672449 */
    23682450static void ShClX11ReadDataFromX11Worker(void *pvUserData, void * /* interval */)
     
    23702452    AssertPtrReturnVoid(pvUserData);
    23712453
    2372     CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pvUserData;
     2454    PSHCLX11REQUEST   pReq = (PSHCLX11REQUEST)pvUserData;
    23732455    SHCLX11CTX       *pCtx = pReq->pCtx;
    23742456    AssertPtrReturnVoid(pCtx);
    23752457
    2376     LogFlowFunc(("pReq->uFmtVBox=%#x, idxFmtX11=%#x\n", pReq->uFmtVBox, pReq->idxFmtX11));
     2458    LogFlowFunc(("pReq->uFmtVBox=%#x, idxFmtX11=%#x\n", pReq->Read.uFmtVBox, pReq->Read.idxFmtX11));
    23772459
    23782460    int rc = VERR_NO_DATA; /* VBox thinks we have data and we don't. */
     
    23882470    else
    23892471#endif
    2390     if (pReq->uFmtVBox & VBOX_SHCL_FMT_UNICODETEXT)
    2391     {
    2392         pReq->idxFmtX11 = pCtx->idxFmtText;
    2393         if (pReq->idxFmtX11 != SHCLX11FMT_INVALID)
     2472    if (pReq->Read.uFmtVBox & VBOX_SHCL_FMT_UNICODETEXT)
     2473    {
     2474        pReq->Read.idxFmtX11 = pCtx->idxFmtText;
     2475        if (pReq->Read.idxFmtX11 != SHCLX11FMT_INVALID)
    23942476        {
    23952477            /* Send out a request for the data to the current clipboard owner. */
     
    23972479        }
    23982480    }
    2399     else if (pReq->uFmtVBox & VBOX_SHCL_FMT_BITMAP)
    2400     {
    2401         pReq->idxFmtX11 = pCtx->idxFmtBmp;
    2402         if (pReq->idxFmtX11 != SHCLX11FMT_INVALID)
     2481    else if (pReq->Read.uFmtVBox & VBOX_SHCL_FMT_BITMAP)
     2482    {
     2483        pReq->Read.idxFmtX11 = pCtx->idxFmtBmp;
     2484        if (pReq->Read.idxFmtX11 != SHCLX11FMT_INVALID)
    24032485        {
    24042486            /* Send out a request for the data to the current clipboard owner. */
     
    24062488        }
    24072489    }
    2408     else if (pReq->uFmtVBox & VBOX_SHCL_FMT_HTML)
    2409     {
    2410         pReq->idxFmtX11 = pCtx->idxFmtHTML;
    2411         if (pReq->idxFmtX11 != SHCLX11FMT_INVALID)
     2490    else if (pReq->Read.uFmtVBox & VBOX_SHCL_FMT_HTML)
     2491    {
     2492        pReq->Read.idxFmtX11 = pCtx->idxFmtHTML;
     2493        if (pReq->Read.idxFmtX11 != SHCLX11FMT_INVALID)
    24122494        {
    24132495            /* Send out a request for the data to the current clipboard owner. */
     
    24162498    }
    24172499#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    2418     else if (pReq->uFmtVBox & VBOX_SHCL_FMT_URI_LIST)
    2419     {
    2420         pReq->idxFmtX11 = pCtx->idxFmtURI;
    2421         if (pReq->idxFmtX11 != SHCLX11FMT_INVALID)
     2500    else if (pReq->Read.uFmtVBox & VBOX_SHCL_FMT_URI_LIST)
     2501    {
     2502        pReq->Read.idxFmtX11 = pCtx->idxFmtURI;
     2503        if (pReq->Read.idxFmtX11 != SHCLX11FMT_INVALID)
    24222504        {
    24232505            /* Send out a request for the data to the current clipboard owner. */
     
    24342516    }
    24352517
    2436     if (RT_FAILURE(rc))
    2437     {
    2438         /* The clipboard callback was never scheduled, so we must signal
    2439          * that the request processing is finished and clean up ourselves. */
    2440         SHCLX11READDATAREQ SendData;
    2441         RT_ZERO(SendData);
    2442         SendData.pReq         = pReq->pReq;
    2443         SendData.rcCompletion = rc;
    2444 
    2445         pCtx->Callbacks.pfnOnSendDataToDest(pReq->pCtx->pFrontend, NULL /* pv */ ,0 /* cb */, &SendData);
    2446         RTMemFree(pReq);
    2447     }
    2448 
    24492518    LogFlowFuncLeaveRC(rc);
    24502519}
    24512520
    24522521/**
    2453  * Called when VBox wants to read the X11 clipboard.
     2522 * Reads the X11 clipboard (asynchronously).
    24542523 *
    24552524 * @returns VBox status code.
     
    24582527 * @param   pCtx                Context data for the clipboard backend.
    24592528 * @param   uFmt                The format that the VBox would like to receive the data in.
    2460  * @param   pReq                Read callback request to use. Will be free'd in the callback on success.
    2461  *                              Otherwise the caller has to free this again on error.
    2462  *
    2463  * @note   We allocate a request structure which must be freed by the worker.
    2464  */
    2465 int ShClX11ReadDataFromX11(PSHCLX11CTX pCtx, SHCLFORMAT uFmt, CLIPREADCBREQ *pReq)
    2466 {
    2467     AssertPtrReturn(pReq, VERR_INVALID_POINTER);
     2529 * @param   cbMax               Maximum data to read (in bytes).
     2530 *                              Specify UINT32_MAX to read as much as available.
     2531 * @param   pEvent              Event to use for waiting for data to arrive.
     2532 *                              The event's payload will contain the data read. Needs to be free'd with ShClEventRelease().
     2533 */
     2534int ShClX11ReadDataFromX11Async(PSHCLX11CTX pCtx, SHCLFORMAT uFmt, uint32_t cbMax, PSHCLEVENT pEvent)
     2535{
     2536    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
    24682537    /*
    24692538     * Immediately return if we are not connected to the X server.
     
    24742543    int rc = VINF_SUCCESS;
    24752544
    2476     CLIPREADX11CBREQ *pX11Req = (CLIPREADX11CBREQ *)RTMemAllocZ(sizeof(CLIPREADX11CBREQ));
    2477     if (pX11Req)
    2478     {
    2479         pX11Req->pCtx     = pCtx;
    2480         pX11Req->uFmtVBox = uFmt;
    2481         pX11Req->pReq     = pReq;
     2545    PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)RTMemAllocZ(sizeof(SHCLX11REQUEST));
     2546    if (pReq)
     2547    {
     2548        pReq->pCtx          = pCtx;
     2549        pReq->Read.uFmtVBox = uFmt;
     2550        pReq->Read.cbMax    = cbMax;
     2551        pReq->pEvent        = pEvent;
    24822552
    24832553        /* We use this to schedule a worker function on the event thread. */
    2484         rc = clipThreadScheduleCall(pCtx, ShClX11ReadDataFromX11Worker, (XtPointer)pX11Req);
     2554        rc = clipThreadScheduleCall(pCtx, ShClX11ReadDataFromX11Worker, (XtPointer)pReq);
    24852555        if (RT_FAILURE(rc))
    2486             RTMemFree(pX11Req);
     2556            RTMemFree(pReq);
    24872557    }
    24882558    else
     
    24922562    return rc;
    24932563}
     2564
  • trunk/src/VBox/GuestHost/SharedClipboard/testcase/Makefile.kmk

    r99940 r100204  
    3232 if1of ($(KBUILD_TARGET), freebsd linux netbsd openbsd solaris)
    3333
    34   PROGRAMS += tstClipboardGH-X11 tstClipboardGH-X11Smoke
     34  PROGRAMS += tstClipboardGH-X11Smoke
     35  ## @todo BUGBUG Make tstClipboardGH-X11 build again and enable!
    3536  TESTING  += \
    3637        $(tstClipboardGH-X11_0_OUTDIR)/tstClipboardGH-X11.run \
  • trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardGH-X11.cpp

    r98103 r100204  
    103103    g_tst_pvDataVBox = NULL;
    104104    g_tst_cbDataVBox = 0;
    105     ShClX11ReportFormatsToX11(pCtx, 0);
     105    ShClX11ReportFormatsToX11Async(pCtx, 0);
    106106}
    107107
     
    125125    g_tst_pvDataVBox = pv;
    126126    g_tst_cbDataVBox = cb;
    127     ShClX11ReportFormatsToX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT);
     127    ShClX11ReportFormatsToX11Async(pCtx, VBOX_SHCL_FMT_UNICODETEXT);
    128128    return VINF_SUCCESS;
    129129}
     
    385385static int g_tst_rcCompleted = VINF_SUCCESS;
    386386static int g_tst_cbCompleted = 0;
    387 static CLIPREADCBREQ *g_tst_pCompletedReq = NULL;
     387static SHCLX11REQUEST *g_tst_pCompletedReq = NULL;
    388388static char g_tst_abCompletedBuf[TESTCASE_MAX_BUF_SIZE];
    389389
     
    413413    RT_NOREF(pCtx);
    414414
    415     PSHCLX11READDATAREQ pData = (PSHCLX11READDATAREQ)pvUser;
     415    PSHCLX11RESPONSE pData = (PSHCLX11RESPONSE)pvUser;
    416416
    417417    if (cb <= TESTCASE_MAX_BUF_SIZE)
    418418    {
    419         g_tst_rcCompleted = pData->rcCompletion;
     419        g_tst_rcCompleted = pData->rc;
    420420        if (cb != 0)
    421421            memcpy(g_tst_abCompletedBuf, pv, cb);
     
    465465}
    466466
    467 static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, CLIPREADCBREQ **ppReq)
     467static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, SHCLX11REQREAD **ppReq)
    468468{
    469469    *prc = g_tst_rcCompleted;
     
    485485    {
    486486        char *pc;
    487         CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
    488         ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
     487        SHCLX11REQREAD *pReq = (SHCLX11REQREAD *)&pReq, *pReqRet = NULL;
     488        ShClX11ReadDataFromX11Async(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
    489489        int rc = VINF_SUCCESS;
    490490        uint32_t cbActual = 0;
     
    542542    {
    543543        char *pc;
    544         CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
    545         ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
     544        SHCLX11REQREAD *pReq = (SHCLX11REQREAD *)&pReq, *pReqRet = NULL;
     545        ShClX11ReadDataFromX11Async(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
    546546        int rc = VINF_SUCCESS;
    547547        uint32_t cbActual = 0;
     
    618618static void tstNoX11(PSHCLX11CTX pCtx, const char *pcszTestCtx)
    619619{
    620     CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq;
    621     int rc = ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
     620    SHCLX11REQREAD *pReq = (SHCLX11REQREAD *)&pReq;
     621    int rc = ShClX11ReadDataFromX11Async(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
    622622    RTTESTI_CHECK_MSG(rc == VERR_NO_DATA, ("context: %s\n", pcszTestCtx));
    623623}
     
    655655    {
    656656        char *pc;
    657         CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
    658         ShClX11ReadDataFromX11(pCtx, 0xF000 /* vboxFormat */, pReq);  /* Bad format. */
     657        SHCLX11REQREAD *pReq = (SHCLX11REQREAD *)&pReq, *pReqRet = NULL;
     658        ShClX11ReadDataFromX11Async(pCtx, 0xF000 /* vboxFormat */, pReq);  /* Bad format. */
    659659        int rc = VINF_SUCCESS;
    660660        uint32_t cbActual = 0;
     
    696696    char *pc;
    697697    uint32_t cbActual;
    698     CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
     698    SHCLX11REQREAD *pReq = (SHCLX11REQREAD *)&pReq, *pReqRet = NULL;
    699699
    700700    /* UTF-8 from X11 */
     
    778778    tstClipSetSelectionValues("UTF8_STRING", XA_STRING, NULL,
    779779                              0, 8);
    780     ShClX11ReadDataFromX11(&X11Ctx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
     780    ShClX11ReadDataFromX11Async(&X11Ctx, VBOX_SHCL_FMT_UNICODETEXT, pReq);
    781781    tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
    782782    RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,
     
    802802    /* Testing for 0xffff will go into handling VBOX_SHCL_FMT_UNICODETEXT, where we don't have
    803803     * have any data at the moment so far, so this will return VERR_NO_DATA. */
    804     ShClX11ReadDataFromX11(&X11Ctx, 0xffff /* vboxFormat */, pReq);
     804    ShClX11ReadDataFromX11Async(&X11Ctx, 0xffff /* vboxFormat */, pReq);
    805805    tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);
    806806    RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,
     
    898898    tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);
    899899    tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2);
    900     ShClX11ReportFormatsToX11(&X11Ctx, 0xa0000);
     900    ShClX11ReportFormatsToX11Async(&X11Ctx, 0xa0000);
    901901    RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel,
    902902                     (hTest, "VBox grabbed the clipboard with unknown data and we ignored it\n"));
  • trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardHttpServer.cpp

    r99937 r100204  
    178178    RTTEST_CHECK(hTest, ShClTransferHttpServerIsRunning(&HttpSrv) == false);
    179179    if (uPort)
    180         rc = ShClTransferHttpServerCreateEx(&HttpSrv, uPort);
     180        rc = ShClTransferHttpServerStartEx(&HttpSrv, uPort);
    181181    else
    182         rc = ShClTransferHttpServerCreate(&HttpSrv, 32 /* cMaxAttempts */, &uPort);
     182        rc = ShClTransferHttpServerStart(&HttpSrv, 32 /* cMaxAttempts */, &uPort);
    183183    RTTEST_CHECK_RC_OK(hTest, rc);
    184     RTTEST_CHECK(hTest, ShClTransferHttpServerHasTransfer(&HttpSrv, 0) == false);
    185     RTTEST_CHECK(hTest, ShClTransferHttpServerHasTransfer(&HttpSrv, 42) == false);
     184    RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 0) == false);
     185    RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 42) == false);
    186186
    187187    char *pszSrvAddr = ShClTransferHttpServerGetAddressA(&HttpSrv);
     
    208208                RTTEST_CHECK_RC_OK(hTest, ShClTransferCreate(&pTx));
    209209                RTTEST_CHECK_RC_OK(hTest, ShClTransferInit(pTx, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL));
    210                 RTTEST_CHECK_RC_OK(hTest, ShClTransferRootsSetAsFile(pTx, ValueUnion.psz));
     210                RTTEST_CHECK_RC_OK(hTest, ShClTransferRootsInitFromFile(pTx, ValueUnion.psz));
    211211                RTTEST_CHECK_RC_OK(hTest, ShClTransferCtxTransferRegister(&TxCtx, pTx, NULL));
    212212                RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerRegisterTransfer(&HttpSrv, pTx));
  • 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