Python ctypes,回调函数增强类型是C++参考



我通过ctypes将dll集成到python中,dll需要设置一个回调函数。但是dll回调函数声明如下

void setCallBack(void(*)(Data &a))
Data is C struct, declare as below
typedef struct {
int index,
....
}Data

我不清楚如何通过ctypes设置它,我尝试如下,但返回" Windows错误:[错误-1073741795] Windows错误0xC000001D"错误,您能否帮助举例说明如何设置回调。

mydll = cdll.LoadLibrary("XXX.dll")  
callback_type = CFUNCTYPE(None, POINTER(Data))
callback = callback_type(Data)
mydll.setCallBack(callback)
def dataResponse(data):
print data.index
class Data(ctypes.Structure):
_fields_ = [("index", c_int)]

你的结构看起来是正确的,但是如果你调用Windows API,你的调用约定可能会关闭(你使用的是cdecl,但如果这是一个Windows API调用,你需要stdcall)。

尝试将mydll = cdll.LoadLibrary("XXX.dll")替换为mydll = WinDLL("XXX.dll")

您可能还需要提供一个使用 stdcall 而不是 cdecl 的回调函数。如果是这样,请将CFUNCTYPE切换到WINFUNCTYPE。正在调用的 API 应提供有关其预期内容的详细信息。

看看这是否有帮助。

一个错误是你的回调包装了你的数据结构,而不是你的回调函数。 改变:

callback_type = CFUNCTYPE(None, POINTER(Data))
callback = callback_type(Data)
mydll.setCallBack(callback)
def dataResponse(data):
print data.index

自:

def dataResponse(data):
print data.index
callback = callback_type(dataResponse)
mydll.setCallBack(callback)

或者您可以使用装饰器语法:

@CFUNCTYPE(None, POINTER(Data))
def dataResponse(data):
print data.index
mydll.setCallBack(dataResponse)

下面是一个完整的示例。 还可以使用extern "C"以避免C++名称重整:

测试.cpp (视窗)

struct Data {
int index;
};
typedef void (*CALLBACK)(Data&);
CALLBACK g_callback;
extern "C" {
__declspec(dllexport)void setCallBack(CALLBACK f) {
g_callback = f;
}
__declspec(dllexport) void func() {
Data d;
d.index = 42;
if(g_callback)
g_callback(d);
}
}

test.py

from ctypes import *
class Data(Structure):
_fields_ = [('index',c_int)]
CALLBACK = CFUNCTYPE(None,POINTER(Data))
dll = CDLL('test')
dll.setCallBack.argtypes = CALLBACK,
dll.setCallBack.restype = None
dll.func.argtypes = None
dll.restype = None
@CALLBACK
def dataResponse(data):
print(data.contents.index)
dll.setCallBack(dataResponse)
dll.func()

输出

42

ctypes 不适用于 Cpp,它仅适用于 C,您的 Cpp 函数需要具有extern "C"链接。
不起作用的原因与 Cpp 名称重整有关。你的函数void setCallBack(void(*)(Data &a))的名称在 Cpp 中被篡改为_Z11setCallBackPFvR4DataE,但如果你从中放入extern "C"(extern "C" void setCallBack(void(*)(Data &a))),它会 C 重整规则,所以它会被破坏为setCallBack
因此,当你这样做时mydll.setCallBackctypes 正在寻找一个名为setCallBack的函数,但它没有找到它,它会找到一个名为_Z11setCallBackPFvR4DataE的函数,它无法识别并给你一个错误。

最新更新