sys.stdout/sys.stderr 和 GetStdHandle 是否在 Windows 上同步?
Are sys.stdout/sys.stderr and GetStdHandle synced on Windows?
我知道 sys.stdout
是 Python object that wraps the output file handle 但我想知道这些文件句柄是否“同步”并且始终相同?
例如,假设 sys.stdout.isatty()
为真。我调用 GetStdHandle(-11)
(-11 is STDOUT on Windows) and then some Windows Console API that fails and find that the error's errno is 6 (The handle is invalid). AFAIK, this means that the handle is not a valid console handle. In that case, they are not "synced". In other words, is it possible to redirect sys.stdout
while the STDOUT handle returned by GetStdHandle
is not redirected? My code uses GetStdHandle
所以最终我应该测试 errno 6 但如果我可以只依赖 sys.stdout.isatty
.
就好了
这是一个示例(我目前无法访问 windows 机器,但希望代码是正确的)。 运行 有和没有重定向(或者通常在调用 subprocess.check_output
.
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$ + CreateFile
API。我对在重定向下获取输入或输出句柄不感兴趣,但对了解 Windows 控制台句柄 APIs 和 sys.stdout
.
之间的关系感兴趣
是的,我可以用 C++ 重现这个问题。
您可以使用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.
在 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
returns 1.它们都会打印在test.txt.
当你删除sys.stdout = open('test.txt', 'w')
.
我知道 sys.stdout
是 Python object that wraps the output file handle 但我想知道这些文件句柄是否“同步”并且始终相同?
例如,假设 sys.stdout.isatty()
为真。我调用 GetStdHandle(-11)
(-11 is STDOUT on Windows) and then some Windows Console API that fails and find that the error's errno is 6 (The handle is invalid). AFAIK, this means that the handle is not a valid console handle. In that case, they are not "synced". In other words, is it possible to redirect sys.stdout
while the STDOUT handle returned by GetStdHandle
is not redirected? My code uses GetStdHandle
所以最终我应该测试 errno 6 但如果我可以只依赖 sys.stdout.isatty
.
这是一个示例(我目前无法访问 windows 机器,但希望代码是正确的)。 运行 有和没有重定向(或者通常在调用 subprocess.check_output
.
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$ + CreateFile
API。我对在重定向下获取输入或输出句柄不感兴趣,但对了解 Windows 控制台句柄 APIs 和 sys.stdout
.
是的,我可以用 C++ 重现这个问题。
您可以使用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.
在 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
returns 1.它们都会打印在test.txt.
当你删除sys.stdout = open('test.txt', 'w')
.