我正在考虑在终端中使用python创建一个进度条。首先,我必须得到终端窗口的宽度(列)。在python 2.7中,没有标准库可以在Windows上执行此操作。我知道也许我必须手动调用Windows Console API。
根据MSDN和Python文档,我编写了以下代码:
import ctypes
import ctypes.wintypes
class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
_fields_ = [
('dwSize', ctypes.wintypes._COORD),
('dwCursorPosition', ctypes.wintypes._COORD),
('wAttributes', ctypes.c_ushort),
('srWindow', ctypes.wintypes._SMALL_RECT),
('dwMaximumWindowSize', ctypes.wintypes._COORD)
]
hstd = ctypes.windll.kernel32.GetStdHandle(ctypes.c_ulong(-11)) # STD_OUTPUT_HANDLE = -11
print hstd
csbi = CONSOLE_SCREEN_BUFFER_INFO()
print ctypes.sizeof(csbi) # <---------------
ret = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(ctypes.c_ulong(hstd), csbi)
print ret
print csbi.dwSize.X
工作正常。我开始在代码中删除一些print
。但在那之后,它不起作用! GetLastError
返回6(无效句柄)。经过多次尝试,我发现代码的指向位置必须有一些东西,例如print 'hello'
,import sys
或sys.stdout.flush()
。起初,我想也许需要时间做点什么。所以我试着将time.sleep(2)
放在那个位置,但它仍然不起作用。
但是,如果我使用struct
代替ctypes.Structure
,则没有这样的问题。
import ctypes
import struct
hstd = ctypes.windll.kernel32.GetStdHandle(-11) # STD_OUTPUT_HANDLE = -11
csbi = ctypes.create_string_buffer(22)
res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(hstd, csbi)
width, height, curx, cury, wattr, left, top, right, bottom, maxx, maxy = struct.unpack("hhhhHhhhhhh", csbi.raw)
print bufx
有没有人可以告诉我为什么不相关的代码会产生这样的差异?
答案 0 :(得分:2)
您需要通过引用传递结构:
ret = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(
ctypes.c_ulong(hstd),
ctypes.byref(csbi)
)
我还建议您为restype
声明GetStdHandle
。这意味着您的代码已准备好在64位进程下运行。我会这样写:
ctypes.windll.kernel32.GetStdHandle.restype = ctypes.wintypes.HANDLE
hstd = ctypes.windll.kernel32.GetStdHandle(-11) # STD_OUTPUT_HANDLE = -11
csbi = CONSOLE_SCREEN_BUFFER_INFO()
ret = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(
hstd,
ctypes.byref(csbi)
)
实际上,在我的Python版本中,您编写的代码报告了一个更有用的错误。我明白这一点:
Traceback (most recent call last): File "test.py", line 16, in ret = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(ctypes.c_ulong(hstd), csbi) ValueError: Procedure probably called with too many arguments (20 bytes in excess)
这足以清楚地表明Python代码和本机代码之间的接口存在二进制不匹配。
我怀疑如果你得到更新版本的Python,你也会受益于这种堆栈不平衡检查。