我有以下编译成 DLL 的 C 源代码:
int (*pfuncExtB)(int a, int b);
int funcB(int a, int b)
{
return funcExtB(a, b);
}
int funcExtB(int a, int b)
{
return pfuncExtB(a, b);
}
我想做的是让 pfuncExtB “指向”一个 Python 函数,所以这就是我在 Python 中所做的:
from ctypes import *
def add(a, b):
return a + b
mutdll = cdll.LoadLibrary("my.dll")
pfuncExtB = (POINTER(CFUNCTYPE(c_int, c_int, c_int))).in_dll(mutdll, 'pfuncExtB')
funcB = mutdll.funcB
funcB.argtypes = [c_int, c_int]
funcB.restype = c_int
pfuncExtB.contents = CFUNCTYPE(c_int, c_int, c_int)(add)
print funcB(3 , 4)
在此之后,我希望以下调用返回 7
print funcB(3, 4)
但我得到:
Traceback (most recent call last):
..................
print funcB(3, 4)
WindowsError: exception: access violation reading 0x00000001
那么我在这里做错了什么?是否可以将 Python 函数“分配”给 ctypes 函数指针变量?
编辑:在看到 Mark Tolonen 的解决方法(用 C 编写的指向函数变量的指针的集合函数)后,我发现为什么我尝试它时它对我不起作用。
这不起作用:
set(CFUNCTYPE(c_int,c_int,c_int)(add))
print funcB(2, 3)
虽然这有效:
callback = CFUNCTYPE(c_int,c_int,c_int)(add)
set(callback)
print funcB(2, 3)
其中 set 是一个 C 函数,它将指向函数的参数分配给全局,就像 Mark 的回答一样。正如他指出的那样,答案就在文档中:
回调函数的重要说明: 确保您保留对 CFUNCTYPE() 对象的引用,只要它们是从 C 代码中使用的。ctypes 不会,如果您不这样做,它们可能会被垃圾收集,从而在进行回调时使您的程序崩溃。