[issue41151] Support for new Windows pseudoterminals in the subprocess module

Eryk Sun report at bugs.python.org
Sun Jun 28 18:57:37 EDT 2020


Eryk Sun <eryksun at gmail.com> added the comment:

> However, the API is a bit weird. Unlike Unix, when you create a 
> Windows pty, there's no way to directly get access to the "slave" 
> handle. Instead, you first call CreatePseudoConsole to get a 
> special "HPCON" object, which is similar to a Unix pty master. 
> And then you can have to use a special CreateProcess incantation 
> to spawn a child process that's attached to our pty.

As implemented in Windows 8+ (the previous implementation is very different), if a process is attached to a console session, the ConsoleHandle value in the PEB ProcessParameters is a file handle for "\Device\ConDrv\Connect", which is a connection to a console session that's hosted by conhost.exe (or openconsole.exe if using Windows Terminal). The connection handle is used implicitly with NtDeviceIoControlFile to implement API functions such as GetConsoleWindow, GetConsoleTitle, GetConsoleCP, GetConsoleAliases, GetConsoleProcessList, GenerateConsoleCtrlEvent, and so on. Console I/O, on the other hand, uses dedicated files on "\Device\ConDrv". The initial files used for standard I/O are generic "Input" and "Output", which work with any console connection. There are other ConDrv files that, when opened, attach to a particular console session and are only valid when the process is connected to that session, including "Console" (CON), "CurrentIn" (CONIN$), "CurrentOut" (CONOUT$), and "ScreenBuffer" (CreateConsoleScreenBuffer). Simple ReadFile and WriteFile use NT NtReadFile and NtWriteFile system calls. Console-specific I/O functions such as GetConsoleMode, ReadConsoleW, and WriteConsoleW use NtDeviceIoControlFile.

If a console connection is inherited, initially the ConsoleHandle value is a handle for "\Device\ConDrv\Reference", which references the console session. (If a console session isn't inherited, the ConsoleHandle value may be one of the values reserved for the creation flags CREATE_NEW_CONSOLE, CREATE_NO_WINDOW, and DETACHED_PROCESS.) The base API opens the "\Connect" connection handle relative to the reference handle. The NtCreateFile call in this case uses the reserved EaBuffer (extended attributes) argument to send the console session host the information it needs about the connecting client process. Once connected, depending on the state, the base API may close inherited console handles (i.e. handles with the NT device type FILE_DEVICE_CONSOLE) that are set in StandardInput, StandardOutput, and StandardError, in which case new generic "Input" and "Output" handles are opened relative to the connection handle.

The pseudoconsole API apparently uses PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE to explicitly pass the "\Device\ConDrv\Reference" handle to client processes, instead of inheriting the reference handle of the current process, if the current process even has a console. An HPCON appears to be just a pointer to an array of three handles. One of the handles is the "Reference" handle that client processes need. The other two handles are for the API -- one for the console-session host process (conhost.exe) and one for the signal pipe. You can see the handle value for the other end of the signal pipe passed on the conhost.exe command line as the "--signal" parameter.

----------
nosy: +eryksun

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue41151>
_______________________________________


More information about the Python-bugs-list mailing list