fix(windows/conpty): pass HPCON value, not &hPC (v0.7.8)
All checks were successful
PR Check / check (pull_request) Successful in 1m3s

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
This commit is contained in:
Muyue
2026-04-27 14:39:26 +02:00
parent af5fbf9324
commit a3487392c0
3 changed files with 30 additions and 2 deletions

View File

@@ -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()

View File

@@ -7,7 +7,7 @@ import (
const (
Name = "muyue"
Version = "0.7.7"
Version = "0.7.8"
Author = "La Légion de Muyue"
)