Ctypes: 无法导入 windll。

5

我正在运行 Windows 7 64 位系统上的 Python 2.7 32 位版本(Anaconda)。

我希望使用 ctypes 来进行 win32 API 调用,但是出现了一个非常奇怪的问题:我可以导入 ctypes,但无法导入 ctypes.windll,我得到以下错误:

ImportError: No module named windll

我已经爬过网络和SO,但我没有找到任何类似于我的问题(要么是完全无法导入ctypes,要么是您尝试导入的DLL中存在错误)。
有人知道我做错了什么吗?
1个回答

6

看起来你不能只是 import ctypes.windll,你需要先 import ctypes ,然后使用 ctypes.windll。我通过打印 ctypes 的所有属性来发现这一点:

import ctypes
print dir(ctypes)

有趣的是,在这里IPython自动完成是有误导性的,因为在输入“import ctypes.”后按TAB自动完成时,它没有显示“windll”作为可能的选择。

3
请记住,使用 ctypes.windll 可能会受制于加载相同 DLL 并设置原型 (restype, argtypes, errcheck) 的任何模块,而你也在调用的函数上。函数指针实例被缓存在 WinDLL 实例上,WinDLL 实例被缓存在 windll 上,因此在定义类型和 errcheck 函数与其他用户定义的方式不一致时,可能会发生冲突。从长远来看,最好调用 ctypes.WinDLL 来获取特定于您的模块或脚本的实例。 - Eryk Sun
@eryksun非常感谢您的提示! - gaborous
回应 eryksun 的评论:你不能直接调用 ctypes.WinDLL.kernel32,你需要执行以下操作:from ctypes import LibraryLoader; windll = LibraryLoader(ctypes.WinDLL),然后你就可以调用 windll.kernel32,而不会出现 eryksun 提到的重新定义问题。 - gaborous
3
不要使用windll.kernel32,而是通过属性获取函数指针实例,例如windll.kernel32.CreateFileW。使用加载器的另一个问题是无法传递参数use_last_error=True,它需要与ctypes.get_last_error()ctypes.set_last_error()配合使用。建议使用kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) - Eryk Sun
2
当一个在MSDN文档上记录了设置最后错误值的函数失败时,您可以使用raise ctypes.WinError(ctypes.get_last_error())获取一个格式良好的异常。 - Eryk Sun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接