在 python 中使用 ctypes 调用的函数的正确回调签名是什么?
我必须在 Python 中定义一个回调函数,该函数将从 DLL 中调用。
BOOL setCallback (LONG nPort, void ( _stdcall *pFileRefDone) (DWORD nPort, DWORD nUser), DWORD nUser);
我尝试了这段代码,它似乎在 Python 2.5 中工作,但在 Python 2.7 中它崩溃了,我认为我做错了什么。
import ctypes, ctypes.wintypes
from ctypes.wintypes import DWORD
def cbFunc(port, user_data):
print "Hurrah!"
CB_Func = ctypes.WINFUNCTYPE(None, DWORD, DWORD)
mydll.setCallback(ctypes.c_long(0), CB_Func(cbFunc), DWORD(0))
错误在哪里?
注意:该平台仅在 32 位上运行(Windows 和 Python)。 DLL 加载成功,并且从 Python 调用时,内部的其他函数也可以正常工作。
重现此内容的完整示例代码可在 https://github.com/ssbarnea/pyHikvision 获取 - 只需在 py25 和 py27 下运行 Video.py。
I have to define a callback function in Python, one that will be called from a DLL.
BOOL setCallback (LONG nPort, void ( _stdcall *pFileRefDone) (DWORD nPort, DWORD nUser), DWORD nUser);
I tried this code, that seems to work in Python 2.5 but with Python 2.7 it crashes and I assume I did something wrong.
import ctypes, ctypes.wintypes
from ctypes.wintypes import DWORD
def cbFunc(port, user_data):
print "Hurrah!"
CB_Func = ctypes.WINFUNCTYPE(None, DWORD, DWORD)
mydll.setCallback(ctypes.c_long(0), CB_Func(cbFunc), DWORD(0))
Where is the mistake?
Note: The platform is running on 32bit only (both Windows and Python). The DLL loads successfully and also other functions from inside do work just fine while called from Python.
A full sample code that reproduces this is available at https://github.com/ssbarnea/pyHikvision - just run Video.py under py25 and py27.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的 CB_Func(cbFunc) 参数在 setCallback 函数之后立即被垃圾收集。只要可以调用回调,该对象就必须持续存在(15.17 .1.17. 回调函数,最后一段)。将其分配给一个变量并保留它。这是我的工作示例:
DLL
Failing Script
Passing Script
Edit:此外,由于
CALLBACK
是一个返回函数的函数,因此它可以用作 Python 回调的装饰器,从而消除回调超出范围的问题:Your CB_Func(cbFunc) parameter gets garbage-collected right after the setCallback function. That object has to persist as long as the callback can be called (15.17.1.17. Callback functions, last paragraph). Assign it to a variable and keep it around. Here's my working example:
DLL
Failing Script
Passing Script
Edit: Also, since
CALLBACK
is a function returning a function, it can be used as a decorator for the Python callback, eliminating problem of the callback going out of scope:函数的 Video 类 的上下文中:
在使用嵌套 有点难看,但更自然的变体在回调期间失败并出现 TypeError:
要修复可以创建特殊函数描述符的问题:
用法:
另外 MethodDescriptor 保存对 C 函数的引用以防止它们被垃圾收集。
In the context of Video class using a nested function:
It is somewhat ugly but a more natural variant fails with TypeError during callback:
To fix that a special function descriptor could be created:
Usage:
Additionally MethodDescriptor saves references to C functions to prevent them being garbage collected.