- Timestamp:
- Jun 19, 2023 9:11:37 AM (18 months ago)
- Location:
- trunk
- Files:
-
- 33 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/GuestHost/SharedClipboard-transfers.h
r99966 r100204 40 40 # pragma once 41 41 #endif 42 43 #include <map>44 42 45 43 #include <iprt/assert.h> … … 67 65 */ 68 66 69 /** No Shared Clipboard list ingfeature flags defined. */67 /** No Shared Clipboard list feature flags defined. */ 70 68 #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) 71 71 /** Shared Clipboard feature flags valid mask. */ 72 #define SHCL_TRANSFER_LIST_FEATURE_F_VALID_MASK 0x 072 #define SHCL_TRANSFER_LIST_FEATURE_F_VALID_MASK 0x1 73 73 74 74 /** Defines the maximum length (in chars) a Shared Clipboard transfer path can have. */ … … 80 80 /** Defines the default maximum object handles a Shared Clipboard transfer can have. */ 81 81 #define SHCL_TRANSFER_DEFAULT_MAX_OBJ_HANDLES _4K 82 /** Defines the default timeout (in ms) to use for clipboard operations. */83 #define SHCL_T IMEOUT_DEFAULT_MS RT_MS_30SEC82 /** Defines the separator for the entries of an URI list (as a string). */ 83 #define SHCL_TRANSFER_URI_LIST_SEP_STR "\r\n" 84 84 85 85 /** … … 92 92 /** The transfer has been initialized but is not running yet. */ 93 93 SHCLTRANSFERSTATUS_INITIALIZED, 94 /** The transfer has been uninitialized and is not usable anymore. */ 95 SHCLTRANSFERSTATUS_UNINITIALIZED, 94 96 /** The transfer is active and running. */ 95 97 SHCLTRANSFERSTATUS_STARTED, … … 100 102 /** The transfer has been killed. */ 101 103 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. */ 103 106 SHCLTRANSFERSTATUS_ERROR, 104 107 /** The usual 32-bit hack. */ … … 401 404 typedef _SHCLLISTENTRY SHCLLISTENTRY; 402 405 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 _SHCLROOTLISTHDR412 {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 _SHCLROOTLIST425 {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 434 406 /** 435 407 * Structure for maintaining Shared Clipboard list open parameters. … … 458 430 /** Feature flag(s) of type SHCL_TRANSFER_LIST_FEATURE_F_XXX. */ 459 431 uint32_t fFeatures; 460 /** Total objects returned. */461 uint64_t c TotalObjects;432 /** Total entries of the list. */ 433 uint64_t cEntries; 462 434 /** Total size (in bytes) returned. */ 463 435 uint64_t cbTotalSize; … … 467 439 468 440 /** 469 * Structure for a Shared Clipboard list entry.441 * Structure for a generic Shared Clipboard list entry. 470 442 */ 471 443 typedef struct _SHCLLISTENTRY 472 444 { 445 /** List node. */ 446 RTLISTNODE Node; 473 447 /** Entry name. */ 474 char *pszName;448 char *pszName; 475 449 /** Size (in bytes) of entry name. 476 450 * 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; 480 454 /** Size (in bytes) of the actual list entry. */ 481 uint32_t cbInfo;455 uint32_t cbInfo; 482 456 /** Data of the actual list entry. */ 483 void *pvInfo;457 void *pvInfo; 484 458 } SHCLLISTENTRY; 485 459 /** Pointer to a Shared Clipboard list entry. */ 486 460 typedef SHCLLISTENTRY *PSHCLLISTENTRY; 461 /** Pointer to a const Shared Clipboard list entry. */ 462 typedef SHCLLISTENTRY *PCSHCLLISTENTRY; 487 463 488 464 /** 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 maintaininga generic Shared Clipboard list.465 #define SHCLLISTENTRY_MAX_NAME 1024 466 467 /** 468 * Structure for a generic Shared Clipboard list. 493 469 */ 494 470 typedef struct _SHCLLIST 495 471 { 496 472 /** List header. */ 497 SHCLLISTHDR 498 /** List entries . */499 SHCLROOTLISTENTRY *paEntries;473 SHCLLISTHDR Hdr; 474 /** List entries of type PSHCLLISTENTRY. */ 475 RTLISTANCHOR lstEntries; 500 476 } SHCLLIST; 501 /** Pointer to a Shared Clipboard transfer transfer list. */477 /** Pointer to a generic Shared Clipboard transfer transfer list. */ 502 478 typedef SHCLLIST *PSHCLLIST; 503 479 … … 637 613 638 614 /** 639 * Structure for keeping a single transfer root list entry.640 */641 typedef struct _SHCLLISTROOT642 {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 /**652 615 * Structure for maintaining an Shared Clipboard transfer state. 653 616 * Everything in here will be part of a saved state (later). … … 696 659 { 697 660 /** 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. 699 664 * 700 665 * @returns VBox status code. 701 666 * @param pCtx Provider context to use. 702 * @param p pRootListWhere to store the root list on success.703 */ 704 DECLCALLBACKMEMBER(int, pfnRoot sGet,(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList));667 * @param pRootList Where to store the root list on success. 668 */ 669 DECLCALLBACKMEMBER(int, pfnRootListRead,(PSHCLTXPROVIDERCTX pCtx)); 705 670 /** 706 671 * Opens a transfer list. … … 805 770 /** Queries (assigns) a Shared Clipboard provider interface. */ 806 771 #define SHCLTXPROVIDERIFACE_QUERY(a_Iface, a_Name) \ 807 a_Iface->pfnRoot sGet = a_Name ## RootsGet; \772 a_Iface->pfnRootListRead = a_Name ## RootListRead; \ 808 773 a_Iface->pfnListOpen = a_Name ## ListOpen; \ 809 774 a_Iface->pfnListClose = a_Name ## ListClose; \ … … 822 787 823 788 /** 824 * Structure for the Shared Clipboard transfer provider creation context.825 */ 826 typedef struct _SHCLTXPROVIDER CREATIONCTX789 * Structure for Shared Clipboard transfer provider. 790 */ 791 typedef struct _SHCLTXPROVIDER 827 792 { 828 793 /** Specifies what the source of the provider is. */ 829 794 SHCLSOURCE enmSource; 830 /** The provider interface table . */795 /** The provider interface table to use. */ 831 796 SHCLTXPROVIDERIFACE Interface; 832 797 /** User-provided callback data. */ … … 834 799 /** Size (in bytes) of data at user pointer. */ 835 800 size_t cbUser; 836 } SHCLTXPROVIDER CREATIONCTX;837 /** Pointer to a Shared Clipboard transfer provider creation context. */838 typedef SHCLTXPROVIDER CREATIONCTX *PSHCLTXPROVIDERCREATIONCTX;801 } SHCLTXPROVIDER; 802 /** Pointer to Shared Clipboard transfer provider. */ 803 typedef SHCLTXPROVIDER *PSHCLTXPROVIDER; 839 804 840 805 /** … … 856 821 * Shared Clipboard transfer callback table. 857 822 * 858 * All callbacks are optional and can provide additional information / feedback to a frontend.823 * All callbacks are optional (hence all returning void). 859 824 */ 860 825 typedef struct _SHCLTRANSFERCALLBACKTABLE 861 826 { 862 827 /** 863 * Called when the transfer getsinitialized.828 * Called after the transfer got initialized. 864 829 * 865 830 * @param pCbCtx Pointer to callback context to use. 866 831 */ 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. 870 835 * 871 836 * @param pCbCtx Pointer to callback context to use. 872 837 */ 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)); 874 845 /** 875 846 * Called when the transfer has been complete. … … 888 859 DECLCALLBACKMEMBER(void, pfnOnError,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError)); 889 860 /** 890 * Called whentransfer got registered to a transfer context.861 * Called after a transfer got registered to a transfer context. 891 862 * 892 863 * @param pCbCtx Pointer to callback context to use. … … 895 866 DECLCALLBACKMEMBER(void, pfnOnRegistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)); 896 867 /** 897 * Called whentransfer got unregistered from a transfer context.868 * Called after a transfer got unregistered from a transfer context. 898 869 * 899 870 * @param pCbCtx Pointer to callback context to use. … … 908 879 } SHCLTRANSFERCALLBACKTABLE; 909 880 /** Pointer to a Shared Clipboard transfer callback table. */ 910 typedef SHCLTRANSFERCALLBACKTABLE *PSHCLTRANSFERCALLBACK TABLE;881 typedef SHCLTRANSFERCALLBACKTABLE *PSHCLTRANSFERCALLBACKS; 911 882 912 883 /** … … 949 920 /** The transfer's own event source. */ 950 921 SHCLEVENTSOURCE Events; 951 /** Current number of concurrent list handles . */922 /** Current number of concurrent list handles in \a lstHandles. */ 952 923 uint32_t cListHandles; 953 /** Maximum number of concurrent list handles . */924 /** Maximum number of concurrent list handles allowed. */ 954 925 uint32_t cMaxListHandles; 955 /** Next upcoming list handle. */926 /** Next upcoming list handle. For book keeping. */ 956 927 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; 961 930 /** List of root entries of this transfer. */ 962 RTLISTANCHORlstRoots;963 /** Current number of concurrent object handles. */931 SHCLLIST lstRoots; 932 /** Current number of concurrent object handles. in \a lstObj. */ 964 933 uint32_t cObjHandles; 965 934 /** Maximum number of concurrent object handles. */ 966 935 uint32_t cMaxObjHandles; 967 /** Next upcoming object handle. */936 /** Next upcoming object handle. For book keeping. */ 968 937 SHCLOBJHANDLE uObjHandleNext; 969 938 /** Map of all objects handles related to this transfer. */ … … 1006 975 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP 1007 976 /** 977 * Enumeration for HTTP server status changes. 978 * 979 * Keep those as flags, so that we can wait for multiple statuses, if needed. 980 */ 981 typedef 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 /** 1008 992 * Structure for keeping a Shared Clipboard HTTP server instance. 1009 993 */ … … 1011 995 { 1012 996 /** 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; 1014 1003 /** Handle of the HTTP server instance. */ 1015 RTHTTPSERVER hHTTPServer;1004 RTHTTPSERVER hHTTPServer; 1016 1005 /** Port number the HTTP server is running on. 0 if not running. */ 1017 uint16_t uPort;1006 uint16_t uPort; 1018 1007 /** List of registered HTTP transfers. */ 1019 RTLISTANCHOR lstTransfers;1008 RTLISTANCHOR lstTransfers; 1020 1009 /** Number of registered HTTP transfers. */ 1021 uint32_t cTransfers;1010 uint32_t cTransfers; 1022 1011 /** Number of files served (via GET) so far. 1023 1012 * Only complete downloads count (i.e. no aborted). */ 1024 uint32_t cDownloaded;1013 uint32_t cDownloaded; 1025 1014 /** Cached response data. */ 1026 RTHTTPSERVERRESP Resp;1015 RTHTTPSERVERRESP Resp; 1027 1016 } SHCLHTTPSERVER; 1028 1017 /** Pointer to Shared Clipboard HTTP server. */ … … 1068 1057 * @{ 1069 1058 */ 1070 PSHCLTXPROVIDERIFACE VBClTransfer QueryIfaceLocal(PSHCLTXPROVIDERIFACE pIface);1059 PSHCLTXPROVIDERIFACE VBClTransferProviderLocalQueryInterface(PSHCLTXPROVIDER pProvider); 1071 1060 /** @} */ 1072 1061 … … 1104 1093 int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource); 1105 1094 int ShClTransferDestroy(PSHCLTRANSFER pTransfer); 1095 void ShClTransferReset(PSHCLTRANSFER pTransfer); 1106 1096 1107 1097 int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser); … … 1126 1116 bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList); 1127 1117 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); 1118 PSHCLLIST ShClTransferListAlloc(void); 1119 void ShClTransferListFree(PSHCLLIST pList); 1120 void ShClTransferListInit(PSHCLLIST pList); 1121 void ShClTransferListDestroy(PSHCLLIST pList); 1122 int ShClTransferListAddEntry(PSHCLLIST pList, PSHCLLISTENTRY pEntry, bool fAppend); 1142 1123 1143 1124 int ShClTransferListHandleInfoInit(PSHCLLISTHANDLEINFO pInfo); … … 1159 1140 int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry); 1160 1141 void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry); 1161 int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc); 1162 PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry); 1142 int ShClTransferListEntryInitEx(PSHCLLISTENTRY pListEntry, uint32_t fInfo, const char *pszName, void *pvInfo, uint32_t cbInfo); 1163 1143 int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry); 1164 1144 void ShClTransferListEntryDestroy(PSHCLLISTENTRY pListEntry); 1165 1145 bool 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); 1146 int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc); 1147 PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry); 1148 1149 void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKS pCallbacksDst, PSHCLTRANSFERCALLBACKS pCallbacksSrc); 1150 void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKS pCallbacks); 1151 int ShClTransferSetProvider(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDER pProvider); 1152 1153 int ShClTransferRootsInitFromStringList(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots); 1154 int ShClTransferRootsInitFromFile(PSHCLTRANSFER pTransfer, const char *pszFile); 1155 uint64_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer); 1156 PCSHCLLISTENTRY ShClTransferRootsEntryGet(PSHCLTRANSFER pTransfer, uint64_t uIndex); 1157 int ShClTransferRootListRead(PSHCLTRANSFER pTransfer); 1177 1158 /** @} */ 1178 1159 … … 1201 1182 * @{ 1202 1183 */ 1203 int ShCl HttpTransferRegisterAndMaybeStart(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer);1204 int ShCl HttpTransferUnregisterAndMaybeStop(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer);1184 int ShClTransferHttpServerMaybeStart(PSHCLHTTPCONTEXT pCtx); 1185 int ShClTransferHttpServerMaybeStop(PSHCLHTTPCONTEXT pCtx); 1205 1186 /** @} */ 1206 1187 … … 1208 1189 * @{ 1209 1190 */ 1210 int ShClTransferHttpServer Create(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort);1211 int ShClTransferHttpServer CreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort);1191 int ShClTransferHttpServerStart(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort); 1192 int ShClTransferHttpServerStartEx(PSHCLHTTPSERVER pSrv, uint16_t uPort); 1212 1193 int ShClTransferHttpServerDestroy(PSHCLHTTPSERVER pSrv); 1213 voidShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv);1194 int ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv); 1214 1195 int ShClTransferHttpServerRegisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); 1215 1196 int ShClTransferHttpServerUnregisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); 1216 bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); 1197 PSHCLTRANSFER ShClTransferHttpServerGetTransferFirst(PSHCLHTTPSERVER pSrv); 1198 bool ShClTransferHttpServerGetTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); 1217 1199 uint16_t ShClTransferHttpServerGetPort(PSHCLHTTPSERVER pSrv); 1218 1200 uint32_t ShClTransferHttpServerGetTransferCount(PSHCLHTTPSERVER pSrv); … … 1220 1202 char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); 1221 1203 bool ShClTransferHttpServerIsRunning(PSHCLHTTPSERVER pSrv); 1204 int ShClTransferHttpServerWaitForStatusChange(PSHCLHTTPSERVER pSrv, SHCLHTTPSERVERSTATUS fStatus, RTMSINTERVAL msTimeout); 1222 1205 /** @} */ 1223 1206 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ … … 1226 1209 * @{ 1227 1210 */ 1211 int ShClPathSanitizeFilename(char *pszPath, size_t cbPath); 1212 int ShClPathSanitize(char *pszPath, size_t cbPath); 1228 1213 const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus); 1229 1214 int ShClTransferValidatePath(const char *pcszPath, bool fMustExist); 1230 void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc); 1215 int ShClFsObjInfoQuery(const char *pszPath, PSHCLFSOBJINFO pObjInfo); 1216 int ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc); 1231 1217 /** @} */ 1232 1218 -
trunk/include/VBox/GuestHost/SharedClipboard-win.h
r98103 r100204 42 42 #include <iprt/critsect.h> 43 43 #include <iprt/types.h> 44 #include <iprt/req.h> 44 45 #include <iprt/win/windows.h> 45 46 … … 109 110 bool fCBChainPingInProcess; 110 111 } SHCLWINAPIOLD, *PSHCLWINAPIOLD; 112 113 /** Forward declaration for the Windows data object. */ 114 class SharedClipboardWinDataObject; 111 115 112 116 /** … … 131 135 /** Structure for maintaining the old clipboard API. */ 132 136 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; 133 147 } SHCLWINCTX, *PSHCLWINCTX; 134 148 … … 154 168 155 169 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 156 int SharedClipboardWinGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); 157 int SharedClipboardWinDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList); 170 int SharedClipboardWinTransferGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); 171 int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList); 172 int SharedClipboardWinTransferGetRootsFromClipboard(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); 173 int SharedClipboardWinTransferCreateAndSetDataObject(PSHCLWINCTX pWinCtx, PSHCLCONTEXT pCtx, PSHCLCALLBACKS pCallbacks); 158 174 #endif 159 175 … … 188 204 /** The object is uninitialized (not ready). */ 189 205 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! */ 191 208 Initialized, 209 /** Transfer is running. */ 210 Running, 192 211 /** The operation has been successfully completed. */ 193 212 Completed, … … 200 219 public: 201 220 202 SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer, 203 LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0); 221 SharedClipboardWinDataObject(void); 204 222 virtual ~SharedClipboardWinDataObject(void); 223 224 public: 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); 205 230 206 231 public: /* IUnknown methods. */ … … 234 259 public: 235 260 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); 239 263 240 264 public: … … 257 281 void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL, 258 282 LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL); 283 int setStatusLocked(Status enmStatus, int rc = VINF_SUCCESS); 284 259 285 protected: 260 286 … … 265 291 { 266 292 /** Relative path of the object. */ 267 Utf8Str strPath;293 char *pszPath; 268 294 /** Related (cached) object information. */ 269 295 SHCLFSOBJINFO objInfo; … … 273 299 typedef std::vector<FSOBJENTRY> FsObjEntryList; 274 300 301 /** Shared Clipboard context to use. */ 302 PSHCLCONTEXT m_pCtx; 303 /** Callbacks table to use. */ 304 SHCLCALLBACKS m_Callbacks; 275 305 /** The object's current status. */ 276 306 Status m_enmStatus; … … 290 320 /** List of (cached) file system objects. */ 291 321 FsObjEntryList m_lstEntries; 322 /** Critical section to serialize access. */ 323 RTCRITSECT m_CritSect; 292 324 /** Whether the transfer thread is running. */ 293 bool m_f Running;325 bool m_fThreadRunning; 294 326 /** Event being triggered when reading the transfer list been completed. */ 295 327 RTSEMEVENT m_EventListComplete; 296 /** Event being triggered when the transfer has been completed. */297 RTSEMEVENT m_Event TransferComplete;328 /** Event being triggered when the transfer status has been changed. */ 329 RTSEMEVENT m_EventStatusChanged; 298 330 /** Registered format for CFSTR_FILEDESCRIPTORA. */ 299 331 UINT m_cfFileDescriptorA; … … 310 342 public: 311 343 312 SharedClipboardWinEnumFormatEtc( LPFORMATETC pFormatEtc, ULONG cFormats);344 SharedClipboardWinEnumFormatEtc(void); 313 345 virtual ~SharedClipboardWinEnumFormatEtc(void); 346 347 public: 348 349 int Init(LPFORMATETC pFormatEtc, ULONG cFormats); 350 void Destroy(void); 314 351 315 352 public: /* IUnknown methods. */ -
trunk/include/VBox/GuestHost/SharedClipboard-x11.h
r98103 r100204 42 42 #include <X11/Intrinsic.h> 43 43 44 #include <iprt/req.h> 44 45 #include <iprt/thread.h> 45 46 … … 113 114 /** Flag indicating that the thread is in a started state. */ 114 115 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; 115 120 /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */ 116 121 Widget pWidget; … … 159 164 160 165 /** 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 */ 168 typedef 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. */ 195 typedef SHCLX11REQUEST *PSHCLX11REQUEST; 196 197 /** 198 * Structure describing an X11 clipboard response to an X11 clipboard request. 199 */ 200 typedef 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. */ 210 typedef SHCLX11RESPONSE *PSHCLX11RESPONSE; 172 211 173 212 /** @name Shared Clipboard APIs for X11. … … 179 218 int ShClX11ThreadStartEx(PSHCLX11CTX pCtx, const char *pszName, bool fGrab); 180 219 int ShClX11ThreadStop(PSHCLX11CTX pCtx); 181 int ShClX11ReportFormatsToX11 (PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats);182 int ShClX11ReadDataFromX11 (PSHCLX11CTX pCtx, SHCLFORMATS vboxFormat, CLIPREADCBREQ *pReq);220 int ShClX11ReportFormatsToX11Async(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats); 221 int ShClX11ReadDataFromX11Async(PSHCLX11CTX pCtx, SHCLFORMAT uFmt, uint32_t cbData, PSHCLEVENT pEvent); 183 222 void ShClX11SetCallbacks(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks); 184 223 /** @} */ -
trunk/include/VBox/GuestHost/SharedClipboard.h
r98103 r100204 55 55 /** Shared Clipboard format is HTML. */ 56 56 #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 */ 59 71 # define VBOX_SHCL_FMT_URI_LIST RT_BIT(3) 60 #endif61 72 /** @} */ 62 73 … … 71 82 /** Pointer to a bit map of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */ 72 83 typedef SHCLFORMATS *PSHCLFORMATS; 84 85 /** Defines the default timeout (in ms) to use for clipboard operations. */ 86 #define SHCL_TIMEOUT_DEFAULT_MS RT_MS_30SEC 73 87 74 88 … … 193 207 * @{ 194 208 */ 209 int ShClPayloadInit(uint32_t uID, void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload); 195 210 int ShClPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload); 196 211 void ShClPayloadFree(PSHCLEVENTPAYLOAD pPayload); … … 316 331 * Runs in Xt event thread for the X11 code. 317 332 * 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. 319 335 * @param pCtx Opaque context pointer for the glue code. 320 336 * @param uFmt The format in which the data should be transferred … … 345 361 /** @} */ 346 362 347 /** Opaque request structure for X11 clipboard data.348 * @{ */349 struct CLIPREADCBREQ;350 typedef struct CLIPREADCBREQ CLIPREADCBREQ;351 /** @} */352 353 363 #endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_h */ 354 364 -
trunk/include/VBox/HostServices/VBoxClipboardSvc.h
r100021 r100204 798 798 799 799 /** No listing flags specified. */ 800 #define VBOX_SHCL_LIST_F LAG_NONE0800 #define VBOX_SHCL_LIST_F_NONE 0 801 801 /** Only returns one entry per read. */ 802 #define VBOX_SHCL_LIST_F LAG_RETURN_ONERT_BIT(0)802 #define VBOX_SHCL_LIST_F_RETURN_ONE RT_BIT(0) 803 803 /** 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 807 812 808 813 /** No additional information provided. */ 809 #define VBOX_SHCL_INFO_F LAG_NONE0814 #define VBOX_SHCL_INFO_F_NONE 0 810 815 /** 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 812 819 813 820 /** … … 929 936 /** uint32_t, in: VBOX_SHCL_INFO_FLAG_XXX. */ 930 937 HGCMFunctionParameter fInfo; 931 /** uint 32_t, in: Index of root list entry to get (zero-based). */938 /** uint64_t, in: Index of root list entry to get (zero-based). */ 932 939 HGCMFunctionParameter uIndex; 933 940 } VBoxShClRootListEntryParms; … … 957 964 /** in/out: Request parameters. */ 958 965 VBoxShClRootListEntryParms Parms; 959 /** pointer, in/out: Entry name. */ 966 /** pointer, in/out: Entry name. 967 * Up to SHCLLISTENTRY_MAX_NAME. */ 960 968 HGCMFunctionParameter szName; 961 969 /** uint32_t, out: Bytes to be used for information/How many bytes were used. */ -
trunk/include/VBox/VBoxGuestLib.h
r99739 r100204 688 688 struct 689 689 { 690 /** ID of the tr nasfer. */690 /** ID of the transfer. */ 691 691 SHCLTRANSFERID uID; 692 692 /** Transfer direction. */ 693 693 SHCLTRANSFERDIR enmDir; 694 /** Additional rep roting information. */694 /** Additional reporting information. */ 695 695 SHCLTRANSFERREPORT Report; 696 696 } TransferStatus; … … 717 717 VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures); 718 718 VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures); 719 VBGLR3DECL(int) VbglR3ClipboardMsgPeek(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck); 719 720 VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck); 720 721 VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent); … … 724 725 725 726 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 726 VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PSHCLTRANSFERCALLBACK TABLEpCallbacks);727 VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PSHCLTRANSFERCALLBACKS pCallbacks); 727 728 VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFERCTX pTransferCtx, PVBGLR3CLIPBOARDEVENT pEvent); 728 729 729 730 VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus); 730 731 731 VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCL ROOTLIST *ppRootList);732 VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLLIST *ppRootList); 732 733 733 734 VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots); 734 VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCL ROOTLIST pRootList);735 VBGLR3DECL(int) VbglR3ClipboardRootsWrite(PVBGLR3SHCLCMDCTX pCtx, PSHCL ROOTLISTHDR pRoots);735 VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLIST pRootList); 736 VBGLR3DECL(int) VbglR3ClipboardRootsWrite(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRoots); 736 737 737 738 VBGLR3DECL(int) VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
r100090 r100204 93 93 *********************************************************************************************************************************/ 94 94 #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); 95 static DECLCALLBACK(void) vbtrShClTransferInitializedCallback(PSHCLTXPROVIDERCTX pCtx); 96 static DECLCALLBACK(void) vbtrShClTransferStartedCallback(PSHCLTXPROVIDERCTX pCtx); 97 static DECLCALLBACK(void) vbtrShClTransferErrorCallback(PSHCLTXPROVIDERCTX pCtx, int rc); 99 98 #endif 100 99 … … 108 107 * @param pTransfer Pointer to transfer to cleanup. 109 108 */ 110 static void vb oxClipboardTransferCallbackCleanup(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer)109 static void vbtrShClTransferCallbackCleanup(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer) 111 110 { 112 111 LogFlowFuncEnter(); … … 130 129 } 131 130 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 */ 136 static 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 */ 209 DECLCALLBACK(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 */ 226 static DECLCALLBACK(void) vbtrShClTransferStartedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx) 134 227 { 135 228 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser; 136 229 AssertPtr(pCtx); 137 230 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 */ 271 static DECLCALLBACK(void) vbtrShClTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion) 147 272 { 148 273 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser; 149 274 AssertPtr(pCtx); 150 275 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 */ 283 static DECLCALLBACK(void) vbtrShClTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError) 204 284 { 205 285 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser; 206 286 AssertPtr(pCtx); 207 287 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 220 288 LogRel(("Shared Clipboard: Transfer to destination failed with %Rrc\n", rcError)); 221 289 222 vb oxClipboardTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer);290 vbtrShClTransferCallbackCleanup(&pCtx->TransferCtx, pCbCtx->pTransfer); 223 291 } 224 292 225 293 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 226 294 227 static LRESULT vb oxClipboardWinProcessMsg(PSHCLCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)295 static LRESULT vbtrShClWndProcWorker(PSHCLCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 228 296 { 229 297 AssertPtr(pCtx); … … 335 403 } 336 404 337 case WM_RENDERFORMAT: 405 case WM_RENDERFORMAT: /* Guest wants to render the clipboard data. */ 338 406 { 339 407 LogFunc(("WM_RENDERFORMAT\n")); … … 346 414 LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat)); 347 415 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 348 422 if (fFormat == VBOX_SHCL_FMT_NONE) 349 423 { 350 Log Func(("WM_RENDERFORMAT: Unsupported format requested\n"));424 LogRel(("Shared Clipboard: Unsupported format (%#x) requested\n", cfFormat)); 351 425 SharedClipboardWinClear(); 352 426 } … … 535 609 } 536 610 537 case SHCL_WIN_WM_REPORT_FORMATS: 611 case SHCL_WIN_WM_REPORT_FORMATS: /* Host reported clipboard formats. */ 538 612 { 539 613 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS\n")); … … 546 620 const SHCLFORMATS fFormats = pEvent->u.fReportedFormats; 547 621 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 548 628 if (fFormats != VBOX_SHCL_FMT_NONE) /* Could arrive with some older GA versions. */ 549 629 { 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 { 555 635 /* 556 636 * Creating and starting the actual transfer will be done in vbglR3ClipboardTransferStart() as soon … … 558 638 * Transfers always are controlled and initiated on the host side! 559 639 * 560 * So don't announce the transfer to the OS here yet. Don't touch the clipboard in any way here; otherwise561 * 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". 562 642 */ 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); 569 648 } 570 649 #endif … … 575 654 } 576 655 577 case SHCL_WIN_WM_READ_DATA: 656 case SHCL_WIN_WM_READ_DATA: /* Host wants to read clipboard data from the guest. */ 578 657 { 579 658 /* Send data in the specified format to the host. */ … … 585 664 586 665 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 588 672 int rc = SharedClipboardWinOpen(hwnd); 589 673 HANDLE hClip = NULL; … … 673 757 } 674 758 675 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS676 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 #endif701 759 case WM_DESTROY: 702 760 { … … 726 784 } 727 785 728 static LRESULT CALLBACK vb oxClipboardWinWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);729 730 static int vb oxClipboardCreateWindow(PSHCLCONTEXT pCtx)786 static LRESULT CALLBACK vbtrShClWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 787 788 static int vbtrShClCreateWindow(PSHCLCONTEXT pCtx) 731 789 { 732 790 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 747 805 { 748 806 wc.style = CS_NOCLOSE; 749 wc.lpfnWndProc = vb oxClipboardWinWndProc;807 wc.lpfnWndProc = vbtrShClWndProc; 750 808 wc.hInstance = pCtx->pEnv->hInstance; 751 809 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); … … 788 846 } 789 847 790 static DECLCALLBACK(int) vb oxClipboardWindowThread(RTTHREAD hThread, void *pvUser)848 static DECLCALLBACK(int) vbtrShClWindowThread(RTTHREAD hThread, void *pvUser) 791 849 { 792 850 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pvUser; … … 802 860 else 803 861 LogRel(("Shared Clipboard: Initialized OLE in window thread\n")); 804 #endif 805 806 int rc = vb oxClipboardCreateWindow(pCtx);862 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 863 864 int rc = vbtrShClCreateWindow(pCtx); 807 865 if (RT_FAILURE(rc)) 808 866 { … … 855 913 } 856 914 857 static void vboxClipboardDestroy(PSHCLCONTEXT pCtx) 858 { 915 static 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 924 DECLCALLBACK(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 991 DECLCALLBACK(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 1156 DECLCALLBACK(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 1180 DECLCALLBACK(void) vbtrShClDestroy(void *pInstance) 1181 { 1182 AssertPtrReturnVoid(pInstance); 1183 1184 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance; 859 1185 AssertPtrReturnVoid(pCtx); 1186 1187 /* Make sure that we are disconnected. */ 1188 Assert(pCtx->CmdCtx.idClient == 0); 860 1189 861 1190 LogFlowFunc(("pCtx=%p\n", pCtx)); … … 884 1213 SharedClipboardWinCtxDestroy(&pCtx->Win); 885 1214 1215 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 1216 ShClTransferCtxDestroy(&pCtx->TransferCtx); 1217 #endif 1218 1219 RTReqQueueDestroy(pCtx->Win.hReqQ); 1220 886 1221 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_TRANSFERS926 /*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 #endif940 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_TRANSFERS949 rc = ShClTransferCtxInit(&pCtx->TransferCtx);950 #endif951 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 else972 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 continue990 * 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_TRANSFERS1002 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 else1009 LogRel(("Shared Clipboard: Initialized OLE in worker thread\n"));1010 #endif1011 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_TRANSFERS1029 rc = VbglR3ClipboardEventGetNextEx(idMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);1030 #else1031 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, &pCtx->CmdCtx, pEvent);1032 #endif1033 }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 else1050 {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 later1060 * 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_TRANSFERS1086 case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:1087 {1088 /* Nothing to do here. */1089 rc = VINF_SUCCESS;1090 break;1091 }1092 #endif1093 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_TRANSFERS1120 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */1121 OleUninitialize();1122 #endif1123 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_TRANSFERS1165 ShClTransferCtxDestroy(&pCtx->TransferCtx);1166 #endif1167 1222 1168 1223 return; … … 1179 1234 "Shared Clipboard", 1180 1235 /* methods */ 1181 VBoxShClInit,1182 VBoxShClWorker,1183 VBoxShClStop,1184 VBoxShClDestroy1236 vbtrShClInit, 1237 vbtrShClWorker, 1238 vbtrShClStop, 1239 vbtrShClDestroy 1185 1240 }; -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
r99739 r100204 98 98 static VBOXSERVICEINFO g_aServices[] = 99 99 { 100 { &g_SvcDescDnD, NIL_RTTHREAD, NULL, false, false, false, false, true }100 { &g_SvcDescClipboard, NIL_RTTHREAD, NULL, false, false, false, false, true } 101 101 }; 102 102 #else … … 533 533 RTLogSetDefaultInstance(g_pLoggerRelease); 534 534 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" }; 536 537 char szGroupSettings[_1K]; 537 538 -
trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
r100015 r100204 54 54 #include <iprt/string.h> 55 55 #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> 56 62 57 63 #include "VBoxGuestR3LibInternal.h" … … 176 182 { 177 183 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS)) 178 LogRel 2(("Shared Clipboard: Host does not support transfers\n"));184 LogRel(("Shared Clipboard: Host does not support transfers\n")); 179 185 } 180 186 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ … … 424 430 * Reads data from the host clipboard. 425 431 * 426 * Legacy function, do not use anymore.427 *428 432 * @returns VBox status code. 429 433 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for. … … 433 437 * @param pvData Where to store the data. 434 438 * @param cbData The size of the buffer pointed to by \a pvData. 439 * This also indicates the maximum size to read. 435 440 * @param pcbRead The actual size of the host clipboard data. May be larger than \a cbData. 436 441 */ … … 438 443 uint32_t *pcbRead) 439 444 { 440 LogFlowFunc Enter();445 LogFlowFunc(("fFormat=%#x, pvData=%p, cbData=%RU32\n", fFormat, pvData, cbData)); 441 446 442 447 struct … … 532 537 533 538 /** 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 */ 562 static 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 /** 534 630 * Peeks at the next host message, waiting for one to turn up. 535 631 * … … 556 652 uint32_t *pcParameters, uint64_t *pidRestoreCheck) 557 653 { 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 */ 680 VBGLR3DECL(int) VbglR3ClipboardMsgPeek(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, 681 uint32_t *pcParameters, uint64_t *pidRestoreCheck) 682 { 683 return vbglR3ClipboardMsgPeekEx(pCtx, false /* fWait */, pidMsg, pcParameters, pidRestoreCheck); 618 684 } 619 685 … … 627 693 * @param pRootListHdr Where to store the received root list header. 628 694 */ 629 static int vbglR3ClipboardRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCL ROOTLISTHDR pRootListHdr)695 static int vbglR3ClipboardRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr) 630 696 { 631 697 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 645 711 if (RT_SUCCESS(rc)) 646 712 { 647 rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->f Roots); AssertRC(rc);648 if (RT_SUCCESS(rc)) 649 { 650 rc = Msg.cRoots.GetUInt64(&pRootListHdr->c Roots);713 rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fFeatures); AssertRC(rc); 714 if (RT_SUCCESS(rc)) 715 { 716 rc = Msg.cRoots.GetUInt64(&pRootListHdr->cEntries); 651 717 AssertRC(rc); 718 719 pRootListHdr->cbTotalSize = 0; /* Unused for the root list header. */ 652 720 } 653 721 } … … 665 733 * @param pRootListEntry Where to store the root list entry read from the host. 666 734 */ 667 static int vbglR3ClipboardRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint 32_t uIndex, PSHCLROOTLISTENTRY pRootListEntry)735 static int vbglR3ClipboardRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint64_t uIndex, PSHCLLISTENTRY pRootListEntry) 668 736 { 669 737 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 675 743 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ); 676 744 745 uint32_t const fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; /* For now the only info we have. */ 746 677 747 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); 697 799 698 800 LogFlowFuncLeaveRC(rc); … … 705 807 * @returns VBox status code. 706 808 * @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 */ 812 VBGLR3DECL(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)) 724 828 { 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 */); 744 832 } 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 } 756 841 757 842 LogFlowFuncLeaveRC(rc); … … 891 976 * @param pRootListHdr Root lsit header to reply to the host. 892 977 */ 893 VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCL ROOTLISTHDR pRootListHdr)978 VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr) 894 979 { 895 980 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 901 986 902 987 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext); 903 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->f Roots);904 905 Msg.cRoots.SetUInt64(pRootListHdr->c Roots);988 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fFeatures); 989 990 Msg.cRoots.SetUInt64(pRootListHdr->cEntries); 906 991 907 992 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); … … 961 1046 * @param pEntry Actual root list entry to reply. 962 1047 */ 963 VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCL ROOTLISTENTRY pEntry)1048 VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLLISTENTRY pEntry) 964 1049 { 965 1050 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 1202 1287 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures); 1203 1288 if (RT_SUCCESS(rc)) 1204 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->c TotalObjects);1289 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cEntries); 1205 1290 if (RT_SUCCESS(rc)) 1206 1291 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize); … … 1271 1356 Msg.fFeatures.SetUInt32(0); 1272 1357 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures); 1273 Msg.cTotalObjects.SetUInt64(pListHdr->c TotalObjects);1358 Msg.cTotalObjects.SetUInt64(pListHdr->cEntries); 1274 1359 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize); 1275 1360 … … 1681 1766 Msg.uContext.SetUInt64(pCtx->idContext); 1682 1767 Msg.uHandle.SetUInt64(hObj); 1768 Msg.cbData.SetUInt32(cbData); 1683 1769 Msg.pvData.SetPtr(pvData, cbData); 1770 Msg.cbChecksum.SetUInt32(0); 1684 1771 Msg.pvChecksum.SetPtr(NULL, 0); 1685 1772 … … 1702 1789 *********************************************************************************************************************************/ 1703 1790 1704 /** @copydoc SHCLTXPROVIDERIFACE::pfnRoot sGet*/1705 static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceRoot sGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)1791 /** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */ 1792 static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx) 1706 1793 { 1707 1794 LogFlowFuncEnter(); … … 1710 1797 AssertPtr(pCmdCtx); 1711 1798 1712 int rc = VbglR3ClipboardRootListRead(pCmdCtx, p pRootList);1799 int rc = VbglR3ClipboardRootListRead(pCmdCtx, pCtx->pTransfer); 1713 1800 1714 1801 LogFlowFuncLeaveRC(rc); … … 1832 1919 1833 1920 /** 1834 * Starts a transfer on the guest side.1921 * Initializes a transfer on the guest side. 1835 1922 * 1836 1923 * @returns VBox status code. 1837 1924 * @param pCmdCtx Command context to use. 1838 * @param pTransferCtx Transfer context to createtransfer 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. 1842 1929 * @param ppTransfer Where to return the transfer object on success. Optional. 1843 1930 */ 1844 static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, 1845 SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, 1846 PSHCLTRANSFER *ppTransfer) 1847 { 1931 static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, 1932 SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, 1933 PSHCLTRANSFER *ppTransfer) 1934 { 1935 LogFlowFuncEnter(); 1936 1848 1937 PSHCLTRANSFER pTransfer; 1849 1938 int rc = ShClTransferCreate(&pTransfer); 1850 1939 if (RT_SUCCESS(rc)) 1851 1940 { 1941 /* Set the callbacks the (OS-dependent) implementation relies on. Optional. */ 1852 1942 ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks); 1853 1943 … … 1855 1945 if (RT_SUCCESS(rc)) 1856 1946 { 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. */ 1858 1974 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); 1889 1976 1890 1977 if (RT_FAILURE(rc)) … … 1898 1985 *ppTransfer = pTransfer; 1899 1986 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")); 1904 1990 } 1905 1991 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 */ 2019 static 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 */ 2068 static 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; 1907 2090 1908 2091 /* Send a reply in any case. */ … … 1913 2096 rc = rc2; 1914 2097 1915 if (RT_FAILURE(rc))1916 {1917 ShClTransferDestroy(pTransfer);1918 pTransfer = NULL;1919 }1920 1921 2098 LogFlowFuncLeaveRC(rc); 1922 2099 return rc; … … 1934 2111 SHCLTRANSFERID uTransferID) 1935 2112 { 2113 LogFlowFuncEnter(); 2114 1936 2115 int rc; 1937 2116 … … 1942 2121 if (RT_SUCCESS(rc)) 1943 2122 { 1944 LogRel 2(("Shared Clipboard: Transfer ID=%RU32 successfully stopped\n", uTransferID));2123 LogRel(("Shared Clipboard: Transfer %RU32 successfully stopped\n", uTransferID)); 1945 2124 } 1946 2125 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)); 1954 2127 } 1955 2128 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; 1957 2137 1958 2138 LogFlowFuncLeaveRC(rc); … … 1966 2146 * @param pCallbacks Pointer to callback table to set. 1967 2147 */ 1968 VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACK TABLEpCallbacks)2148 VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACKS pCallbacks) 1969 2149 { 1970 2150 AssertPtrReturnVoid(pCmdCtx); … … 2000 2180 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext); 2001 2181 2002 Log FlowFunc(("[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)); 2004 2184 2005 2185 switch (transferReport.uStatus) 2006 2186 { 2187 case SHCLTRANSFERSTATUS_NONE: 2188 AssertFailed(); /* Should never happen. */ 2189 break; 2190 2007 2191 case SHCLTRANSFERSTATUS_INITIALIZED: 2008 RT_FALL_THROUGH();2009 case SHCLTRANSFERSTATUS_STARTED:2010 2192 { 2011 2193 SHCLSOURCE enmSource = SHCLSOURCE_INVALID; 2012 2194 2013 2195 /* 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 */ 2015 2197 { 2016 2198 enmDir = SHCLTRANSFERDIR_FROM_REMOTE; 2017 2199 enmSource = SHCLSOURCE_REMOTE; 2200 2201 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransferCtx, uTransferID, 2202 enmDir, enmSource, NULL /* ppTransfer */); 2018 2203 } 2019 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) 2204 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host */ 2020 2205 { 2206 /* Already initialized when remote (host) was reading the URI data. */ 2021 2207 enmDir = SHCLTRANSFERDIR_TO_REMOTE; 2022 2208 enmSource = SHCLSOURCE_LOCAL; 2209 2210 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransferCtx, uTransferID, 2211 enmDir, enmSource, NULL /* ppTransfer */); 2023 2212 } 2024 2213 else 2025 2214 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER); 2026 2215 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); 2029 2228 break; 2030 2229 } … … 2044 2243 2045 2244 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)); 2046 2248 rc = VERR_NOT_SUPPORTED; 2047 2249 break; … … 2055 2257 2056 2258 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));2061 2259 } 2062 2260 } … … 2077 2275 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND); 2078 2276 2079 SHCL ROOTLISTHDR rootListHdr;2080 RT_ZERO(rootListHdr);2081 2082 rootListHdr.c Roots = ShClTransferRootsCount(pTransfer);2083 2084 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.c Roots));2277 SHCLLISTHDR rootListHdr; 2278 ShClTransferListHdrInit(&rootListHdr); 2279 2280 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer); 2281 2282 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries)); 2085 2283 2086 2284 rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr); … … 2100 2298 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND); 2101 2299 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; 2106 2307 } 2107 2308 break; … … 2553 2754 VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData) 2554 2755 { 2555 LogFlowFunc(("ENTER: fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));2556 2756 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)); 2559 2760 2560 2761 int rc; -
trunk/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h
r98103 r100204 71 71 72 72 /* The shared clipboard service prototypes. */ 73 int VBoxShClInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);73 int vbtrShClInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread); 74 74 unsigned __stdcall VBoxShClThread(void *pInstance); 75 void VBoxShClDestroy(const VBOXSERVICEENV *pEnv, void *pInstance);75 void vbtrShClDestroy(const VBOXSERVICEENV *pEnv, void *pInstance); 76 76 77 77 #endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h */ -
trunk/src/VBox/Additions/x11/VBoxClient/clipboard-x11.cpp
r99987 r100204 40 40 #include <iprt/semaphore.h> 41 41 42 #include <VBox/log.h> 42 #define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD 43 #include <iprt/log.h> 44 43 45 #include <VBox/VBoxGuestLib.h> 44 46 #include <VBox/HostServices/VBoxClipboardSvc.h> … … 50 52 #include "clipboard.h" 51 53 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 */ 62 static 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 */ 78 static 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 */ 113 static 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 */ 156 static 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 */ 174 static 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 */ 187 static 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 */ 199 static 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 */ 208 static 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 */ 53 281 static DECLCALLBACK(int) vbclX11OnRequestDataFromSourceCallback(PSHCLCONTEXT pCtx, 54 282 SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser) … … 58 286 LogFlowFunc(("pCtx=%p, uFmt=%#x\n", pCtx, uFmt)); 59 287 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 63 295 if (uFmt == VBOX_SHCL_FMT_URI_LIST) 64 296 { 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) 94 304 { 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 } 98 321 } 99 322 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")); 110 324 } 111 325 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 */ 122 329 123 330 if (RT_FAILURE(rc)) … … 129 336 130 337 /** 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 */ 340 static 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 */ 141 359 static DECLCALLBACK(int) vbclX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser) 142 360 { 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; 168 369 } 169 370 … … 181 382 Callbacks.pfnReportFormats = vbclX11ReportFormatsCallback; 182 383 Callbacks.pfnOnRequestDataFromSource = vbclX11OnRequestDataFromSourceCallback; 183 Callbacks.pfnOnSendDataToDest = vbclX11OnSendDataToDestCallback;184 384 185 385 int rc = ShClX11Init(&g_Ctx.X11, &Callbacks, &g_Ctx, false /* fHeadless */); … … 220 420 } 221 421 222 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP223 /** @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 262 422 /** 263 423 * The main loop of the X11-specifc Shared Clipboard code. 264 424 * 265 425 * @returns VBox status code. 426 * 427 * @thread Clipboard service worker thread. 266 428 */ 267 429 int VBClX11ClipboardMain(void) 268 430 { 269 int rc;270 271 431 PSHCLCONTEXT pCtx = &g_Ctx; 432 433 int rc = RTReqQueueCreate(&pCtx->X11.hReqQ); 434 AssertRCReturn(rc, rc); 272 435 273 436 bool fShutdown = false; … … 286 449 pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT); 287 450 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; 291 455 # endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ 292 456 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 293 457 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; 295 463 for (;;) 296 464 { 297 PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT)); 465 if (!pEvent) 466 pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT)); 298 467 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));302 468 303 469 uint32_t idMsg = 0; 304 470 uint32_t cParms = 0; 305 rc = VbglR3ClipboardMsgPeek Wait(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);471 rc = VbglR3ClipboardMsgPeek(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */); 306 472 if (RT_SUCCESS(rc)) 307 473 { … … 312 478 #endif 313 479 } 480 else if (rc == VERR_TRY_AGAIN) /* No new message (yet). */ 481 { 482 RTReqQueueProcess(pCtx->X11.hReqQ, RT_MS_1SEC); 483 continue; 484 } 314 485 315 486 if (RT_FAILURE(rc)) … … 324 495 325 496 /* Wait a bit before retrying. */ 326 RTThreadSleep( 1000);497 RTThreadSleep(RT_MS_1SEC); 327 498 continue; 328 499 } … … 336 507 case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS: 337 508 { 338 ShClX11ReportFormatsToX11 (&g_Ctx.X11, pEvent->u.fReportedFormats);509 ShClX11ReportFormatsToX11Async(&g_Ctx.X11, pEvent->u.fReportedFormats); 339 510 break; 340 511 } … … 342 513 case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA: 343 514 { 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)) 348 518 { 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; 351 544 } 352 else 353 rc = VERR_NO_MEMORY; 545 546 if (RT_FAILURE(rc)) 547 VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pEvent->u.fReadData, NULL, 0); 548 354 549 break; 355 550 } … … 365 560 case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS: 366 561 { 367 /* Nothing to do here. */ 562 if (pEvent->u.TransferStatus.Report.uStatus == SHCLTRANSFERSTATUS_STARTED) 563 { 564 565 } 368 566 rc = VINF_SUCCESS; 369 567 break; … … 394 592 } 395 593 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 33 33 34 34 /** 35 * Struct keeping a Shared Clipboard context.35 * Struct keeping am X11 Shared Clipboard context. 36 36 */ 37 37 struct SHCLCONTEXT … … 45 45 union 46 46 { 47 /** Event source for waiting for request responses. */ 48 SHCLEVENTSOURCE EventSrc; 47 49 /** X11 clipboard context. */ 48 50 SHCLX11CTX X11; -
trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp
r99967 r100204 38 38 #include <iprt/win/shlwapi.h> 39 39 40 #include <iprt/thread.h> // REMOVE 41 40 42 #include <iprt/asm.h> 41 43 #include <iprt/err.h> … … 52 54 //#define VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 1 53 55 54 SharedClipboardWinDataObject::SharedClipboardWinDataObject( PSHCLTRANSFER pTransfer,55 LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)56 :m_enmStatus(Uninitialized)56 SharedClipboardWinDataObject::SharedClipboardWinDataObject(void) 57 : m_pCtx(NULL) 58 , m_enmStatus(Uninitialized) 57 59 , m_lRefCount(0) 58 60 , m_cFormats(0) 59 , m_pTransfer( pTransfer)61 , m_pTransfer(NULL) 60 62 , m_pStream(NULL) 61 63 , m_uObjIdx(0) 62 , m_f Running(false)64 , m_fThreadRunning(false) 63 65 , m_EventListComplete(NIL_RTSEMEVENT) 64 , m_EventTransferComplete(NIL_RTSEMEVENT) 65 { 66 AssertPtr(m_pTransfer); 67 68 HRESULT hr; 66 , m_EventStatusChanged(NIL_RTSEMEVENT) 67 { 68 } 69 70 SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void) 71 { 72 Destroy(); 73 74 LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount)); 75 } 76 77 /** 78 * Initializes a data object instance. 79 * 80 * @returns VBox status code. 81 * @param pFormatEtc FormatETC to use. 82 * @param pStgMed Storage medium to use. 83 * @param cFormats Number of formats in \a pFormatEtc and \a pStgMed. 84 */ 85 int SharedClipboardWinDataObject::Init(PSHCLCONTEXT pCtx, 86 LPFORMATETC pFormatEtc /* = NULL */, LPSTGMEDIUM pStgMed /* = NULL */, 87 ULONG cFormats /* = 0 */) 88 { 89 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 90 AssertReturn(cFormats == 0 || (RT_VALID_PTR(pFormatEtc) && RT_VALID_PTR(pStgMed)), VERR_INVALID_POINTER); 91 92 int rc = VINF_SUCCESS; 93 94 m_pCtx = pCtx; /* Save opaque context. */ 69 95 70 96 ULONG cFixedFormats = 3; /* CFSTR_FILEDESCRIPTORA + CFSTR_FILECONTENTS + CFSTR_PERFORMEDDROPEFFECT */ … … 74 100 const ULONG cAllFormats = cFormats + cFixedFormats; 75 101 76 try77 {78 m_pFormatEtc = new FORMATETC[cAllFormats];79 RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats);80 m_pStgMedium = new STGMEDIUM[cAllFormats];81 82 83 84 85 86 87 88 89 90 91 92 102 m_pFormatEtc = new FORMATETC[cAllFormats]; 103 AssertPtrReturn(m_pFormatEtc, VERR_NO_MEMORY); 104 RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats); 105 m_pStgMedium = new STGMEDIUM[cAllFormats]; 106 AssertPtrReturn(m_pStgMedium, VERR_NO_MEMORY); 107 RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cAllFormats); 108 109 /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */ 110 111 /* 112 * Register fixed formats. 113 */ 114 unsigned uIdx = 0; 115 116 LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n")); 117 m_cfFileDescriptorA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA); 118 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorA); 93 119 #ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 94 95 96 120 LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n")); 121 m_cfFileDescriptorW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); 122 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorW); 97 123 #endif 98 124 99 /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */ 100 LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n")); 101 m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS); 102 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */); 103 104 /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */ 105 LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n")); 106 m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); 107 registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT); 108 109 /* 110 * Registration of dynamic formats needed? 111 */ 112 LogFlowFunc(("%RU32 dynamic formats\n", cFormats)); 113 if (cFormats) 114 { 115 AssertPtr(pFormatEtc); 116 AssertPtr(pStgMed); 117 118 for (ULONG i = 0; i < cFormats; i++) 119 { 120 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n", 121 i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect)); 122 m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i]; 123 m_pStgMedium[cFixedFormats + i] = pStgMed[i]; 124 } 125 } 126 127 hr = S_OK; 128 } 129 catch (std::bad_alloc &) 130 { 131 hr = E_OUTOFMEMORY; 132 } 133 134 if (SUCCEEDED(hr)) 125 /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */ 126 LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n")); 127 m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS); 128 registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */); 129 130 /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */ 131 LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n")); 132 m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); 133 registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT); 134 135 /* 136 * Registration of dynamic formats needed? 137 */ 138 LogFlowFunc(("%RU32 dynamic formats\n", cFormats)); 139 if (cFormats) 140 { 141 for (ULONG i = 0; i < cFormats; i++) 142 { 143 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n", 144 i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect)); 145 m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i]; 146 m_pStgMedium[cFixedFormats + i] = pStgMed[i]; 147 } 148 } 149 150 if (RT_SUCCESS(rc)) 135 151 { 136 152 m_cFormats = cAllFormats; 137 153 m_enmStatus = Initialized; 138 154 139 int rc2 = RTSemEventCreate(&m_EventListComplete); 140 AssertRC(rc2); 141 rc2 = RTSemEventCreate(&m_EventTransferComplete); 142 AssertRC(rc2); 143 } 144 145 LogFlowFunc(("cAllFormats=%RU32, hr=%Rhrc\n", cAllFormats, hr)); 146 } 147 148 SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void) 155 rc = RTCritSectInit(&m_CritSect); 156 if (RT_SUCCESS(rc)) 157 { 158 rc = RTSemEventCreate(&m_EventListComplete); 159 if (RT_SUCCESS(rc)) 160 rc = RTSemEventCreate(&m_EventStatusChanged); 161 } 162 } 163 164 LogFlowFunc(("cAllFormats=%RU32, rc=%Rrc\n", cAllFormats, rc)); 165 return rc; 166 } 167 168 /** 169 * Destroys a data object instance. 170 */ 171 void SharedClipboardWinDataObject::Destroy(void) 149 172 { 150 173 LogFlowFuncEnter(); 151 174 152 RTSemEventDestroy(m_EventListComplete); 153 m_EventListComplete = NIL_RTSEMEVENT; 154 155 RTSemEventDestroy(m_EventTransferComplete); 156 m_EventTransferComplete = NIL_RTSEMEVENT; 175 AssertReturnVoid(m_lRefCount == 0); 176 177 int rc = RTCritSectDelete(&m_CritSect); 178 AssertRC(rc); 179 180 if (m_EventListComplete != NIL_RTSEMEVENT) 181 { 182 rc = RTSemEventDestroy(m_EventListComplete); 183 AssertRC(rc); 184 m_EventListComplete = NIL_RTSEMEVENT; 185 } 186 187 if (m_EventStatusChanged != NIL_RTSEMEVENT) 188 { 189 rc = RTSemEventDestroy(m_EventStatusChanged); 190 AssertRC(rc); 191 m_EventStatusChanged = NIL_RTSEMEVENT; 192 } 157 193 158 194 if (m_pStream) 195 { 159 196 m_pStream->Release(); 197 m_pStream = NULL; 198 } 160 199 161 200 if (m_pFormatEtc) 201 { 162 202 delete[] m_pFormatEtc; 203 m_pFormatEtc = NULL; 204 } 163 205 164 206 if (m_pStgMedium) 207 { 165 208 delete[] m_pStgMedium; 166 167 LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount)); 168 } 169 170 /* 209 m_pStgMedium = NULL; 210 } 211 212 if (m_pTransfer) 213 ShClTransferRelease(m_pTransfer); 214 215 FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin(); 216 while (itRoot != m_lstEntries.end()) 217 { 218 RTStrFree(itRoot->pszPath); 219 ++itRoot; 220 } 221 m_lstEntries.clear(); 222 223 m_enmStatus = Uninitialized; 224 m_fThreadRunning = false; 225 m_pTransfer = NULL; 226 } 227 228 /** 229 * Sets the callbacks for this object. 230 * 231 * @param pCallbacks Pointer to callbacks table to use. 232 */ 233 void SharedClipboardWinDataObject::SetCallbacks(PSHCLCALLBACKS pCallbacks) 234 { 235 AssertPtrReturnVoid(pCallbacks); 236 237 RT_ZERO(m_Callbacks); 238 239 m_Callbacks.pfnOnRequestDataFromSource = pCallbacks->pfnOnRequestDataFromSource; 240 } 241 242 243 /********************************************************************************************************************************* 171 244 * IUnknown methods. 172 * /245 ********************************************************************************************************************************/ 173 246 174 247 STDMETHODIMP_(ULONG) SharedClipboardWinDataObject::AddRef(void) … … 270 343 { 271 344 LogFlowFunc(("cTotalObjects=%RU64, cbTotalSize=%RU64\n\n", 272 hdrList.c TotalObjects, hdrList.cbTotalSize));273 274 for (uint64_t o = 0; o < hdrList.c TotalObjects; o++)345 hdrList.cEntries, hdrList.cbTotalSize)); 346 347 for (uint64_t o = 0; o < hdrList.cEntries; o++) 275 348 { 276 349 SHCLLISTENTRY entryList; … … 291 364 entryList.pszName, pFsObjInfo->cbObject, strPath.c_str())); 292 365 293 if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode)) 366 if ( RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode) 367 || RTFS_IS_FILE (pFsObjInfo->Attr.fMode)) 294 368 { 295 FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo }; 296 297 m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ 298 299 rc = readDir(pTransfer, strPath.c_str()); 300 } 301 else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode)) 302 { 303 FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo }; 369 FSOBJENTRY objEntry; 370 objEntry.pszPath = RTStrDup(strPath.c_str()); 371 AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY); 372 objEntry.objInfo = *pFsObjInfo; 304 373 305 374 m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ 306 375 } 307 else 308 rc = VERR_NOT_SUPPORTED; 376 else /* Not fatal, just skip. */ 377 LogRel(("Shared Clipboard: Warning: File system object '%s' of type %#x not supported, skipping\n", 378 strPath.c_str(), pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK)); 309 379 310 380 /** @todo Handle symlinks. */ … … 330 400 } 331 401 402 if (RT_FAILURE(rc)) 403 LogRel(("Shared Clipboard: Reading directory '%s' failed with %Rrc\n", strDir.c_str(), rc)); 404 332 405 LogFlowFuncLeaveRC(rc); 333 406 return rc; … … 362 435 LogRel2(("Shared Clipboard: Calculating transfer ...\n")); 363 436 364 PSHCLROOTLIST pRootList; 365 int rc = ShClTransferRootsGet(pTransfer, &pRootList); 437 int rc = ShClTransferRootListRead(pTransfer); 366 438 if (RT_SUCCESS(rc)) 367 439 { 368 LogFlowFunc(("cRoots=%RU32\n\n", pRootList->Hdr.cRoots)); 369 370 for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++) 371 { 372 PSHCLLISTENTRY pRootEntry = &pRootList->paEntries[i]; 373 AssertPtr(pRootEntry); 374 375 Assert(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO)); 376 PSHCLFSOBJINFO pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo; 377 378 LogFlowFunc(("pszRoot=%s, fMode=0x%x\n", pRootEntry->pszName, pFsObjInfo->Attr.fMode)); 440 uint64_t const cRoots = ShClTransferRootsCount(pTransfer); 441 442 LogFlowFunc(("cRoots=%RU64\n\n", cRoots)); 443 444 for (uint32_t i = 0; i < cRoots; i++) 445 { 446 PCSHCLLISTENTRY pRootEntry = ShClTransferRootsEntryGet(pTransfer, i); 447 448 AssertBreakStmt(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO), rc = VERR_INVALID_PARAMETER); 449 PSHCLFSOBJINFO const pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo; 450 451 LogFlowFunc(("pszRoot=%s, fMode=0x%x (type %#x)\n", 452 pRootEntry->pszName, pFsObjInfo->Attr.fMode, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK))); 379 453 380 454 if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode)) 381 455 { 382 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo }; 456 FSOBJENTRY objEntry; 457 objEntry.pszPath = RTStrDup(pRootEntry->pszName); 458 AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY); 459 objEntry.objInfo = *pFsObjInfo; 383 460 384 461 pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ … … 388 465 else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode)) 389 466 { 390 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo }; 467 FSOBJENTRY objEntry; 468 objEntry.pszPath = RTStrDup(pRootEntry->pszName); 469 AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY); 470 objEntry.objInfo = *pFsObjInfo; 391 471 392 472 pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */ 393 473 } 394 474 else 475 { 476 LogRel(("Shared Clipboard: Root entry '%s': File type %#x not supported\n", 477 pRootEntry->pszName, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK))); 395 478 rc = VERR_NOT_SUPPORTED; 479 } 396 480 397 481 if (ASMAtomicReadBool(&pTransfer->Thread.fStop)) … … 404 488 break; 405 489 } 406 407 ShClTransferRootListFree(pRootList);408 pRootList = NULL;409 490 410 491 if ( RT_SUCCESS(rc) … … 424 505 LogRel2(("Shared Clipboard: Waiting for transfer to complete ...\n")); 425 506 426 LogFlowFunc(("Waiting for transfer to complete ...\n"));427 428 507 /* Transferring stuff can take a while, so don't use any timeout here. */ 429 rc2 = RTSemEventWait(pThis->m_Event TransferComplete, RT_INDEFINITE_WAIT);508 rc2 = RTSemEventWait(pThis->m_EventStatusChanged, RT_INDEFINITE_WAIT); 430 509 AssertRC(rc2); 431 510 … … 499 578 char *pszFileSpec = NULL; 500 579 501 FsObjEntryList::const_iterator itRoot = m_lstEntries. begin();580 FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin(); 502 581 while (itRoot != m_lstEntries.end()) 503 582 { … … 505 584 RT_BZERO(pFD, cbFileDescriptor); 506 585 507 const char *pszFile = itRoot-> strPath.c_str();586 const char *pszFile = itRoot->pszPath; 508 587 AssertPtr(pszFile); 509 588 … … 584 663 585 664 /** 586 * Retrieves the data stored in this object and store the result in 587 * pMedium. 588 * 589 * @return IPRT status code. 665 * Retrieves the data stored in this object and store the result in pMedium. 666 * 590 667 * @return HRESULT 591 * @param pFormatEtc 592 * @param pMedium 668 * @param pFormatEtc Format to retrieve. 669 * @param pMedium Where to store the data on success. 670 * 671 * @thread Windows event thread. 593 672 */ 594 673 STDMETHODIMP SharedClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium) … … 597 676 AssertPtrReturn(pMedium, DV_E_FORMATETC); 598 677 599 LogFlowFuncEnter(); 600 601 LogFlowFunc(("lIndex=%RI32\n", pFormatEtc->lindex)); 678 int rc2 = RTCritSectEnter(&m_CritSect); 679 AssertRCReturn(rc2, E_UNEXPECTED); 680 681 LogFlowFunc(("lIndex=%RI32, enmStatus=%#x\n", pFormatEtc->lindex, m_enmStatus)); 602 682 603 683 /* … … 607 687 608 688 HRESULT hr = DV_E_FORMATETC; /* Play safe. */ 689 690 int rc = VINF_SUCCESS; 609 691 610 692 if ( pFormatEtc->cfFormat == m_cfFileDescriptorA … … 614 696 ) 615 697 { 616 const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW; 617 618 const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer); 619 RT_NOREF(enmTransferStatus); 620 621 LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n", 622 fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fRunning)); 623 624 int rc; 625 626 /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */ 627 if (!m_fRunning) 628 { 629 /* Start the transfer asynchronously in a separate thread. */ 630 rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this); 631 if (RT_SUCCESS(rc)) 698 switch (m_enmStatus) 699 { 700 case Initialized: 632 701 { 633 m_fRunning = true; 634 635 /* Don't block for too long here, as this also will screw other apps running on the OS. */ 636 LogFunc(("Waiting for listing to arrive ...\n")); 637 rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS); 702 LogRel2(("Shared Clipboard: Requesting data for IDataObject ...\n")); 703 704 /* Leave lock while requesting + waiting. */ 705 rc2 = RTCritSectLeave(&m_CritSect); 706 AssertRCReturn(rc2, E_UNEXPECTED); 707 708 /* Request the transfer from the source. 709 * This will generate a transfer status message which we're waiting for here. */ 710 AssertPtr(m_Callbacks.pfnOnRequestDataFromSource); 711 rc = m_Callbacks.pfnOnRequestDataFromSource(m_pCtx, 712 VBOX_SHCL_FMT_URI_LIST, NULL /* ppv */, NULL /* pv */, 713 this /* pvUser */); 714 AssertRCBreak(rc); 715 716 LogRel2(("Shared Clipboard: Waiting for IDataObject started status ...\n")); 717 718 rc = RTSemEventWait(m_EventStatusChanged, SHCL_TIMEOUT_DEFAULT_MS); 719 720 /* Re-acquire lock. */ 721 rc2 = RTCritSectEnter(&m_CritSect); 722 AssertRCReturn(rc2, E_UNEXPECTED); 723 638 724 if (RT_SUCCESS(rc)) 639 725 { 640 LogFunc(("Listing complete\n")); 726 if (m_enmStatus != Running) 727 { 728 LogRel(("Shared Clipboard: Received wrong IDataObject status (%#x)\n", m_enmStatus)); 729 rc = VERR_WRONG_ORDER; 730 break; 731 } 732 733 /* There now must be a transfer assigned. */ 734 AssertPtrBreakStmt(m_pTransfer, rc = VERR_WRONG_ORDER); 735 } 736 else /* Bail out on failure. */ 737 break; 738 739 RT_FALL_THROUGH(); 740 } 741 742 case Running: 743 { 744 const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW; 745 746 const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer); 747 RT_NOREF(enmTransferStatus); 748 749 LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n", 750 fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fThreadRunning)); 751 752 /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */ 753 if (!m_fThreadRunning) 754 { 755 /* Start the transfer asynchronously in a separate thread. */ 756 rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this /* pvUser */); 757 if (RT_SUCCESS(rc)) 758 { 759 m_fThreadRunning = true; 760 761 /* Leave lock while waiting. */ 762 rc2 = RTCritSectLeave(&m_CritSect); 763 AssertRCReturn(rc2, E_UNEXPECTED); 764 765 /* Don't block for too long here, as this also will screw other apps running on the OS. */ 766 LogRel2(("Shared Clipboard: Waiting for IDataObject listing to arrive ...\n")); 767 rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS); 768 769 /* Re-acquire lock. */ 770 rc2 = RTCritSectEnter(&m_CritSect); 771 AssertRCReturn(rc2, E_UNEXPECTED); 772 } 773 } 774 775 if (RT_SUCCESS(rc)) 776 { 777 HGLOBAL hGlobal; 778 rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal); 779 if (RT_SUCCESS(rc)) 780 { 781 pMedium->tymed = TYMED_HGLOBAL; 782 pMedium->hGlobal = hGlobal; 783 /* Note: hGlobal now is being owned by pMedium / the caller. */ 784 785 hr = S_OK; 786 } 787 } 788 789 break; 790 } 791 792 default: 793 break; 794 } 795 796 if (RT_FAILURE(rc)) 797 { 798 LogRel(("Shared Clipboard: Error getting data for IDataObject, rc=%Rrc\n", rc)); 799 hr = E_UNEXPECTED; /* We can't tell any better to the caller, unfortunately. */ 800 } 801 } 802 803 if (RT_SUCCESS(rc)) 804 { 805 if (pFormatEtc->cfFormat == m_cfFileContents) 806 { 807 if ( pFormatEtc->lindex >= 0 808 && (ULONG)pFormatEtc->lindex < m_lstEntries.size()) 809 { 810 m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */ 811 812 FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx); 813 814 LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.pszPath)); 815 816 LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.pszPath)); 817 818 /* Hand-in the provider so that our IStream implementation can continue working with it. */ 819 hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer, 820 fsObjEntry.pszPath /* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */, 821 &m_pStream); 822 if (SUCCEEDED(hr)) 823 { 824 /* Hand over the stream to the caller. */ 825 pMedium->tymed = TYMED_ISTREAM; 826 pMedium->pstm = m_pStream; 641 827 } 642 828 } 643 829 } 644 else 645 rc = VINF_SUCCESS; 646 647 if (RT_SUCCESS(rc)) 648 { 649 HGLOBAL hGlobal; 650 rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal); 651 if (RT_SUCCESS(rc)) 652 { 653 pMedium->tymed = TYMED_HGLOBAL; 654 pMedium->hGlobal = hGlobal; 655 /* Note: hGlobal now is being owned by pMedium / the caller. */ 656 657 hr = S_OK; 658 } 659 else /* We can't tell any better to the caller, unfortunately. */ 660 hr = E_UNEXPECTED; 661 } 662 663 if (RT_FAILURE(rc)) 664 LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc)); 665 } 666 667 if (pFormatEtc->cfFormat == m_cfFileContents) 668 { 669 if ( pFormatEtc->lindex >= 0 670 && (ULONG)pFormatEtc->lindex < m_lstEntries.size()) 671 { 672 m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */ 673 674 FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx); 675 676 LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.strPath.c_str())); 677 678 LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.strPath.c_str())); 679 680 /* Hand-in the provider so that our IStream implementation can continue working with it. */ 681 hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer, 682 fsObjEntry.strPath.c_str()/* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */, 683 &m_pStream); 684 if (SUCCEEDED(hr)) 685 { 686 /* Hand over the stream to the caller. */ 687 pMedium->tymed = TYMED_ISTREAM; 688 pMedium->pstm = m_pStream; 689 } 690 } 691 } 692 else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect) 693 { 694 HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD)); 695 696 DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal); 697 *pdwDropEffect = DROPEFFECT_COPY; 698 699 GlobalUnlock(hGlobal); 700 701 pMedium->tymed = TYMED_HGLOBAL; 702 pMedium->hGlobal = hGlobal; 703 pMedium->pUnkForRelease = NULL; 704 } 705 706 if ( FAILED(hr) 707 && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */ 708 { 709 LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr)); 710 } 830 else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect) 831 { 832 HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD)); 833 834 DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal); 835 *pdwDropEffect = DROPEFFECT_COPY; 836 837 GlobalUnlock(hGlobal); 838 839 pMedium->tymed = TYMED_HGLOBAL; 840 pMedium->hGlobal = hGlobal; 841 pMedium->pUnkForRelease = NULL; 842 } 843 844 if ( FAILED(hr) 845 && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */ 846 { 847 LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr)); 848 } 849 } 850 851 rc2 = RTCritSectLeave(&m_CritSect); 852 AssertRCReturn(rc2, E_UNEXPECTED); 711 853 712 854 LogFlowFunc(("hr=%Rhrc\n", hr)); … … 786 928 LogRel2(("Shared Clipboard: Transfer canceled by user interaction\n")); 787 929 788 OnTransferCanceled();930 SetStatus(Canceled); 789 931 } 790 932 /** @todo Detect move / overwrite actions here. */ … … 871 1013 */ 872 1014 873 int SharedClipboardWinDataObject::Init(void) 874 { 875 LogFlowFuncLeaveRC(VINF_SUCCESS); 876 return VINF_SUCCESS; 877 } 878 879 void SharedClipboardWinDataObject::OnTransferComplete(int rc /* = VINF_SUCESS */) 880 { 881 RT_NOREF(rc); 882 883 LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size())); 884 1015 /** 1016 * Assigns a transfer object and starts the transfer for the data object. 1017 * 1018 * @returns VBox status code. 1019 * @param pTransfer Transfer to assign. 1020 */ 1021 int SharedClipboardWinDataObject::SetAndStartTransfer(PSHCLTRANSFER pTransfer) 1022 { 1023 AssertReturn(m_pTransfer == NULL, VERR_WRONG_ORDER); /* Transfer already set? */ 1024 1025 int rc = RTCritSectEnter(&m_CritSect); 885 1026 if (RT_SUCCESS(rc)) 886 1027 { 887 const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */; 888 if (fComplete) 889 { 890 m_enmStatus = Completed; 891 } 892 } 893 else 894 m_enmStatus = Error; 895 896 if (m_enmStatus != Initialized) 897 { 898 if (m_EventTransferComplete != NIL_RTSEMEVENT) 899 { 900 int rc2 = RTSemEventSignal(m_EventTransferComplete); 901 AssertRC(rc2); 902 } 903 } 904 905 LogFlowFuncLeaveRC(rc); 906 } 907 908 void SharedClipboardWinDataObject::OnTransferCanceled(void) 909 { 910 LogFlowFuncEnter(); 911 912 m_enmStatus = Canceled; 913 914 if (m_EventTransferComplete != NIL_RTSEMEVENT) 915 { 916 int rc2 = RTSemEventSignal(m_EventTransferComplete); 917 AssertRC(rc2); 918 } 919 920 LogFlowFuncLeave(); 1028 if (m_enmStatus == Initialized) 1029 { 1030 m_pTransfer = pTransfer; 1031 1032 ShClTransferAcquire(pTransfer); 1033 1034 rc = setStatusLocked(Running); 1035 } 1036 else 1037 AssertFailedStmt(rc = VERR_WRONG_ORDER); 1038 1039 RTCritSectLeave(&m_CritSect); 1040 } 1041 1042 return rc; 1043 } 1044 1045 /** 1046 * Sets a new status to the data object and signals its waiter. 1047 * 1048 * @returns VBox status code. 1049 * @param enmStatus New status to signal. 1050 * @param rc Result code. Optional. 1051 * 1052 * @note Called by the main clipboard thread + SharedClipboardWinStreamImpl. 1053 */ 1054 int SharedClipboardWinDataObject::SetStatus(Status enmStatus, int rc /* = VINF_SUCCESS */) 1055 { 1056 int rc2 = RTCritSectEnter(&m_CritSect); 1057 if (RT_SUCCESS(rc2)) 1058 { 1059 setStatusLocked(enmStatus, rc); 1060 1061 RTCritSectLeave(&m_CritSect); 1062 } 1063 1064 return rc2; 921 1065 } 922 1066 … … 977 1121 logFormat(pFormatEtc->cfFormat); 978 1122 } 1123 1124 /** 1125 * Sets a new status to the data object and signals its waiter. 1126 * 1127 * @returns VBox status code. 1128 * @param enmStatus New status to signal. 1129 * @param rc Result code. Optional. 1130 * 1131 * @note Caller must have taken the critical section. 1132 */ 1133 int SharedClipboardWinDataObject::setStatusLocked(Status enmStatus, int rc /* = VINF_SUCCESS */) 1134 { 1135 AssertReturn(enmStatus == Error || RT_SUCCESS(rc), VERR_INVALID_PARAMETER); 1136 AssertReturn(RTCritSectIsOwned(&m_CritSect), VERR_WRONG_ORDER); 1137 1138 RT_NOREF(rc); 1139 1140 int rc2 = RTCritSectEnter(&m_CritSect); 1141 if (RT_SUCCESS(rc2)) 1142 { 1143 LogFlowFunc(("enmStatus=%#x (current is: %#x)\n", enmStatus, m_enmStatus)); 1144 1145 switch (enmStatus) 1146 { 1147 case Completed: 1148 { 1149 LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size())); 1150 1151 const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */; 1152 if (fComplete) 1153 m_enmStatus = Completed; 1154 break; 1155 } 1156 1157 default: 1158 { 1159 m_enmStatus = enmStatus; 1160 break; 1161 } 1162 } 1163 1164 if (RT_FAILURE(rc)) 1165 LogRel(("Shared Clipboard: Data object received error %Rrc (status %#x)\n", rc, enmStatus)); 1166 1167 if (m_EventStatusChanged != NIL_RTSEMEVENT) 1168 rc2 = RTSemEventSignal(m_EventStatusChanged); 1169 1170 RTCritSectLeave(&m_CritSect); 1171 } 1172 1173 return rc2; 1174 } 1175 -
trunk/src/VBox/GuestHost/SharedClipboard/ClipboardEnumFormatEtcImpl-win.cpp
r98103 r100204 41 41 42 42 43 SharedClipboardWinEnumFormatEtc::SharedClipboardWinEnumFormatEtc( LPFORMATETC pFormatEtc, ULONG cFormats)43 SharedClipboardWinEnumFormatEtc::SharedClipboardWinEnumFormatEtc(void) 44 44 : m_lRefCount(1), 45 45 m_nIndex(0) 46 46 { 47 HRESULT hr;48 49 try50 {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));73 47 } 74 48 75 49 SharedClipboardWinEnumFormatEtc::~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 */ 63 int 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 */ 87 void SharedClipboardWinEnumFormatEtc::Destroy(void) 76 88 { 77 89 if (m_pFormatEtc) … … 87 99 } 88 100 89 LogFlowFunc(("m_lRefCount=%RI32\n", m_lRefCount));101 m_nNumFormats = 0; 90 102 } 91 103 … … 191 203 192 204 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 200 214 hr = E_OUTOFMEMORY; 201 }202 215 203 216 return hr; -
trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp
r98103 r100204 39 39 #include <VBox/GuestHost/SharedClipboard.h> 40 40 #include <VBox/GuestHost/SharedClipboard-win.h> 41 #include <strsafe.h>42 41 43 42 #include <VBox/log.h> … … 61 60 , m_lRefCount(1) /* Our IDataObjct *always* holds the last reference to this object; needed for the callbacks. */ 62 61 , m_pTransfer(pTransfer) 63 , m_hObj( SHCLOBJHANDLE_INVALID)62 , m_hObj(NIL_SHCLOBJHANDLE) 64 63 , m_strPath(strPath) 65 64 , m_objInfo(*pObjInfo) … … 187 186 int rc; 188 187 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()); 196 199 if (RT_SUCCESS(rc)) 197 200 { 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); 208 202 } 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)) 221 222 { 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); 229 225 } 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) 235 234 { 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); 244 237 } 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; 264 254 } 265 255 -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp
r99974 r100204 63 63 * @returns VBox status code. 64 64 * @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 */ 70 int 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. 67 97 * @param ppPayload Where to store the allocated event payload on success. 68 98 */ … … 73 103 AssertReturn(cbData > 0, VERR_INVALID_PARAMETER); 74 104 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 90 109 return VERR_NO_MEMORY; 91 110 } … … 418 437 * Detaches a payload from an event, internal version. 419 438 * 420 * @returns Pointer to the detached payload. Can be NULL if the payloadhas no payload.439 * @returns Pointer to the detached payload. Can be NULL if the event has no payload. 421 440 * @param pEvent Event to detach payload for. 422 441 */ … … 480 499 481 500 /** 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. 483 502 * 484 503 * @returns New reference count, or UINT32_MAX if failed. -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers-http.cpp
r99937 r100204 49 49 #include <iprt/path.h> 50 50 #include <iprt/rand.h> 51 #include <iprt/semaphore.h> 51 52 #include <iprt/stream.h> 52 53 #include <iprt/string.h> … … 74 75 PSHCLTRANSFER pTransfer; 75 76 /** The (cached) root list of the transfer. NULL if not cached yet. */ 76 PSHCL ROOTLISTpRootList;77 PSHCLLIST pRootList; 77 78 /** Critical section for serializing access. */ 78 79 RTCRITSECT CritSect; … … 92 93 static const char *shClTransferHttpServerGetHost(PSHCLHTTPSERVER pSrv); 93 94 static int shClTransferHttpServerDestroyTransfer(PSHCLHTTPSERVER pSrv, PSHCLHTTPSERVERTRANSFER pSrvTx); 95 static SHCLHTTPSERVERSTATUS shclTransferHttpServerSetStatusLocked(PSHCLHTTPSERVER pSrv, SHCLHTTPSERVERSTATUS enmStatus); 94 96 95 97 … … 188 190 189 191 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;207 192 } 208 193 … … 350 335 PRTHTTPSERVERREQ pReq, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint) 351 336 { 337 RT_NOREF(pData); 352 338 RT_NOREF(ppszMIMEHint); 353 354 PSHCLHTTPSERVER pThis = (PSHCLHTTPSERVER)pData->pvUser;355 Assert(pData->cbUser == sizeof(SHCLHTTPSERVER));356 339 357 340 int rc; … … 360 343 if (pSrvTx) 361 344 { 362 rc = shClTransferHttpGetTransferRoots(pThis, pSrvTx); 345 SHCLOBJOPENCREATEPARMS openParms; 346 rc = ShClTransferObjOpenParmsInit(&openParms); 363 347 if (RT_SUCCESS(rc)) 364 348 { 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) 368 358 { 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); 378 360 if (RT_SUCCESS(rc)) 379 361 { 380 rc = RTStrCopy(openParms.pszPath, openParms.cbPath, ListEntry.pszName);362 rc = ShClTransferObjOpen(pTx, &openParms, &pSrvTx->hObj); 381 363 if (RT_SUCCESS(rc)) 382 364 { 383 rc = ShClTransferObjOpen(pTx, &openParms, &pSrvTx->hObj); 365 char szPath[RTPATH_MAX]; 366 rc = ShClTransferGetRootPathAbs(pTx, szPath, sizeof(szPath)); 384 367 if (RT_SUCCESS(rc)) 385 368 { 386 char szPath[RTPATH_MAX]; 387 rc = ShClTransferGetRootPathAbs(pTx, szPath, sizeof(szPath)); 369 rc = RTPathAppend(szPath, sizeof(szPath), openParms.pszPath); 388 370 if (RT_SUCCESS(rc)) 389 371 { 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); 396 374 } 397 375 } 398 376 } 399 377 } 400 401 ShClTransferObjOpenParmsDestroy(&openParms);402 378 } 379 else 380 rc = VERR_NOT_FOUND; 381 382 ShClTransferObjOpenParmsDestroy(&openParms); 403 383 } 404 384 } … … 453 433 } 454 434 435 rc = RTSemEventDestroy(pSrv->StatusEvent); 436 pSrv->StatusEvent = NIL_RTSEMEVENT; 437 455 438 return rc; 456 439 } … … 481 464 * Initializes a new Shared Clipboard HTTP server instance. 482 465 * 466 * @return VBox status code. 483 467 * @param pSrv HTTP server instance to initialize. 484 468 */ 485 static void shClTransferHttpServerInitInternal(PSHCLHTTPSERVER pSrv) 486 { 469 static 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 487 477 pSrv->hHTTPServer = NIL_RTHTTPSERVER; 488 478 pSrv->uPort = 0; 489 479 RTListInit(&pSrv->lstTransfers); 490 480 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; 493 486 } 494 487 … … 501 494 * Initializes a new Shared Clipboard HTTP server instance. 502 495 * 496 * @return VBox status code. 503 497 * @param pSrv HTTP server instance to initialize. 504 498 */ 505 voidShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv)506 { 507 AssertPtrReturn Void(pSrv);508 509 shClTransferHttpServerInitInternal(pSrv);499 int ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv) 500 { 501 AssertPtrReturn(pSrv, VERR_INVALID_POINTER); 502 503 return shClTransferHttpServerInitInternal(pSrv); 510 504 } 511 505 … … 534 528 535 529 /** 536 * Creates a newShared Clipboard HTTP server instance, extended version.530 * Starts the Shared Clipboard HTTP server instance, extended version. 537 531 * 538 532 * @returns VBox status code. … … 541 535 * @param uPort TCP port number to use. 542 536 */ 543 int ShClTransferHttpServer CreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort)537 int ShClTransferHttpServerStartEx(PSHCLHTTPSERVER pSrv, uint16_t uPort) 544 538 { 545 539 AssertPtrReturn(pSrv, VERR_INVALID_POINTER); … … 564 558 if (RT_SUCCESS(rc)) 565 559 { 566 rc = RTCritSectInit(&pSrv->CritSect);567 AssertRCReturn(rc, rc);568 569 560 pSrv->uPort = uPort; 570 561 … … 584 575 585 576 /** 586 * Creates a newShared Clipboard HTTP server instance using a random port (>= 1024).577 * Starts the Shared Clipboard HTTP server instance using a random port (>= 1024). 587 578 * 588 579 * This does automatic probing of TCP ports if a port already is being used. … … 593 584 * @param puPort Where to return the TCP port number being used on success. Optional. 594 585 */ 595 int ShClTransferHttpServer Create(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort)586 int ShClTransferHttpServerStart(PSHCLHTTPSERVER pSrv, unsigned cMaxAttempts, uint16_t *puPort) 596 587 { 597 588 AssertPtrReturn(pSrv, VERR_INVALID_POINTER); … … 615 606 continue; 616 607 617 rc = ShClTransferHttpServer CreateEx(pSrv, (uint32_t)uPort);608 rc = ShClTransferHttpServerStartEx(pSrv, (uint32_t)uPort); 618 609 if (RT_SUCCESS(rc)) 619 610 { … … 723 714 VERR_INVALID_PARAMETER); 724 715 725 uint 32_t const cRoots = ShClTransferRootsCount(pTransfer);716 uint64_t const cRoots = ShClTransferRootsCount(pTransfer); 726 717 AssertMsgReturn(cRoots > 0, ("Transfer has no root entries\n"), VERR_INVALID_PARAMETER); 727 718 AssertMsgReturn(cRoots == 1, ("Only single files are supported for now\n"), VERR_NOT_SUPPORTED); … … 744 735 AssertRC(rc); 745 736 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) 749 739 { 750 740 #ifdef DEBUG_andy … … 752 742 * Every transfer has a dedicated HTTP path (but live in the same URL namespace). */ 753 743 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); 755 745 #else 756 746 /* Create the virtual HTTP path for the transfer. 757 747 * Every transfer has a dedicated HTTP path (but live in the same URL namespace). */ 758 748 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); 760 750 #endif 761 751 AssertReturn(cch, VERR_BUFFER_OVERFLOW); … … 767 757 RTListAppend(&pSrv->lstTransfers, &pSrvTx->Node); 768 758 pSrv->cTransfers++; 759 760 shclTransferHttpServerSetStatusLocked(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED); 769 761 770 762 LogFunc(("pTransfer=%p, idTransfer=%RU16, szPath=%s -> %RU32 transfers\n", … … 811 803 { 812 804 rc = shClTransferHttpServerDestroyTransfer(pSrv, pSrvTx); 805 if (RT_SUCCESS(rc)) 806 shclTransferHttpServerSetStatusLocked(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_UNREGISTERED); 813 807 break; 814 808 } … … 822 816 823 817 /** 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 */ 826 static 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. 827 848 * @param pSrv HTTP server instance. 828 * @param idTransfer Transfer ID to check for. 829 */ 830 bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer) 849 */ 850 PSHCLTRANSFER 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 */ 868 bool ShClTransferHttpServerGetTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer) 831 869 { 832 870 AssertPtrReturn(pSrv, false); … … 834 872 shClTransferHttpServerLock(pSrv); 835 873 836 const bool fRc = shClTransferHttpServerGetTransferById(pSrv, idTransfer) != NULL;874 PSHCLHTTPSERVERTRANSFER pTransfer = shClTransferHttpServerGetTransferById(pSrv, idTransfer); 837 875 838 876 shClTransferHttpServerUnlock(pSrv); 839 877 840 return fRc;878 return pTransfer; 841 879 } 842 880 … … 945 983 } 946 984 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 */ 994 int 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 947 1028 948 1029 /********************************************************************************************************************************* … … 951 1032 952 1033 /** 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. 954 1035 * 955 1036 * @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 */ 1039 int ShClTransferHttpServerMaybeStart(PSHCLHTTPCONTEXT pCtx) 960 1040 { 961 1041 int rc = VINF_SUCCESS; … … 963 1043 /* Start the built-in HTTP server to serve file(s). */ 964 1044 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. 975 1052 * 976 1053 * @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 */ 1056 int ShClTransferHttpServerMaybeStop(PSHCLHTTPCONTEXT pCtx) 981 1057 { 982 1058 int rc = VINF_SUCCESS; … … 984 1060 if (ShClTransferHttpServerIsRunning(&pCtx->HttpServer)) 985 1061 { 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 129 129 * @returns VBox status code. 130 130 * @param pTransfer Clipboard transfer to resolve path for. 131 * @param pszPath Path to resolve.131 * @param pszPath Relative path to resolve. 132 132 * @param fFlags Resolve flags. Currently not used and must be 0. 133 133 * @param ppszResolved Where to store the allocated resolved path. Must be free'd by the called using RTStrFree(). … … 145 145 if (RT_SUCCESS(rc)) 146 146 { 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; 172 173 173 174 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 } 179 185 } 180 186 181 187 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)); 183 189 184 190 LogFlowFuncLeaveRC(rc); … … 202 208 if (RT_SUCCESS(rc)) 203 209 { 204 pHdr->cbTotalSize 205 pHdr->c TotalObjects++;210 pHdr->cbTotalSize += cbSize; 211 pHdr->cEntries++; 206 212 } 207 213 … … 254 260 break; 255 261 256 pHdr->c TotalObjects++;262 pHdr->cEntries++; 257 263 break; 258 264 } … … 303 309 * Creates a new list handle (local only). 304 310 * 305 * @returns New List handle on success, or SHCLLISTHANDLE_INVALIDon error.311 * @returns New List handle on success, or NIL_SHCLLISTHANDLE on error. 306 312 * @param pTransfer Clipboard transfer to create new list handle for. 307 313 */ … … 311 317 } 312 318 313 static DECLCALLBACK(int) vbclTransferIfaceLocalRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList) 319 static 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 */ 350 static DECLCALLBACK(int) shclTransferIfaceLocalRootListRead(PSHCLTXPROVIDERCTX pCtx) 314 351 { 315 352 LogFlowFuncEnter(); 316 353 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 326 354 int rc = VINF_SUCCESS; 327 355 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 */ 370 static DECLCALLBACK(int) shclTransferIfaceLocalListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, 362 371 PSHCLLISTHANDLE phList) 363 372 { … … 416 425 pInfo->hList = shClTransferListHandleNew(pTransfer); 417 426 418 RTListAppend(&pTransfer->lst List, &pInfo->Node);427 RTListAppend(&pTransfer->lstHandles, &pInfo->Node); 419 428 pTransfer->cListHandles++; 420 429 … … 457 466 } 458 467 459 static DECLCALLBACK(int) vbclTransferIfaceLocalListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList) 468 /** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */ 469 static DECLCALLBACK(int) shclTransferIfaceLocalListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList) 460 470 { 461 471 LogFlowFuncEnter(); … … 500 510 } 501 511 502 static DECLCALLBACK(int) vbclTransferIfaceLocalListHdrRead(PSHCLTXPROVIDERCTX pCtx, 512 /** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */ 513 static DECLCALLBACK(int) shclTransferIfaceLocalListHdrRead(PSHCLTXPROVIDERCTX pCtx, 503 514 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr) 504 515 { … … 530 541 LogFlowFunc(("FileAbs: %s\n", pInfo->pszPathLocalAbs)); 531 542 532 pListHdr->c TotalObjects = 1;543 pListHdr->cEntries = 1; 533 544 534 545 RTFSOBJINFO objInfo; … … 549 560 } 550 561 551 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pListHdr->c TotalObjects, pListHdr->cbTotalSize));562 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pListHdr->cEntries, pListHdr->cbTotalSize)); 552 563 } 553 564 else … … 558 569 } 559 570 560 static DECLCALLBACK(int) vbclTransferIfaceLocalListEntryRead(PSHCLTXPROVIDERCTX pCtx, 571 /** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */ 572 static DECLCALLBACK(int) shclTransferIfaceLocalListEntryRead(PSHCLTXPROVIDERCTX pCtx, 561 573 SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry) 562 574 { … … 628 640 Assert (pEntry->cbInfo == sizeof(SHCLFSOBJINFO)); 629 641 630 ShClFsObj FromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);642 ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info); 631 643 632 644 LogFlowFunc(("Entry pszName=%s, pvInfo=%p, cbInfo=%RU32\n", … … 662 674 if (RT_SUCCESS(rc)) 663 675 { 664 ShClFsObj FromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo);676 ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo); 665 677 666 678 pEntry->cbInfo = sizeof(SHCLFSOBJINFO); 667 pEntry->fInfo = VBOX_SHCL_INFO_F LAG_FSOBJINFO;679 pEntry->fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; 668 680 } 669 681 } … … 687 699 } 688 700 689 static DECLCALLBACK(int) vbclTransferIfaceLocalObjOpen(PSHCLTXPROVIDERCTX pCtx, 701 /** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */ 702 static DECLCALLBACK(int) shclTransferIfaceLocalObjOpen(PSHCLTXPROVIDERCTX pCtx, 690 703 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj) 691 704 { … … 745 758 } 746 759 747 static DECLCALLBACK(int) vbclTransferIfaceLocalObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj) 760 /** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */ 761 static DECLCALLBACK(int) shclTransferIfaceLocalObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj) 748 762 { 749 763 LogFlowFuncEnter(); … … 809 823 } 810 824 811 static DECLCALLBACK(int) vbclTransferIfaceLocalObjRead(PSHCLTXPROVIDERCTX pCtx, 825 /** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */ 826 static DECLCALLBACK(int) shclTransferIfaceLocalObjRead(PSHCLTXPROVIDERCTX pCtx, 812 827 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, 813 828 uint32_t fFlags, uint32_t *pcbRead) … … 851 866 } 852 867 853 static DECLCALLBACK(int) vbclTransferIfaceLocalObjWrite(PSHCLTXPROVIDERCTX pCtx,868 static DECLCALLBACK(int) shclTransferIfaceLocalObjWrite(PSHCLTXPROVIDERCTX pCtx, 854 869 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, uint32_t fFlags, 855 870 uint32_t *pcbWritten) … … 892 907 * The local provider is being used for accessing files on local file systems. 893 908 * 894 * @returns Interface pointer the provider get assigned to.895 * @param p Iface Interface to assign providerto.909 * @returns Interface pointer assigned to the provider. 910 * @param pProvider Provider to assign interface to. 896 911 */ 897 PSHCLTXPROVIDERIFACE VBClTransfer QueryIfaceLocal(PSHCLTXPROVIDERIFACE pIface)898 { 899 p Iface->pfnRootsGet = vbclTransferIfaceLocalRootsGet;900 p Iface->pfnListOpen = vbclTransferIfaceLocalListOpen;901 p Iface->pfnListClose = vbclTransferIfaceLocalListClose;902 p Iface->pfnListHdrRead = vbclTransferIfaceLocalListHdrRead;903 p Iface->pfnListEntryRead = vbclTransferIfaceLocalListEntryRead;904 p Iface->pfnObjOpen = vbclTransferIfaceLocalObjOpen;905 p Iface->pfnObjClose = vbclTransferIfaceLocalObjClose;906 p Iface->pfnObjRead = vbclTransferIfaceLocalObjRead;907 p Iface->pfnObjWrite = vbclTransferIfaceLocalObjWrite;908 909 return pIface;910 } 911 912 PSHCLTXPROVIDERIFACE 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 35 35 #include <iprt/rand.h> 36 36 #include <iprt/semaphore.h> 37 #include <iprt/uri.h> 37 38 38 39 #include <VBox/err.h> … … 50 51 51 52 /** 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 */ 57 void 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 */ 68 void 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 */ 92 int 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 */ 113 PSHCLLIST 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 67 129 * invalid after returning from this function. 68 130 */ 69 void ShClTransfer RootListFree(PSHCLROOTLIST pRootList)70 { 71 if (!p RootList)131 void ShClTransferListFree(PSHCLLIST pList) 132 { 133 if (!pList) 72 134 return; 73 135 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 */ 149 DECLINLINE(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; 179 164 } 180 165 … … 446 431 * 447 432 * @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(). 449 435 */ 450 436 int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry) … … 454 440 return VERR_NO_MEMORY; 455 441 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); 460 458 return rc; 461 459 } … … 464 462 * Frees a clipboard list entry structure. 465 463 * 466 * @param p ListEntryClipboard list entry structure to free.464 * @param pEntry Clipboard list entry structure to free. 467 465 * The pointer will be invalid on return. 468 466 */ 469 void ShClTransferListEntryFree(PSHCLLISTENTRY p ListEntry)470 { 471 if (!p ListEntry)467 void ShClTransferListEntryFree(PSHCLLISTENTRY pEntry) 468 { 469 if (!pEntry) 472 470 return; 473 471 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; 476 477 } 477 478 … … 528 529 * 529 530 * @returns Duplicated clipboard list entry structure on success. 530 * @param p ListEntryClipboard list entry to duplicate.531 */ 532 PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY p ListEntry)533 { 534 AssertPtrReturn(p ListEntry, NULL);531 * @param pEntry Clipboard list entry to duplicate. 532 */ 533 PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pEntry) 534 { 535 AssertPtrReturn(pEntry, NULL); 535 536 536 537 int rc = VINF_SUCCESS; … … 538 539 PSHCLLISTENTRY pListEntryDup = (PSHCLLISTENTRY)RTMemAllocZ(sizeof(SHCLLISTENTRY)); 539 540 if (pListEntryDup) 540 rc = ShClTransferListEntryCopy(pListEntryDup, p ListEntry);541 rc = ShClTransferListEntryCopy(pListEntryDup, pEntry); 541 542 542 543 if (RT_FAILURE(rc)) … … 586 587 * @returns VBox status code. 587 588 * @param pListEntry Clipboard list entry structure to initialize. 589 * @param fInfo Info flags (of type VBOX_SHCL_INFO_FLAG_XXX). 588 590 * @param pszName Name (e.g. filename) to use. Can be NULL if not being used. 589 591 * 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 */ 596 int ShClTransferListEntryInitEx(PSHCLLISTENTRY pListEntry, uint32_t fInfo, const char *pszName, void *pvInfo, uint32_t cbInfo) 592 597 { 593 598 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER); 594 599 AssertReturn ( pszName == NULL 595 600 || shclTransferListEntryNameIsValid(pszName, strlen(pszName) + 1), VERR_INVALID_PARAMETER); 601 /* pvInfo + cbInfo depend on fInfo. See below. */ 596 602 597 603 RT_BZERO(pListEntry, sizeof(SHCLLISTENTRY)); … … 599 605 if (pszName) 600 606 { 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; 617 617 } 618 618 … … 625 625 int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry) 626 626 { 627 return ShClTransferListEntryInitEx(pListEntry, NULL);627 return ShClTransferListEntryInitEx(pListEntry, VBOX_SHCL_INFO_F_NONE, NULL /* pszName */, NULL /* pvInfo */, 0 /* cbInfo */); 628 628 } 629 629 … … 862 862 AssertPtrReturn(phObj, VERR_INVALID_POINTER); 863 863 AssertMsgReturn(pTransfer->pszPathRootAbs, ("Transfer has no root path set\n"), VERR_INVALID_PARAMETER); 864 /** @todo Check pOpenCreateParms->fCreate flags. */ 864 865 AssertMsgReturn(pOpenCreateParms->pszPath, ("No path in open/create params set\n"), VERR_INVALID_PARAMETER); 865 866 … … 1068 1069 pTransfer->cbUser = 0; 1069 1070 1070 RTListInit(&pTransfer->lst List);1071 RTListInit(&pTransfer->lstHandles); 1071 1072 RTListInit(&pTransfer->lstObj); 1072 1073 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); 1075 1079 1076 1080 int rc = ShClEventSourceCreate(&pTransfer->Events, 0 /* uID */); … … 1118 1122 return VINF_SUCCESS; 1119 1123 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 1120 1128 AssertMsgReturn(pTransfer->cRefs == 0, ("Number of references > 0 (%RU32)\n", pTransfer->cRefs), VERR_WRONG_ORDER); 1121 1129 … … 1144 1152 int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource) 1145 1153 { 1154 AssertMsgReturn(pTransfer->State.enmStatus < SHCLTRANSFERSTATUS_INITIALIZED, 1155 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)), 1156 VERR_WRONG_ORDER); 1157 1146 1158 pTransfer->cRefs = 0; 1147 1159 … … 1152 1164 pTransfer->State.uID, pTransfer->State.enmDir, pTransfer->State.enmSource)); 1153 1165 1154 pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_INITIALIZED; /* Now we're ready to run. */1155 1156 1166 pTransfer->cListHandles = 0; 1157 1167 pTransfer->uListHandleNext = 1; … … 1160 1170 pTransfer->uObjHandleNext = 1; 1161 1171 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 1162 1178 int rc = VINF_SUCCESS; 1163 1179 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 } 1166 1189 1167 1190 LogFlowFuncLeaveRC(rc); … … 1279 1302 { 1280 1303 PSHCLLISTHANDLEINFO pIt; 1281 RTListForEach(&pTransfer->lst List, pIt, SHCLLISTHANDLEINFO, Node) /** @todo Sloooow ... improve this. */1304 RTListForEach(&pTransfer->lstHandles, pIt, SHCLLISTHANDLEINFO, Node) /** @todo Sloooow ... improve this. */ 1282 1305 { 1283 1306 if (pIt->hList == hList) … … 1392 1415 * destination callback table will be unset. 1393 1416 */ 1394 void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACK TABLEpCallbacksDst,1395 PSHCLTRANSFERCALLBACK TABLEpCallbacksSrc)1417 void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKS pCallbacksDst, 1418 PSHCLTRANSFERCALLBACKS pCallbacksSrc) 1396 1419 { 1397 1420 AssertPtrReturnVoid(pCallbacksDst); … … 1403 1426 pCallbacksDst->a_pfnCallback = pCallbacksSrc->a_pfnCallback 1404 1427 1405 SET_CALLBACK(pfnOnInitialize); 1406 SET_CALLBACK(pfnOnStart); 1428 SET_CALLBACK(pfnOnInitialized); 1429 SET_CALLBACK(pfnOnDestroy); 1430 SET_CALLBACK(pfnOnStarted); 1407 1431 SET_CALLBACK(pfnOnCompleted); 1408 1432 SET_CALLBACK(pfnOnError); … … 1426 1450 * @param pCallbacks Pointer to callback table to set. If set to NULL, 1427 1451 * existing callbacks for this transfer will be unset. 1452 * 1453 * @note Must come before initializing the transfer via ShClTransferInit(). 1428 1454 */ 1429 1455 void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, 1430 PSHCLTRANSFERCALLBACK TABLEpCallbacks)1456 PSHCLTRANSFERCALLBACKS pCallbacks) 1431 1457 { 1432 1458 AssertPtrReturnVoid(pTransfer); … … 1437 1463 1438 1464 /** 1439 * Sets the transfer provider interfacefor a given transfer.1465 * Sets the transfer provider for a given transfer. 1440 1466 * 1441 1467 * @returns VBox status code. 1442 1468 * @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 */ 1471 int ShClTransferSetProvider(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDER pProvider) 1472 { 1473 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1474 AssertPtrReturn(pProvider, VERR_INVALID_POINTER); 1450 1475 1451 1476 LogFlowFuncEnter(); … … 1453 1478 int rc = VINF_SUCCESS; 1454 1479 1455 pTransfer->ProviderIface = p CreationCtx->Interface;1480 pTransfer->ProviderIface = pProvider->Interface; 1456 1481 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)); 1458 1486 1459 1487 LogFlowFuncLeaveRC(rc); … … 1462 1490 1463 1491 /** 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 */ 1497 uint64_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. 1465 1507 * 1466 1508 * @param pTransfer Transfer to clear transfer root list for. 1467 1509 */ 1468 static void shClTransfer ListRootsClear(PSHCLTRANSFER pTransfer)1510 static void shClTransferRootsReset(PSHCLTRANSFER pTransfer) 1469 1511 { 1470 1512 AssertPtrReturnVoid(pTransfer); … … 1476 1518 } 1477 1519 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); 1490 1521 } 1491 1522 … … 1501 1532 LogFlowFuncEnter(); 1502 1533 1503 shClTransfer ListRootsClear(pTransfer);1534 shClTransferRootsReset(pTransfer); 1504 1535 1505 1536 PSHCLLISTHANDLEINFO pItList, pItListNext; 1506 RTListForEachSafe(&pTransfer->lst List, pItList, pItListNext, SHCLLISTHANDLEINFO, Node)1537 RTListForEachSafe(&pTransfer->lstHandles, pItList, pItListNext, SHCLLISTHANDLEINFO, Node) 1507 1538 { 1508 1539 ShClTransferListHandleInfoDestroy(pItList); … … 1525 1556 1526 1557 /** 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 /**1560 1558 * Get a specific root list entry. 1561 1559 * 1562 * @returns VBox status code.1560 * @returns Const pointer to root list entry if found, or NULL if not found.. 1563 1561 * @param pTransfer Clipboard transfer to get root list entry of. 1564 1562 * @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 */ 1564 PCSHCLLISTENTRY 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 */ 1582 int ShClTransferRootListRead(PSHCLTRANSFER pTransfer) 1569 1583 { 1570 1584 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(); 1575 1587 1576 1588 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); 1641 1591 else 1642 1592 rc = VERR_NOT_SUPPORTED; 1643 1593 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 1644 1602 LogFlowFuncLeaveRC(rc); 1645 1603 return rc; … … 1647 1605 1648 1606 /** 1649 * Setsroot list entries for a given clipboard transfer.1607 * Initializes the root list entries for a given clipboard transfer. 1650 1608 * 1651 1609 * @returns VBox status code. … … 1653 1611 * @param pszRoots String list (separated by CRLF) of root entries to set. 1654 1612 * 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 */ 1617 int ShClTransferRootsInitFromStringList(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots) 1658 1618 { 1659 1619 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); … … 1661 1621 AssertReturn(cbRoots, VERR_INVALID_PARAMETER); 1662 1622 1623 LogFlowFuncEnter(); 1624 1663 1625 if (!RTStrIsValidEncoding(pszRoots)) 1664 1626 return VERR_INVALID_UTF8_ENCODING; … … 1666 1628 int rc = VINF_SUCCESS; 1667 1629 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 1673 1639 for (size_t i = 0; i < lstRootEntries.size(); ++i) 1674 1640 { 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 } 1679 1656 1680 1657 LogFlowFunc(("pszPathCur=%s\n", pszPathCur)); 1658 1659 rc = ShClTransferValidatePath(pszPathCur, false); 1660 if (RT_FAILURE(rc)) 1661 { 1662 RT_BREAKPOINT(); 1663 break; 1664 } 1681 1665 1682 1666 /* No root path determined yet? */ … … 1696 1680 } 1697 1681 else 1698 rc = VERR_ INVALID_PARAMETER;1682 rc = VERR_PATH_IS_RELATIVE; 1699 1683 } 1700 1684 else … … 1702 1686 } 1703 1687 1704 if (RT_FAILURE(rc)) 1705 break; 1706 1707 pListRoot->pszPathAbs = RTStrDup(pszPathCur); 1708 if (!pListRoot->pszPathAbs) 1688 if (RT_SUCCESS(rc)) 1709 1689 { 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 } 1712 1735 } 1713 1736 1714 RTListAppend(&pTransfer->lstRoots, &pListRoot->Node); 1715 1716 pTransfer->cRoots++; 1737 RTStrFree(pszPathCur); 1717 1738 } 1718 1739 1719 1740 /* No (valid) root directory found? Bail out early. */ 1720 1741 if (!pszPathRootAbs) 1721 rc = VERR_PATH_ NOT_FOUND;1742 rc = VERR_PATH_DOES_NOT_START_WITH_ROOT; 1722 1743 1723 1744 if (RT_SUCCESS(rc)) 1724 1745 { 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 {1748 1746 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)); 1750 1748 1751 1749 LogRel2(("Shared Clipboard: Transfer uses root '%s'\n", pTransfer->pszPathRootAbs)); … … 1754 1752 { 1755 1753 LogRel(("Shared Clipboard: Unable to set roots for transfer, rc=%Rrc\n", rc)); 1754 ShClTransferListDestroy(pLstRoots); 1756 1755 RTStrFree(pszPathRootAbs); 1757 1756 } … … 1762 1761 1763 1762 /** 1764 * Sets a single file as a transfer root.1763 * Initializes a single file as a transfer root. 1765 1764 * 1766 1765 * @returns VBox status code. … … 1770 1769 * @note Convenience function, uses ShClTransferRootsSet() internally. 1771 1770 */ 1772 int ShClTransferRoots SetAsFile(PSHCLTRANSFER pTransfer, const char *pszFile)1771 int ShClTransferRootsInitFromFile(PSHCLTRANSFER pTransfer, const char *pszFile) 1773 1772 { 1774 1773 char *pszRoots = NULL; 1774 1775 LogFlowFuncEnter(); 1775 1776 1776 1777 int rc = RTStrAAppend(&pszRoots, pszFile); … … 1778 1779 rc = RTStrAAppend(&pszRoots, "\r\n"); 1779 1780 AssertRCReturn(rc, rc); 1780 rc = ShClTransferRoots Set(pTransfer, pszRoots, strlen(pszRoots) + 1);1781 rc = ShClTransferRootsInitFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1 /* Include terminator */); 1781 1782 RTStrFree(pszRoots); 1782 1783 return rc; … … 1821 1822 { 1822 1823 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1824 AssertMsgReturn(pTransfer->pszPathRootAbs, ("Transfer has no root path set (yet)\n"), VERR_WRONG_ORDER); 1823 1825 1824 1826 return RTStrCopy(pszPath, cbPath, pTransfer->pszPathRootAbs); … … 1849 1851 AssertPtrReturn(pTransfer, SHCLTRANSFERSTATUS_NONE); 1850 1852 1851 LogFlowFunc(("[Transfer %RU32] enmStatus=%RU32\n", pTransfer->State.uID, pTransfer->State.enmStatus));1852 1853 return pTransfer->State.enmStatus; 1853 1854 } … … 1890 1891 1891 1892 /* Ready to start? */ 1893 AssertMsgReturn(pTransfer->ProviderIface.pfnRootListRead != NULL, 1894 ("No provider interface set (yet)\n"), 1895 VERR_WRONG_ORDER); 1892 1896 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_INITIALIZED, 1893 1897 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)), 1894 1898 VERR_WRONG_ORDER); 1895 1899 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); 1909 1906 1910 1907 LogFlowFuncLeaveRC(rc); … … 1935 1932 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc, 1936 1933 pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, 1937 "shclp ");1934 "shclptx"); 1938 1935 if (RT_SUCCESS(rc)) 1939 1936 { … … 2189 2186 } 2190 2187 2191 Log2Func(("pTransfer=%p, idTransfer=%RU32 (%RU16 transfers)\n", pTransfer, idTransfer, pTransferCtx->cTransfers));2192 2193 2188 pTransfer->State.uID = idTransfer; 2194 2189 … … 2196 2191 2197 2192 pTransferCtx->cTransfers++; 2193 2194 Log2Func(("pTransfer=%p, idTransfer=%RU32 -- now %RU16 transfer(s)\n", pTransfer, idTransfer, pTransferCtx->cTransfers)); 2198 2195 2199 2196 if (pTransfer->Callbacks.pfnOnRegistered) … … 2342 2339 * Copies file system objinfo from IPRT to Shared Clipboard format. 2343 2340 * 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 */ 2345 int ShClFsObjInfoFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc) 2346 { 2347 AssertPtrReturn(pDst, VERR_INVALID_POINTER); 2348 AssertPtrReturn(pSrc, VERR_INVALID_POINTER); 2349 2349 2350 pDst->cbObject = pSrc->cbObject; 2350 2351 pDst->cbAllocated = pSrc->cbAllocated; … … 2360 2361 { 2361 2362 default: 2363 RT_FALL_THROUGH(); 2362 2364 case RTFSOBJATTRADD_NOTHING: 2363 2365 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_NOTHING; … … 2381 2383 break; 2382 2384 } 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 */ 2396 int 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; 2383 2410 } 2384 2411 … … 2395 2422 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_NONE); 2396 2423 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_INITIALIZED); 2424 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_UNINITIALIZED); 2397 2425 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STARTED); 2398 2426 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STOPPED); … … 2449 2477 else /* Everything else (e.g. symbolic links) are not supported. */ 2450 2478 { 2451 LogRel2(("Shared Clipboard: Path '%s' contains a symbolic link or jun ktion, which are not supported\n", pcszPath));2479 LogRel2(("Shared Clipboard: Path '%s' contains a symbolic link or junction, which are not supported\n", pcszPath)); 2452 2480 rc = VERR_NOT_SUPPORTED; 2453 2481 } … … 2461 2489 return rc; 2462 2490 } 2463 -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp
r98103 r100204 26 26 */ 27 27 28 #define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD29 28 #include <VBox/GuestHost/SharedClipboard.h> 30 29 … … 40 39 #endif 41 40 41 #ifdef LOG_GROUP 42 # undef LOG_GROUP 43 #endif 44 #define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD 42 45 #include <VBox/log.h> 43 46 … … 48 51 #include <VBox/GuestHost/SharedClipboard-win.h> 49 52 #include <VBox/GuestHost/clipboard-helper.h> 53 54 55 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 56 int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **ppszList, uint32_t *pcbList); 57 #endif 50 58 51 59 … … 833 841 * a separate WM_RENDERFORMAT message. 834 842 * 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. 836 845 * @param pWinCtx Windows context to use. 837 846 * @param fFormats Clipboard format(s) to announce. … … 841 850 LogFunc(("fFormats=0x%x\n", fFormats)); 842 851 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); 843 856 /* 844 857 * Set the clipboard formats. … … 846 859 static struct 847 860 { 861 /** VBox format to handle. */ 848 862 uint32_t fVBoxFormat; 863 /** Native Windows format to use. 864 * Set to 0 if unused / needs special handling. */ 849 865 UINT uWinFormat; 850 const char *pszWinFormat; 866 /** Own registered format. Set to NULL if not used / applicable. */ 867 const char *pszRegFormat; 851 868 const char *pszLog; 852 869 } s_aFormats[] = 853 870 { 854 871 { 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 855 877 { 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" } 857 879 }; 880 858 881 unsigned cSuccessfullySet = 0; 859 882 SHCLFORMATS fFormatsLeft = fFormats; … … 863 886 if (fFormatsLeft & s_aFormats[i].fVBoxFormat) 864 887 { 865 Log Func(("%s\n", s_aFormats[i].pszLog));888 LogRel2(("Shared Clipboard: Announcing format '%s' to clipboard\n", s_aFormats[i].pszLog)); 866 889 fFormatsLeft &= ~s_aFormats[i].fVBoxFormat; 867 890 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). */ 870 901 if (!uWinFormat) 871 902 { 872 uWinFormat = RegisterClipboardFormat(s_aFormats[i].pszWinFormat);873 AssertContinue(uWinFormat != 0);903 cSuccessfullySet++; 904 continue; 874 905 } 875 906 … … 903 934 else if (RT_SUCCESS(rc) && fFormatsLeft != 0) 904 935 { 905 Log Func(("Unsupported formats: %#x (%#x)\n", fFormatsLeft, fFormats));936 LogRel(("Shared Clipboard: Unable to announce unsupported/invalid formats: %#x (%#x)\n", fFormatsLeft, fFormats)); 906 937 rc = VERR_NOT_SUPPORTED; 907 938 } … … 917 948 * a separate WM_RENDERFORMAT message. 918 949 * 919 * @returns VBox status code. VERR_NOT_SUPPORTED if the format is not supported / handled.950 * @returns VBox status code. 920 951 * @param pWinCtx Windows context to use. 921 952 * @param fFormats Clipboard format(s) to announce. … … 1003 1034 1004 1035 #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. 1008 1038 * 1009 1039 * This creates the necessary IDataObject + IStream implementations and initiates the actual transfers required for getting … … 1012 1042 * @returns VBox status code. 1013 1043 * @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 */ 1048 int 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); 1024 1053 1025 1054 /* Make sure to enter the critical section before setting the clipboard data, as otherwise WM_CLIPBOARDUPDATE … … 1028 1057 if (RT_SUCCESS(rc)) 1029 1058 { 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 */ 1137 int 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 { 1030 1150 SharedClipboardWinTransferCtx *pWinURITransferCtx = new SharedClipboardWinTransferCtx(); 1031 1151 if (pWinURITransferCtx) … … 1034 1154 pTransfer->cbUser = sizeof(SharedClipboardWinTransferCtx); 1035 1155 1036 pWinURITransferCtx->pDataObj = new SharedClipboardWinDataObject( pTransfer);1156 pWinURITransferCtx->pDataObj = new SharedClipboardWinDataObject(); 1037 1157 if (pWinURITransferCtx->pDataObj) 1038 1158 { 1039 rc = pWinURITransferCtx->pDataObj->Init( );1159 rc = pWinURITransferCtx->pDataObj->Init(pCtx); 1040 1160 if (RT_SUCCESS(rc)) 1041 1161 { … … 1090 1210 return rc; 1091 1211 } 1212 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 1092 1213 1093 1214 /** … … 1133 1254 * @param pTransfer Transfer to get roots for. 1134 1255 */ 1135 int SharedClipboardWin GetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer)1256 int SharedClipboardWinTransferGetRootsFromClipboard(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer) 1136 1257 { 1137 1258 AssertPtrReturn(pWinCtx, VERR_INVALID_POINTER); … … 1151 1272 if (hDrop) 1152 1273 { 1153 char *p apszList = NULL;1274 char *pszList = NULL; 1154 1275 uint32_t cbList; 1155 rc = SharedClipboardWin DropFilesToStringList((DROPFILES *)hDrop, &papszList, &cbList);1276 rc = SharedClipboardWinTransferDropFilesToStringList((DROPFILES *)hDrop, &pszList, &cbList); 1156 1277 1157 1278 GlobalUnlock(hClip); … … 1159 1280 if (RT_SUCCESS(rc)) 1160 1281 { 1161 rc = ShClTransferRootsSet(pTransfer, 1162 papszList, cbList + 1 /* Include termination */); 1163 RTStrFree(papszList); 1282 rc = ShClTransferRootsInitFromStringList(pTransfer, pszList, cbList); 1283 RTStrFree(pszList); 1164 1284 } 1165 1285 } … … 1179 1299 1180 1300 /** 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. 1182 1302 * Does not do any locking on the input data. 1183 1303 * 1184 1304 * @returns VBox status code. 1185 1305 * @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(). 1187 1308 * @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 */ 1311 int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **ppszList, uint32_t *pcbList) 1190 1312 { 1191 1313 AssertPtrReturn(pDropFiles, VERR_INVALID_POINTER); 1192 AssertPtrReturn(p apszList,VERR_INVALID_POINTER);1314 AssertPtrReturn(ppszList, VERR_INVALID_POINTER); 1193 1315 AssertPtrReturn(pcbList, VERR_INVALID_POINTER); 1194 1316 … … 1293 1415 /* Add separation between filenames. 1294 1416 * 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 */); 1296 1418 if (RT_SUCCESS(rc)) 1297 cchFiles += 2; /* Include \r\n*/1419 cchFiles += 2; /* Include SHCL_TRANSFER_URI_LIST_SEP_STR */ 1298 1420 } 1299 1421 … … 1306 1428 cFiles, cchFiles, cbFiles, pszFiles)); 1307 1429 1308 *p apszList = pszFiles;1430 *ppszList = pszFiles; 1309 1431 *pcbList = cbFiles; 1310 1432 } … … 1318 1440 return rc; 1319 1441 } 1320 1321 1442 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 1322 1443 -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp
r99953 r100204 190 190 * Internal structures * 191 191 *********************************************************************************************************************************/ 192 193 /**194 * A structure containing information about where to store a request195 * for the X11 clipboard contents.196 */197 typedef struct _CLIPREADX11CBREQ198 {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 210 192 211 193 #ifdef TESTCASE … … 1500 1482 * Needs to be free'd with RTMemFree() by the caller. 1501 1483 * @param pcb Returns the amount of data read (in bytes) on success. 1484 * 1485 * @thread X11 event thread. 1502 1486 */ 1503 1487 static int shClX11RequestDataForX11CallbackHelper(PSHCLX11CTX pCtx, SHCLFORMAT uFmt, … … 1507 1491 AssertPtrReturn(ppv, VERR_INVALID_POINTER); 1508 1492 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 1509 1502 1510 1503 LogFlowFunc(("pCtx=%p, uFmt=%#x\n", pCtx, uFmt)); … … 1535 1528 rc = pCtx->Callbacks.pfnOnRequestDataFromSource(pCtx->pFrontend, uFmt, &pv, &cb, NULL /* pvUser */); 1536 1529 1537 1538 1530 /* Safey net in case the callbacks above misbehave 1539 1531 * (must return VERR_NO_DATA if no data available). */ … … 1547 1539 *pcb = cb; 1548 1540 } 1541 1542 if (RT_FAILURE(rc)) 1543 LogRel(("Shared Clipboard: Requesting data for X11 from source failed with %Rrc\n", rc)); 1549 1544 1550 1545 LogFlowFunc(("Returning pv=%p, cb=%RU32, rc=%Rrc\n", pv, cb, rc)); … … 1880 1875 1881 1876 /** 1882 * Structure used to pass information about formats that VBox supports.1883 */1884 typedef struct _CLIPNEWVBOXFORMATS1885 {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 /**1895 1877 * Invalidates the local cache of the data in the VBox clipboard. 1896 1878 * … … 1940 1922 1941 1923 /** 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 1946 1927 * information about the VBox formats available and the 1947 1928 * clipboard context data. Must be freed by the worker. 1929 * 1930 * @thread X11 event thread. 1948 1931 */ 1949 1932 static void ShClX11ReportFormatsToX11Worker(void *pvUserData, void * /* interval */) … … 1951 1934 AssertPtrReturnVoid(pvUserData); 1952 1935 1953 CLIPNEWVBOXFORMATS *pFormats = (CLIPNEWVBOXFORMATS *)pvUserData;1954 1955 PSHCLX11CTX pCtx = p Formats->pCtx;1956 SHCLFORMATS fFormats = p Formats->Formats;1957 1958 RTMemFree(p Formats);1936 PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)pvUserData; 1937 1938 PSHCLX11CTX pCtx = pReq->pCtx; 1939 SHCLFORMATS fFormats = pReq->Formats.fFormats; 1940 1941 RTMemFree(pReq); 1959 1942 1960 1943 #ifdef LOG_ENABLED … … 1979 1962 * @param uFormats Clipboard formats offered. 1980 1963 */ 1981 int ShClX11ReportFormatsToX11 (PSHCLX11CTX pCtx, SHCLFORMATS uFormats)1964 int ShClX11ReportFormatsToX11Async(PSHCLX11CTX pCtx, SHCLFORMATS uFormats) 1982 1965 { 1983 1966 /* … … 1989 1972 int rc; 1990 1973 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); 1999 1981 if (RT_FAILURE(rc)) 2000 RTMemFree(p Formats);1982 RTMemFree(pReq); 2001 1983 } 2002 1984 else … … 2007 1989 } 2008 1990 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 */ 2003 int 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. 2012 2059 * 2013 2060 * Converts the text obtained UTF-16LE with Windows EOLs. 2014 2061 * Converts full BMP data to DIB format. 2062 * 2063 * @thread X11 event thread. 2015 2064 */ 2016 2065 SHCL_X11_DECL(void) clipConvertDataFromX11Worker(void *pClient, void *pvSrc, unsigned cbSrc) 2017 2066 { 2018 CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pClient;2067 PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)pClient; 2019 2068 AssertPtrReturnVoid(pReq); 2020 2069 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)); 2025 2074 2026 2075 AssertPtr(pReq->pCtx); 2027 Assert(pReq-> uFmtVBox != VBOX_SHCL_FMT_NONE); /* Sanity. */2076 Assert(pReq->Read.uFmtVBox != VBOX_SHCL_FMT_NONE); /* Sanity. */ 2028 2077 2029 2078 int rc = VINF_SUCCESS; … … 2048 2097 rc = VERR_NO_DATA; 2049 2098 } 2050 else if (pReq-> uFmtVBox == VBOX_SHCL_FMT_UNICODETEXT)2099 else if (pReq->Read.uFmtVBox == VBOX_SHCL_FMT_UNICODETEXT) 2051 2100 { 2052 2101 /* In which format is the clipboard data? */ 2053 switch (clipRealFormatForX11Format(pReq-> idxFmtX11))2102 switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11)) 2054 2103 { 2055 2104 case SHCLX11FMT_UTF8: … … 2069 2118 cwDst += 1 /* Include terminator */; 2070 2119 cbDst = cwDst * sizeof(RTUTF16); /* Convert RTUTF16 units to bytes. */ 2120 2121 LogFlowFunc(("UTF-16 text (%zu bytes):\n%ls\n", cbDst, pvDst)); 2071 2122 } 2072 2123 break; … … 2080 2131 } 2081 2132 } 2082 else if (pReq-> uFmtVBox == VBOX_SHCL_FMT_BITMAP)2133 else if (pReq->Read.uFmtVBox == VBOX_SHCL_FMT_BITMAP) 2083 2134 { 2084 2135 /* In which format is the clipboard data? */ 2085 switch (clipRealFormatForX11Format(pReq-> idxFmtX11))2136 switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11)) 2086 2137 { 2087 2138 case SHCLX11FMT_BMP: … … 2112 2163 } 2113 2164 } 2114 else if (pReq-> uFmtVBox == VBOX_SHCL_FMT_HTML)2165 else if (pReq->Read.uFmtVBox == VBOX_SHCL_FMT_HTML) 2115 2166 { 2116 2167 /* In which format is the clipboard data? */ 2117 switch (clipRealFormatForX11Format(pReq-> idxFmtX11))2168 switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11)) 2118 2169 { 2119 2170 case SHCLX11FMT_HTML: … … 2175 2226 } 2176 2227 # 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) 2178 2229 { 2179 2230 /* In which format is the clipboard data? */ 2180 switch (clipRealFormatForX11Format(pReq-> idxFmtX11))2231 switch (clipRealFormatForX11Format(pReq->Read.idxFmtX11)) 2181 2232 { 2182 2233 case SHCLX11FMT_URI_LIST: 2183 2234 { 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)) 2186 2238 { 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 2189 2240 for (size_t i = 0; i < lstRootEntries.size(); ++i) 2190 2241 { 2191 char *pszEntry = RTUriFilePath(lstRootEntries.at(i).c_str()) ;2242 char *pszEntry = RTUriFilePath(lstRootEntries.at(i).c_str()) 2192 2243 AssertPtrBreakStmt(pszEntry, VERR_INVALID_PARAMETER); 2244 2245 LogFlowFunc(("Entry '%s' -> ", (char *)pszEntry)); 2193 2246 2194 2247 rc = RTStrAAppend((char **)&pvDst, "http://localhost"); … … 2205 2258 cbDst += (uint32_t)strlen(pszEntry); 2206 2259 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); 2210 2263 AssertRCBreakStmt(rc, VERR_NO_MEMORY); 2211 cbDst += (uint32_t)strlen( "\r\n");2264 cbDst += (uint32_t)strlen(SHCL_TRANSFER_URI_LIST_SEP_STR); 2212 2265 2213 2266 RTStrFree(pszEntry); … … 2216 2269 if (cbDst) 2217 2270 cbDst++; /* Include final (zero) termination. */ 2218 2219 LogFlowFunc(("URI list: cbDst=%RU32\n", cbDst)); 2271 #endif 2272 2273 2220 2274 } 2221 else2222 rc = VERR_INVALID_PARAMETER;2223 2275 break; 2224 2276 } … … 2235 2287 rc = VERR_NOT_SUPPORTED; 2236 2288 2289 LogFlowFunc(("pvDst=%p, cbDst=%RU32\n", pvDst, cbDst)); 2290 2237 2291 if (RT_FAILURE(rc)) 2238 2292 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); 2248 2330 RTMemFree(pvDst); 2249 RTMemFree(pReq);2250 2331 2251 2332 LogFlowFuncLeaveRC(rc); … … 2253 2334 2254 2335 /** 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. 2260 2339 */ 2261 2340 SHCL_X11_DECL(void) clipConvertDataFromX11(Widget widget, XtPointer pClient, … … 2268 2347 int rc = VINF_SUCCESS; 2269 2348 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 2280 2349 if (*atomType == XT_CONVERT_FAIL) /* Xt timeout */ 2281 2350 { … … 2285 2354 else 2286 2355 { 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. */ 2294 2366 { 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 } 2298 2376 } 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; 2302 2382 } 2303 2383 … … 2305 2385 { 2306 2386 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. */ 2308 2389 clipConvertDataFromX11Worker(pClient, NULL, 0); 2309 2390 } … … 2322 2403 */ 2323 2404 static int clipGetSelectionValueEx(PSHCLX11CTX pCtx, const char *pszWhere, SHCLX11FMTIDX idxFmt, 2324 CLIPREADX11CBREQ *pReq)2405 PSHCLX11REQUEST pReq) 2325 2406 { 2326 2407 AssertPtrReturn(pszWhere, VERR_INVALID_POINTER); … … 2354 2435 * @sa clipGetSelectionValueEx() for requesting data for a specific selection. 2355 2436 */ 2356 static int clipGetSelectionValue(PSHCLX11CTX pCtx, SHCLX11FMTIDX idxFmt, CLIPREADX11CBREQ *pReq)2437 static int clipGetSelectionValue(PSHCLX11CTX pCtx, SHCLX11FMTIDX idxFmt, PSHCLX11REQUEST pReq) 2357 2438 { 2358 2439 return clipGetSelectionValueEx(pCtx, "CLIPBOARD", idxFmt, pReq); … … 2360 2441 2361 2442 /** 2362 * Worker function for ShClX11ReadDataFromX11 which runs on the event thread.2363 * 2364 * @param pvUserDataPointer to a CLIPREADX11CBREQ structure containing2443 * Worker function for ShClX11ReadDataFromX11Async. 2444 * 2445 * @param pvUserData Pointer to a CLIPREADX11CBREQ structure containing 2365 2446 * information about the clipboard read request. 2366 2447 * Must be free'd by the worker. 2448 * @thread X11 event thread. 2367 2449 */ 2368 2450 static void ShClX11ReadDataFromX11Worker(void *pvUserData, void * /* interval */) … … 2370 2452 AssertPtrReturnVoid(pvUserData); 2371 2453 2372 CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pvUserData;2454 PSHCLX11REQUEST pReq = (PSHCLX11REQUEST)pvUserData; 2373 2455 SHCLX11CTX *pCtx = pReq->pCtx; 2374 2456 AssertPtrReturnVoid(pCtx); 2375 2457 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)); 2377 2459 2378 2460 int rc = VERR_NO_DATA; /* VBox thinks we have data and we don't. */ … … 2388 2470 else 2389 2471 #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) 2394 2476 { 2395 2477 /* Send out a request for the data to the current clipboard owner. */ … … 2397 2479 } 2398 2480 } 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) 2403 2485 { 2404 2486 /* Send out a request for the data to the current clipboard owner. */ … … 2406 2488 } 2407 2489 } 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) 2412 2494 { 2413 2495 /* Send out a request for the data to the current clipboard owner. */ … … 2416 2498 } 2417 2499 #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) 2422 2504 { 2423 2505 /* Send out a request for the data to the current clipboard owner. */ … … 2434 2516 } 2435 2517 2436 if (RT_FAILURE(rc))2437 {2438 /* The clipboard callback was never scheduled, so we must signal2439 * 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 2449 2518 LogFlowFuncLeaveRC(rc); 2450 2519 } 2451 2520 2452 2521 /** 2453 * Called when VBox wants to read the X11 clipboard.2522 * Reads the X11 clipboard (asynchronously). 2454 2523 * 2455 2524 * @returns VBox status code. … … 2458 2527 * @param pCtx Context data for the clipboard backend. 2459 2528 * @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(p Req, 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 */ 2534 int ShClX11ReadDataFromX11Async(PSHCLX11CTX pCtx, SHCLFORMAT uFmt, uint32_t cbMax, PSHCLEVENT pEvent) 2535 { 2536 AssertPtrReturn(pEvent, VERR_INVALID_POINTER); 2468 2537 /* 2469 2538 * Immediately return if we are not connected to the X server. … … 2474 2543 int rc = VINF_SUCCESS; 2475 2544 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; 2482 2552 2483 2553 /* We use this to schedule a worker function on the event thread. */ 2484 rc = clipThreadScheduleCall(pCtx, ShClX11ReadDataFromX11Worker, (XtPointer)p X11Req);2554 rc = clipThreadScheduleCall(pCtx, ShClX11ReadDataFromX11Worker, (XtPointer)pReq); 2485 2555 if (RT_FAILURE(rc)) 2486 RTMemFree(p X11Req);2556 RTMemFree(pReq); 2487 2557 } 2488 2558 else … … 2492 2562 return rc; 2493 2563 } 2564 -
trunk/src/VBox/GuestHost/SharedClipboard/testcase/Makefile.kmk
r99940 r100204 32 32 if1of ($(KBUILD_TARGET), freebsd linux netbsd openbsd solaris) 33 33 34 PROGRAMS += tstClipboardGH-X11 tstClipboardGH-X11Smoke 34 PROGRAMS += tstClipboardGH-X11Smoke 35 ## @todo BUGBUG Make tstClipboardGH-X11 build again and enable! 35 36 TESTING += \ 36 37 $(tstClipboardGH-X11_0_OUTDIR)/tstClipboardGH-X11.run \ -
trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardGH-X11.cpp
r98103 r100204 103 103 g_tst_pvDataVBox = NULL; 104 104 g_tst_cbDataVBox = 0; 105 ShClX11ReportFormatsToX11 (pCtx, 0);105 ShClX11ReportFormatsToX11Async(pCtx, 0); 106 106 } 107 107 … … 125 125 g_tst_pvDataVBox = pv; 126 126 g_tst_cbDataVBox = cb; 127 ShClX11ReportFormatsToX11 (pCtx, VBOX_SHCL_FMT_UNICODETEXT);127 ShClX11ReportFormatsToX11Async(pCtx, VBOX_SHCL_FMT_UNICODETEXT); 128 128 return VINF_SUCCESS; 129 129 } … … 385 385 static int g_tst_rcCompleted = VINF_SUCCESS; 386 386 static int g_tst_cbCompleted = 0; 387 static CLIPREADCBREQ*g_tst_pCompletedReq = NULL;387 static SHCLX11REQUEST *g_tst_pCompletedReq = NULL; 388 388 static char g_tst_abCompletedBuf[TESTCASE_MAX_BUF_SIZE]; 389 389 … … 413 413 RT_NOREF(pCtx); 414 414 415 PSHCLX11RE ADDATAREQ pData = (PSHCLX11READDATAREQ)pvUser;415 PSHCLX11RESPONSE pData = (PSHCLX11RESPONSE)pvUser; 416 416 417 417 if (cb <= TESTCASE_MAX_BUF_SIZE) 418 418 { 419 g_tst_rcCompleted = pData->rc Completion;419 g_tst_rcCompleted = pData->rc; 420 420 if (cb != 0) 421 421 memcpy(g_tst_abCompletedBuf, pv, cb); … … 465 465 } 466 466 467 static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, CLIPREADCBREQ**ppReq)467 static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, SHCLX11REQREAD **ppReq) 468 468 { 469 469 *prc = g_tst_rcCompleted; … … 485 485 { 486 486 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); 489 489 int rc = VINF_SUCCESS; 490 490 uint32_t cbActual = 0; … … 542 542 { 543 543 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); 546 546 int rc = VINF_SUCCESS; 547 547 uint32_t cbActual = 0; … … 618 618 static void tstNoX11(PSHCLX11CTX pCtx, const char *pcszTestCtx) 619 619 { 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); 622 622 RTTESTI_CHECK_MSG(rc == VERR_NO_DATA, ("context: %s\n", pcszTestCtx)); 623 623 } … … 655 655 { 656 656 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. */ 659 659 int rc = VINF_SUCCESS; 660 660 uint32_t cbActual = 0; … … 696 696 char *pc; 697 697 uint32_t cbActual; 698 CLIPREADCBREQ *pReq = (CLIPREADCBREQ*)&pReq, *pReqRet = NULL;698 SHCLX11REQREAD *pReq = (SHCLX11REQREAD *)&pReq, *pReqRet = NULL; 699 699 700 700 /* UTF-8 from X11 */ … … 778 778 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, NULL, 779 779 0, 8); 780 ShClX11ReadDataFromX11 (&X11Ctx, VBOX_SHCL_FMT_UNICODETEXT, pReq);780 ShClX11ReadDataFromX11Async(&X11Ctx, VBOX_SHCL_FMT_UNICODETEXT, pReq); 781 781 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet); 782 782 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA, … … 802 802 /* Testing for 0xffff will go into handling VBOX_SHCL_FMT_UNICODETEXT, where we don't have 803 803 * 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); 805 805 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet); 806 806 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA, … … 898 898 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8); 899 899 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2); 900 ShClX11ReportFormatsToX11 (&X11Ctx, 0xa0000);900 ShClX11ReportFormatsToX11Async(&X11Ctx, 0xa0000); 901 901 RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel, 902 902 (hTest, "VBox grabbed the clipboard with unknown data and we ignored it\n")); -
trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardHttpServer.cpp
r99937 r100204 178 178 RTTEST_CHECK(hTest, ShClTransferHttpServerIsRunning(&HttpSrv) == false); 179 179 if (uPort) 180 rc = ShClTransferHttpServer CreateEx(&HttpSrv, uPort);180 rc = ShClTransferHttpServerStartEx(&HttpSrv, uPort); 181 181 else 182 rc = ShClTransferHttpServer Create(&HttpSrv, 32 /* cMaxAttempts */, &uPort);182 rc = ShClTransferHttpServerStart(&HttpSrv, 32 /* cMaxAttempts */, &uPort); 183 183 RTTEST_CHECK_RC_OK(hTest, rc); 184 RTTEST_CHECK(hTest, ShClTransferHttpServer HasTransfer(&HttpSrv, 0) == false);185 RTTEST_CHECK(hTest, ShClTransferHttpServer HasTransfer(&HttpSrv, 42) == false);184 RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 0) == false); 185 RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 42) == false); 186 186 187 187 char *pszSrvAddr = ShClTransferHttpServerGetAddressA(&HttpSrv); … … 208 208 RTTEST_CHECK_RC_OK(hTest, ShClTransferCreate(&pTx)); 209 209 RTTEST_CHECK_RC_OK(hTest, ShClTransferInit(pTx, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL)); 210 RTTEST_CHECK_RC_OK(hTest, ShClTransferRoots SetAsFile(pTx, ValueUnion.psz));210 RTTEST_CHECK_RC_OK(hTest, ShClTransferRootsInitFromFile(pTx, ValueUnion.psz)); 211 211 RTTEST_CHECK_RC_OK(hTest, ShClTransferCtxTransferRegister(&TxCtx, pTx, NULL)); 212 212 RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerRegisterTransfer(&HttpSrv, pTx)); -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp
r98103 r100204 262 262 * Now, request the data from the guest. 263 263 */ 264 return ShClSvc GuestDataRequest(pClient, fFormats, NULL /* pidEvent */);264 return ShClSvcReadDataFromGuestAsync(pClient, fFormats, NULL /* ppEvent */); 265 265 } 266 266 -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h
r99951 r100204 186 186 /** Transfer context. */ 187 187 SHCLTRANSFERCTX Ctx; 188 /** Transfers callbacks to use. */ 189 SHCLTRANSFERCALLBACKTABLE Callbacks; 188 190 } SHCLIENTTRANSFERS, *PSHCLIENTTRANSFERS; 189 191 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ … … 302 304 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 303 305 int shClSvcTransferModeSet(uint32_t fMode); 304 int shClSvcTransferStart(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, PSHCLTRANSFER *ppTransfer); 305 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer); 306 int shClSvcTransferInit(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, PSHCLTRANSFER *ppTransfer); 307 int shClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer); 308 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest); 306 309 bool shClSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg); 307 310 void shClSvcClientTransfersReset(PSHCLCLIENT pClient); … … 312 315 * @{ 313 316 */ 314 int ShClSvc GuestDataRequest(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent);317 int ShClSvcReadDataFromGuestAsync(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent); 315 318 int ShClSvcGuestDataSignal(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData); 316 319 int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats); … … 493 496 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ 494 497 495 int shClSvcTransferIfaceRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList); 496 498 int shClSvcTransferIfaceRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLLIST pRootList); 497 499 int shClSvcTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); 498 500 int shClSvcTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList); -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp
r99969 r100204 97 97 *********************************************************************************************************************************/ 98 98 99 /** @copydoc SHCLTXPROVIDERIFACE::pfnRoot sGet*/100 DECLCALLBACK(int) shClSvcTransferIfaceRoot sGet(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)99 /** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */ 100 DECLCALLBACK(int) shClSvcTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx) 101 101 { 102 102 LogFlowFuncEnter(); … … 132 132 if (RT_SUCCESS(rc)) 133 133 { 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++) 141 140 { 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); 194 146 if (RT_SUCCESS(rc)) 195 147 { 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; 200 174 } 201 175 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; 205 183 } 206 else 207 rc = VERR_NO_MEMORY;184 185 ShClPayloadFree(pPayloadHdr); 208 186 } 209 187 } … … 212 190 } 213 191 else 192 { 193 shClSvcMsgFree(pClient, pMsgHdr); 214 194 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 195 } 215 196 } 216 197 else … … 246 227 if (RT_SUCCESS(rc)) 247 228 { 229 shClSvcClientLock(pClient); 230 248 231 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 249 250 232 rc = shClSvcClientWakeup(pClient); 233 234 shClSvcClientUnlock(pClient); 235 251 236 if (RT_SUCCESS(rc)) 252 237 { … … 274 259 } 275 260 else 261 { 262 shClSvcMsgFree(pClient, pMsg); 276 263 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 264 } 277 265 } 278 266 else … … 307 295 if (RT_SUCCESS(rc)) 308 296 { 297 shClSvcClientLock(pClient); 298 309 299 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 310 311 300 rc = shClSvcClientWakeup(pClient); 301 302 shClSvcClientUnlock(pClient); 303 312 304 if (RT_SUCCESS(rc)) 313 305 { … … 322 314 } 323 315 else 316 { 317 shClSvcMsgFree(pClient, pMsg); 324 318 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 319 } 325 320 } 326 321 else … … 355 350 HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fFlags */); 356 351 352 shClSvcClientLock(pClient); 353 357 354 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 358 359 355 rc = shClSvcClientWakeup(pClient); 356 357 shClSvcClientUnlock(pClient); 358 360 359 if (RT_SUCCESS(rc)) 361 360 { … … 375 374 } 376 375 else 376 { 377 shClSvcMsgFree(pClient, pMsg); 377 378 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 379 } 378 380 } 379 381 else … … 419 421 HGCMSvcSetU32(&pMsg->aParms[2], 0 /* fInfo */); 420 422 423 shClSvcClientLock(pClient); 424 421 425 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 422 423 426 rc = shClSvcClientWakeup(pClient); 427 428 shClSvcClientUnlock(pClient); 429 424 430 if (RT_SUCCESS(rc)) 425 431 { … … 439 445 } 440 446 else 447 { 448 shClSvcMsgFree(pClient, pMsg); 441 449 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 450 } 442 451 } 443 452 else … … 460 469 461 470 /** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */ 462 int shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, 463 PSHCLOBJHANDLE phObj) 471 DECLCALLBACK(int) shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj) 464 472 { 465 473 LogFlowFuncEnter(); … … 485 493 pCtx->pTransfer->State.uID, pEvent->idEvent)); 486 494 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); 490 499 491 500 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 492 493 501 rc = shClSvcClientWakeup(pClient); 502 503 shClSvcClientUnlock(pClient); 504 494 505 if (RT_SUCCESS(rc)) 495 506 { … … 516 527 } 517 528 else 529 { 530 shClSvcMsgFree(pClient, pMsg); 518 531 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 532 } 519 533 } 520 534 else … … 526 540 527 541 /** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */ 528 intshClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)542 DECLCALLBACK(int) shClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj) 529 543 { 530 544 LogFlowFuncEnter(); … … 547 561 HGCMSvcSetU64(&pMsg->aParms[1], hObj); 548 562 563 shClSvcClientLock(pClient); 564 549 565 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 550 551 566 rc = shClSvcClientWakeup(pClient); 567 568 shClSvcClientUnlock(pClient); 569 552 570 if (RT_SUCCESS(rc)) 553 571 { … … 572 590 } 573 591 else 592 { 593 shClSvcMsgFree(pClient, pMsg); 574 594 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 595 } 575 596 } 576 597 else … … 582 603 583 604 /** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */ 584 intshClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,585 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)605 DECLCALLBACK(int) shClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, 606 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead) 586 607 { 587 608 LogFlowFuncEnter(); … … 606 627 HGCMSvcSetU32(&pMsg->aParms[3], fFlags); 607 628 629 shClSvcClientLock(pClient); 630 608 631 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 609 610 632 rc = shClSvcClientWakeup(pClient); 633 634 shClSvcClientUnlock(pClient); 635 611 636 if (RT_SUCCESS(rc)) 612 637 { … … 634 659 } 635 660 else 661 { 662 shClSvcMsgFree(pClient, pMsg); 636 663 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 664 } 637 665 } 638 666 else … … 644 672 645 673 /** @copydoc SHCLTXPROVIDERIFACE::pfnObjWrite */ 646 intshClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,647 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)674 DECLCALLBACK(int) shClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, 675 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten) 648 676 { 649 677 LogFlowFuncEnter(); … … 668 696 HGCMSvcSetU64(&pMsg->aParms[3], fFlags); 669 697 698 shClSvcClientLock(pClient); 699 670 700 shClSvcMsgAdd(pClient, pMsg, true /* fAppend */); 671 672 701 rc = shClSvcClientWakeup(pClient); 702 703 shClSvcClientUnlock(pClient); 704 673 705 if (RT_SUCCESS(rc)) 674 706 { … … 691 723 } 692 724 else 725 { 726 shClSvcMsgFree(pClient, pMsg); 693 727 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 728 } 694 729 } 695 730 else … … 883 918 */ 884 919 static int shClSvcTransferGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM aParms[], 885 PSHCL ROOTLISTHDR pRootLstHdr)920 PSHCLLISTHDR pRootLstHdr) 886 921 { 887 922 int rc; … … 889 924 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE) 890 925 { 891 rc = HGCMSvcGetU32(&aParms[1], &pRootLstHdr->f Roots);892 if (RT_SUCCESS(rc)) 893 rc = HGCMSvcGetU 32(&aParms[2], &pRootLstHdr->cRoots);926 rc = HGCMSvcGetU32(&aParms[1], &pRootLstHdr->fFeatures); 927 if (RT_SUCCESS(rc)) 928 rc = HGCMSvcGetU64(&aParms[2], &pRootLstHdr->cEntries); 894 929 } 895 930 else … … 909 944 */ 910 945 static int shClSvcTransferGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM aParms[], 911 PSHCL ROOTLISTENTRY pListEntry)946 PSHCLLISTENTRY pListEntry) 912 947 { 913 948 int rc; … … 1047 1082 rc = HGCMSvcGetU32(&aParms[3], &pListHdr->fFeatures); 1048 1083 if (RT_SUCCESS(rc)) 1049 rc = HGCMSvcGetU64(&aParms[4], &pListHdr->c TotalObjects);1084 rc = HGCMSvcGetU64(&aParms[4], &pListHdr->cEntries); 1050 1085 if (RT_SUCCESS(rc)) 1051 1086 rc = HGCMSvcGetU64(&aParms[5], &pListHdr->cbTotalSize); … … 1082 1117 1083 1118 HGCMSvcSetU32(&aParms[3], pListHdr->fFeatures); 1084 HGCMSvcSetU64(&aParms[4], pListHdr->c TotalObjects);1119 HGCMSvcSetU64(&aParms[4], pListHdr->cEntries); 1085 1120 HGCMSvcSetU64(&aParms[5], pListHdr->cbTotalSize); 1086 1121 … … 1190 1225 if (RT_SUCCESS(rc)) 1191 1226 { 1192 uint32_t cb Data;1193 rc = HGCMSvcGetU32(&aParms[2], &cb Data);1227 uint32_t cbToRead; 1228 rc = HGCMSvcGetU32(&aParms[2], &cbToRead); 1194 1229 if (RT_SUCCESS(rc)) 1195 1230 { 1196 1231 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. */ 1201 1237 } 1202 1238 } … … 1241 1277 { 1242 1278 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 1243 1306 RT_FALL_THROUGH(); 1307 } 1244 1308 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN: 1245 1309 RT_FALL_THROUGH(); … … 1333 1397 PSHCLTRANSFER pTransfer = NULL; 1334 1398 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 1335 1404 switch (u32Function) 1336 1405 { … … 1347 1416 break; 1348 1417 1418 ASSERT_GUEST_RETURN(aParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE); 1419 1349 1420 rc = HGCMSvcGetU64(&aParms[0], &uCID); 1350 1421 if (RT_FAILURE(rc)) … … 1381 1452 break; 1382 1453 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 1383 1457 if ( ShClTransferGetSource(pTransfer) == SHCLSOURCE_LOCAL 1384 1458 && ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_TO_REMOTE) … … 1388 1462 } 1389 1463 else 1390 {1391 rc = VERR_INVALID_PARAMETER;1392 1464 break; 1393 } 1394 1395 SHCLROOTLISTHDR rootListHdr; 1465 1466 SHCLLISTHDR rootListHdr; 1396 1467 RT_ZERO(rootListHdr); 1397 1468 1398 rootListHdr.cRoots = ShClTransferRootsCount(pTransfer); 1469 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer); 1470 /** @todo BUGBUG What about the features? */ 1399 1471 1400 1472 HGCMSvcSetU64(&aParms[0], 0 /* Context ID */); 1401 HGCMSvcSetU32(&aParms[1], rootListHdr.f Roots);1402 HGCMSvcSetU 32(&aParms[2], rootListHdr.cRoots);1473 HGCMSvcSetU32(&aParms[1], rootListHdr.fFeatures); 1474 HGCMSvcSetU64(&aParms[2], rootListHdr.cEntries); 1403 1475 1404 1476 rc = VINF_SUCCESS; … … 1408 1480 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE: 1409 1481 { 1410 SHCL ROOTLISTHDR lstHdr;1482 SHCLLISTHDR lstHdr; 1411 1483 rc = shClSvcTransferGetRootListHdr(cParms, aParms, &lstHdr); 1412 1484 if (RT_SUCCESS(rc)) 1413 1485 { 1414 void *pvData = ShClTransfer RootListHdrDup(&lstHdr);1415 uint32_t cbData = sizeof(SHCL ROOTLISTHDR);1486 void *pvData = ShClTransferListHdrDup(&lstHdr); 1487 uint32_t cbData = sizeof(SHCLLISTHDR); 1416 1488 1417 1489 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID)); … … 1438 1510 break; 1439 1511 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 1454 1547 break; 1455 1548 } … … 1457 1550 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE: 1458 1551 { 1459 SHCL ROOTLISTENTRY lstEntry;1552 SHCLLISTENTRY lstEntry; 1460 1553 rc = shClSvcTransferGetRootListEntry(cParms, aParms, &lstEntry); 1461 1554 if (RT_SUCCESS(rc)) 1462 1555 { 1463 void *pvData = ShClTransfer RootListEntryDup(&lstEntry);1464 uint32_t cbData = sizeof(SHCL ROOTLISTENTRY);1556 void *pvData = ShClTransferListEntryDup(&lstEntry); 1557 uint32_t cbData = sizeof(SHCLLISTENTRY); 1465 1558 1466 1559 const PSHCLEVENT pEvent = ShClEventSourceGetFromId(&pClient->EventSrc, VBOX_SHCL_CONTEXTID_GET_EVENT(uCID)); … … 1658 1751 break; 1659 1752 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 1660 1759 SHCLOBJHANDLE hObj; 1661 1760 rc = HGCMSvcGetU64(&aParms[1], &hObj); /* Get object handle. */ 1761 AssertRCBreak(rc); 1662 1762 1663 1763 uint32_t cbToRead = 0; 1664 if (RT_SUCCESS(rc))1665 rc = HGCMSvcGetU32(&aParms[2], &cbToRead);1764 rc = HGCMSvcGetU32(&aParms[2], &cbToRead); 1765 AssertRCBreak(rc); 1666 1766 1667 1767 void *pvBuf = NULL; 1668 1768 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); 1671 1771 1672 1772 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, cbToRead=%RU32, rc=%Rrc\n", hObj, cbBuf, cbToRead, rc)); … … 1688 1788 if (RT_SUCCESS(rc)) 1689 1789 { 1690 HGCMSvcSetU32(&aParms[ 3], cbRead);1790 HGCMSvcSetU32(&aParms[2], cbRead); 1691 1791 1692 1792 /** @todo Implement checksum support. */ … … 1699 1799 { 1700 1800 SHCLOBJDATACHUNK dataChunk; 1801 1701 1802 rc = shClSvcTransferGetObjDataChunk(cParms, aParms, &dataChunk); 1702 1803 if (RT_SUCCESS(rc)) … … 1751 1852 switch (u32Function) 1752 1853 { 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. */ 1757 1858 break; 1758 1859 … … 1793 1894 * @param ppEvent Where to return the wait event on success. Optional. 1794 1895 * Must be released by the caller with ShClEventRelease(). 1896 * 1897 * @note Caller must enter critical section. 1795 1898 */ 1796 1899 int shClSvcTransferSendStatus(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus, … … 1838 1941 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 1839 1942 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 1840 1947 LogFlowFuncLeaveRC(rc); 1841 1948 return rc; … … 1843 1950 1844 1951 /** 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 */ 1958 void 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. 1846 1987 * 1847 1988 * @note Assumes that the client's critical section is taken. … … 1853 1994 * @param ppTransfer Where to return the created transfer on success. Optional. 1854 1995 */ 1855 int shClSvcTransferStart(PSHCLCLIENT pClient, 1856 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, 1857 PSHCLTRANSFER *ppTransfer) 1858 { 1996 int shClSvcTransferInit(PSHCLCLIENT pClient, 1997 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, 1998 PSHCLTRANSFER *ppTransfer) 1999 { 2000 Assert(RTCritSectIsOwner(&pClient->CritSect)); 2001 1859 2002 AssertPtrReturn(pClient, VERR_INVALID_POINTER); 1860 2003 /* ppTransfer is optional. */ … … 1862 2005 LogFlowFuncEnter(); 1863 2006 2007 shClSvcTransferCleanupAllUnused(pClient); 2008 1864 2009 PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx; 1865 2010 1866 ShClTransferCtxCleanup(pTxCtx);1867 1868 2011 int rc; 1869 2012 1870 2013 if (!ShClTransferCtxTransfersMaximumReached(pTxCtx)) 1871 2014 { 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")); 1873 2017 1874 2018 PSHCLTRANSFER pTransfer; … … 1876 2020 if (RT_SUCCESS(rc)) 1877 2021 { 1878 SHCLTXPROVIDER CREATIONCTX creationCtx;1879 RT_ZERO( creationCtx);2022 SHCLTXPROVIDER Provider; 2023 RT_ZERO(Provider); 1880 2024 1881 2025 /* Assign local provider first and overwrite interface methods below if needed. */ 1882 VBClTransfer QueryIfaceLocal(&creationCtx.Interface);2026 VBClTransferProviderLocalQueryInterface(&Provider); 1883 2027 1884 2028 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host. */ 1885 2029 { 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; 1896 2040 } 1897 2041 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Host -> Guest. */ 1898 2042 { 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; 1902 2046 } 1903 2047 else 1904 2048 AssertFailed(); 1905 2049 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 1912 2058 rc = ShClTransferInit(pTransfer, enmDir, enmSource); 1913 2059 if (RT_SUCCESS(rc)) … … 1920 2066 if (RT_SUCCESS(rc)) 1921 2067 { 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 */); 1975 2071 } 1976 2072 } … … 2007 2103 2008 2104 /** 2009 * St ops (and destroys)a transfer, communicating the status to the guest side.2105 * Starts a transfer, communicating the status to the guest side. 2010 2106 * 2011 2107 * @returns VBox status code. … … 2013 2109 * @param pTransfer Transfer to stop. 2014 2110 */ 2015 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer) 2016 { 2111 int 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 */ 2138 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest) 2139 { 2140 LogRel2(("Shared Clipboard: Stopping transfer %RU32 ...\n", pTransfer->State.uID)); 2141 2142 shClSvcClientLock(pClient); 2143 2017 2144 PSHCLEVENT pEvent; 2018 2145 int rc = shClSvcTransferSendStatus(pClient, pTransfer, 2019 2146 SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS, &pEvent); 2020 if (RT_SUCCESS(rc)) 2147 if ( RT_SUCCESS(rc) 2148 && fWaitForGuest) 2021 2149 { 2022 2150 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID)); 2023 2151 2152 shClSvcClientUnlock(pClient); 2153 2024 2154 rc = ShClEventWait(pEvent, pTransfer->uTimeoutMs, NULL /* ppPayload */); 2025 2155 if (RT_SUCCESS(rc)) … … 2027 2157 2028 2158 ShClEventRelease(pEvent); 2159 2160 shClSvcClientLock(pClient); 2029 2161 } 2030 2162 … … 2043 2175 } 2044 2176 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 2045 2186 LogFlowFuncLeaveRC(rc); 2046 2187 return rc; -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp
r99967 r100204 68 68 { 69 69 /** Handle for window message handling thread. */ 70 RTTHREAD hThread;70 RTTHREAD hThread; 71 71 /** Structure for keeping and communicating with service client. */ 72 PSHCLCLIENT pClient;72 PSHCLCLIENT pClient; 73 73 /** Windows-specific context data. */ 74 SHCLWINCTX Win;74 SHCLWINCTX Win; 75 75 }; 76 76 … … 93 93 * (specified in @a pcbActualDst output parameter). 94 94 * @param u32Format VBox clipboard format (VBOX_SHCL_FMT_XXX) of copied data. 95 * VBOX_SHCL_FMT_NONE returns 0 data. 95 96 * @param pvSrc Pointer to host clipboard data. 96 97 * @param cbSrc Size (in bytes) of actual clipboard data to copy. … … 102 103 * function returns VINF_BUFFER_OVERFLOW. 103 104 */ 104 static int vboxClipboardSvcWinDataGet( uint32_tu32Format, const void *pvSrc, uint32_t cbSrc,105 static int vboxClipboardSvcWinDataGet(SHCLFORMAT u32Format, const void *pvSrc, uint32_t cbSrc, 105 106 void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst) 106 107 { 107 AssertPtrReturn(pvSrc, VERR_INVALID_POINTER);108 AssertReturn (cbSrc, VERR_INVALID_PARAMETER);109 AssertPtrReturn(pvDst, VERR_INVALID_POINTER);110 AssertReturn (cbDst, VERR_INVALID_PARAMETER);111 108 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); 112 119 113 120 LogFlowFunc(("cbSrc = %d, cbDst = %d\n", cbSrc, cbDst)); … … 152 159 } 153 160 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 */ 164 static int vboxClipboardSvcWinReadDataFromGuestWorker(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppvData, uint32_t *pcbData) 165 { 166 LogFlowFunc(("uFmt=%#x\n", uFmt)); 167 168 int rc; 164 169 165 170 PSHCLEVENT pEvent; 166 int rc = ShClSvcGuestDataRequest(pCtx->pClient, fFormat, &pEvent);171 rc = ShClSvcReadDataFromGuestAsync(pCtx->pClient, uFmt, &pEvent); 167 172 if (RT_SUCCESS(rc)) 168 173 { … … 171 176 if (RT_SUCCESS(rc)) 172 177 { 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; 175 182 } 176 183 … … 183 190 LogFlowFuncLeaveRC(rc); 184 191 return rc; 192 } 193 194 static 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 */ 216 static 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 */ 237 static 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)); 185 272 } 186 273 … … 295 382 void *pvData = NULL; 296 383 uint32_t cbData = 0; 297 int rc = vboxClipboardSvcWin DataRead(pCtx, uFormat, &pvData, &cbData);384 int rc = vboxClipboardSvcWinReadDataFromGuest(pCtx, uFormat, &pvData, &cbData); 298 385 if ( RT_SUCCESS(rc) 299 386 && pvData … … 343 430 } 344 431 345 case SHCL_WIN_WM_REPORT_FORMATS: 432 case SHCL_WIN_WM_REPORT_FORMATS: /* Guest reported clipboard formats. */ 346 433 { 347 434 /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT (or via IDataObject). */ … … 349 436 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: fFormats=%#xn", fFormats)); 350 437 438 int rc = SharedClipboardWinClearAndAnnounceFormats(pWinCtx, fFormats, hWnd); 351 439 #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 } 372 461 #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 380 465 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: lastErr=%ld\n", GetLastError())); 381 466 break; … … 605 690 else 606 691 LogRel(("Shared Clipboard: Initialized OLE\n")); 607 #endif 692 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 608 693 609 694 return VINF_SUCCESS; … … 635 720 { 636 721 rc = RTThreadCreate(&pCtx->hThread, vboxClipboardSvcWinThread, pCtx /* pvUser */, _64K /* Stack size */, 637 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "S HCLIP");722 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "ShClWin"); 638 723 if (RT_SUCCESS(rc)) 639 724 { … … 645 730 pClient->State.pCtx = pCtx; 646 731 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 */ 647 743 } 648 744 else … … 718 814 * The guest announced formats. Forward to the window thread. 719 815 */ 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 */); 723 817 724 818 LogFlowFuncLeaveRC(VINF_SUCCESS); … … 821 915 else if (uFmt & VBOX_SHCL_FMT_URI_LIST) 822 916 { 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())); 824 946 } 825 947 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ … … 827 949 } 828 950 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 835 951 if (RT_FAILURE(rc)) 836 952 LogRel(("Shared Clipboard: Error reading host clipboard data in format %#x from Windows, rc=%Rrc\n", uFmt, rc)); … … 882 998 const PSHCLWINCTX pWinCtx = &pClient->State.pCtx->Win; 883 999 884 int rc = SharedClipboardWin GetRoots(pWinCtx, pTransfer);1000 int rc = SharedClipboardWinTransferGetRootsFromClipboard(pWinCtx, pTransfer); 885 1001 886 1002 LogFlowFuncLeaveRC(rc); -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp
r100018 r100204 44 44 #include <iprt/errcore.h> 45 45 46 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP 47 # include <VBox/GuestHost/SharedClipboard-transfers.h> 48 #endif 49 46 50 #include "VBoxSharedClipboardSvc-internal.h" 47 51 … … 74 78 * Prototypes * 75 79 *********************************************************************************************************************************/ 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); 80 static DECLCALLBACK(int) shClSvcX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser); 81 static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser); 79 82 80 83 … … 91 94 RT_ZERO(pBackend->Callbacks); 92 95 /* 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; 96 98 97 99 return VINF_SUCCESS; … … 112 114 113 115 SET_FN_IF_NOT_NULL(ReportFormats); 114 SET_FN_IF_NOT_NULL(OnClipboardRead);115 SET_FN_IF_NOT_NULL(OnClipboardWrite);116 116 SET_FN_IF_NOT_NULL(OnRequestDataFromSource); 117 SET_FN_IF_NOT_NULL(OnSendDataToDest);118 117 119 118 #undef SET_FN_IF_NOT_NULL … … 190 189 } 191 190 192 /* 193 * Shut down the shared clipboard service and "disconnect" the guest.191 /** 192 * Shuts down the shared clipboard service and "disconnect" the guest. 194 193 * Note! Host glue code 195 194 */ … … 225 224 } 226 225 226 /** 227 * Reports clipboard formats to the host clipboard. 228 */ 227 229 int ShClBackendReportFormats(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, SHCLFORMATS fFormats) 228 230 { 229 231 RT_NOREF(pBackend); 230 232 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 * 251 244 * @note We always fail or complete asynchronously. 252 * @note On success allocates a CLIPREADCBREQ structure which must be253 * freed in ClipCompleteDataRequestFromX11 when it is called back from254 * the backend code.255 245 */ 256 246 int ShClBackendReadData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, … … 269 259 pClient, uFormat, pvData, cbData, pcbActual)); 270 260 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); 278 266 if (RT_SUCCESS(rc)) 279 267 { 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); 287 270 if (RT_SUCCESS(rc)) 288 271 { 289 PSHCLEVENTPAYLOAD pPayload; 290 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload); 291 if (RT_SUCCESS(rc)) 272 if (pPayload) 292 273 { 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); 303 289 } 290 else /* No payload given; could happen on invalid / not-expected formats. */ 291 *pcbActual = 0; 304 292 } 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 } 314 297 315 298 if (RT_FAILURE(rc)) … … 320 303 } 321 304 322 int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData) 305 int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, 306 SHCLFORMAT uFormat, void *pvData, uint32_t cbData) 323 307 { 324 308 RT_NOREF(pBackend, pClient, pCmdCtx, uFormat, pvData, cbData); … … 332 316 } 333 317 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 */ 323 static DECLCALLBACK(int) shClSvcX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser) 336 324 { 337 325 RT_NOREF(pvUser); … … 362 350 } 363 351 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 */ 359 static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx, 360 SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser) 416 361 { 417 362 RT_NOREF(pvUser); … … 426 371 } 427 372 428 PSHCLCLIENT pClient = pCtx->pClient;429 AssertPtr(pClient);430 431 RTCritSectEnter(&pClient->CritSect);432 433 373 int rc = VINF_SUCCESS; 434 374 435 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 375 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP 436 376 /* 437 377 * Note: We always return a generic URI list here. … … 441 381 if (uFmt == VBOX_SHCL_FMT_URI_LIST) 442 382 { 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! */ 453 391 454 392 *ppv = NULL; … … 461 399 if (RT_SUCCESS(rc)) 462 400 { 463 /* Request data from the guest . */401 /* Request data from the guest and for data to arrive. */ 464 402 PSHCLEVENT pEvent; 465 rc = ShClSvc GuestDataRequest(pCtx->pClient, uFmt, &pEvent);403 rc = ShClSvcReadDataFromGuestAsync(pCtx->pClient, uFmt, &pEvent); 466 404 if (RT_SUCCESS(rc)) 467 405 { 468 RTCritSectLeave(&pClient->CritSect);469 470 406 PSHCLEVENTPAYLOAD pPayload; 471 407 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload); … … 484 420 } 485 421 486 RTCritSectEnter(&pClient->CritSect);487 488 422 ShClEventRelease(pEvent); 489 423 } 490 424 } 491 492 RTCritSectLeave(&pClient->CritSect);493 425 494 426 if (RT_FAILURE(rc)) … … 507 439 /* We only need to start the HTTP server (and register the transfer to it) when we actually receive data from the guest. */ 508 440 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) 509 return ShCl HttpTransferRegisterAndMaybeStart(&pClient->State.pCtx->X11.HttpCtx, pTransfer);441 return ShClTransferHttpServerMaybeStart(&pClient->State.pCtx->X11.HttpCtx); 510 442 #else 511 443 RT_NOREF(pClient, pTransfer); … … 520 452 /* See comment in ShClBackendTransferCreate(). */ 521 453 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) 522 return ShCl HttpTransferUnregisterAndMaybeStop(&pClient->State.pCtx->X11.HttpCtx, pTransfer);454 return ShClTransferHttpServerMaybeStop(&pClient->State.pCtx->X11.HttpCtx); 523 455 #else 524 456 RT_NOREF(pClient, pTransfer); … … 537 469 if (RT_SUCCESS(rc)) 538 470 { 539 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));540 if ( pReq)541 { 542 pReq->idEvent = pEvent->idEvent;543 544 rc = ShCl X11ReadDataFromX11(&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); 545 477 if (RT_SUCCESS(rc)) 546 478 { 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) 551 480 { 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; 559 498 } 499 else 500 rc = VERR_NO_DATA; /* No payload. */ 560 501 } 561 502 } 562 else563 rc = VERR_NO_MEMORY;564 503 565 504 ShClEventRelease(pEvent); -
trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp
r100017 r100204 552 552 553 553 RTListAppend(&pClient->MsgQueue, &pMsg->ListEntry); 554 return shClSvcClientWakeup(pClient); 554 return shClSvcClientWakeup(pClient); /** @todo r=andy Remove message if waking up failed? */ 555 555 } 556 556 … … 1173 1173 * @returns VBox status code. 1174 1174 * @retval VINF_NO_CHANGE if the client is not in pending mode. 1175 *1176 1175 * @param pClient Client to wake up. 1177 * @note Caller must enter pClient->CritSect. 1176 * 1177 * @note Caller must enter critical section. 1178 1178 */ 1179 1179 int shClSvcClientWakeup(PSHCLCLIENT pClient) … … 1225 1225 * @param pClient Client to request to read data form. 1226 1226 * @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 */ 1235 int ShClSvcReadDataFromGuestAsync(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent) 1231 1236 { 1232 1237 AssertPtrReturn(pClient, VERR_INVALID_POINTER); … … 1248 1253 else if (fFormats & VBOX_SHCL_FMT_HTML) 1249 1254 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 1250 1259 else 1251 1260 AssertMsgFailedBreak(("%#x\n", fFormats)); … … 1269 1278 if (pMsg) 1270 1279 { 1271 /* 1272 * Enter the critical section and generate an event. 1273 */ 1274 RTCritSectEnter(&pClient->CritSect); 1280 shClSvcClientLock(pClient); 1275 1281 1276 1282 PSHCLEVENT pEvent; … … 1316 1322 1317 1323 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. */ 1320 1328 if (ppEvent) 1321 {1322 1329 *ppEvent = pEvent; 1323 }1324 1325 shClSvcClientWakeup(pClient);1326 1330 } 1327 1331 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 1328 1351 /* Remove event from list if caller did not request event handle or in case 1329 1352 * of failure (in this case caller should not release event). */ … … 1332 1355 { 1333 1356 ShClEventRelease(pEvent); 1357 pEvent = NULL; 1334 1358 } 1335 1359 } … … 1337 1361 rc = VERR_SHCLPB_MAX_EVENTS_REACHED; 1338 1362 1339 RTCritSectLeave(&pClient->CritSect);1340 1341 1363 if (RT_FAILURE(rc)) 1342 1364 shClSvcMsgFree(pClient, pMsg); 1365 1366 shClSvcClientUnlock(pClient); 1343 1367 } 1344 1368 else … … 1350 1374 1351 1375 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)); 1353 1377 1354 1378 LogFlowFuncLeaveRC(rc); … … 1367 1391 * @param cbData Size (in bytes) of clipboard data received. 1368 1392 * This can be zero. 1393 * 1394 * @thread Backend thread. 1369 1395 */ 1370 1396 int ShClSvcGuestDataSignal(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData) … … 1414 1440 1415 1441 /** 1416 * Reports available VBoxclipboard formats to the guest.1442 * Reports clipboard formats to the guest. 1417 1443 * 1418 1444 * @note Host backend callers must check if it's active (use … … 1424 1450 * @param fFormats The formats to report (VBOX_SHCL_FMT_XXX), zero 1425 1451 * is okay (empty the clipboard). 1452 * 1453 * @thread Backend thread. 1426 1454 */ 1427 1455 int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats) 1428 1456 { 1457 LogFlowFuncEnter(); 1458 1429 1459 /* 1430 1460 * Check if the service mode allows this operation and whether the guest is … … 1479 1509 1480 1510 RTCritSectEnter(&pClient->CritSect); 1481 shClSvcMsgAddAndWakeupClient(pClient, pMsg);1511 rc = shClSvcMsgAddAndWakeupClient(pClient, pMsg); 1482 1512 RTCritSectLeave(&pClient->CritSect); 1483 1484 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS1485 /* Create a transfer locally and also tell the guest to create a transfer on the guest side. */1486 if ( !fSkipTransfers1487 && 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 else1498 #endif1499 rc = VINF_SUCCESS;1500 1513 } 1501 1514 else … … 1749 1762 else 1750 1763 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 1751 1787 } 1752 1788 … … 1976 2012 int rc = VINF_SUCCESS; 1977 2013 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)); 1986 2017 1987 2018 LogFlowFuncLeaveRC(rc); … … 2725 2756 /* The service extension wants read data from the guest. */ 2726 2757 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 } 2728 2783 break; 2784 } 2785 2786 /** @todo BUGBUG Why no VBOX_CLIPBOARD_EXT_FN_DATA_WRITE here? */ 2729 2787 2730 2788 default: -
trunk/src/VBox/HostServices/SharedClipboard/testcase/Makefile.kmk
r100011 r100204 78 78 $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp \ 79 79 $(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 80 84 endif 81 85 -
trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp
r99968 r100204 140 140 static void testMsgAddReadData(PSHCLCLIENT pClient, SHCLFORMATS fFormats) 141 141 { 142 int rc = ShClSvc GuestDataRequest(pClient, fFormats, NULL /* pidEvent */);142 int rc = ShClSvcReadDataFromGuestAsync(pClient, fFormats, NULL /* ppEvent */); 143 143 RTTESTI_CHECK_RC_OK(rc); 144 144 } -
trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardTransfers.cpp
r98103 r100204 215 215 RTTESTI_CHECK_RC_OK(rc); 216 216 217 SHCLTXPROVIDER Provider; 218 RTTESTI_CHECK(VBClTransferProviderLocalQueryInterface(&Provider) != NULL); 219 RTTESTI_CHECK_RC_OK(ShClTransferSetProvider(pTransfer, &Provider)); 220 217 221 char szTestTransferRootsSetDir[RTPATH_MAX]; 218 222 rc = testCreateTempDir(hTest, "testTransferRootsSet", szTestTransferRootsSetDir, sizeof(szTestTransferRootsSetDir)); … … 227 231 RTTESTI_CHECK_RC_OK_RETV(rc); 228 232 229 rc = ShClTransferRoots Set(pTransfer, pszRoots, strlen(pszRoots) + 1);233 rc = ShClTransferRootsInitFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1); 230 234 RTTESTI_CHECK_RC(rc, rcExpected); 231 235 … … 243 247 PSHCLTRANSFER pTransfer; 244 248 int rc = ShClTransferCreate(&pTransfer); 249 RTTESTI_CHECK_RC_OK(rc); 250 251 SHCLTXPROVIDER Provider; 252 VBClTransferProviderLocalQueryInterface(&Provider); 253 254 rc = ShClTransferSetProvider(pTransfer, &Provider); 245 255 RTTESTI_CHECK_RC_OK(rc); 246 256 … … 262 272 RTTESTI_CHECK_RC_OK_RETV(rc); 263 273 264 rc = ShClTransferRoots Set(pTransfer, pszRoots, strlen(pszRoots) + 1);274 rc = ShClTransferRootsInitFromStringList(pTransfer, pszRoots, strlen(pszRoots) + 1); 265 275 RTTESTI_CHECK_RC_OK(rc); 266 276 … … 303 313 rc = ShClTransferDestroy(pTransfer); 304 314 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. */ 305 330 } 306 331 … … 387 412 return RTTestSummaryAndDestroy(hTest); 388 413 } 389
Note:
See TracChangeset
for help on using the changeset viewer.