fix(host/windows): re-isolate/re-attach desktop ONLY on the secure desktop
recreate_dupl called reassert_isolation (a display-TOPOLOGY change via isolate_displays) + attach_input_desktop on EVERY ACCESS_LOST rebuild — 200× in a 6 s SDR session. A topology change itself invalidates the freshly-rebuilt duplication, so the next acquire is ACCESS_LOST → recreate → reassert → a self-feeding 0x887A0026 churn that freezes the stream and never recovers across context changes (lock / login / post-login). Gate both behind is_secure_desktop(): the heavy topology work runs only on the actual Winlogon (secure/login) desktop — where a physical monitor can grab the secure desktop off our virtual output. Routine churn, the lock screen, and post-login are all on the normal desktop, so they take a light re-duplicate with no topology meddling. Apollo isolates once at startup; its recovery just re-duplicates — this matches that. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -101,7 +101,7 @@ impl Drop for DesktopWatcher {
|
|||||||
|
|
||||||
/// True if the current input desktop is "Winlogon" (the secure desktop). Best-effort: if the desktop
|
/// True if the current input desktop is "Winlogon" (the secure desktop). Best-effort: if the desktop
|
||||||
/// can't be opened or named, report not-secure (the safe default — keep WGC/normal capture).
|
/// can't be opened or named, report not-secure (the safe default — keep WGC/normal capture).
|
||||||
unsafe fn is_secure_desktop() -> bool {
|
pub(crate) unsafe fn is_secure_desktop() -> bool {
|
||||||
let desk = match OpenInputDesktop(
|
let desk = match OpenInputDesktop(
|
||||||
DESKTOP_CONTROL_FLAGS(0),
|
DESKTOP_CONTROL_FLAGS(0),
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -1401,12 +1401,18 @@ impl DuplCapturer {
|
|||||||
if let Some(n) = crate::vdisplay::sudovda::resolve_gdi_name(self.target_id) {
|
if let Some(n) = crate::vdisplay::sudovda::resolve_gdi_name(self.target_id) {
|
||||||
self.gdi_name = n;
|
self.gdi_name = n;
|
||||||
}
|
}
|
||||||
attach_input_desktop();
|
// Heavy topology work — re-attach the thread to the input desktop AND re-isolate the virtual
|
||||||
// Re-route the secure (Winlogon) desktop back to the virtual output. The lock/UAC switch can
|
// output — ONLY on the actual secure (Winlogon) desktop. Entering it can re-attach a physical
|
||||||
// re-attach a physical monitor so the secure desktop lands there and our virtual output goes
|
// monitor and move the secure desktop off our virtual output, which re-isolation fixes. But on
|
||||||
// perpetually ACCESS_LOST; re-isolating (as a fresh session's `create` does) is the delta that
|
// the NORMAL desktop this is just routine ACCESS_LOST churn (HDR overlay / MPO / periodic IddCx
|
||||||
// makes in-session recovery work like a reconnect. Idempotent/cheap when already isolated.
|
// invalidation), and re-isolating there is a DISPLAY-TOPOLOGY CHANGE that itself invalidates the
|
||||||
crate::vdisplay::sudovda::reassert_isolation(&self.gdi_name);
|
// freshly-rebuilt duplication → a self-feeding ACCESS_LOST storm (200 rebuilds/session observed).
|
||||||
|
// Apollo isolates once at startup and its recovery just re-duplicates; match that off the secure
|
||||||
|
// desktop. (The lock screen / post-login are NOT Winlogon, so they take this light path too.)
|
||||||
|
if crate::capture::desktop_watch::is_secure_desktop() {
|
||||||
|
attach_input_desktop();
|
||||||
|
crate::vdisplay::sudovda::reassert_isolation(&self.gdi_name);
|
||||||
|
}
|
||||||
let (dev, ctx, out, dupl) = reopen_duplication(&self.gdi_name)?; // Err → caller repeats + retries
|
let (dev, ctx, out, dupl) = reopen_duplication(&self.gdi_name)?; // Err → caller repeats + retries
|
||||||
|
|
||||||
// (The born-lost guard is now the capture-acquire at the end: we adopt, then grab the current
|
// (The born-lost guard is now the capture-acquire at the end: we adopt, then grab the current
|
||||||
|
|||||||
Reference in New Issue
Block a user