fix(desktop): silence wsl.exe stderr banner + detached explorer relaunch rung
Follow-ups to the salvaged WSL-bridge gating (#66447): - wsl-path-bridge.ts: discard wsl.exe stderr so the 'WSL is not installed' banner can never leak into an attached console on WSL-less machines (#80184). - scripts/desktop-update/windows.ps1: add an explorer.exe-mediated detached relaunch rung between the WMI attempt and the tethered Start-Process fallback. When Win32_Process.Create fails (observed ReturnValue 8), the Desktop no longer re-attaches to the hand-off console, so its stdout stops flooding the window and the console can close.
This commit is contained in:
@@ -86,6 +86,11 @@ export function resolveDefaultWslDistro(): string {
|
||||
const out = execFileSync('wsl.exe', ['-l', '-q'], {
|
||||
encoding: 'utf8',
|
||||
env: { ...process.env, WSL_UTF8: '1' },
|
||||
// On WSL-less machines wsl.exe prints "The Windows Subsystem for Linux
|
||||
// is not installed..." to stderr; stderr is inherited by default, so
|
||||
// that banner leaks into whatever console the app is attached to
|
||||
// (visible e.g. during the update hand-off). Discard it. (#80184)
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
timeout: 2000,
|
||||
windowsHide: true
|
||||
})
|
||||
|
||||
@@ -571,6 +571,59 @@ function Start-DesktopRelaunch {
|
||||
} catch {
|
||||
Write-HandoffLog "WARNING: WMI relaunch failed: $($_.Exception.Message); falling back"
|
||||
}
|
||||
if (-not $spawned) {
|
||||
# Middle rung: explorer.exe-mediated launch. On some machines
|
||||
# Win32_Process.Create fails outright (observed ReturnValue 8,
|
||||
# "unknown failure"), and the tethered fallback below re-attaches the
|
||||
# Desktop to this console — its stdout then floods the console and the
|
||||
# window can't close while the app lives. Explorer re-parents the
|
||||
# target exactly like a normal shell launch, giving the same
|
||||
# no-console detachment WMI would have. Explorer returns no pid, so
|
||||
# verify by watching for a fresh Hermes process.
|
||||
try {
|
||||
$exeName = [System.IO.Path]::GetFileNameWithoutExtension($RelaunchExe)
|
||||
$before = @(Get-Process -Name $exeName -ErrorAction SilentlyContinue | ForEach-Object { $_.Id })
|
||||
Start-Process -FilePath 'explorer.exe' -ArgumentList ('"{0}"' -f $RelaunchExe) | Out-Null
|
||||
$explorerDeadline = (Get-Date).AddSeconds(15)
|
||||
while ((Get-Date) -lt $explorerDeadline) {
|
||||
$fresh = @(Get-Process -Name $exeName -ErrorAction SilentlyContinue | Where-Object { $before -notcontains $_.Id })
|
||||
if ($fresh.Count -gt 0) {
|
||||
Write-HandoffLog "desktop relaunched detached via explorer (pid $($fresh[0].Id))"
|
||||
$spawned = $true
|
||||
# Same foreground hand-off as the WMI rung: the new process
|
||||
# starts unfocused and only the current foreground owner
|
||||
# (us) can delegate that right.
|
||||
try {
|
||||
if ($script:Win32) {
|
||||
[HermesHandoff.Win32]::AllowSetForegroundWindow([int]$fresh[0].Id) | Out-Null
|
||||
$focusDeadline = (Get-Date).AddSeconds(20)
|
||||
while ((Get-Date) -lt $focusDeadline) {
|
||||
$hwnd = [System.IntPtr]::Zero
|
||||
try { $hwnd = (Get-Process -Id $fresh[0].Id -ErrorAction Stop).MainWindowHandle } catch { break }
|
||||
if ($hwnd -ne [System.IntPtr]::Zero) {
|
||||
[HermesHandoff.Win32]::ShowWindow($hwnd, 9) | Out-Null # SW_RESTORE
|
||||
[HermesHandoff.Win32]::SetForegroundWindow($hwnd) | Out-Null
|
||||
Write-HandoffLog "focused relaunched desktop window"
|
||||
break
|
||||
}
|
||||
Start-Sleep -Milliseconds 400
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-HandoffLog "WARNING: could not focus relaunched desktop: $($_.Exception.Message)"
|
||||
}
|
||||
break
|
||||
}
|
||||
Start-Sleep -Milliseconds 400
|
||||
if ($script:Ui) { [System.Windows.Forms.Application]::DoEvents() }
|
||||
}
|
||||
if (-not $spawned) {
|
||||
Write-HandoffLog "WARNING: explorer relaunch did not produce a $exeName process; falling back"
|
||||
}
|
||||
} catch {
|
||||
Write-HandoffLog "WARNING: explorer relaunch failed: $($_.Exception.Message); falling back"
|
||||
}
|
||||
}
|
||||
if (-not $spawned) {
|
||||
try {
|
||||
# Fallback keeps the old behavior (console tie-in and all) --
|
||||
|
||||
Reference in New Issue
Block a user