Fix/windows empty file clipboard on disconn (#10242)

* fix: windows, empty file clipboard on disconn

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact: Don't send files copied before the conn

Signed-off-by: fufesou <linlong1266@gmail.com>

* 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 <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2024-12-10 11:01:34 +08:00
committed by GitHub
parent fe06cf77da
commit 0751005073

View File

@@ -211,6 +211,11 @@ struct wf_clipboard
BOOL sync; BOOL sync;
UINT32 capabilities; 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_size;
size_t map_capacity; size_t map_capacity;
formatMapping *format_mappings; formatMapping *format_mappings;
@@ -263,6 +268,8 @@ static UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 con
ULONG index, UINT32 flag, DWORD positionhigh, ULONG index, UINT32 flag, DWORD positionhigh,
DWORD positionlow, ULONG request); DWORD positionlow, ULONG request);
static BOOL is_file_descriptor_from_remote();
static void CliprdrDataObject_Delete(CliprdrDataObject *instance); static void CliprdrDataObject_Delete(CliprdrDataObject *instance);
static CliprdrEnumFORMATETC *CliprdrEnumFORMATETC_New(ULONG nFormats, FORMATETC *pFormatEtc); static CliprdrEnumFORMATETC *CliprdrEnumFORMATETC_New(ULONG nFormats, FORMATETC *pFormatEtc);
@@ -712,6 +719,15 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO
if (!clipboard) if (!clipboard)
return E_INVALIDARG; 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) if ((idx = cliprdr_lookup_format(instance, pFormatEtc)) == -1)
{ {
// empty clipboard here? // empty clipboard here?
@@ -1479,6 +1495,8 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID)
// send // send
rc = clipboard->context->ClientFormatList(clipboard->context, &formatList); 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++) for (index = 0; index < numFormats; index++)
{ {
@@ -2274,7 +2292,9 @@ static UINT wf_cliprdr_monitor_ready(CliprdrClientContext *context,
if (rc != CHANNEL_RC_OK) if (rc != CHANNEL_RC_OK)
return rc; 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; UINT32 i;
formatMapping *mapping; formatMapping *mapping;
CLIPRDR_FORMAT *format; 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)) if (!clear_format_map(clipboard))
return ERROR_INTERNAL_ERROR; return ERROR_INTERNAL_ERROR;
clipboard->copied = TRUE;
for (i = 0; i < formatList->numFormats; i++) for (i = 0; i < formatList->numFormats; i++)
{ {
format = &(formatList->formats[i]); format = &(formatList->formats[i]);
@@ -3060,6 +3089,19 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
return rc; 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) BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
{ {
if (!clipboard || !cliprdr) if (!clipboard || !cliprdr)
@@ -3071,6 +3113,7 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
clipboard->map_size = 0; clipboard->map_size = 0;
clipboard->hUser32 = LoadLibraryA("user32.dll"); clipboard->hUser32 = LoadLibraryA("user32.dll");
clipboard->data_obj = NULL; clipboard->data_obj = NULL;
clipboard->copied = FALSE;
if (clipboard->hUser32) if (clipboard->hUser32)
{ {
@@ -3126,14 +3169,18 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
if (!clipboard || !cliprdr) if (!clipboard || !cliprdr)
return FALSE; return FALSE;
clipboard->copied = FALSE;
cliprdr->Custom = NULL; cliprdr->Custom = NULL;
/* discard all contexts in clipboard */ /* discard all contexts in clipboard */
if (try_open_clipboard(clipboard->hwnd)) 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()) if (!CloseClipboard())
{ {
@@ -3227,6 +3274,8 @@ BOOL wf_do_empty_cliprdr(wfClipboard *clipboard)
return FALSE; return FALSE;
} }
clipboard->copied = FALSE;
if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0) if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0)
{ {
return FALSE; return FALSE;
@@ -3248,10 +3297,14 @@ BOOL wf_do_empty_cliprdr(wfClipboard *clipboard)
break; break;
} }
if (!EmptyClipboard()) if (is_file_descriptor_from_remote())
{ {
rc = FALSE; if (!EmptyClipboard())
{
rc = FALSE;
}
} }
if (!CloseClipboard()) if (!CloseClipboard())
{ {
// critical error!!! // critical error!!!