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",))]
|
#[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::{
|
use hbb_common::{
|
||||||
lazy_static,
|
lazy_static,
|
||||||
tokio::sync::{
|
tokio::sync::{
|
||||||
@ -25,6 +25,8 @@ pub use context_send::*;
|
|||||||
const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001;
|
const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
const ERR_CODE_INVALID_PARAMETER: u32 = 0x00000002;
|
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;
|
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",))]
|
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn send_data(conn_id: i32, data: ClipboardFile) {
|
fn send_data(conn_id: i32, data: ClipboardFile) -> ResultType<()> {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
return send_data_to_channel(conn_id, data);
|
return send_data_to_channel(conn_id, data);
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[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",))]
|
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn send_data_to_channel(conn_id: i32, data: ClipboardFile) {
|
fn send_data_to_channel(conn_id: i32, data: ClipboardFile) -> ResultType<()> {
|
||||||
// no need to handle result here
|
|
||||||
if let Some(msg_channel) = VEC_MSG_CHANNEL
|
if let Some(msg_channel) = VEC_MSG_CHANNEL
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.find(|x| x.conn_id == conn_id)
|
.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")]
|
#[cfg(feature = "unix-file-copy-paste")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn send_data_to_all(data: ClipboardFile) {
|
fn send_data_to_all(data: ClipboardFile) -> ResultType<()> {
|
||||||
// no need to handle result here
|
// Need more tests to see if it's necessary to handle the error.
|
||||||
for msg_channel in VEC_MSG_CHANNEL.read().unwrap().iter() {
|
for msg_channel in VEC_MSG_CHANNEL.read().unwrap().iter() {
|
||||||
allow_err!(msg_channel.sender.send(data.clone()));
|
allow_err!(msg_channel.sender.send(data.clone()));
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
allow_err, send_data, ClipboardFile, CliprdrError, CliprdrServiceContext, ResultType,
|
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 hbb_common::log;
|
||||||
use std::{
|
use std::{
|
||||||
@ -998,7 +998,7 @@ extern "C" fn notify_callback(conn_id: UINT32, msg: *const NOTIFICATION_MESSAGE)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// no need to handle result here
|
// no need to handle result here
|
||||||
send_data(conn_id as _, data);
|
allow_err!(send_data(conn_id as _, data));
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@ -1045,7 +1045,13 @@ extern "C" fn client_format_list(
|
|||||||
.iter()
|
.iter()
|
||||||
.for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone())));
|
.for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone())));
|
||||||
} else {
|
} 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
|
0
|
||||||
@ -1067,9 +1073,13 @@ extern "C" fn client_format_list_response(
|
|||||||
msg_flags
|
msg_flags
|
||||||
);
|
);
|
||||||
let data = ClipboardFile::FormatListResponse { msg_flags };
|
let data = ClipboardFile::FormatListResponse { msg_flags };
|
||||||
send_data(conn_id, data);
|
match send_data(conn_id, data) {
|
||||||
|
Ok(_) => 0,
|
||||||
0
|
Err(e) => {
|
||||||
|
log::error!("failed to send format list response: {:?}", e);
|
||||||
|
ERR_CODE_SEND_MSG
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn client_format_data_request(
|
extern "C" fn client_format_data_request(
|
||||||
@ -1090,10 +1100,13 @@ extern "C" fn client_format_data_request(
|
|||||||
conn_id,
|
conn_id,
|
||||||
requested_format_id
|
requested_format_id
|
||||||
);
|
);
|
||||||
// no need to handle result here
|
match send_data(conn_id, data) {
|
||||||
send_data(conn_id, data);
|
Ok(_) => 0,
|
||||||
|
Err(e) => {
|
||||||
0
|
log::error!("failed to send format data request: {:?}", e);
|
||||||
|
ERR_CODE_SEND_MSG
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn client_format_data_response(
|
extern "C" fn client_format_data_response(
|
||||||
@ -1125,9 +1138,13 @@ extern "C" fn client_format_data_response(
|
|||||||
msg_flags,
|
msg_flags,
|
||||||
format_data,
|
format_data,
|
||||||
};
|
};
|
||||||
send_data(conn_id, data);
|
match send_data(conn_id, data) {
|
||||||
|
Ok(_) => 0,
|
||||||
0
|
Err(e) => {
|
||||||
|
log::error!("failed to send format data response: {:?}", e);
|
||||||
|
ERR_CODE_SEND_MSG
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn client_file_contents_request(
|
extern "C" fn client_file_contents_request(
|
||||||
@ -1175,9 +1192,13 @@ extern "C" fn client_file_contents_request(
|
|||||||
clip_data_id,
|
clip_data_id,
|
||||||
};
|
};
|
||||||
log::debug!("client_file_contents_request called, data: {:?}", &data);
|
log::debug!("client_file_contents_request called, data: {:?}", &data);
|
||||||
send_data(conn_id, data);
|
match send_data(conn_id, data) {
|
||||||
|
Ok(_) => 0,
|
||||||
0
|
Err(e) => {
|
||||||
|
log::error!("failed to send file contents request: {:?}", e);
|
||||||
|
ERR_CODE_SEND_MSG
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn client_file_contents_response(
|
extern "C" fn client_file_contents_response(
|
||||||
@ -1213,7 +1234,11 @@ extern "C" fn client_file_contents_response(
|
|||||||
msg_flags,
|
msg_flags,
|
||||||
stream_id
|
stream_id
|
||||||
);
|
);
|
||||||
send_data(conn_id, data);
|
match send_data(conn_id, data) {
|
||||||
|
Ok(_) => 0,
|
||||||
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;
|
HWND hwnd;
|
||||||
HANDLE hmem;
|
HANDLE hmem;
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
HANDLE response_data_event;
|
HANDLE formatDataRespEvent;
|
||||||
|
BOOL formatDataRespReceived;
|
||||||
|
|
||||||
LPDATAOBJECT data_obj;
|
LPDATAOBJECT data_obj;
|
||||||
HANDLE data_obj_mutex;
|
HANDLE data_obj_mutex;
|
||||||
@ -228,6 +229,7 @@ struct wf_clipboard
|
|||||||
ULONG req_fsize;
|
ULONG req_fsize;
|
||||||
char *req_fdata;
|
char *req_fdata;
|
||||||
HANDLE req_fevent;
|
HANDLE req_fevent;
|
||||||
|
BOOL req_f_received;
|
||||||
|
|
||||||
size_t nFiles;
|
size_t nFiles;
|
||||||
size_t file_array_size;
|
size_t file_array_size;
|
||||||
@ -1444,7 +1446,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID)
|
|||||||
return rc;
|
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;
|
UINT rc = ERROR_SUCCESS;
|
||||||
clipboard->context->IsStopped = FALSE;
|
clipboard->context->IsStopped = FALSE;
|
||||||
@ -1456,8 +1458,15 @@ UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, vo
|
|||||||
DWORD waitRes = WaitForSingleObject(event, waitOnceTimeoutMillis);
|
DWORD waitRes = WaitForSingleObject(event, waitOnceTimeoutMillis);
|
||||||
if (waitRes == WAIT_TIMEOUT && clipboard->context->IsStopped == FALSE)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (clipboard->context->IsStopped == TRUE)
|
if (clipboard->context->IsStopped == TRUE)
|
||||||
{
|
{
|
||||||
@ -1524,13 +1533,14 @@ static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UIN
|
|||||||
formatDataRequest.connID = connID;
|
formatDataRequest.connID = connID;
|
||||||
formatDataRequest.requestedFormatId = remoteFormatId;
|
formatDataRequest.requestedFormatId = remoteFormatId;
|
||||||
clipboard->requestedFormatId = formatId;
|
clipboard->requestedFormatId = formatId;
|
||||||
|
clipboard->formatDataRespReceived = FALSE;
|
||||||
rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest);
|
rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest);
|
||||||
if (rc != ERROR_SUCCESS)
|
if (rc != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return rc;
|
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,
|
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.cbRequested = nreq;
|
||||||
fileContentsRequest.clipDataId = 0;
|
fileContentsRequest.clipDataId = 0;
|
||||||
fileContentsRequest.msgFlags = 0;
|
fileContentsRequest.msgFlags = 0;
|
||||||
|
clipboard->req_f_received = FALSE;
|
||||||
rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest);
|
rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest);
|
||||||
if (rc != ERROR_SUCCESS)
|
if (rc != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return rc;
|
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(
|
static UINT cliprdr_send_response_filecontents(
|
||||||
@ -2545,7 +2556,7 @@ exit:
|
|||||||
response.requestedFormatData = (BYTE *)buff;
|
response.requestedFormatData = (BYTE *)buff;
|
||||||
if (ERROR_SUCCESS != clipboard->context->ClientFormatDataResponse(clipboard->context, &response))
|
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)
|
if (buff)
|
||||||
@ -2621,9 +2632,11 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context,
|
|||||||
rc = CHANNEL_RC_OK;
|
rc = CHANNEL_RC_OK;
|
||||||
} while (0);
|
} 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;
|
rc = ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@ -2899,7 +2912,9 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
|
|||||||
|
|
||||||
if (!SetEvent(clipboard->req_fevent))
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -2934,14 +2949,16 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
|
|||||||
(formatMapping *)calloc(clipboard->map_capacity, sizeof(formatMapping))))
|
(formatMapping *)calloc(clipboard->map_capacity, sizeof(formatMapping))))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
if (!(clipboard->formatDataRespEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||||
goto error;
|
goto error;
|
||||||
|
clipboard->formatDataRespReceived = FALSE;
|
||||||
|
|
||||||
if (!(clipboard->data_obj_mutex = CreateMutex(NULL, FALSE, "data_obj_mutex")))
|
if (!(clipboard->data_obj_mutex = CreateMutex(NULL, FALSE, "data_obj_mutex")))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||||
goto error;
|
goto error;
|
||||||
|
clipboard->req_f_received = FALSE;
|
||||||
|
|
||||||
if (!(clipboard->thread = CreateThread(NULL, 0, cliprdr_thread_func, clipboard, 0, NULL)))
|
if (!(clipboard->thread = CreateThread(NULL, 0, cliprdr_thread_func, clipboard, 0, NULL)))
|
||||||
goto error;
|
goto error;
|
||||||
@ -3002,8 +3019,8 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
|
|||||||
clipboard->data_obj = NULL;
|
clipboard->data_obj = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clipboard->response_data_event)
|
if (clipboard->formatDataRespEvent)
|
||||||
CloseHandle(clipboard->response_data_event);
|
CloseHandle(clipboard->formatDataRespEvent);
|
||||||
|
|
||||||
if (clipboard->data_obj_mutex)
|
if (clipboard->data_obj_mutex)
|
||||||
CloseHandle(clipboard->data_obj_mutex);
|
CloseHandle(clipboard->data_obj_mutex);
|
||||||
|
@ -353,6 +353,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
} else {
|
} else {
|
||||||
if let Err(e) = ContextSend::make_sure_enabled() {
|
if let Err(e) = ContextSend::make_sure_enabled() {
|
||||||
log::error!("failed to restart clipboard context: {}", e);
|
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");
|
log::debug!("Send system clipboard message to remote");
|
||||||
let msg = crate::clipboard_file::clip_2_msg(clip);
|
let msg = crate::clipboard_file::clip_2_msg(clip);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user