Skip to content

Commit

Permalink
fix: win, file clipboard, try empty (rustdesk#10609)
Browse files Browse the repository at this point in the history
Signed-off-by: fufesou <[email protected]>
  • Loading branch information
fufesou authored Jan 27, 2025
1 parent f08cb04 commit 55005f8
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 7 deletions.
11 changes: 11 additions & 0 deletions libs/clipboard/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pub enum ClipboardFile {
stream_id: i32,
requested_data: Vec<u8>,
},
TryEmpty,
}

struct MsgChannel {
Expand Down Expand Up @@ -226,6 +227,16 @@ fn send_data_to_channel(conn_id: i32, data: ClipboardFile) -> ResultType<()> {
}
}

#[cfg(target_os = "windows")]
pub fn send_data_exclude(conn_id: i32, data: ClipboardFile) {
use hbb_common::log;
for msg_channel in VEC_MSG_CHANNEL.read().unwrap().iter() {
if msg_channel.conn_id != conn_id {
allow_err!(msg_channel.sender.send(data.clone()));
}
}
}

#[cfg(feature = "unix-file-copy-paste")]
#[inline]
fn send_data_to_all(data: ClipboardFile) -> ResultType<()> {
Expand Down
10 changes: 8 additions & 2 deletions libs/clipboard/src/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
#![allow(deref_nullptr)]

use crate::{
allow_err, send_data, ClipboardFile, CliprdrError, CliprdrServiceContext, ResultType,
send_data, send_data_exclude, ClipboardFile, CliprdrError, CliprdrServiceContext, ResultType,
ERR_CODE_INVALID_PARAMETER, ERR_CODE_SEND_MSG, ERR_CODE_SERVER_FUNCTION_NONE, VEC_MSG_CHANNEL,
};
use hbb_common::log;
use hbb_common::{allow_err, log};
use std::{
boxed::Box,
ffi::{CStr, CString},
Expand Down Expand Up @@ -643,6 +643,7 @@ pub fn server_clip_file(
conn_id,
&format_list
);
send_data_exclude(conn_id as _, ClipboardFile::TryEmpty);
ret = server_format_list(context, conn_id, format_list);
log::debug!(
"server_format_list called, conn_id {}, return {}",
Expand Down Expand Up @@ -740,6 +741,11 @@ pub fn server_clip_file(
ret
);
}
ClipboardFile::TryEmpty => {
log::debug!("empty_clipboard called");
let ret = empty_clipboard(context, conn_id);
log::debug!("empty_clipboard called, conn_id {}, return {}", conn_id, ret);
}
}
ret
}
Expand Down
46 changes: 42 additions & 4 deletions libs/clipboard/src/windows/wf_cliprdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ static UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 con
DWORD positionlow, ULONG request);

static BOOL is_file_descriptor_from_remote();
static BOOL is_set_by_instance(wfClipboard *clipboard);

static void CliprdrDataObject_Delete(CliprdrDataObject *instance);

Expand Down Expand Up @@ -600,8 +601,11 @@ static CliprdrStream *CliprdrStream_New(UINT32 connID, ULONG index, void *pData,
clipboard->req_fdata = NULL;
}
}
else
else {
instance->m_lSize.QuadPart =
((UINT64)instance->m_Dsc.nFileSizeHigh << 32) | instance->m_Dsc.nFileSizeLow;
success = TRUE;
}
}
}

Expand Down Expand Up @@ -1745,8 +1749,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
DEBUG_CLIPRDR("info: WM_CLIPBOARDUPDATE");
// if (clipboard->sync)
{
if ((GetClipboardOwner() != clipboard->hwnd) &&
(S_FALSE == OleIsCurrentClipboard(clipboard->data_obj)))
if (!is_set_by_instance(clipboard))
{
if (clipboard->hmem)
{
Expand Down Expand Up @@ -2086,6 +2089,8 @@ static FILEDESCRIPTORW *wf_cliprdr_get_file_descriptor(WCHAR *file_name, size_t
return NULL;
}

// to-do: use `fd->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI`.
// We keep `fd->dwFlags = FD_ATTRIBUTES | FD_WRITESTIME | FD_PROGRESSUI` for compatibility.
// fd->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI;
fd->dwFlags = FD_ATTRIBUTES | FD_WRITESTIME | FD_PROGRESSUI;
fd->dwFileAttributes = GetFileAttributesW(file_name);
Expand Down Expand Up @@ -2849,6 +2854,31 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
goto exit;
}

// If the clipboard is set by the instance, or the file descriptor is from remote,
// we should not process the request.
// Because this may be the following cases:
// 1. `A` -> `B`, `C`
// 2. Copy in `A`
// 3. Copy in `B`
// 4. Paste in `C`
// In this case, `C` should not get the file content from `A`. The clipboard is set by `B`.
//
// Or
// 1. `B` -> `A` -> `C`
// 2. Copy in `A`
// 2. Copy in `B`
// 3. Paste in `C`
// In this case, `C` should not get the file content from `A`. The clipboard is set by `B`.
//
// We can simply notify `C` to clear the clipboard when `A` received copy message from `B`,
// if connections are in the same process.
// But if connections are in different processes, it is not easy to notify the other process.
// So we just ignore the request from `C` in this case.
if (is_set_by_instance(clipboard) || is_file_descriptor_from_remote()) {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}

cbRequested = fileContentsRequest->cbRequested;
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
cbRequested = sizeof(UINT64);
Expand Down Expand Up @@ -3089,6 +3119,14 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
return rc;
}

BOOL is_set_by_instance(wfClipboard *clipboard)
{
if (GetClipboardOwner() == clipboard->hwnd || S_OK == OleIsCurrentClipboard(clipboard->data_obj)) {
return TRUE;
}
return FALSE;
}

BOOL is_file_descriptor_from_remote()
{
UINT fsid = 0;
Expand Down Expand Up @@ -3175,7 +3213,7 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
/* discard all contexts in clipboard */
if (try_open_clipboard(clipboard->hwnd))
{
if (is_file_descriptor_from_remote())
if (is_set_by_instance(clipboard) || is_file_descriptor_from_remote())
{
if (!EmptyClipboard())
{
Expand Down
2 changes: 1 addition & 1 deletion libs/hbb_common
10 changes: 10 additions & 0 deletions src/clipboard_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ pub fn clip_2_msg(clip: ClipboardFile) -> Message {
})),
..Default::default()
},
ClipboardFile::TryEmpty => Message {
union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::TryEmpty(CliprdrTryEmpty {
..Default::default()
})),
..Default::default()
})),
..Default::default()
},
}
}

Expand Down Expand Up @@ -176,6 +185,7 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipboardFile> {
requested_data: data.requested_data.into(),
})
}
Some(cliprdr::Union::TryEmpty(_)) => Some(ClipboardFile::TryEmpty),
_ => None,
}
}

0 comments on commit 55005f8

Please sign in to comment.