From a3487392c02af07b15e6da4806f88575a3b39e12 Mon Sep 17 00:00:00 2001 From: Muyue Date: Mon, 27 Apr 2026 14:39:26 +0200 Subject: [PATCH] fix(windows/conpty): pass HPCON value, not &hPC (v0.7.8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User reported regression introduced in v0.7.6: PowerShell / cmd open in a separate external console window instead of attaching to the xterm.js tab (v0.7.5 worked). Root cause: the ConPTY wiring used attrList.Update(PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, unsafe.Pointer(&hPC), // ← wrong unsafe.Sizeof(hPC)) The PSEUDOCONSOLE attribute is a Win32 API quirk: lpValue must be the HPCON *value* (cast to PVOID), not a pointer to the local variable holding the handle. With &hPC the kernel reads garbage, silently drops the attribute, and CreateProcessW spawns the child with a fresh console — hence the external window. Fix is one line: unsafe.Pointer(uintptr(hPC)) Confirmed against Microsoft's EchoCon sample and Go libraries that work in production (UserExistsError/conpty, aymanbagabas/go-pty). - internal/version/version.go: 0.7.7 → 0.7.8 - CHANGELOG.md: v0.7.8 entry with the diagnostic write-up --- CHANGELOG.md | 22 ++++++++++++++++++++++ internal/api/terminal_conpty_windows.go | 8 +++++++- internal/version/version.go | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74e4b69..b917b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## v0.7.8 + +### Fix régression v0.7.6 : terminaux ouverts en fenêtre externe + +Symptôme rapporté : depuis v0.7.6, cliquer sur PowerShell / cmd dans l'onglet Terminal ouvre une **fenêtre console séparée** au lieu de s'afficher dans le tab xterm.js (régression — v0.7.5 fonctionnait). + +**Cause** : le binding ConPTY introduit en v0.7.6 passait `&hPC` (pointeur vers la variable Go locale) à `UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, …)`. Or cet attribut est un quirk de l'API Win32 : `lpValue` doit être la **valeur du handle** (cast en `PVOID`), **pas** un pointeur vers la variable. Avec `&hPC`, le kernel lisait des octets aléatoires, l'attribut PSEUDOCONSOLE était silencieusement ignoré, et `CreateProcessW` créait une nouvelle console pour l'enfant — d'où la fenêtre externe. + +**Fix** (1 ligne) : + +```go +// Avant +unsafe.Pointer(&hPC) + +// Après +unsafe.Pointer(uintptr(hPC)) // le HPCON value comme PVOID +``` + +Référence : Microsoft EchoCon sample + bibliothèques Go ConPTY existantes (`UserExistsError/conpty`, `aymanbagabas/go-pty`) utilisent toutes la valeur du handle directement. + +Conséquence : terminaux PowerShell / cmd / WSL s'ouvrent à nouveau **dans** le tab xterm.js avec TTY complet (ANSI, prompt couleur, vim, etc.). + ## v0.7.7 ### Fix : install Windows échoue silencieusement quand une version précédente tourne diff --git a/internal/api/terminal_conpty_windows.go b/internal/api/terminal_conpty_windows.go index 24aa9bb..92555a6 100644 --- a/internal/api/terminal_conpty_windows.go +++ b/internal/api/terminal_conpty_windows.go @@ -80,9 +80,15 @@ func startConptySession(cmd *exec.Cmd) (termSession, error) { windows.CloseHandle(outRead) return nil, fmt.Errorf("NewProcThreadAttributeList: %w", err) } + // PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE is a quirk of the Win32 API: lpValue + // is the HPCON *value* (cast to PVOID), not a pointer to the handle. If + // we pass &hPC the kernel reads garbage, the PC attribute is silently + // ignored, and cmd/pwsh get their own external console window — which is + // exactly the regression v0.7.6 introduced. The cbSize stays the size of + // the handle (8 bytes on amd64). Reference: Microsoft EchoCon sample. if err := attrList.Update( procThreadAttributePseudoconsole, - unsafe.Pointer(&hPC), + unsafe.Pointer(uintptr(hPC)), unsafe.Sizeof(hPC), ); err != nil { attrList.Delete() diff --git a/internal/version/version.go b/internal/version/version.go index c475816..9b4dc74 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -7,7 +7,7 @@ import ( const ( Name = "muyue" - Version = "0.7.7" + Version = "0.7.8" Author = "La Légion de Muyue" )