diff --git a/src/clipboard.rs b/src/clipboard.rs index e4bd00390..329b392bb 100644 --- a/src/clipboard.rs +++ b/src/clipboard.rs @@ -272,6 +272,15 @@ impl ClipboardContext { } fn get_formats(&mut self, formats: &[ClipboardFormat]) -> ResultType> { + // If there're multiple threads or processes trying to access the clipboard at the same time, + // the previous clipboard owner will fail to access the clipboard. + // `GetLastError()` will return `ERROR_CLIPBOARD_NOT_OPEN` (OSError(1418): Thread does not have a clipboard open) at this time. + // See https://github.com/rustdesk-org/arboard/blob/747ab2d9b40a5c9c5102051cf3b0bb38b4845e60/src/platform/windows.rs#L34 + // + // This is a common case on Windows, so we retry here. + // Related issues: + // https://github.com/rustdesk/rustdesk/issues/9263 + // https://github.com/rustdesk/rustdesk/issues/9222#issuecomment-2329233175 for i in 0..CLIPBOARD_GET_MAX_RETRY { match self.inner.get_formats(SUPPORTED_FORMATS) { Ok(data) => { diff --git a/src/server/clipboard_service.rs b/src/server/clipboard_service.rs index a2a3b3153..d6bea7520 100644 --- a/src/server/clipboard_service.rs +++ b/src/server/clipboard_service.rs @@ -131,9 +131,12 @@ impl Handler { check_clipboard(&mut self.ctx, ClipboardSide::Host, false) } - // It's ok to do async operation in the clipboard service because: - // 1. the clipboard is not used frequently. - // 2. the clipboard handle is sync and will not block the main thread. + // Read clipboard data from cm using ipc. + // + // We cannot use `#[tokio::main(flavor = "current_thread")]` here, + // because the auto-managed tokio runtime (async context) will be dropped after the call. + // The next call will create a new runtime, which will cause the previous stream to be unusable. + // So we need to manage the tokio runtime manually. #[cfg(windows)] fn read_clipboard_from_cm_ipc(&mut self) -> ResultType> { if self.rt.is_none() {