问题描述
我正在考虑在终端中使用python创建进度条.首先,我必须获取终端窗口的宽度(列).在python 2.7中,没有标准库可以在Windows上执行此操作.我知道也许我必须手动调用Windows Console API.
I am thinking to make a progress bar with python in terminal. First, I have to get the width(columns) of terminal window. In python 2.7, there is no standard library can do this on Windows. I know maybe I have to call Windows Console API manually.
根据MSDN和Python文档,我编写了以下代码:
According to MSDN and Python Documentation, I wrote the following code:
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)
放在该位置,但是仍然无法正常工作.
It works fine. I set about deleting some print
in code. But after that, it doesn't work! GetLastError
return 6 (Invalid Handle). After times of trying, I found that there must be SOMETHING at the pointed position of the code such as print 'hello'
, import sys
or sys.stdout.flush()
. At first, I guess that maybe it need time to do something. So I tried to put time.sleep(2)
at that position, but it still doesn't work.
但是,如果我确实使用 struct
而不是 ctypes.Structure
,则不会出现此类问题.
But, if I do use struct
instead of ctypes.Structure
, there's no such problem.
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
有没有人可以告诉我,无关的代码为何如此不同?
Is there any one can tell me why the irrelevant code made such a difference?
推荐答案
您需要通过引用传递该结构:
You need to pass the struct by reference:
ret = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(
ctypes.c_ulong(hstd),
ctypes.byref(csbi)
)
我还建议您为 GetStdHandle
声明 restype
.这意味着您的代码已准备好在64位进程下运行.我会这样写:
I would also recommend that you declare the restype
for GetStdHandle
. That will mean that your code is ready to run under a 64 bit process. I'd write it like this:
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版本中,您的代码报告了一个更为有用的错误.我看到了:
Actually, in my version of Python, your code reports a much more useful error. I see this:
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代码与本机代码之间的接口存在二进制不匹配.
This is enough to make it clear that there is an binary mismatch at the interface between the Python code and the native code.
我怀疑,如果您获得更新版本的Python,您还将从此堆栈不平衡检查中受益.
I suspect that if you get a more recent version of Python, you'd also benefit from this stack imbalance checking.
这篇关于为什么无关的代码有所作为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!