【问题标题】:Problem with using CreatePseudoConsole to create a pty pipe in python使用 CreatePseudoConsole 在 python 中创建 pty 管道的问题
【发布时间】:2021-06-25 21:40:42
【问题描述】:

我正在尝试制作 pty 管道。为此,我必须使用 Windows api 中的 CreatePseudoConsole 函数。我正在松散地复制this,它是this,但在python中。

我不知道这是否相关,但我使用的是 Python 3.7.9 和 Windows 10。

这是我的代码:

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")

问题是它无法从管道中读取。我预计它会打印"a",但它只是卡在os.read 上。请注意,这是我第一次使用 WinAPI,所以问题可能存在。

【问题讨论】:

  • 请注意,这是一个非常新的 Win32 API,甚至不是所有版本的 Windows 10 都支持它。
  • @BenVoigt 我不知道,但我主要将这个项目用于我的计算机。它是否使用 Win64 API(只是猜测)?我也知道 Windows 具有令人惊讶的向后兼容性。这不是说所有 Windows 10 版本都应该支持 Win32 API 吗?
  • 上世纪 90 年代的所有 Windows 版本都使用某种形式的 Win32 API。但是新版本向 API 添加了新功能。向后兼容意味着不会删除任何功能。如the official documentation page 所示,此特定功能已添加到“Windows 10 October 2018 Update(版本 1809)”中。如果您只在自己的计算机上运行,​​并且它具有至少应用了该功能更新的 Windows 10 版本,则可以使用它。
  • @BenVoigt 哦,这就是你的意思。我知道 CreatePseudoConsole 函数是相当新的(从 2018 年开始),这就是我遇到这么多问题的原因。我想我会没事的,因为我不太可能切换到其他版本的 Windows。您对导致我的问题的原因有什么想法吗?
  • 我不知道os.pipe在python中的实现,但我认为问题是管道的读写句柄引起的,也许你可以参考:Cannot input to New Console as child process in c跨度>

标签: python-3.x winapi console pipe pty


【解决方案1】:

代码没有错:你错的是你的期望。

您正在做的事情是写入旨在将“键盘”输入提供给程序的管道,并从另一个返回程序“屏幕”输出的管道读取。但是在任一管道的另一端都没有实际的程序,因此 read 调用无法返回任何内容。

CreatePseudoConsole API 返回的HPCON 句柄应该在线程属性列表中通过CreateProcess 传递给新生成的进程。除此之外,几乎没有什么可以做的。 (您甚至无法将自己连接到伪控制台,就像在 Unix 上那样。)以这种方式传递句柄后,您可以使用 read_fdwrite_fd 描述符与进程通信。

article on MSDN 提供了一个完整的 C 语言示例,该示例创建了一个伪控制台并将其传递给一个新进程; exact same thing 是由您链接的来源完成的。

【讨论】:

  • 我搞定了。我能够处理大多数 ANSI 字符,但我遇到了 2 个问题。如果子进程写入stderr,为什么控制台不输出ANSI字符将颜色变为红色?此外,我一直看到控制台写了一个ESC[nX,其中n 是一个数字。那个角色是什么?
  • 谢谢。我正在使用wikipedia 这对我没有帮助。最后一个问题:为什么写入stderr 的文本中的PseudoConsole 没有颜色? cmd也有同样的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-21
  • 2019-09-18
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多