如何解决EnumWindows()Python回调失败问题

时间:2017-11-06 18:52:14

标签: python windows python-3.x ctypes

问题

我尝试使用Python中的EnumWindows()(使用ctypes)。我的回调函数似乎遇到了一些问题,但它只发生在1K(棒球场数)上调用回调之后。

例如:

from ctypes import *
import ctypes.wintypes as wintypes

WNDENUMPROC = CFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.INT)
EnumWindows = windll.user32.EnumWindows
EnumWindows.argtypes = [ WNDENUMPROC, wintypes.INT ]
EnumWindows.restype = wintypes.BOOL

def py_callback( hwnd, lparam ):
    print('{}'.format(hwnd))
    return True

EnumWindows(WNDENUMPROC(py_callback),0)

当我运行它时(使用WinPython零,python 3.5),回调被成功调用多次。我看到窗口句柄整数print()ed。 但在某些时候,它失败了:

...
3740010
4597178
65918
196762
Traceback (most recent call last):
  File "t.py", line 13, in <module>
    EnumWindows(WNDENUMPROC(py_callback),0)
ValueError: Procedure probably called with not enough arguments (5043578 bytes missing)

缺少&#34;字节&#34;价值每次都在变化。

Python Distro

我有一个Python的微安装部署到一堆生产机器上(或者我可能只是更新Python发行版)。它是WinPython Zero 3.5.2。

脚本在我的制作发行版上失败了。我尝试了最新的3.6.2 WinPython,结果是一样的。

我可以使用Python 3.6(Anaconda)运行相同的脚本而不会出错。

我需要弄清楚这里出了什么问题,这样如果我需要修理客户,我可以做出最小的改变。

故障排除

大多数对此错误消息的引用&#34;调用时没有足够的参数&#34;建议仔细检查调用约定,但回调在失败之前会多次运行。我对此持怀疑态度。

我可以看到一些潜在的依赖关系可以解释我在Python发行版之间看到的不同行为吗?

在窗口列表的末尾似乎失败了。如果我从一个工作发行版和一个糟糕的发行版中连续运行脚本,我会得到相同数量的发出句柄。

关于为什么这会在一段时间内起作用然后失败的任何想法?

1 个答案:

答案 0 :(得分:2)

您的脚本中存在一些错误:

from ctypes import *
import ctypes.wintypes as wintypes

# LPARAM is not necessarily INT-sized.  Use the correct type.
# CALLBACK is __stdcall, so WINFUNCTYPE should be used instead of CFUNCTYPE,
# which is __cdecl calling convention
WNDENUMPROC = WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)

# WinDLL should be used instead of windll.  Setting argtypes/restype on the windll
# common instance could affect other modules.
EnumWindows = WinDLL('user32').EnumWindows
EnumWindows.argtypes = WNDENUMPROC, wintypes.LPARAM  # LPARAM not INT
EnumWindows.restype = wintypes.BOOL

# Using a decorator keeps a reference to the callback.
# Building it in the EnumWindows call means it is released after the call.
# Not a problem in EnumWindows case since it isn't needed after the call
# returns, but for functions that register a callback and return immediately
# it is a problem.
@WNDENUMPROC
def py_callback( hwnd, lparam ):
    print(hwnd)
    return True

EnumWindows(py_callback,0)