sys.stdout/sys.stderr和GetStdHandle是否在Windows上同步?

2024-09-23 10:20:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道sys.stdout是一个Python object that wraps the output file handle,但我想知道这些文件句柄是否“同步”并且总是相同的

例如,假设sys.stdout.isatty()是真的。我调用^{}(-11是Windows上的标准输出),然后调用一些Windows控制台API失败,发现错误的errno是6(句柄无效)。好的,这意味着句柄不是有效的控制台句柄。在这种情况下,它们不会“同步”。换句话说,当^{}返回的STDOUT句柄没有重定向时,是否可以重定向sys.stdout?我的代码使用了^{},所以最终我应该测试errno 6,但是如果我可以依赖sys.stdout.isatty,那就太好了

下面是一个示例(我目前无法访问windows计算机,但希望代码是正确的)。在有重定向和无重定向的情况下运行(或在对^{}的调用中正常运行)

import sys
from ctypes import WinError, wintypes

STDOUT = -11
ERROR_INVALID_HANDLE = 6
kernel32 = ctypes.WinDLL('kernel32', use_errno=True, use_last_error=True)
handle = kernel32.GetStdHandle(STDOUT)

# Assume we set argtypes/restype for all win api functions here

if handle == wintypes.HANDLE(-1).value:
    raise WinError()

console_mode = wintypes.DWORD(0)

# We use GetConsoleMode here but it could be any function that expects a
# valid console handle
retval = kernel32.GetConsoleMode(handle, ctypes.byref(console_mode))

# Are the following assertions always true?
if retval == 0:
    errno = ctypes.get_last_error()

    if errno == ERROR_INVALID_HANDLE:
        print('Invalid handle')
        assert not sys.stdout.isatty()
    else:
        # Another error happened
        raise WinError()
else:
    assert sys.stdout.isatty()

我试图搜索CPython源代码,但找不到任何可以证实或否认这一点的东西。也许有人对代码库更有经验,可以为我指出正确的方向

编辑:我知道CONOUT$+^{}API。我不想重定向输入或输出句柄,而是想了解Windows控制台句柄API和sys.stdout之间的关系


Tags: 代码apiwindowsstdoutsysctypes句柄重定向
1条回答
网友
1楼 · 发布于 2024-09-23 10:20:21
是的,我可以在C++中重现这个问题。p>

您可以使用CreateFile获取控制台的输出句柄,然后在调用windows控制台API时将该句柄用作参数

The CreateFile function enables a process to get a handle to its console's input buffer and active screen buffer, even if STDIN and STDOUT have been redirected. To open a handle to a console's input buffer, specify the CONIN$ value in a call to CreateFile. Specify the CONOUT$ value in a call to CreateFile to open a handle to a console's active screen buffer. CreateFile enables you to specify the read/write access of the handle that it returns.

参考:Console Handles

在C++中,看起来是这样的,

 HANDLE hConsole = CreateFile("CONOUT$",
        GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

它运行良好,您可以根据需要将其转换为python代码

更新:

import sys
import ctypes
from ctypes import WinError, wintypes

STDOUT = -11
sys.stdout = open('test.txt', 'w')
kernel32 = ctypes.WinDLL('kernel32', use_errno=True, use_last_error=True)
handle = kernel32.GetStdHandle(STDOUT)
if handle == wintypes.HANDLE(-1).value:
    raise WinError()

console_mode = wintypes.DWORD(0)
retval = kernel32.GetConsoleMode(handle, ctypes.byref(console_mode))
print(retval)

if sys.stdout.isatty():
    print('You are running in a real terminal')
else:
    print('You are being piped or redirected')

retval返回1。它们都将在test.txt中打印

enter image description here

当您删除sys.stdout = open('test.txt', 'w')

enter image description here

相关问题 更多 >