Created
September 5, 2020 18:14
Revisions
-
UserExistsError created this gist
Sep 5, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,113 @@ package main // Windows pty example // https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/ import ( "io" "os" "fmt" "log" "unsafe" "syscall" "os/exec" "path/filepath" ) var kernel32Path = filepath.Join(os.Getenv("windir"), "System32", "kernel32.dll") var ( hKernel32 = syscall.NewLazyDLL(kernel32Path) fCreatePseudoConsole = hKernel32.NewProc("CreatePseudoConsole") fResizePseudoConsole = hKernel32.NewProc("ResizePseudoConsole") fClosePseudoConsole = hKernel32.NewProc("ClosePseudoConsole") ) const ( S_OK uintptr = 0 ) type HandleIO struct { handle syscall.Handle } type COORD struct { X, Y int16 } func (c *COORD) Pack() uintptr { return uintptr((int32(c.Y) << 16) | int32(c.X)) } type HPCON syscall.Handle func (h *HandleIO) Read(p []byte) (int, error) { var numRead uint32 = 0 err := syscall.ReadFile(h.handle, p, &numRead, nil) return int(numRead), err } func (h *HandleIO) Write(p []byte) (int, error) { var numWritten uint32 = 0 err := syscall.WriteFile(h.handle, p, &numWritten, nil) return int(numWritten), err } func (h *HandleIO) Close() error { return syscall.CloseHandle(h.handle) } func ClosePseudoConsole(hPc HPCON) { fClosePseudoConsole.Call(uintptr(hPc)) } func ResizePseudoConsole(hPc HPCON, coord *COORD) error { ret, _, _ := fResizePseudoConsole.Call(uintptr(hPc), coord.Pack()) if ret != S_OK { return fmt.Errorf("ResizePseudoConsole failed with status 0x%x", ret) } return nil } func CreatePseudoConsole(hIn, hOut syscall.Handle) (HPCON, error){ var hPc HPCON coord := &COORD{80,40} ret, _, _ := fCreatePseudoConsole.Call( coord.Pack(), uintptr(hIn), uintptr(hOut), 0, uintptr(unsafe.Pointer(&hPc))) if ret != S_OK { return 0, fmt.Errorf("CreatePseudoConsole() failed with status 0x%x", ret) } return hPc, nil } func main() { var cmdIn, cmdOut syscall.Handle var ptyIn, ptyOut syscall.Handle if err := syscall.CreatePipe(&ptyIn, &cmdIn, nil, 0); err != nil { log.Fatal("CreatePipe: %v", err) } if err := syscall.CreatePipe(&cmdOut, &ptyOut, nil, 0); err != nil { log.Fatal("CreatePipe: %v", err) } cmd := exec.Command("cmd.exe") cmd.Stdin = &HandleIO{ptyIn} cmd.Stdout = &HandleIO{ptyOut} cmd.Stderr = &HandleIO{ptyOut} hPc, err := CreatePseudoConsole(ptyIn, ptyOut) if err != nil { log.Fatalf("CreatePseudoConsole %s", err) } defer ClosePseudoConsole(hPc) go io.Copy(os.Stdout, &HandleIO{cmdOut}) go io.Copy(&HandleIO{cmdIn}, os.Stdin) err = cmd.Run() log.Printf("cmd.Run(): %v", err) }