From 0751005073de715abc5758bd58675313ec232e23 Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:01:34 +0800 Subject: [PATCH] Fix/windows empty file clipboard on disconn (#10242) * fix: windows, empty file clipboard on disconn Signed-off-by: fufesou * refact: Don't send files copied before the conn Signed-off-by: fufesou * refact: windows, file clipboard Empty clipboard if no `Ctrl+C` is pressed, but `CliprdrDataObject_GetData()` is called. `CliprdrDataObject_GetData()` is only called in the clipboard object set by RustDesk. Signed-off-by: fufesou --------- Signed-off-by: fufesou --- libs/clipboard/src/windows/wf_cliprdr.c | 65 ++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index c2b7556a4..6f8381a6a 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -211,6 +211,11 @@ struct wf_clipboard BOOL sync; UINT32 capabilities; + // This flag is not really needed, + // but we can use it to double confirm that files can only be pasted after `Ctrl+C`. + // Not sure `is_file_descriptor_from_remote()` is engough to check all cases on all Windows. + BOOL copied; + size_t map_size; size_t map_capacity; formatMapping *format_mappings; @@ -263,6 +268,8 @@ static UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 con ULONG index, UINT32 flag, DWORD positionhigh, DWORD positionlow, ULONG request); +static BOOL is_file_descriptor_from_remote(); + static void CliprdrDataObject_Delete(CliprdrDataObject *instance); static CliprdrEnumFORMATETC *CliprdrEnumFORMATETC_New(ULONG nFormats, FORMATETC *pFormatEtc); @@ -712,6 +719,15 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO if (!clipboard) return E_INVALIDARG; + // If `Ctrl+C` is not pressed yet, do not handle the file paste, and empty the clipboard. + if (!clipboard->copied) { + if (try_open_clipboard(clipboard->hwnd)) { + EmptyClipboard(); + CloseClipboard(); + } + return E_UNEXPECTED; + } + if ((idx = cliprdr_lookup_format(instance, pFormatEtc)) == -1) { // empty clipboard here? @@ -1479,6 +1495,8 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) // send rc = clipboard->context->ClientFormatList(clipboard->context, &formatList); + // No need to check `rc`, `copied` is only used to indicate `Ctrl+C` is pressed. + clipboard->copied = TRUE; for (index = 0; index < numFormats; index++) { @@ -2274,7 +2292,9 @@ static UINT wf_cliprdr_monitor_ready(CliprdrClientContext *context, if (rc != CHANNEL_RC_OK) return rc; - return cliprdr_send_format_list(clipboard, monitorReady->connID); + return rc; + // Don't send format list here, because we don't want to paste files copied before the connection. + // return cliprdr_send_format_list(clipboard, monitorReady->connID); } /** @@ -2321,11 +2341,20 @@ static UINT wf_cliprdr_server_format_list(CliprdrClientContext *context, UINT32 i; formatMapping *mapping; CLIPRDR_FORMAT *format; - wfClipboard *clipboard = (wfClipboard *)context->Custom; + wfClipboard *clipboard = NULL; + + if (!context || !formatList) + return ERROR_INTERNAL_ERROR; + + clipboard = (wfClipboard *)context->Custom; + if (!clipboard) + return ERROR_INTERNAL_ERROR; if (!clear_format_map(clipboard)) return ERROR_INTERNAL_ERROR; + clipboard->copied = TRUE; + for (i = 0; i < formatList->numFormats; i++) { format = &(formatList->formats[i]); @@ -3060,6 +3089,19 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context, return rc; } +BOOL is_file_descriptor_from_remote() +{ + UINT fsid = 0; + if (IsClipboardFormatAvailable(CF_HDROP)) { + return FALSE; + } + fsid = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); + if (IsClipboardFormatAvailable(fsid)) { + return TRUE; + } + return FALSE; +} + BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr) { if (!clipboard || !cliprdr) @@ -3071,6 +3113,7 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr) clipboard->map_size = 0; clipboard->hUser32 = LoadLibraryA("user32.dll"); clipboard->data_obj = NULL; + clipboard->copied = FALSE; if (clipboard->hUser32) { @@ -3126,14 +3169,18 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr) if (!clipboard || !cliprdr) return FALSE; + clipboard->copied = FALSE; cliprdr->Custom = NULL; /* discard all contexts in clipboard */ if (try_open_clipboard(clipboard->hwnd)) { - if (!EmptyClipboard()) + if (is_file_descriptor_from_remote()) { - DEBUG_CLIPRDR("EmptyClipboard failed with 0x%x", GetLastError()); + if (!EmptyClipboard()) + { + DEBUG_CLIPRDR("EmptyClipboard failed with 0x%x", GetLastError()); + } } if (!CloseClipboard()) { @@ -3227,6 +3274,8 @@ BOOL wf_do_empty_cliprdr(wfClipboard *clipboard) return FALSE; } + clipboard->copied = FALSE; + if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0) { return FALSE; @@ -3248,10 +3297,14 @@ BOOL wf_do_empty_cliprdr(wfClipboard *clipboard) break; } - if (!EmptyClipboard()) + if (is_file_descriptor_from_remote()) { - rc = FALSE; + if (!EmptyClipboard()) + { + rc = FALSE; + } } + if (!CloseClipboard()) { // critical error!!!