From 8834251eec3fa2ef1009a26df1ff62ecfbb0e08d Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 22 Feb 2022 14:17:50 +0800 Subject: [PATCH 1/5] move clipboard file service to cm module Signed-off-by: fufesou --- Cargo.lock | 2 + libs/clipboard/Cargo.toml | 2 + libs/clipboard/src/lib.rs | 600 ++++++++++++++---------- libs/clipboard/src/windows/wf_cliprdr.c | 26 +- src/clipboard_file.rs | 207 ++++++++ src/ipc.rs | 2 + src/lib.rs | 3 + src/server.rs | 4 - src/server/clipboard_file_service.rs | 104 ---- src/server/connection.rs | 36 +- src/ui/cm.rs | 81 +++- src/ui/remote.rs | 44 +- 12 files changed, 720 insertions(+), 391 deletions(-) create mode 100644 src/clipboard_file.rs delete mode 100644 src/server/clipboard_file_service.rs diff --git a/Cargo.lock b/Cargo.lock index 32e50572e..72bc94475 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,6 +395,8 @@ dependencies = [ "cc", "hbb_common", "lazy_static", + "serde 1.0.135", + "serde_derive", "thiserror", ] diff --git a/libs/clipboard/Cargo.toml b/libs/clipboard/Cargo.toml index 3d2b5ef77..3a27833cc 100644 --- a/libs/clipboard/Cargo.toml +++ b/libs/clipboard/Cargo.toml @@ -12,4 +12,6 @@ cc = "1.0" [dependencies] thiserror = "1.0.30" lazy_static = "1.4" +serde = "1.0" +serde_derive = "1.0" hbb_common = { path = "../hbb_common" } diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index bf5a0f140..37db74549 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -1,14 +1,13 @@ use cliprdr::*; use hbb_common::{ log, - message_proto::cliprdr as msg_cliprdr, - message_proto::*, tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, }, ResultType, }; +use serde_derive::{Deserialize, Serialize}; use std::{ boxed::Box, ffi::{CStr, CString}, @@ -22,111 +21,241 @@ pub struct ConnID { pub remote_conn_id: u32, } +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "t", content = "c")] +pub enum ClipbaordFile { + ServerFormatList { + server_conn_id: i32, + remote_conn_id: i32, + format_list: Vec<(i32, String)>, + }, + ServerFormatListResponse { + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + }, + ServerFormatDataRequest { + server_conn_id: i32, + remote_conn_id: i32, + requested_format_id: i32, + }, + ServerFormatDataResponse { + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + format_data: Vec, + }, + FileContentsRequest { + server_conn_id: i32, + remote_conn_id: i32, + stream_id: i32, + list_index: i32, + dw_flags: i32, + n_position_low: i32, + n_position_high: i32, + cb_requested: i32, + have_clip_data_id: bool, + clip_data_id: i32, + }, + FileContentsResponse { + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + stream_id: i32, + requested_data: Vec, + }, +} + lazy_static::lazy_static! { - static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, Message)>, TokioMutex>) = { + static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, ClipbaordFile)>, TokioMutex>) = { let (tx, rx) = unbounded_channel(); (tx, TokioMutex::new(rx)) }; } #[inline(always)] -pub fn get_rx_client_msg<'a>() -> &'a TokioMutex> { +pub fn get_rx_clip_client<'a>() -> &'a TokioMutex> { &MSG_CHANNEL_CLIENT.1 } -pub fn server_msg(context: &mut Box, conn_id: ConnID, msg: Cliprdr) -> u32 { - match msg.union { - Some(msg_cliprdr::Union::ready(_)) => { - // proc ready - 0 - } - Some(msg_cliprdr::Union::format_list(req)) => { +pub fn server_clip_file( + context: &mut Box, + conn_id: ConnID, + msg: ClipbaordFile, +) -> u32 { + match msg { + ClipbaordFile::ServerFormatList { + mut server_conn_id, + mut remote_conn_id, + format_list, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("server_format_list called"); - let ret = server_format_list(context, conn_id, req); + let ret = server_format_list(context, server_conn_id, remote_conn_id, format_list); log::debug!("server_format_list called, return {}", ret); ret } - Some(msg_cliprdr::Union::format_list_response(req)) => { + ClipbaordFile::ServerFormatListResponse { + mut server_conn_id, + mut remote_conn_id, + msg_flags, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("format_list_response called"); - let ret = server_format_list_response(context, conn_id, req); + let ret = + server_format_list_response(context, server_conn_id, remote_conn_id, msg_flags); log::debug!("server_format_list_response called, return {}", ret); ret } - Some(msg_cliprdr::Union::format_data_request(req)) => { + ClipbaordFile::ServerFormatDataRequest { + mut server_conn_id, + mut remote_conn_id, + requested_format_id, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("format_data_request called"); - let ret = server_format_data_request(context, conn_id, req); + let ret = server_format_data_request( + context, + server_conn_id, + remote_conn_id, + requested_format_id, + ); log::debug!("server_format_data_request called, return {}", ret); ret } - Some(msg_cliprdr::Union::format_data_response(req)) => { + ClipbaordFile::ServerFormatDataResponse { + mut server_conn_id, + mut remote_conn_id, + msg_flags, + format_data, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("format_data_response called"); - let ret = server_format_data_response(context, conn_id, req); + let ret = server_format_data_response( + context, + server_conn_id, + remote_conn_id, + msg_flags, + format_data, + ); log::debug!("server_format_data_response called, return {}", ret); ret } - Some(msg_cliprdr::Union::file_contents_request(req)) => { + ClipbaordFile::FileContentsRequest { + mut server_conn_id, + mut remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("file_contents_request called"); - let ret = server_file_contents_request(context, conn_id, req); + let ret = server_file_contents_request( + context, + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + ); log::debug!("server_file_contents_request called, return {}", ret); ret } - Some(msg_cliprdr::Union::file_contents_response(req)) => { + ClipbaordFile::FileContentsResponse { + mut server_conn_id, + mut remote_conn_id, + msg_flags, + stream_id, + requested_data, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("file_contents_response called"); - let ret = server_file_contents_response(context, conn_id, req); + let ret = server_file_contents_response( + context, + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + ); log::debug!("server_file_contents_response called, return {}", ret); ret } - None => { - // unreachable!() - 0 - } } } -fn server_format_list( +pub fn server_format_list( context: &mut Box, - conn_id: ConnID, - data: CliprdrServerFormatList, + server_conn_id: i32, + remote_conn_id: i32, + format_list: Vec<(i32, String)>, ) -> u32 { - // do not check msgFlags for now unsafe { - let num_formats = data.formats.len() as UINT32; - let mut formats = data - .formats + let num_formats = format_list.len() as UINT32; + let mut formats = format_list .into_iter() .map(|format| { - if format.format.is_empty() { + if format.1.is_empty() { CLIPRDR_FORMAT { - formatId: format.id as UINT32, + formatId: format.0 as UINT32, formatName: 0 as *mut _, } } else { - let n = match CString::new(format.format) { + let n = match CString::new(format.1) { Ok(n) => n, Err(_) => CString::new("").unwrap(), }; CLIPRDR_FORMAT { - formatId: format.id as UINT32, + formatId: format.0 as UINT32, formatName: n.into_raw(), } } }) .collect::>(); - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; - let format_list = CLIPRDR_FORMAT_LIST { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, msgFlags: 0 as UINT16, dataLen: 0 as UINT32, @@ -146,28 +275,18 @@ fn server_format_list( ret as u32 } } -fn server_format_list_response( +pub fn server_format_list_response( context: &mut Box, - conn_id: ConnID, - data: CliprdrServerFormatListResponse, + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; - let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, - msgFlags: data.msg_flags as UINT16, + msgFlags: msg_flags as UINT16, dataLen: 0 as UINT32, }; @@ -177,59 +296,41 @@ fn server_format_list_response( ret as u32 } } -fn server_format_data_request( +pub fn server_format_data_request( context: &mut Box, - conn_id: ConnID, - data: CliprdrServerFormatDataRequest, + server_conn_id: i32, + remote_conn_id: i32, + requested_format_id: i32, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; - let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, msgFlags: 0 as UINT16, dataLen: 0 as UINT32, - requestedFormatId: data.requested_format_id as UINT32, + requestedFormatId: requested_format_id as UINT32, }; let ret = ((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request); ret as u32 } } -fn server_format_data_response( +pub fn server_format_data_response( context: &mut Box, - conn_id: ConnID, - mut data: CliprdrServerFormatDataResponse, + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + mut format_data: Vec, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, - msgFlags: data.msg_flags as UINT16, - dataLen: data.format_data.len() as UINT32, - requestedFormatData: data.format_data.as_mut_ptr(), + msgFlags: msg_flags as UINT16, + dataLen: format_data.len() as UINT32, + requestedFormatData: format_data.as_mut_ptr(), }; let ret = ((**context).ServerFormatDataResponse.unwrap())( &mut (**context), @@ -238,36 +339,34 @@ fn server_format_data_response( ret as u32 } } -fn server_file_contents_request( +pub fn server_file_contents_request( context: &mut Box, - conn_id: ConnID, - data: CliprdrFileContentsRequest, + server_conn_id: i32, + remote_conn_id: i32, + stream_id: i32, + list_index: i32, + dw_flags: i32, + n_position_low: i32, + n_position_high: i32, + cb_requested: i32, + have_clip_data_id: bool, + clip_data_id: i32, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, msgFlags: 0 as UINT16, dataLen: 0 as UINT32, - streamId: data.stream_id as UINT32, - listIndex: data.list_index as UINT32, - dwFlags: data.dw_flags as UINT32, - nPositionLow: data.n_position_low as UINT32, - nPositionHigh: data.n_position_high as UINT32, - cbRequested: data.cb_requested as UINT32, - haveClipDataId: if data.have_clip_data_id { TRUE } else { FALSE }, - clipDataId: data.clip_data_id as UINT32, + streamId: stream_id as UINT32, + listIndex: list_index as UINT32, + dwFlags: dw_flags as UINT32, + nPositionLow: n_position_low as UINT32, + nPositionHigh: n_position_high as UINT32, + cbRequested: cb_requested as UINT32, + haveClipDataId: if have_clip_data_id { TRUE } else { FALSE }, + clipDataId: clip_data_id as UINT32, }; let ret = ((**context).ServerFileContentsRequest.unwrap())( &mut (**context), @@ -276,31 +375,24 @@ fn server_file_contents_request( ret as u32 } } -fn server_file_contents_response( +pub fn server_file_contents_response( context: &mut Box, - conn_id: ConnID, - mut data: CliprdrFileContentsResponse, + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + stream_id: i32, + mut requested_data: Vec, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, - msgFlags: data.msg_flags as UINT16, - dataLen: 4 + data.requested_data.len() as UINT32, - streamId: data.stream_id as UINT32, - cbRequested: data.requested_data.len() as UINT32, - requestedData: data.requested_data.as_mut_ptr(), + msgFlags: msg_flags as UINT16, + dataLen: 4 + requested_data.len() as UINT32, + streamId: stream_id as UINT32, + cbRequested: requested_data.len() as UINT32, + requestedData: requested_data.as_mut_ptr(), }; let ret = ((**context).ServerFileContentsResponse.unwrap())( &mut (**context), @@ -310,7 +402,10 @@ fn server_file_contents_response( } } -pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> ResultType> { +pub fn create_cliprdr_context( + enable_files: bool, + enable_others: bool, +) -> ResultType> { Ok(CliprdrClientContext::create( enable_files, enable_others, @@ -325,21 +420,19 @@ pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> Result extern "C" fn client_format_list( _context: *mut CliprdrClientContext, - format_list: *const CLIPRDR_FORMAT_LIST, + clip_format_list: *const CLIPRDR_FORMAT_LIST, ) -> UINT { log::debug!("client_format_list called"); - let mut data = CliprdrServerFormatList::default(); + let server_conn_id; + let remote_conn_id; + let mut format_list: Vec<(i32, String)> = Vec::new(); unsafe { let mut i = 0u32; - while i < (*format_list).numFormats { - let format_data = &(*(*format_list).formats.offset(i as isize)); + while i < (*clip_format_list).numFormats { + let format_data = &(*(*clip_format_list).formats.offset(i as isize)); if format_data.formatName.is_null() { - data.formats.push(CliprdrFormat { - id: format_data.formatId as i32, - format: "".to_owned(), - ..Default::default() - }); + format_list.push((format_data.formatId as i32, "".to_owned())); } else { let format_name = CStr::from_ptr(format_data.formatName).to_str(); let format_name = match format_name { @@ -349,30 +442,25 @@ extern "C" fn client_format_list( "".to_owned() } }; - data.formats.push(CliprdrFormat { - id: format_data.formatId as i32, - format: format_name, - ..Default::default() - }); + format_list.push((format_data.formatId as i32, format_name)); } + // log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name); i += 1; } - - data.server_conn_id = (*format_list).serverConnID as i32; - data.remote_conn_id = (*format_list).remoteConnID as i32; + server_conn_id = (*clip_format_list).serverConnID as i32; + remote_conn_id = (*clip_format_list).remoteConnID as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatList { + server_conn_id, + remote_conn_id, + format_list, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_list(data); - msg.set_cliprdr(cliprdr); - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -383,23 +471,25 @@ extern "C" fn client_format_list_response( ) -> UINT { log::debug!("client_format_list_response called"); - let mut data = CliprdrServerFormatListResponse::default(); + let server_conn_id; + let remote_conn_id; + let msg_flags; unsafe { - data.server_conn_id = (*format_list_response).serverConnID as i32; - data.remote_conn_id = (*format_list_response).remoteConnID as i32; - data.msg_flags = (*format_list_response).msgFlags as i32; + server_conn_id = (*format_list_response).serverConnID as i32; + remote_conn_id = (*format_list_response).remoteConnID as i32; + msg_flags = (*format_list_response).msgFlags as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatListResponse { + server_conn_id, + remote_conn_id, + msg_flags, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_list_response(data); - msg.set_cliprdr(cliprdr); // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -410,23 +500,25 @@ extern "C" fn client_format_data_request( ) -> UINT { log::debug!("client_format_data_request called"); - let mut data = CliprdrServerFormatDataRequest::default(); + let server_conn_id; + let remote_conn_id; + let requested_format_id; unsafe { - data.server_conn_id = (*format_data_request).serverConnID as i32; - data.remote_conn_id = (*format_data_request).remoteConnID as i32; - data.requested_format_id = (*format_data_request).requestedFormatId as i32; + server_conn_id = (*format_data_request).serverConnID as i32; + remote_conn_id = (*format_data_request).remoteConnID as i32; + requested_format_id = (*format_data_request).requestedFormatId as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatDataRequest { + server_conn_id, + remote_conn_id, + requested_format_id, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_data_request(data); - msg.set_cliprdr(cliprdr); // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -437,28 +529,32 @@ extern "C" fn client_format_data_response( ) -> UINT { log::debug!("client_format_data_response called"); - let mut data = CliprdrServerFormatDataResponse::default(); + let server_conn_id; + let remote_conn_id; + let msg_flags; + let format_data; unsafe { - data.server_conn_id = (*format_data_response).serverConnID as i32; - data.remote_conn_id = (*format_data_response).remoteConnID as i32; - data.msg_flags = (*format_data_response).msgFlags as i32; - data.format_data = std::slice::from_raw_parts( + server_conn_id = (*format_data_response).serverConnID as i32; + remote_conn_id = (*format_data_response).remoteConnID as i32; + msg_flags = (*format_data_response).msgFlags as i32; + format_data = std::slice::from_raw_parts( (*format_data_response).requestedFormatData, (*format_data_response).dataLen as usize, ) .to_vec(); } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatDataResponse { + server_conn_id, + remote_conn_id, + msg_flags, + format_data, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_data_response(data); - msg.set_cliprdr(cliprdr); // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -479,30 +575,47 @@ extern "C" fn client_file_contents_request( // return ERROR_INVALID_PARAMETER; // } - let mut data = CliprdrFileContentsRequest::default(); + let server_conn_id; + let remote_conn_id; + let stream_id; + let list_index; + let dw_flags; + let n_position_low; + let n_position_high; + let cb_requested; + let have_clip_data_id; + let clip_data_id; unsafe { - data.server_conn_id = (*file_contents_request).serverConnID as i32; - data.remote_conn_id = (*file_contents_request).remoteConnID as i32; - data.stream_id = (*file_contents_request).streamId as i32; - data.list_index = (*file_contents_request).listIndex as i32; - data.dw_flags = (*file_contents_request).dwFlags as i32; - data.n_position_low = (*file_contents_request).nPositionLow as i32; - data.n_position_high = (*file_contents_request).nPositionHigh as i32; - data.cb_requested = (*file_contents_request).cbRequested as i32; - data.have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; - data.clip_data_id = (*file_contents_request).clipDataId as i32; + server_conn_id = (*file_contents_request).serverConnID as i32; + remote_conn_id = (*file_contents_request).remoteConnID as i32; + stream_id = (*file_contents_request).streamId as i32; + list_index = (*file_contents_request).listIndex as i32; + dw_flags = (*file_contents_request).dwFlags as i32; + n_position_low = (*file_contents_request).nPositionLow as i32; + n_position_high = (*file_contents_request).nPositionHigh as i32; + cb_requested = (*file_contents_request).cbRequested as i32; + have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; + clip_data_id = (*file_contents_request).clipDataId as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, }; - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_file_contents_request(data); - msg.set_cliprdr(cliprdr); + let data = ClipbaordFile::FileContentsRequest { + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -513,29 +626,36 @@ extern "C" fn client_file_contents_response( ) -> UINT { log::debug!("client_file_contents_response called"); - let mut data = CliprdrFileContentsResponse::default(); + let server_conn_id; + let remote_conn_id; + let msg_flags; + let stream_id; + let requested_data; unsafe { - data.server_conn_id = (*file_contents_response).serverConnID as i32; - data.remote_conn_id = (*file_contents_response).remoteConnID as i32; - data.msg_flags = (*file_contents_response).msgFlags as i32; - data.stream_id = (*file_contents_response).streamId as i32; - data.requested_data = std::slice::from_raw_parts( + server_conn_id = (*file_contents_response).serverConnID as i32; + remote_conn_id = (*file_contents_response).remoteConnID as i32; + msg_flags = (*file_contents_response).msgFlags as i32; + stream_id = (*file_contents_response).streamId as i32; + requested_data = std::slice::from_raw_parts( (*file_contents_response).requestedData, (*file_contents_response).cbRequested as usize, ) .to_vec(); } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, }; - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_file_contents_response(data); - msg.set_cliprdr(cliprdr); + let data = ClipbaordFile::FileContentsResponse { + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 99fccfb18..26294df8a 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -1355,7 +1355,16 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) /* Ignore if other app is holding clipboard */ if (try_open_clipboard(clipboard->hwnd)) { + // If current process is running as service with SYSTEM user. + // Clipboard api works fine for text, but copying files works no good. + // GetLastError() returns various error codes count = CountClipboardFormats(); + if (count == 0) + { + CloseClipboard(); + return CHANNEL_RC_NULL_DATA; + } + numFormats = (UINT32)count; formats = (CLIPRDR_FORMAT *)calloc(numFormats, sizeof(CLIPRDR_FORMAT)); @@ -1377,7 +1386,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) } else { - while (formatId = EnumClipboardFormats(formatId)) + while (formatId = EnumClipboardFormats(formatId) && index < numFormats) formats[index++].formatId = formatId; } @@ -1395,6 +1404,10 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) { formats[index].formatName = _strdup(formatName); } + else + { + formats[index].formatName = NULL; + } } } @@ -1408,11 +1421,16 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) rc = clipboard->context->ClientFormatList(clipboard->context, &formatList); for (index = 0; index < numFormats; index++) - free(formats[index].formatName); - + { + if (formats[index].formatName != NULL) + { + free(formats[index].formatName); + formats[index].formatName = NULL; + } + } free(formats); + return rc; - // return 0; } static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *clipboard, UINT32 formatId) diff --git a/src/clipboard_file.rs b/src/clipboard_file.rs new file mode 100644 index 000000000..093dcd90a --- /dev/null +++ b/src/clipboard_file.rs @@ -0,0 +1,207 @@ +use clipboard::ClipbaordFile; +use hbb_common::message_proto::*; + +pub fn clip_2_msg(clip: ClipbaordFile) -> Message { + match clip { + ClipbaordFile::ServerFormatList { + server_conn_id, + remote_conn_id, + format_list, + } => { + let mut formats: Vec = Vec::new(); + for v in format_list.iter() { + formats.push(CliprdrFormat { + server_conn_id: 0, + remote_conn_id: 0, + id: v.0, + format: v.1.clone(), + ..Default::default() + }); + } + Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_list(CliprdrServerFormatList { + server_conn_id, + remote_conn_id, + formats, + ..Default::default() + })), + ..Default::default() + })), + ..Default::default() + } + } + ClipbaordFile::ServerFormatListResponse { + server_conn_id, + remote_conn_id, + msg_flags, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_list_response( + CliprdrServerFormatListResponse { + server_conn_id, + remote_conn_id, + msg_flags, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::ServerFormatDataRequest { + server_conn_id, + remote_conn_id, + requested_format_id, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_data_request( + CliprdrServerFormatDataRequest { + server_conn_id, + remote_conn_id, + requested_format_id, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::ServerFormatDataResponse { + server_conn_id, + remote_conn_id, + msg_flags, + format_data, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_data_response( + CliprdrServerFormatDataResponse { + server_conn_id, + remote_conn_id, + msg_flags, + format_data, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::FileContentsRequest { + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::file_contents_request( + CliprdrFileContentsRequest { + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::FileContentsResponse { + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::file_contents_response( + CliprdrFileContentsResponse { + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + } +} + +pub fn msg_2_clip(msg: Cliprdr) -> Option { + match msg.union { + Some(cliprdr::Union::format_list(data)) => { + let mut format_list: Vec<(i32, String)> = Vec::new(); + for v in data.formats.iter() { + format_list.push((v.id, v.format.clone())); + } + Some(ClipbaordFile::ServerFormatList { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + format_list, + }) + } + Some(cliprdr::Union::format_list_response(data)) => { + Some(ClipbaordFile::ServerFormatListResponse { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + msg_flags: data.msg_flags, + }) + } + Some(cliprdr::Union::format_data_request(data)) => { + Some(ClipbaordFile::ServerFormatDataRequest { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + requested_format_id: data.requested_format_id, + }) + } + Some(cliprdr::Union::format_data_response(data)) => { + Some(ClipbaordFile::ServerFormatDataResponse { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + msg_flags: data.msg_flags, + format_data: data.format_data, + }) + } + Some(cliprdr::Union::file_contents_request(data)) => { + Some(ClipbaordFile::FileContentsRequest { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + stream_id: data.stream_id, + list_index: data.list_index, + dw_flags: data.dw_flags, + n_position_low: data.n_position_low, + n_position_high: data.n_position_high, + cb_requested: data.cb_requested, + have_clip_data_id: data.have_clip_data_id, + clip_data_id: data.clip_data_id, + }) + } + Some(cliprdr::Union::file_contents_response(data)) => { + Some(ClipbaordFile::FileContentsResponse { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + msg_flags: data.msg_flags, + stream_id: data.stream_id, + requested_data: data.requested_data, + }) + } + _ => None, + } +} diff --git a/src/ipc.rs b/src/ipc.rs index 30c643ec5..fa48280bf 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,4 +1,5 @@ use crate::rendezvous_mediator::RendezvousMediator; +pub use clipboard::ClipbaordFile; use hbb_common::{ allow_err, bail, bytes, bytes_codec::BytesCodec, @@ -103,6 +104,7 @@ pub enum Data { to: String, }, SyncConfigToUserResp(bool), + ClipbaordFile(ClipbaordFile), } #[tokio::main(flavor = "current_thread")] diff --git a/src/lib.rs b/src/lib.rs index 2df657ab0..0f788cb67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,3 +28,6 @@ pub mod cli; #[cfg(not(any(target_os = "android", target_os = "ios")))] mod port_forward; mod lang; + +#[cfg(windows)] +pub mod clipboard_file; diff --git a/src/server.rs b/src/server.rs index a1d0454ae..ef0070d77 100644 --- a/src/server.rs +++ b/src/server.rs @@ -29,8 +29,6 @@ use std::{ pub mod audio_service; mod clipboard_service; -#[cfg(windows)] -pub mod clipboard_file_service; mod connection; pub mod input_service; mod service; @@ -63,8 +61,6 @@ pub fn new() -> ServerPtr { server.add_service(Box::new(audio_service::new())); server.add_service(Box::new(video_service::new())); server.add_service(Box::new(clipboard_service::new())); - #[cfg(windows)] - server.add_service(Box::new(clipboard_file_service::new())); server.add_service(Box::new(input_service::new_cursor())); server.add_service(Box::new(input_service::new_pos())); Arc::new(RwLock::new(server)) diff --git a/src/server/clipboard_file_service.rs b/src/server/clipboard_file_service.rs deleted file mode 100644 index 718f44434..000000000 --- a/src/server/clipboard_file_service.rs +++ /dev/null @@ -1,104 +0,0 @@ -use super::*; -use clipboard::{create_cliprdr_context, get_rx_client_msg, server_msg, ConnID}; -use hbb_common::{ - log, - tokio::sync::{ - mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, - Mutex as TokioMutex, - }, - tokio::time::{self, Duration, Instant}, - ResultType, -}; -use std::sync::atomic::{AtomicBool, Ordering}; - -pub const NAME: &'static str = "cliprdr"; - -lazy_static::lazy_static! { - static ref MSG_CHANNEL_SERVER: (UnboundedSender<(ConnID, Cliprdr)>, TokioMutex>) = { - let (tx, rx) = unbounded_channel(); - (tx, TokioMutex::new(rx)) - }; -} - -static RUNNING: AtomicBool = AtomicBool::new(false); - -pub fn new() -> GenericService { - let sp = GenericService::new(NAME, true); - sp.run::<_>(listen::run); - sp -} - -pub fn handle_serve_cliprdr_msg(id: i32, msg: Cliprdr) { - if RUNNING.load(Ordering::SeqCst) { - log::debug!("handle handle_serve_cliprdr_msg"); - MSG_CHANNEL_SERVER - .0 - .send(( - ConnID { - server_conn_id: id as u32, - remote_conn_id: 0, - }, - msg, - )) - .unwrap(); - } else { - // should not reach this branch - } -} - -mod listen { - use super::*; - - static WAIT: Duration = Duration::from_millis(1500); - - #[tokio::main] - pub async fn run(sp: GenericService) -> ResultType<()> { - let mut cliprdr_context = create_cliprdr_context(true, false)?; - - RUNNING.store(false, Ordering::SeqCst); - - let mut timer = time::interval_at(Instant::now() + WAIT, WAIT); - let mut client_rx = get_rx_client_msg().lock().await; - let mut server_rx = MSG_CHANNEL_SERVER.1.lock().await; - while sp.ok() { - RUNNING.store(true, Ordering::SeqCst); - - tokio::select! { - msg = client_rx.recv() => { - match msg { - Some((conn_id, msg)) => { - if conn_id.server_conn_id == 0 { - sp.send(msg) - } else { - sp.send_to(msg, conn_id.server_conn_id as i32) - } - } - None => { - // unreachable!() - } - } - } - msg = server_rx.recv() => { - match msg { - Some((conn_id, msg)) => { - let res = server_msg(&mut cliprdr_context, conn_id, msg); - if res != 0 { - // log::warn!("failed to process message for {}", id); - } - } - None => { - // unreachable!() - } - } - } - _ = timer.tick() => {}, - } - sp.snapshot(|_| Ok(()))?; - } - - RUNNING.store(false, Ordering::SeqCst); - log::info!("Clipboard listener stopped!"); - - Ok(()) - } -} diff --git a/src/server/connection.rs b/src/server/connection.rs index 2e4f40aa3..11c8815a7 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1,4 +1,7 @@ use super::{input_service::*, *}; +#[cfg(windows)] +use crate::{clipboard_file::*, common::update_clipboard, ipc}; +#[cfg(not(windows))] use crate::{common::update_clipboard, ipc}; use hbb_common::{ config::Config, @@ -243,17 +246,17 @@ impl Connection { } else if &name == "file" { conn.file = enabled; conn.send_permission(Permission::File, enabled).await; - #[cfg(windows)] - if let Some(s) = conn.server.upgrade() { - s.write().unwrap().subscribe( - super::clipboard_file_service::NAME, - conn.inner.clone(), conn.file_transfer_enabled()); - } } } ipc::Data::RawMessage(bytes) => { allow_err!(conn.stream.send_raw(bytes).await); } + ipc::Data::ClipbaordFile(_clip) => { + if conn.file_transfer_enabled() { + #[cfg(windows)] + allow_err!(conn.stream.send(&clip_2_msg(_clip)).await); + } + } _ => {} } }, @@ -620,10 +623,6 @@ impl Connection { if !self.audio_enabled() { noperms.push(super::audio_service::NAME); } - if !self.file_transfer_enabled() { - #[cfg(windows)] - noperms.push(super::clipboard_file_service::NAME); - } s.write() .unwrap() .add_connection(self.inner.clone(), &noperms); @@ -849,9 +848,13 @@ impl Connection { update_clipboard(cb, None); } } - #[cfg(windows)] - Some(message::Union::cliprdr(clip)) => { - clipboard_file_service::handle_serve_cliprdr_msg(self.inner.id, clip) + Some(message::Union::cliprdr(_clip)) => { + if self.file_transfer_enabled() { + #[cfg(windows)] + if let Some(clip) = msg_2_clip(_clip) { + self.send_to_cm(ipc::Data::ClipbaordFile(clip)) + } + } } Some(message::Union::file_action(fa)) => { if self.file_transfer.is_some() { @@ -1017,13 +1020,6 @@ impl Connection { if let Ok(q) = o.enable_file_transfer.enum_value() { if q != BoolOption::NotSet { self.enable_file_transfer = q == BoolOption::Yes; - if let Some(s) = self.server.upgrade() { - s.write().unwrap().subscribe( - super::clipboard_file_service::NAME, - self.inner.clone(), - self.file_transfer_enabled(), - ); - } } } if let Ok(q) = o.disable_clipboard.enum_value() { diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 138324471..7b6663302 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -1,4 +1,6 @@ use crate::ipc::{self, new_listener, Connection, Data}; +#[cfg(windows)] +use clipboard::{create_cliprdr_context, get_rx_clip_client, server_clip_file, ConnID}; use hbb_common::{ allow_err, config::{Config, ICON}, @@ -106,6 +108,7 @@ impl ConnectionManager { &self, id: i32, data: Data, + _tx_clip_file: &mpsc::UnboundedSender<(i32, ipc::ClipbaordFile)>, write_jobs: &mut Vec, conn: &mut Connection, ) { @@ -186,6 +189,10 @@ impl ConnectionManager { } } }, + Data::ClipbaordFile(_clip) => { + #[cfg(windows)] + allow_err!(_tx_clip_file.send((id, _clip))); + } _ => {} } } @@ -326,6 +333,12 @@ impl sciter::EventHandler for ConnectionManager { #[tokio::main(flavor = "current_thread")] async fn start_ipc(cm: ConnectionManager) { + let (tx_file, _rx_file) = mpsc::unbounded_channel::<(i32, ipc::ClipbaordFile)>(); + #[cfg(windows)] + let cm_clip = cm.clone(); + #[cfg(windows)] + std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file)); + match new_listener("_cm").await { Ok(mut incoming) => { while let Some(result) = incoming.next().await { @@ -333,6 +346,7 @@ async fn start_ipc(cm: ConnectionManager) { Ok(stream) => { let mut stream = Connection::new(stream); let cm = cm.clone(); + let tx_file = tx_file.clone(); tokio::spawn(async move { let mut conn_id: i32 = 0; let (tx, mut rx) = mpsc::unbounded_channel::(); @@ -356,7 +370,7 @@ async fn start_ipc(cm: ConnectionManager) { break; } _ => { - cm.handle_data(conn_id, data, &mut write_jobs, &mut stream).await; + cm.handle_data(conn_id, data, &tx_file, &mut write_jobs, &mut stream).await; } } } @@ -465,3 +479,68 @@ async fn start_pa() { } } } + +#[cfg(windows)] +#[tokio::main(flavor = "current_thread")] +async fn start_clipboard_file( + cm: ConnectionManager, + mut rx: mpsc::UnboundedReceiver<(i32, ipc::ClipbaordFile)>, +) { + let mut cliprdr_context = match create_cliprdr_context(true, false) { + Ok(context) => { + log::info!("clipboard context for file transfer created."); + context + } + Err(err) => { + log::error!( + "Create clipboard context for file transfer: {}", + err.to_string() + ); + return; + } + }; + let mut rx_clip_client = get_rx_clip_client().lock().await; + + loop { + tokio::select! { + clip_file = rx_clip_client.recv() => match clip_file { + Some((conn_id, clip)) => { + cmd_inner_send( + &cm, + conn_id.server_conn_id as i32, + Data::ClipbaordFile(clip) + ); + } + None => { + // + } + }, + server_msg = rx.recv() => match server_msg { + Some((server_conn_id, clip)) => { + let conn_id = ConnID { + server_conn_id: server_conn_id as u32, + remote_conn_id: 0, + }; + server_clip_file(&mut cliprdr_context, conn_id, clip); + } + None => { + break + } + } + } + } +} + +#[cfg(windows)] +fn cmd_inner_send<'a>(cm: &'a ConnectionManager, id: i32, data: Data) { + let lock = cm.read().unwrap(); + if id != 0 { + if let Some(s) = lock.senders.get(&id) { + allow_err!(s.send(data)); + } + } else { + for s in lock.senders.values() { + allow_err!(s.send(data.clone())); + } + } +} diff --git a/src/ui/remote.rs b/src/ui/remote.rs index eb99fa302..d13715178 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -1,12 +1,18 @@ -use crate::client::*; -use crate::common::{ - self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL, +#[cfg(windows)] +use crate::{ + client::*, + clipboard_file::*, + common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}, +}; +#[cfg(not(windows))] +use crate::{ + client::*, + common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}, }; #[cfg(windows)] use clipboard::{ cliprdr::CliprdrClientContext, create_cliprdr_context as create_clipboard_file_context, - get_rx_client_msg as get_clipboard_file_rx_client_msg, server_msg as clipboard_file_msg, - ConnID as ClipboardFileConnID, + get_rx_clip_client, server_clip_file, ConnID as ClipboardFileConnID, }; use enigo::{self, Enigo, KeyboardControllable}; use hbb_common::{ @@ -1313,9 +1319,9 @@ impl Remote { // just build for now #[cfg(not(windows))] - let (_, mut clipboard_file_client_rx) = mpsc::unbounded_channel::(); + let (_, mut rx_clip_client) = mpsc::unbounded_channel::(); #[cfg(windows)] - let mut clipboard_file_client_rx = get_clipboard_file_rx_client_msg().lock().await; + let mut rx_clip_client = get_rx_clip_client().lock().await; loop { tokio::select! { @@ -1347,12 +1353,12 @@ impl Remote { } } } - _msg = clipboard_file_client_rx.recv() => { + _msg = rx_clip_client.recv() => { #[cfg(windows)] match _msg { - Some((conn_id, msg)) => { + Some((conn_id, clip)) => { if conn_id.remote_conn_id == 0 || conn_id.remote_conn_id == self.pid { - allow_err!(peer.send(&msg).await); + allow_err!(peer.send(&clip_2_msg(clip)).await); } } None => { @@ -1740,14 +1746,16 @@ impl Remote { Some(message::Union::cliprdr(clip)) => { if !self.handler.lc.read().unwrap().disable_clipboard { if let Some(context) = &mut self.clipboard_file_context { - clipboard_file_msg( - context, - ClipboardFileConnID { - server_conn_id: 0, - remote_conn_id: self.pid, - }, - clip, - ); + if let Some(clip) = msg_2_clip(clip) { + server_clip_file( + context, + ClipboardFileConnID { + server_conn_id: 0, + remote_conn_id: self.pid, + }, + clip, + ); + } } } } From 2f6b457b3f2968aad7d0c67ad8defa9cace65643 Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 22 Feb 2022 22:26:22 +0800 Subject: [PATCH 2/5] better control of clipboard file transfer Signed-off-by: fufesou --- libs/clipboard/src/cliprdr.h | 3 + libs/clipboard/src/cliprdr.rs | 11 +++ libs/clipboard/src/lib.rs | 52 +++++++++++ libs/clipboard/src/windows/wf_cliprdr.c | 116 +++++++++++++++++++++--- src/ipc.rs | 2 + src/server/connection.rs | 3 + src/ui/cm.rs | 12 ++- 7 files changed, 183 insertions(+), 16 deletions(-) diff --git a/libs/clipboard/src/cliprdr.h b/libs/clipboard/src/cliprdr.h index 0e581cc2f..260db685a 100644 --- a/libs/clipboard/src/cliprdr.h +++ b/libs/clipboard/src/cliprdr.h @@ -192,6 +192,8 @@ extern "C" typedef UINT (*pcCliprdrServerFileContentsResponse)( CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse); + typedef BOOL (*pcCheckEnabled)(UINT32 server_conn_id, UINT32 remote_conn_id); + // TODO: hide more members of clipboard context struct _cliprdr_client_context { @@ -199,6 +201,7 @@ extern "C" BOOL enableFiles; BOOL enableOthers; + pcCheckEnabled CheckEnabled; pcCliprdrServerCapabilities ServerCapabilities; pcCliprdrClientCapabilities ClientCapabilities; pcCliprdrMonitorReady MonitorReady; diff --git a/libs/clipboard/src/cliprdr.rs b/libs/clipboard/src/cliprdr.rs index b88d9c40d..f7233b6b5 100644 --- a/libs/clipboard/src/cliprdr.rs +++ b/libs/clipboard/src/cliprdr.rs @@ -456,6 +456,9 @@ pub type pcCliprdrServerFileContentsResponse = ::std::option::Option< fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE, ) -> UINT, >; +pub type pcCheckEnabled = ::std::option::Option< + unsafe extern "C" fn(server_conn_id: UINT32, remote_conn_id: UINT32) -> BOOL, +>; // TODO: hide more members of clipboard context #[repr(C)] @@ -464,6 +467,7 @@ pub struct _cliprdr_client_context { pub custom: *mut ::std::os::raw::c_void, pub enableFiles: BOOL, pub enableOthers: BOOL, + pub CheckEnabled: pcCheckEnabled, pub ServerCapabilities: pcCliprdrServerCapabilities, pub ClientCapabilities: pcCliprdrClientCapabilities, pub MonitorReady: pcCliprdrMonitorReady, @@ -492,6 +496,11 @@ pub struct _cliprdr_client_context { extern "C" { pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL; pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL; + pub fn empty_clipboard( + context: *mut CliprdrClientContext, + server_conn_id: u32, + remote_conn_id: u32, + ) -> BOOL; } #[derive(Error, Debug)] @@ -508,6 +517,7 @@ impl CliprdrClientContext { pub fn create( enable_files: bool, enable_others: bool, + check_enabled: pcCheckEnabled, client_format_list: pcCliprdrClientFormatList, client_format_list_response: pcCliprdrClientFormatListResponse, client_format_data_request: pcCliprdrClientFormatDataRequest, @@ -519,6 +529,7 @@ impl CliprdrClientContext { custom: 0 as *mut _, enableFiles: if enable_files { TRUE } else { FALSE }, enableOthers: if enable_others { TRUE } else { FALSE }, + CheckEnabled: check_enabled, ServerCapabilities: None, ClientCapabilities: None, MonitorReady: None, diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 37db74549..3ad696118 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -10,7 +10,9 @@ use hbb_common::{ use serde_derive::{Deserialize, Serialize}; use std::{ boxed::Box, + collections::HashMap, ffi::{CStr, CString}, + sync::Mutex, }; pub mod cliprdr; @@ -66,11 +68,19 @@ pub enum ClipbaordFile { }, } +#[derive(Default)] +struct ConnEnabled { + server_conn_enabled: HashMap, + remote_conn_enabled: HashMap, +} + lazy_static::lazy_static! { static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, ClipbaordFile)>, TokioMutex>) = { let (tx, rx) = unbounded_channel(); (tx, TokioMutex::new(rx)) }; + + static ref CLIP_CONN_ENABLED: Mutex = Mutex::new(ConnEnabled::default()); } #[inline(always)] @@ -78,6 +88,16 @@ pub fn get_rx_clip_client<'a>() -> &'a TokioMutex, conn_id: ConnID, @@ -409,6 +429,7 @@ pub fn create_cliprdr_context( Ok(CliprdrClientContext::create( enable_files, enable_others, + Some(check_enabled), Some(client_format_list), Some(client_format_list_response), Some(client_format_data_request), @@ -418,6 +439,37 @@ pub fn create_cliprdr_context( )?) } +extern "C" fn check_enabled(server_conn_id: UINT32, remote_conn_id: UINT32) -> BOOL { + let lock = CLIP_CONN_ENABLED.lock().unwrap(); + if server_conn_id == 0 && remote_conn_id == 0 { + return FALSE; + } + + let mut server_conn_enabled = false; + if server_conn_id != 0 { + if let Some(true) = lock.server_conn_enabled.get(&(server_conn_id as i32)) { + server_conn_enabled = true; + } + } else { + server_conn_enabled = true; + } + + let mut remote_conn_enabled = false; + if remote_conn_id != 0 { + if let Some(true) = lock.remote_conn_enabled.get(&(remote_conn_id as i32)) { + remote_conn_enabled = true; + } + } else { + remote_conn_enabled = true; + } + + if server_conn_enabled && remote_conn_enabled { + return TRUE; + } else { + return FALSE; + } +} + extern "C" fn client_format_list( _context: *mut CliprdrClientContext, clip_format_list: *const CLIPRDR_FORMAT_LIST, diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 26294df8a..c0d1b7af6 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -228,6 +228,8 @@ struct wf_clipboard HANDLE response_data_event; LPDATAOBJECT data_obj; + HANDLE data_obj_mutex; + ULONG req_fsize; char *req_fdata; HANDLE req_fevent; @@ -682,6 +684,10 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO return E_INVALIDARG; clipboard = (wfClipboard *)instance->m_pData; + if (!clipboard->context->CheckEnabled(instance->m_serverConnID, instance->m_remoteConnID)) + { + return E_INVALIDARG; + } if (!clipboard) return E_INVALIDARG; @@ -1450,12 +1456,15 @@ static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, clipboard->requestedFormatId = formatId; rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); - if (WaitForSingleObject(clipboard->response_data_event, INFINITE) != WAIT_OBJECT_0) - rc = ERROR_INTERNAL_ERROR; - else if (!ResetEvent(clipboard->response_data_event)) - rc = ERROR_INTERNAL_ERROR; - - return rc; + while (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) + { + if (WaitForSingleObject(clipboard->response_data_event, 50) != WAIT_OBJECT_0) + rc = ERROR_INTERNAL_ERROR; + else if (!ResetEvent(clipboard->response_data_event)) + rc = ERROR_INTERNAL_ERROR; + return rc; + } + return ERROR_INTERNAL_ERROR; } UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConnID, UINT32 remoteConnID, const void *streamid, ULONG index, @@ -1480,12 +1489,15 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConn fileContentsRequest.msgFlags = 0; rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest); - if (WaitForSingleObject(clipboard->req_fevent, INFINITE) != WAIT_OBJECT_0) - rc = ERROR_INTERNAL_ERROR; - else if (!ResetEvent(clipboard->req_fevent)) - rc = ERROR_INTERNAL_ERROR; - - return rc; + while (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) + { + if (WaitForSingleObject(clipboard->req_fevent, INFINITE) != WAIT_OBJECT_0) + rc = ERROR_INTERNAL_ERROR; + else if (!ResetEvent(clipboard->req_fevent)) + rc = ERROR_INTERNAL_ERROR; + return rc; + } + return ERROR_INTERNAL_ERROR; } static UINT cliprdr_send_response_filecontents(wfClipboard *clipboard, UINT32 serverConnID, UINT32 remoteConnID, UINT32 streamId, UINT32 size, @@ -1540,7 +1552,6 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM case WM_CLIPBOARDUPDATE: DEBUG_CLIPRDR("info: WM_CLIPBOARDUPDATE"); - // if (clipboard->sync) { if ((GetClipboardOwner() != clipboard->hwnd) && @@ -1632,6 +1643,11 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM case OLE_SETCLIPBOARD: DEBUG_CLIPRDR("info: OLE_SETCLIPBOARD"); + if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0) + { + break; + } + if (clipboard->data_obj != NULL) { wf_destroy_file_obj(clipboard->data_obj); @@ -1648,6 +1664,11 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM } free((void *)lParam); + if (!ReleaseMutex(clipboard->data_obj_mutex)) + { + // critical error!!! + } + break; case DELAYED_RENDERING: @@ -2738,6 +2759,9 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr) if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL))) goto error; + if (!(clipboard->data_obj_mutex = CreateMutex(NULL, FALSE, "data_obj_mutex"))) + goto error; + if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL))) goto error; @@ -2806,3 +2830,69 @@ BOOL uninit_cliprdr(CliprdrClientContext *context) { return wf_cliprdr_uninit(&clipboard, context); } + +BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 remote_conn_id) +{ + wfClipboard *clipboard = NULL; + BOOL rc = FALSE; + if (!context) + { + return FALSE; + } + if (server_conn_id == 0 && remote_conn_id == 0) + { + return TRUE; + } + + clipboard = (wfClipboard *)context->custom; + + if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0) + { + return FALSE; + } + + while (0) + { + if (clipboard->data_obj != NULL) + { + CliprdrDataObject *instance = clipboard->data_obj; + if (server_conn_id != 0 && instance->m_serverConnID != server_conn_id) + { + rc = TRUE; + break; + } + if (remote_conn_id != 0 && instance->m_remoteConnID != remote_conn_id) + { + rc = TRUE; + break; + } + + wf_destroy_file_obj(clipboard->data_obj); + clipboard->data_obj = NULL; + } + + /* discard all contexts in clipboard */ + if (!try_open_clipboard(clipboard->hwnd)) + { + DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError()); + rc = FALSE; + break; + } + + if (!EmptyClipboard()) + { + rc = FALSE; + } + if (!CloseClipboard()) + { + // critical error!!! + } + rc = TRUE; + } + + if (!ReleaseMutex(clipboard->data_obj_mutex)) + { + // critical error!!! + } + return rc; +} diff --git a/src/ipc.rs b/src/ipc.rs index fa48280bf..41f59bddb 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -74,6 +74,7 @@ pub enum Data { clipboard: bool, audio: bool, file: bool, + file_transfer_enabled: bool, }, ChatMessage { text: String, @@ -105,6 +106,7 @@ pub enum Data { }, SyncConfigToUserResp(bool), ClipbaordFile(ClipbaordFile), + ClipboardFileEnabled(bool), } #[tokio::main(flavor = "current_thread")] diff --git a/src/server/connection.rs b/src/server/connection.rs index 11c8815a7..97413e0ce 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -246,6 +246,7 @@ impl Connection { } else if &name == "file" { conn.file = enabled; conn.send_permission(Permission::File, enabled).await; + conn.send_to_cm(ipc::Data::ClipboardFileEnabled(conn.file_transfer_enabled())); } } ipc::Data::RawMessage(bytes) => { @@ -654,6 +655,7 @@ impl Connection { clipboard: self.clipboard, audio: self.audio, file: self.file, + file_transfer_enabled: self.file_transfer_enabled(), }); } @@ -1020,6 +1022,7 @@ impl Connection { if let Ok(q) = o.enable_file_transfer.enum_value() { if q != BoolOption::NotSet { self.enable_file_transfer = q == BoolOption::Yes; + self.send_to_cm(ipc::Data::ClipboardFileEnabled(self.file_transfer_enabled())); } } if let Ok(q) = o.disable_clipboard.enum_value() { diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 7b6663302..6f38b22b9 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -1,6 +1,8 @@ use crate::ipc::{self, new_listener, Connection, Data}; #[cfg(windows)] -use clipboard::{create_cliprdr_context, get_rx_clip_client, server_clip_file, ConnID}; +use clipboard::{ + create_cliprdr_context, get_rx_clip_client, server_clip_file, set_conn_enabled, ConnID, +}; use hbb_common::{ allow_err, config::{Config, ICON}, @@ -193,6 +195,9 @@ impl ConnectionManager { #[cfg(windows)] allow_err!(_tx_clip_file.send((id, _clip))); } + Data::ClipboardFileEnabled(enabled) => { + set_conn_enabled(id, 0, enabled); + } _ => {} } } @@ -361,8 +366,9 @@ async fn start_ipc(cm: ConnectionManager) { } Ok(Some(data)) => { match data { - Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file} => { + Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled} => { conn_id = id; + set_conn_enabled(id, 0, file_transfer_enabled); cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, tx.clone()); } Data::Close => { @@ -532,7 +538,7 @@ async fn start_clipboard_file( } #[cfg(windows)] -fn cmd_inner_send<'a>(cm: &'a ConnectionManager, id: i32, data: Data) { +fn cmd_inner_send(cm: &ConnectionManager, id: i32, data: Data) { let lock = cm.read().unwrap(); if id != 0 { if let Some(s) = lock.senders.get(&id) { From 555ff0085adeb69651e9ccaefc269183d79d1a42 Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 22 Feb 2022 23:53:28 +0800 Subject: [PATCH 3/5] empty clipboard, debug crash & failed to copy Signed-off-by: fufesou --- libs/clipboard/src/cliprdr.rs | 6 ++--- libs/clipboard/src/lib.rs | 32 ++++++++++++++++++------- libs/clipboard/src/windows/wf_cliprdr.c | 24 +++++++++++++++++-- src/ui/cm.rs | 26 +++++++++++++++++--- 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/libs/clipboard/src/cliprdr.rs b/libs/clipboard/src/cliprdr.rs index f7233b6b5..184711595 100644 --- a/libs/clipboard/src/cliprdr.rs +++ b/libs/clipboard/src/cliprdr.rs @@ -496,10 +496,10 @@ pub struct _cliprdr_client_context { extern "C" { pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL; pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL; - pub fn empty_clipboard( + pub(crate) fn empty_cliprdr( context: *mut CliprdrClientContext, - server_conn_id: u32, - remote_conn_id: u32, + server_conn_id: UINT32, + remote_conn_id: UINT32, ) -> BOOL; } diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 3ad696118..5e6998ce9 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -98,6 +98,20 @@ pub fn set_conn_enabled(server_conn_id: i32, remote_conn_id: i32, enabled: bool) } } +pub fn empty_clipboard( + context: &mut Box, + server_conn_id: i32, + remote_conn_id: i32, +) -> bool { + unsafe { + TRUE == cliprdr::empty_cliprdr( + &mut (**context), + server_conn_id as u32, + remote_conn_id as u32, + ) + } +} + pub fn server_clip_file( context: &mut Box, conn_id: ConnID, @@ -454,14 +468,16 @@ extern "C" fn check_enabled(server_conn_id: UINT32, remote_conn_id: UINT32) -> B server_conn_enabled = true; } - let mut remote_conn_enabled = false; - if remote_conn_id != 0 { - if let Some(true) = lock.remote_conn_enabled.get(&(remote_conn_id as i32)) { - remote_conn_enabled = true; - } - } else { - remote_conn_enabled = true; - } + // let mut remote_conn_enabled = false; + // remote connection is always enabled + // if remote_conn_id != 0 { + // if let Some(true) = lock.remote_conn_enabled.get(&(remote_conn_id as i32)) { + // remote_conn_enabled = true; + // } + // } else { + // remote_conn_enabled = true; + // } + let remote_conn_enabled = true; if server_conn_enabled && remote_conn_enabled { return TRUE; diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index c0d1b7af6..eb530917d 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -2792,6 +2792,23 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr) cliprdr->custom = NULL; + /* discard all contexts in clipboard */ + if (try_open_clipboard(clipboard->hwnd)) + { + if (!EmptyClipboard()) + { + DEBUG_CLIPRDR("EmptyClipboard failed with 0x%x", GetLastError()); + } + if (!CloseClipboard()) + { + // critical error!!! + } + } + else + { + DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError()); + } + if (clipboard->hwnd) PostMessage(clipboard->hwnd, WM_QUIT, 0, 0); @@ -2810,6 +2827,9 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr) if (clipboard->response_data_event) CloseHandle(clipboard->response_data_event); + if (clipboard->data_obj_mutex) + CloseHandle(clipboard->data_obj_mutex); + if (clipboard->req_fevent) CloseHandle(clipboard->req_fevent); @@ -2851,7 +2871,7 @@ BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 return FALSE; } - while (0) + do { if (clipboard->data_obj != NULL) { @@ -2888,7 +2908,7 @@ BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 // critical error!!! } rc = TRUE; - } + } while (0); if (!ReleaseMutex(clipboard->data_obj_mutex)) { diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 6f38b22b9..31bd6b19b 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -1,7 +1,8 @@ use crate::ipc::{self, new_listener, Connection, Data}; #[cfg(windows)] use clipboard::{ - create_cliprdr_context, get_rx_clip_client, server_clip_file, set_conn_enabled, ConnID, + create_cliprdr_context, empty_clipboard, get_rx_clip_client, server_clip_file, + set_conn_enabled, ConnID, }; use hbb_common::{ allow_err, @@ -111,6 +112,7 @@ impl ConnectionManager { id: i32, data: Data, _tx_clip_file: &mpsc::UnboundedSender<(i32, ipc::ClipbaordFile)>, + _tx_clip_empty: &mpsc::UnboundedSender, write_jobs: &mut Vec, conn: &mut Connection, ) { @@ -197,6 +199,9 @@ impl ConnectionManager { } Data::ClipboardFileEnabled(enabled) => { set_conn_enabled(id, 0, enabled); + if !enabled { + allow_err!(_tx_clip_empty.send(id)); + } } _ => {} } @@ -339,10 +344,11 @@ impl sciter::EventHandler for ConnectionManager { #[tokio::main(flavor = "current_thread")] async fn start_ipc(cm: ConnectionManager) { let (tx_file, _rx_file) = mpsc::unbounded_channel::<(i32, ipc::ClipbaordFile)>(); + let (tx_clip_empty, _rx_clip_empty) = mpsc::unbounded_channel::(); #[cfg(windows)] let cm_clip = cm.clone(); #[cfg(windows)] - std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file)); + std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file, _rx_clip_empty)); match new_listener("_cm").await { Ok(mut incoming) => { @@ -352,6 +358,7 @@ async fn start_ipc(cm: ConnectionManager) { let mut stream = Connection::new(stream); let cm = cm.clone(); let tx_file = tx_file.clone(); + let tx_clip_empty = tx_clip_empty.clone(); tokio::spawn(async move { let mut conn_id: i32 = 0; let (tx, mut rx) = mpsc::unbounded_channel::(); @@ -372,11 +379,13 @@ async fn start_ipc(cm: ConnectionManager) { cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, tx.clone()); } Data::Close => { + allow_err!(tx_clip_empty.send(conn_id)); + set_conn_enabled(conn_id, 0, false); log::info!("cm ipc connection closed from connection request"); break; } _ => { - cm.handle_data(conn_id, data, &tx_file, &mut write_jobs, &mut stream).await; + cm.handle_data(conn_id, data, &tx_file, &tx_clip_empty, &mut write_jobs, &mut stream).await; } } } @@ -491,6 +500,7 @@ async fn start_pa() { async fn start_clipboard_file( cm: ConnectionManager, mut rx: mpsc::UnboundedReceiver<(i32, ipc::ClipbaordFile)>, + mut rx_clip_empty: mpsc::UnboundedReceiver, ) { let mut cliprdr_context = match create_cliprdr_context(true, false) { Ok(context) => { @@ -532,6 +542,16 @@ async fn start_clipboard_file( None => { break } + }, + server_conn_id = rx_clip_empty.recv() => match server_conn_id { + Some(server_conn_id) => { + if !empty_clipboard(&mut cliprdr_context, server_conn_id, 0) { + // log::error!("failed to empty clipboard"); + } + } + None => { + break + } } } } From 128a4aca69fd6763a4ddbac98a88b5b8b64f0f05 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 24 Feb 2022 00:17:59 +0800 Subject: [PATCH 4/5] fix crash on windows clipboard Signed-off-by: fufesou --- libs/clipboard/src/windows/wf_cliprdr.c | 46 +++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index eb530917d..ef8e71571 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -705,7 +705,9 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO // DWORD remote_format_id = get_remote_format_id(clipboard, instance->m_pFormatEtc[idx].cfFormat); // FIXME: origin code may be failed here??? if (cliprdr_send_data_request(instance->m_serverConnID, instance->m_remoteConnID, clipboard, instance->m_pFormatEtc[idx].cfFormat) != 0) + { return E_UNEXPECTED; + } pMedium->hGlobal = clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */ /* GlobalLock returns a pointer to the first byte of the memory block, @@ -1455,13 +1457,29 @@ static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, formatDataRequest.requestedFormatId = remoteFormatId; clipboard->requestedFormatId = formatId; rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); + if (rc != ERROR_SUCCESS) + { + return rc; + } while (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) { - if (WaitForSingleObject(clipboard->response_data_event, 50) != WAIT_OBJECT_0) - rc = ERROR_INTERNAL_ERROR; - else if (!ResetEvent(clipboard->response_data_event)) + DWORD waitRes = WaitForSingleObject(clipboard->response_data_event, 50); + if (waitRes == WAIT_TIMEOUT) + { + continue; + } + + if (waitRes != WAIT_OBJECT_0) + { + return ERROR_INTERNAL_ERROR; + } + + if (!ResetEvent(clipboard->response_data_event)) + { + // NOTE: critical error here, crash may be better rc = ERROR_INTERNAL_ERROR; + } return rc; } return ERROR_INTERNAL_ERROR; @@ -1488,13 +1506,29 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConn fileContentsRequest.clipDataId = 0; fileContentsRequest.msgFlags = 0; rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest); + if (rc != ERROR_SUCCESS) + { + return rc; + } while (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) { - if (WaitForSingleObject(clipboard->req_fevent, INFINITE) != WAIT_OBJECT_0) - rc = ERROR_INTERNAL_ERROR; - else if (!ResetEvent(clipboard->req_fevent)) + DWORD waitRes = WaitForSingleObject(clipboard->req_fevent, 50); + if (waitRes == WAIT_TIMEOUT) + { + continue; + } + + if (waitRes != WAIT_OBJECT_0) + { + return ERROR_INTERNAL_ERROR; + } + + if (!ResetEvent(clipboard->req_fevent)) + { + // NOTE: critical error here, crash may be better rc = ERROR_INTERNAL_ERROR; + } return rc; } return ERROR_INTERNAL_ERROR; From 01591d1abfcc5d5e3bf844656a150991f62f8f84 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 24 Feb 2022 02:32:29 +0800 Subject: [PATCH 5/5] fix hang up Signed-off-by: fufesou --- libs/clipboard/src/lib.rs | 28 +- libs/clipboard/src/windows/wf_cliprdr.c | 383 +++++++++++++++++------- src/ui/cm.rs | 4 + 3 files changed, 303 insertions(+), 112 deletions(-) diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 5e6998ce9..b66b43bba 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -605,11 +605,15 @@ extern "C" fn client_format_data_response( server_conn_id = (*format_data_response).serverConnID as i32; remote_conn_id = (*format_data_response).remoteConnID as i32; msg_flags = (*format_data_response).msgFlags as i32; - format_data = std::slice::from_raw_parts( - (*format_data_response).requestedFormatData, - (*format_data_response).dataLen as usize, - ) - .to_vec(); + if (*format_data_response).requestedFormatData.is_null() { + format_data = Vec::new(); + } else { + format_data = std::slice::from_raw_parts( + (*format_data_response).requestedFormatData, + (*format_data_response).dataLen as usize, + ) + .to_vec(); + } } let conn_id = ConnID { server_conn_id: server_conn_id as u32, @@ -704,11 +708,15 @@ extern "C" fn client_file_contents_response( remote_conn_id = (*file_contents_response).remoteConnID as i32; msg_flags = (*file_contents_response).msgFlags as i32; stream_id = (*file_contents_response).streamId as i32; - requested_data = std::slice::from_raw_parts( - (*file_contents_response).requestedData, - (*file_contents_response).cbRequested as usize, - ) - .to_vec(); + if (*file_contents_response).requestedData.is_null() { + requested_data = Vec::new(); + } else { + requested_data = std::slice::from_raw_parts( + (*file_contents_response).requestedData, + (*file_contents_response).cbRequested as usize, + ) + .to_vec(); + } } let conn_id = ConnID { server_conn_id: server_conn_id as u32, diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index ef8e71571..192af18d1 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -254,6 +254,7 @@ typedef struct wf_clipboard wfClipboard; BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr); BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr); +BOOL wf_do_empty_cliprdr(wfClipboard *clipboard); static BOOL wf_create_file_obj(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *cliprdrrdr, IDataObject **ppDataObject); static void wf_destroy_file_obj(IDataObject *instance); @@ -708,6 +709,10 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO { return E_UNEXPECTED; } + if (!clipboard->hmem) + { + return E_UNEXPECTED; + } pMedium->hGlobal = clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */ /* GlobalLock returns a pointer to the first byte of the memory block, @@ -1462,12 +1467,20 @@ static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, return rc; } - while (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) + // with default 3min timeout + for (int i = 0; i < 20 * 60 * 3; i++) { DWORD waitRes = WaitForSingleObject(clipboard->response_data_event, 50); if (waitRes == WAIT_TIMEOUT) { - continue; + if (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) + { + continue; + } + else + { + break; + } } if (waitRes != WAIT_OBJECT_0) @@ -1480,8 +1493,24 @@ static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, // NOTE: critical error here, crash may be better rc = ERROR_INTERNAL_ERROR; } + + if (!clipboard->hmem) + { + rc = ERROR_INTERNAL_ERROR; + } + return rc; } + + if (clipboard->hmem) + { + if (!ResetEvent(clipboard->response_data_event)) + { + // NOTE: critical error here, crash may be better + } + return ERROR_SUCCESS; + } + return ERROR_INTERNAL_ERROR; } @@ -1511,12 +1540,20 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConn return rc; } - while (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) + // with default 3min timeout + for (int i = 0; i < 20 * 60 * 3; i++) { DWORD waitRes = WaitForSingleObject(clipboard->req_fevent, 50); if (waitRes == WAIT_TIMEOUT) { - continue; + if (clipboard->context->CheckEnabled(serverConnID, remoteConnID)) + { + continue; + } + else + { + break; + } } if (waitRes != WAIT_OBJECT_0) @@ -1529,25 +1566,50 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConn // NOTE: critical error here, crash may be better rc = ERROR_INTERNAL_ERROR; } + if (!clipboard->req_fdata) + { + rc = ERROR_INTERNAL_ERROR; + } + return rc; } + + if (clipboard->req_fdata) + { + if (!ResetEvent(clipboard->req_fevent)) + { + // NOTE: critical error here, crash may be better + } + return ERROR_SUCCESS; + } + return ERROR_INTERNAL_ERROR; } -static UINT cliprdr_send_response_filecontents(wfClipboard *clipboard, UINT32 serverConnID, UINT32 remoteConnID, UINT32 streamId, UINT32 size, - BYTE *data) +static UINT cliprdr_send_response_filecontents( + wfClipboard *clipboard, + UINT32 serverConnID, + UINT32 remoteConnID, + UINT16 msgFlags, + UINT32 streamId, + UINT32 size, + BYTE *data) { CLIPRDR_FILE_CONTENTS_RESPONSE fileContentsResponse; if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsResponse) - return ERROR_INTERNAL_ERROR; + { + data = NULL; + size = 0; + msgFlags = CB_RESPONSE_FAIL; + } fileContentsResponse.serverConnID = serverConnID; fileContentsResponse.remoteConnID = remoteConnID; fileContentsResponse.streamId = streamId; fileContentsResponse.cbRequested = size; fileContentsResponse.requestedData = data; - fileContentsResponse.msgFlags = CB_RESPONSE_OK; + fileContentsResponse.msgFlags = msgFlags; return clipboard->context->ClientFileContentsResponse(clipboard->context, &fileContentsResponse); } @@ -2343,7 +2405,7 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest) { - UINT rc; + UINT rc = ERROR_SUCCESS; size_t size = 0; void *buff = NULL; char *globlemem = NULL; @@ -2353,12 +2415,18 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, wfClipboard *clipboard; if (!context || !formatDataRequest) - return ERROR_INTERNAL_ERROR; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } clipboard = (wfClipboard *)context->custom; if (!clipboard) - return ERROR_INTERNAL_ERROR; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } requestedFormatId = formatDataRequest->requestedFormatId; @@ -2376,7 +2444,10 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, result = OleGetClipboard(&dataObj); if (FAILED(result)) - return ERROR_INTERNAL_ERROR; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } ZeroMemory(&format_etc, sizeof(FORMATETC)); ZeroMemory(&stg_medium, sizeof(STGMEDIUM)); @@ -2389,7 +2460,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, if (FAILED(result)) { - DEBUG_CLIPRDR("dataObj->GetData failed."); + rc = ERROR_INTERNAL_ERROR; goto exit; } @@ -2400,7 +2471,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, GlobalUnlock(stg_medium.hGlobal); ReleaseStgMedium(&stg_medium); clipboard->nFiles = 0; - goto exit; + goto resp; } clear_file_array(clipboard); @@ -2417,7 +2488,6 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, else { char *p; - for (p = (char *)((char *)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0; p += len + 1, clipboard->nFiles++) { @@ -2432,7 +2502,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, GlobalUnlock(stg_medium.hGlobal); ReleaseStgMedium(&stg_medium); - exit: + resp: size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW); groupDsc = (FILEGROUPDESCRIPTORW *)malloc(size); @@ -2450,6 +2520,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, } IDataObject_Release(dataObj); + rc = ERROR_SUCCESS; } else { @@ -2461,26 +2532,50 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context, if (!hClipdata) { CloseClipboard(); - return ERROR_INTERNAL_ERROR; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } } - - globlemem = (char *)GlobalLock(hClipdata); - size = (int)GlobalSize(hClipdata); - buff = malloc(size); - CopyMemory(buff, globlemem, size); - GlobalUnlock(hClipdata); - CloseClipboard(); + else + { + globlemem = (char *)GlobalLock(hClipdata); + size = (int)GlobalSize(hClipdata); + buff = malloc(size); + CopyMemory(buff, globlemem, size); + GlobalUnlock(hClipdata); + CloseClipboard(); + rc = ERROR_SUCCESS; + } + } + else + { + rc = ERROR_INTERNAL_ERROR; } } +exit: + if (rc == ERROR_SUCCESS) + { + response.msgFlags = CB_RESPONSE_OK; + } + else + { + response.msgFlags = CB_RESPONSE_FAIL; + } response.serverConnID = formatDataRequest->serverConnID; response.remoteConnID = formatDataRequest->remoteConnID; - response.msgFlags = CB_RESPONSE_OK; response.dataLen = size; response.requestedFormatData = (BYTE *)buff; - rc = 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 + } - free(buff); + if (buff) + { + free(buff); + } return rc; } @@ -2493,48 +2588,69 @@ static UINT wf_cliprdr_server_format_data_response(CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse) { + UINT rc = ERROR_INTERNAL_ERROR; BYTE *data; HANDLE hMem; wfClipboard *clipboard; - if (!context || !formatDataResponse) - return ERROR_INTERNAL_ERROR; - - if (formatDataResponse->msgFlags != CB_RESPONSE_OK) - return E_FAIL; - - clipboard = (wfClipboard *)context->custom; - - if (!clipboard) - return ERROR_INTERNAL_ERROR; - - hMem = GlobalAlloc(GMEM_MOVEABLE, formatDataResponse->dataLen); - - if (!hMem) - return ERROR_INTERNAL_ERROR; - - data = (BYTE *)GlobalLock(hMem); - - if (!data) + do { - GlobalFree(hMem); - return ERROR_INTERNAL_ERROR; - } + if (!context || !formatDataResponse) + { + rc = ERROR_INTERNAL_ERROR; + break; + } - CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); + clipboard = (wfClipboard *)context->custom; + if (!clipboard) + { + rc = ERROR_INTERNAL_ERROR; + break; + } + clipboard->hmem = NULL; - if (!GlobalUnlock(hMem) && GetLastError()) - { - GlobalFree(hMem); - return ERROR_INTERNAL_ERROR; - } + if (formatDataResponse->msgFlags != CB_RESPONSE_OK) + { + // BOOL emptyRes = wf_do_empty_cliprdr((wfClipboard *)context->custom); + // (void)emptyRes; + rc = E_FAIL; + break; + } - clipboard->hmem = hMem; + hMem = GlobalAlloc(GMEM_MOVEABLE, formatDataResponse->dataLen); + if (!hMem) + { + rc = ERROR_INTERNAL_ERROR; + break; + } + + data = (BYTE *)GlobalLock(hMem); + if (!data) + { + GlobalFree(hMem); + rc = ERROR_INTERNAL_ERROR; + break; + } + + CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); + + if (!GlobalUnlock(hMem) && GetLastError()) + { + GlobalFree(hMem); + rc = ERROR_INTERNAL_ERROR; + break; + } + + clipboard->hmem = hMem; + rc = CHANNEL_RC_OK; + } while (0); if (!SetEvent(clipboard->response_data_event)) - return ERROR_INTERNAL_ERROR; - - return CHANNEL_RC_OK; + { + // CAUTION: critical error here, process will hang up until wait timeout default 3min. + rc = ERROR_INTERNAL_ERROR; + } + return rc; } /** @@ -2561,12 +2677,18 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context, UINT32 cbRequested; if (!context || !fileContentsRequest) - return ERROR_INTERNAL_ERROR; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } clipboard = (wfClipboard *)context->custom; if (!clipboard) - return ERROR_INTERNAL_ERROR; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } cbRequested = fileContentsRequest->cbRequested; if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE) @@ -2575,14 +2697,18 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context, pData = (BYTE *)calloc(1, cbRequested); if (!pData) - goto error; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } hRet = OleGetClipboard(&pDataObj); if (FAILED(hRet)) { printf("filecontents: get ole clipboard failed.\n"); - goto error; + rc = ERROR_INTERNAL_ERROR; + goto exit; } ZeroMemory(&vFormatEtc, sizeof(FORMATETC)); @@ -2666,7 +2792,10 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context, if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE) { if (clipboard->nFiles <= fileContentsRequest->listIndex) - goto error; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } *((UINT32 *)&pData[0]) = clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow; *((UINT32 *)&pData[4]) = @@ -2677,7 +2806,10 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context, { BOOL bRet; if (clipboard->nFiles <= fileContentsRequest->listIndex) - goto error; + { + rc = ERROR_INTERNAL_ERROR; + goto exit; + } bRet = wf_cliprdr_get_file_contents( clipboard->file_names[fileContentsRequest->listIndex], pData, fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, cbRequested, @@ -2687,21 +2819,30 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context, { printf("get file contents failed.\n"); uSize = 0; - goto error; + rc = ERROR_INTERNAL_ERROR; + goto exit; } } } rc = CHANNEL_RC_OK; -error: +exit: if (pDataObj) IDataObject_Release(pDataObj); + if (rc != CHANNEL_RC_OK) + { + uSize = 0; + } + if (uSize == 0) { - free(pData); - pData = NULL; + if (pData) + { + free(pData); + pData = NULL; + } } sRc = @@ -2709,13 +2850,18 @@ error: clipboard, fileContentsRequest->serverConnID, fileContentsRequest->remoteConnID, + rc == CHANNEL_RC_OK ? CB_RESPONSE_OK : CB_RESPONSE_FAIL, fileContentsRequest->streamId, uSize, pData); - free(pData); - if (sRc != CHANNEL_RC_OK) - return sRc; + if (pData) + { + free(pData); + } + + // if (sRc != CHANNEL_RC_OK) + // return sRc; return rc; } @@ -2730,34 +2876,50 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse) { wfClipboard *clipboard; + UINT rc = ERROR_INTERNAL_ERROR; - if (!context || !fileContentsResponse) - return ERROR_INTERNAL_ERROR; + do + { + if (!context || !fileContentsResponse) + { + rc = ERROR_INTERNAL_ERROR; + break; + } - if (fileContentsResponse->msgFlags != CB_RESPONSE_OK) - return E_FAIL; + clipboard = (wfClipboard *)context->custom; + if (!clipboard) + { + rc = ERROR_INTERNAL_ERROR; + break; + } + clipboard->req_fsize = 0; + clipboard->req_fdata = NULL; - clipboard = (wfClipboard *)context->custom; + if (fileContentsResponse->msgFlags != CB_RESPONSE_OK) + { + rc = E_FAIL; + break; + } - if (!clipboard) - return ERROR_INTERNAL_ERROR; + clipboard->req_fsize = fileContentsResponse->cbRequested; + clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested); + if (!clipboard->req_fdata) + { + rc = ERROR_INTERNAL_ERROR; + break; + } - clipboard->req_fsize = fileContentsResponse->cbRequested; - clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested); + CopyMemory(clipboard->req_fdata, fileContentsResponse->requestedData, + fileContentsResponse->cbRequested); - if (!clipboard->req_fdata) - return ERROR_INTERNAL_ERROR; - - CopyMemory(clipboard->req_fdata, fileContentsResponse->requestedData, - fileContentsResponse->cbRequested); + rc = CHANNEL_RC_OK; + } while (0); if (!SetEvent(clipboard->req_fevent)) { - free(clipboard->req_fdata); - return ERROR_INTERNAL_ERROR; + // CAUTION: critical error here, process will hang up until wait timeout default 3min. } - - return CHANNEL_RC_OK; + return rc; } BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr) @@ -2888,6 +3050,7 @@ BOOL uninit_cliprdr(CliprdrClientContext *context) BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 remote_conn_id) { wfClipboard *clipboard = NULL; + CliprdrDataObject *instance = NULL; BOOL rc = FALSE; if (!context) { @@ -2899,6 +3062,34 @@ BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 } clipboard = (wfClipboard *)context->custom; + if (!clipboard) + { + return FALSE; + } + + instance = clipboard->data_obj; + if (instance) + { + if (server_conn_id != 0 && instance->m_serverConnID != server_conn_id) + { + return TRUE; + } + if (remote_conn_id != 0 && instance->m_remoteConnID != remote_conn_id) + { + return TRUE; + } + } + + return wf_do_empty_cliprdr(clipboard); +} + +BOOL wf_do_empty_cliprdr(wfClipboard *clipboard) +{ + BOOL rc = FALSE; + if (!clipboard) + { + return FALSE; + } if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0) { @@ -2909,18 +3100,6 @@ BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 { if (clipboard->data_obj != NULL) { - CliprdrDataObject *instance = clipboard->data_obj; - if (server_conn_id != 0 && instance->m_serverConnID != server_conn_id) - { - rc = TRUE; - break; - } - if (remote_conn_id != 0 && instance->m_remoteConnID != remote_conn_id) - { - rc = TRUE; - break; - } - wf_destroy_file_obj(clipboard->data_obj); clipboard->data_obj = NULL; } diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 31bd6b19b..f7fe3b1e8 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -198,6 +198,7 @@ impl ConnectionManager { allow_err!(_tx_clip_file.send((id, _clip))); } Data::ClipboardFileEnabled(enabled) => { + #[cfg(windows)] set_conn_enabled(id, 0, enabled); if !enabled { allow_err!(_tx_clip_empty.send(id)); @@ -375,11 +376,14 @@ async fn start_ipc(cm: ConnectionManager) { match data { Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled} => { conn_id = id; + #[cfg(windows)] set_conn_enabled(id, 0, file_transfer_enabled); + let _ = file_transfer_enabled; cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, tx.clone()); } Data::Close => { allow_err!(tx_clip_empty.send(conn_id)); + #[cfg(windows)] set_conn_enabled(conn_id, 0, false); log::info!("cm ipc connection closed from connection request"); break;