fix: win, file clipboard (#9243)
1. Return the result of `wait_response_event()` in `cliprdr_send_format_list()` 2. Add recv flags to avoid waiting a long time. Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
		
							parent
							
								
									d4377a13c5
								
							
						
					
					
						commit
						ec28567362
					
				| @ -5,7 +5,7 @@ use std::{ | ||||
| }; | ||||
| 
 | ||||
| #[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))] | ||||
| use hbb_common::{allow_err, log}; | ||||
| use hbb_common::{allow_err, bail}; | ||||
| use hbb_common::{ | ||||
|     lazy_static, | ||||
|     tokio::sync::{ | ||||
| @ -25,6 +25,8 @@ pub use context_send::*; | ||||
| const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001; | ||||
| #[cfg(target_os = "windows")] | ||||
| const ERR_CODE_INVALID_PARAMETER: u32 = 0x00000002; | ||||
| #[cfg(target_os = "windows")] | ||||
| const ERR_CODE_SEND_MSG: u32 = 0x00000003; | ||||
| 
 | ||||
| pub(crate) use platform::create_cliprdr_context; | ||||
| 
 | ||||
| @ -198,7 +200,7 @@ pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<C | ||||
| 
 | ||||
| #[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))] | ||||
| #[inline] | ||||
| fn send_data(conn_id: i32, data: ClipboardFile) { | ||||
| fn send_data(conn_id: i32, data: ClipboardFile) -> ResultType<()> { | ||||
|     #[cfg(target_os = "windows")] | ||||
|     return send_data_to_channel(conn_id, data); | ||||
|     #[cfg(not(target_os = "windows"))] | ||||
| @ -210,25 +212,28 @@ fn send_data(conn_id: i32, data: ClipboardFile) { | ||||
| } | ||||
| #[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))] | ||||
| #[inline] | ||||
| fn send_data_to_channel(conn_id: i32, data: ClipboardFile) { | ||||
|     // no need to handle result here
 | ||||
| fn send_data_to_channel(conn_id: i32, data: ClipboardFile) -> ResultType<()> { | ||||
|     if let Some(msg_channel) = VEC_MSG_CHANNEL | ||||
|         .read() | ||||
|         .unwrap() | ||||
|         .iter() | ||||
|         .find(|x| x.conn_id == conn_id) | ||||
|     { | ||||
|         allow_err!(msg_channel.sender.send(data)); | ||||
|         msg_channel.sender.send(data)?; | ||||
|         Ok(()) | ||||
|     } else { | ||||
|         bail!("conn_id not found"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "unix-file-copy-paste")] | ||||
| #[inline] | ||||
| fn send_data_to_all(data: ClipboardFile) { | ||||
|     // no need to handle result here
 | ||||
| fn send_data_to_all(data: ClipboardFile) -> ResultType<()> { | ||||
|     // Need more tests to see if it's necessary to handle the error.
 | ||||
|     for msg_channel in VEC_MSG_CHANNEL.read().unwrap().iter() { | ||||
|         allow_err!(msg_channel.sender.send(data.clone())); | ||||
|     } | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
| 
 | ||||
| use crate::{ | ||||
|     allow_err, send_data, ClipboardFile, CliprdrError, CliprdrServiceContext, ResultType, | ||||
|     ERR_CODE_INVALID_PARAMETER, ERR_CODE_SERVER_FUNCTION_NONE, VEC_MSG_CHANNEL, | ||||
|     ERR_CODE_INVALID_PARAMETER, ERR_CODE_SEND_MSG, ERR_CODE_SERVER_FUNCTION_NONE, VEC_MSG_CHANNEL, | ||||
| }; | ||||
| use hbb_common::log; | ||||
| use std::{ | ||||
| @ -998,7 +998,7 @@ extern "C" fn notify_callback(conn_id: UINT32, msg: *const NOTIFICATION_MESSAGE) | ||||
|         } | ||||
|     }; | ||||
|     // no need to handle result here
 | ||||
|     send_data(conn_id as _, data); | ||||
|     allow_err!(send_data(conn_id as _, data)); | ||||
| 
 | ||||
|     0 | ||||
| } | ||||
| @ -1045,7 +1045,13 @@ extern "C" fn client_format_list( | ||||
|             .iter() | ||||
|             .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); | ||||
|     } else { | ||||
|         send_data(conn_id, data); | ||||
|         match send_data(conn_id, data) { | ||||
|             Ok(_) => {} | ||||
|             Err(e) => { | ||||
|                 log::error!("failed to send format list: {:?}", e); | ||||
|                 return ERR_CODE_SEND_MSG; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     0 | ||||
| @ -1067,9 +1073,13 @@ extern "C" fn client_format_list_response( | ||||
|         msg_flags | ||||
|     ); | ||||
|     let data = ClipboardFile::FormatListResponse { msg_flags }; | ||||
|     send_data(conn_id, data); | ||||
| 
 | ||||
|     0 | ||||
|     match send_data(conn_id, data) { | ||||
|         Ok(_) => 0, | ||||
|         Err(e) => { | ||||
|             log::error!("failed to send format list response: {:?}", e); | ||||
|             ERR_CODE_SEND_MSG | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| extern "C" fn client_format_data_request( | ||||
| @ -1090,10 +1100,13 @@ extern "C" fn client_format_data_request( | ||||
|         conn_id, | ||||
|         requested_format_id | ||||
|     ); | ||||
|     // no need to handle result here
 | ||||
|     send_data(conn_id, data); | ||||
| 
 | ||||
|     0 | ||||
|     match send_data(conn_id, data) { | ||||
|         Ok(_) => 0, | ||||
|         Err(e) => { | ||||
|             log::error!("failed to send format data request: {:?}", e); | ||||
|             ERR_CODE_SEND_MSG | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| extern "C" fn client_format_data_response( | ||||
| @ -1125,9 +1138,13 @@ extern "C" fn client_format_data_response( | ||||
|         msg_flags, | ||||
|         format_data, | ||||
|     }; | ||||
|     send_data(conn_id, data); | ||||
| 
 | ||||
|     0 | ||||
|     match send_data(conn_id, data) { | ||||
|         Ok(_) => 0, | ||||
|         Err(e) => { | ||||
|             log::error!("failed to send format data response: {:?}", e); | ||||
|             ERR_CODE_SEND_MSG | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| extern "C" fn client_file_contents_request( | ||||
| @ -1175,9 +1192,13 @@ extern "C" fn client_file_contents_request( | ||||
|         clip_data_id, | ||||
|     }; | ||||
|     log::debug!("client_file_contents_request called, data: {:?}", &data); | ||||
|     send_data(conn_id, data); | ||||
| 
 | ||||
|     0 | ||||
|     match send_data(conn_id, data) { | ||||
|         Ok(_) => 0, | ||||
|         Err(e) => { | ||||
|             log::error!("failed to send file contents request: {:?}", e); | ||||
|             ERR_CODE_SEND_MSG | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| extern "C" fn client_file_contents_response( | ||||
| @ -1213,7 +1234,11 @@ extern "C" fn client_file_contents_response( | ||||
|         msg_flags, | ||||
|         stream_id | ||||
|     ); | ||||
|     send_data(conn_id, data); | ||||
| 
 | ||||
|     0 | ||||
|     match send_data(conn_id, data) { | ||||
|         Ok(_) => 0, | ||||
|         Err(e) => { | ||||
|             log::error!("failed to send file contents response: {:?}", e); | ||||
|             ERR_CODE_SEND_MSG | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -220,7 +220,8 @@ struct wf_clipboard | ||||
| 	HWND hwnd; | ||||
| 	HANDLE hmem; | ||||
| 	HANDLE thread; | ||||
| 	HANDLE response_data_event; | ||||
| 	HANDLE formatDataRespEvent; | ||||
| 	BOOL formatDataRespReceived; | ||||
| 
 | ||||
| 	LPDATAOBJECT data_obj; | ||||
| 	HANDLE data_obj_mutex; | ||||
| @ -228,6 +229,7 @@ struct wf_clipboard | ||||
| 	ULONG req_fsize; | ||||
| 	char *req_fdata; | ||||
| 	HANDLE req_fevent; | ||||
| 	BOOL req_f_received; | ||||
| 
 | ||||
| 	size_t nFiles; | ||||
| 	size_t file_array_size; | ||||
| @ -1444,7 +1446,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, void **data) | ||||
| UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, BOOL* recvedFlag, void **data) | ||||
| { | ||||
| 	UINT rc = ERROR_SUCCESS; | ||||
| 	clipboard->context->IsStopped = FALSE; | ||||
| @ -1456,8 +1458,15 @@ UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, vo | ||||
| 		DWORD waitRes = WaitForSingleObject(event, waitOnceTimeoutMillis); | ||||
| 		if (waitRes == WAIT_TIMEOUT && clipboard->context->IsStopped == FALSE) | ||||
| 		{ | ||||
| 			if ((*recvedFlag) == TRUE) { | ||||
| 				// The data has been received, but the event is still not signaled.
 | ||||
| 				// We just skip the rest of the waiting and reset the flag.
 | ||||
| 				*recvedFlag = FALSE; | ||||
| 			} else { | ||||
| 				// The data has not been received yet, we should continue to wait.
 | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (clipboard->context->IsStopped == TRUE) | ||||
| 		{ | ||||
| @ -1524,13 +1533,14 @@ static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UIN | ||||
| 	formatDataRequest.connID = connID; | ||||
| 	formatDataRequest.requestedFormatId = remoteFormatId; | ||||
| 	clipboard->requestedFormatId = formatId; | ||||
| 	clipboard->formatDataRespReceived = FALSE; | ||||
| 	rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); | ||||
| 	if (rc != ERROR_SUCCESS) | ||||
| 	{ | ||||
| 		return rc; | ||||
| 	} | ||||
| 
 | ||||
| 	wait_response_event(connID, clipboard, clipboard->response_data_event, &clipboard->hmem); | ||||
| 	return wait_response_event(connID, clipboard, clipboard->formatDataRespEvent, &clipboard->formatDataRespReceived, &clipboard->hmem); | ||||
| } | ||||
| 
 | ||||
| UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, const void *streamid, ULONG index, | ||||
| @ -1552,13 +1562,14 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, co | ||||
| 	fileContentsRequest.cbRequested = nreq; | ||||
| 	fileContentsRequest.clipDataId = 0; | ||||
| 	fileContentsRequest.msgFlags = 0; | ||||
| 	clipboard->req_f_received = FALSE; | ||||
| 	rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest); | ||||
| 	if (rc != ERROR_SUCCESS) | ||||
| 	{ | ||||
| 		return rc; | ||||
| 	} | ||||
| 
 | ||||
| 	return wait_response_event(connID, clipboard, clipboard->req_fevent, (void **)&clipboard->req_fdata); | ||||
| 	return wait_response_event(connID, clipboard, clipboard->req_fevent, &clipboard->req_f_received, (void **)&clipboard->req_fdata); | ||||
| } | ||||
| 
 | ||||
| static UINT cliprdr_send_response_filecontents( | ||||
| @ -2545,7 +2556,7 @@ exit: | ||||
| 	response.requestedFormatData = (BYTE *)buff; | ||||
| 	if (ERROR_SUCCESS != clipboard->context->ClientFormatDataResponse(clipboard->context, &response)) | ||||
| 	{ | ||||
| 		// CAUTION: if failed to send, server will wait a long time
 | ||||
| 		// CAUTION: if failed to send, server will wait a long time, default 30 seconds.
 | ||||
| 	} | ||||
| 
 | ||||
| 	if (buff) | ||||
| @ -2621,9 +2632,11 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context, | ||||
| 		rc = CHANNEL_RC_OK; | ||||
| 	} while (0); | ||||
| 
 | ||||
| 	if (!SetEvent(clipboard->response_data_event)) | ||||
| 	if (!SetEvent(clipboard->formatDataRespEvent)) | ||||
| 	{ | ||||
| 		// CAUTION: critical error here, process will hang up until wait timeout default 3min.
 | ||||
| 		// If failed to set event, set flag to indicate the event is received.
 | ||||
| 		DEBUG_CLIPRDR("wf_cliprdr_server_format_data_response(), SetEvent failed with 0x%x", GetLastError()); | ||||
| 		clipboard->formatDataRespReceived = TRUE; | ||||
| 		rc = ERROR_INTERNAL_ERROR; | ||||
| 	} | ||||
| 	return rc; | ||||
| @ -2899,7 +2912,9 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context, | ||||
| 
 | ||||
| 	if (!SetEvent(clipboard->req_fevent)) | ||||
| 	{ | ||||
| 		// CAUTION: critical error here, process will hang up until wait timeout default 3min.
 | ||||
| 		// If failed to set event, set flag to indicate the event is received.
 | ||||
| 		DEBUG_CLIPRDR("wf_cliprdr_server_file_contents_response(), SetEvent failed with 0x%x", GetLastError()); | ||||
| 		clipboard->req_f_received = TRUE; | ||||
| 	} | ||||
| 	return rc; | ||||
| } | ||||
| @ -2934,14 +2949,16 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr) | ||||
| 			  (formatMapping *)calloc(clipboard->map_capacity, sizeof(formatMapping)))) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL))) | ||||
| 	if (!(clipboard->formatDataRespEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) | ||||
| 		goto error; | ||||
| 	clipboard->formatDataRespReceived = FALSE; | ||||
| 
 | ||||
| 	if (!(clipboard->data_obj_mutex = CreateMutex(NULL, FALSE, "data_obj_mutex"))) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL))) | ||||
| 		goto error; | ||||
| 	clipboard->req_f_received = FALSE; | ||||
| 
 | ||||
| 	if (!(clipboard->thread = CreateThread(NULL, 0, cliprdr_thread_func, clipboard, 0, NULL))) | ||||
| 		goto error; | ||||
| @ -3002,8 +3019,8 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr) | ||||
| 		clipboard->data_obj = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (clipboard->response_data_event) | ||||
| 		CloseHandle(clipboard->response_data_event); | ||||
| 	if (clipboard->formatDataRespEvent) | ||||
| 		CloseHandle(clipboard->formatDataRespEvent); | ||||
| 
 | ||||
| 	if (clipboard->data_obj_mutex) | ||||
| 		CloseHandle(clipboard->data_obj_mutex); | ||||
|  | ||||
| @ -353,6 +353,7 @@ impl<T: InvokeUiSession> Remote<T> { | ||||
|                     } else { | ||||
|                         if let Err(e) = ContextSend::make_sure_enabled() { | ||||
|                             log::error!("failed to restart clipboard context: {}", e); | ||||
|                             // to-do: Show msgbox with "Don't show again" option
 | ||||
|                         }; | ||||
|                         log::debug!("Send system clipboard message to remote"); | ||||
|                         let msg = crate::clipboard_file::clip_2_msg(clip); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user