6

我正在考虑在终端中使用 python 制作进度条。首先,我必须获取终端窗口的宽度(列)。在 python 2.7 中,没有标准库可以在 Windows 上执行此操作。我知道也许我必须手动调用 Windows 控制台 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 syssys.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

有没有人可以告诉我为什么不相关的代码会产生如此大的差异?

4

1 回答 1

2

您需要通过引用传递结构:

ret = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(
    ctypes.c_ulong(hstd), 
    ctypes.byref(csbi)
)

我还建议您声明restypefor 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 版本中,您的代码报告了一个更有用的错误。我看到这个:

回溯(最近一次通话最后):
  文件“test.py”,第 16 行,在
    ret = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(ctypes.c_ulong(hstd), csbi)
ValueError:过程可能调用了太多参数(20 个字节
过量的)

这足以清楚地表明 Python 代码和本机代码之间的接口处存在二进制不匹配。

我怀疑如果你获得了更新版本的 Python,你也会从这种堆栈不平衡检查中受益。

于 2013-08-01T15:29:46.777 回答