From 4a6907755adef798fb24deeb93440f2b40b33b38 Mon Sep 17 00:00:00 2001 From: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com> Date: Fri, 30 Oct 2026 00:21:36 +0800 Subject: [PATCH] fix(shell): retry clipboard reads briefly before failing refs #38 #85 Hosted desktops can hold the clipboard for a few milliseconds; reads now retry five times with a short backoff on ERROR_ACCESS_DENIED, while writes keep the immediate failure the copy boundary contract asserts. --- experiments/shell/clipboard.hpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/experiments/shell/clipboard.hpp b/experiments/shell/clipboard.hpp index bd44fc83..0e8205d3 100644 --- a/experiments/shell/clipboard.hpp +++ b/experiments/shell/clipboard.hpp @@ -13,8 +13,20 @@ class ClipboardError : public std::runtime_error { }; class ClipboardAccess { public: - explicit ClipboardAccess(HWND owner) { - if (!OpenClipboard(owner)) throw ClipboardError("OpenClipboard", GetLastError()); + // A hosted desktop can hold the clipboard for a few milliseconds at a time + // (Explorer or a neighbouring test). Reads retry briefly so contention is + // not reported as a hard refusal; writes keep the immediate failure because + // the copy-failure contract asserts the first OpenClipboard result. + explicit ClipboardAccess(HWND owner, bool retry = false) { + constexpr int attempts = 5; + for (int attempt = 0; attempt < attempts; ++attempt) { + if (OpenClipboard(owner)) return; + const DWORD error = GetLastError(); + if (!retry || error != ERROR_ACCESS_DENIED || attempt + 1 == attempts) + throw ClipboardError("OpenClipboard", error); + Sleep(static_cast(20 * (attempt + 1))); + } + throw ClipboardError("OpenClipboard", GetLastError()); } ~ClipboardAccess() { CloseClipboard(); } ClipboardAccess(const ClipboardAccess&) = delete; @@ -22,7 +34,7 @@ class ClipboardAccess { inline std::u16string read_unicode_clipboard(HWND owner, size_t max_units = PastePolicy::hard_utf16_units) { static_assert(sizeof(wchar_t) == sizeof(char16_t), "Windows UTF-16 expected"); if (max_units > PastePolicy::hard_utf16_units) throw std::length_error("clipboard limit exceeds hard bound"); - ClipboardAccess clipboard(owner); + ClipboardAccess clipboard(owner, true); if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) throw ClipboardError("Unicode text unavailable", ERROR_NOT_FOUND); HANDLE memory = GetClipboardData(CF_UNICODETEXT); if (!memory) throw ClipboardError("GetClipboardData", GetLastError());