TheLizzard
TheLizzard

Reputation: 7710

Problem with using CreatePseudoConsole to create a pty pipe in python

I am trying to make a pty pipe. For that I have to use the CreatePseudoConsole function from the Windows api. I am loosely copying this which is this but in python.

I don't know if it's relevant but I am using Python 3.7.9 and Windows 10.

This is my code:

from ctypes.wintypes import DWORD, HANDLE, SHORT
from ctypes import POINTER, POINTER, HRESULT
import ctypes
import msvcrt
import os


# The COORD data type used for the size of the console
class COORD(ctypes.Structure):
    _fields_ = [("X", SHORT),
                ("Y", SHORT)]


# HPCON is the same as HANDLE
HPCON = HANDLE


CreatePseudoConsole = ctypes.windll.kernel32.CreatePseudoConsole
CreatePseudoConsole.argtypes = [COORD, HANDLE, HANDLE, DWORD, POINTER(HPCON)]
CreatePseudoConsole.restype = HRESULT


def create_console(width:int, height:int) -> HPCON:
    read_pty_fd, write_fd = os.pipe()
    read_pty_handle = msvcrt.get_osfhandle(read_pty_fd)

    read_fd, write_pty_fd = os.pipe()
    write_pty_handle = msvcrt.get_osfhandle(write_pty_fd)

    # Create the console
    size = COORD(width, height)
    console = HPCON()

    result = CreatePseudoConsole(size, read_pty_handle, write_pty_handle,
                                 DWORD(0), ctypes.byref(console))
    # Check if any errors occured
    if result != 0:
        raise ctypes.WinError(result)

    # Add references for the fds to the console
    console.read_fd = read_fd
    console.write_fd = write_fd

    # Return the console object
    return console


if __name__ == "__main__":
    consol = create_console(80, 80)
    print("Writing...")
    os.write(consol.write_fd, b"abc")
    print("Reading...")
    print(os.read(consol.read_fd, 1))
    print("Done")

The problem is that it isn't able to read from the pipe. I expected it to print "a" but it just gets stuck on the os.read. Please note that this is the first time I use the WinAPI so the problem is likely to be there.

Upvotes: 1

Views: 1423

Answers (1)

dumbass
dumbass

Reputation: 27238

There is nothing wrong with the code: what you got wrong is your expectations.

What you are doing is writing to the pipe meant to feed ‘keyboard’ input to the program, and reading from another pipe that returns ‘screen’ output from the program. But there is no actual program at the other end of either pipe, and so there is nothing the read call can ever return.

The HPCON handle returned by the CreatePseudoConsole API is supposed to be passed in a thread attribute list to a newly-spawned process via CreateProcess. Pretty much nothing can be done with it other than that. (You cannot even connect yourself to the pseudoconsole, as you would be able on Unix.) After the handle is passed in this manner, you can communicate with the process using the read_fd and write_fd descriptors.

An article on MSDN provides a full sample in C that creates a pseudoconsole and passes it to a new process; the exact same thing is done by the very source you linked.

Upvotes: 1

Related Questions