带参数的 Ctypes 回调函数
Ctypes callback function with arguments
不确定我在这里问的是正确的方法(找不到任何类似的问题),但这里是。
我需要启动一个带有自定义参数和 ctypes 参数的回调函数。
函数
def initMessageCallback(myData):
callback = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_long) # return type and output parameter
lib.SetMessageCallback.restype = ctypes.c_bool
lib.SetMessageCallback(callback(callbackFunc))
回调函数
我可以访问 SetMessageCallback
返回的参数,但是如何在 initMessageCallback
期间传递 myData
以便我可以在 callbackFunc
内部访问它而不将其设为全局变量?
def callbackFunc(ID):
# need to access myData here
有几种方法可以做到这一点。您的回调可以是 class 中的方法,并且可以访问实例化 class 的实例数据,或者您可以将数据附加到回调本身。这是后者的示例和一些示例回调代码:
test.c
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
typedef int (*CALLBACK)(int);
CALLBACK g_callback;
API void set_callback(CALLBACK cb)
{
g_callback = cb;
}
API int do_callback()
{
int sum = 0;
for(int i = 0; i < 5; ++i) // Call callback with 0,1,2,3,4 parameters.
if(g_callback)
sum += g_callback(i); // Collect and sum the callback return values.
return sum;
}
test.py
from ctypes import *
CALLBACK = CFUNCTYPE(c_int,c_int)
dll = CDLL('test')
dll.set_callback.argtypes = CALLBACK,
dll.set_callback.restype = c_int
dll.do_callback.argtypes = ()
dll.do_callback.restype = c_int
@CALLBACK
def my_callback(id):
return id + my_callback.my_data # Use the extra callback data.
def init_callback(my_data):
my_callback.my_data = my_data # Simply attach the data as a variable of the callback.
dll.set_callback(my_callback)
init_callback(0)
print(dll.do_callback()) # Expect (0+0)+(1+0)+(2+0)+(3+0)+(4+0) = 10
init_callback(1)
print(dll.do_callback()) # Expect (0+1)+(1+1)+(2+1)+(3+1)+(4+1) = 15
输出
10
15
关于示例代码的注释。 callback(callbackFunc)
被创建并传递给 lib.SetMessageCallback()
但由于在该行执行后不存在引用,回调被销毁。当您尝试使用回调时,这可能会使您的系统崩溃。像我上面那样对回调函数使用装饰器 (@CALLBACK) 相当于 my_callback = CALLBACK(my_callback)
。函数名称是全局级别的,不会超出范围。因此,在生成回调时请记住这一点。将它们存储在一个变量中,并确保它一直在范围内,直到您完成它。
不确定我在这里问的是正确的方法(找不到任何类似的问题),但这里是。
我需要启动一个带有自定义参数和 ctypes 参数的回调函数。
函数
def initMessageCallback(myData):
callback = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_long) # return type and output parameter
lib.SetMessageCallback.restype = ctypes.c_bool
lib.SetMessageCallback(callback(callbackFunc))
回调函数
我可以访问 SetMessageCallback
返回的参数,但是如何在 initMessageCallback
期间传递 myData
以便我可以在 callbackFunc
内部访问它而不将其设为全局变量?
def callbackFunc(ID):
# need to access myData here
有几种方法可以做到这一点。您的回调可以是 class 中的方法,并且可以访问实例化 class 的实例数据,或者您可以将数据附加到回调本身。这是后者的示例和一些示例回调代码:
test.c
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
typedef int (*CALLBACK)(int);
CALLBACK g_callback;
API void set_callback(CALLBACK cb)
{
g_callback = cb;
}
API int do_callback()
{
int sum = 0;
for(int i = 0; i < 5; ++i) // Call callback with 0,1,2,3,4 parameters.
if(g_callback)
sum += g_callback(i); // Collect and sum the callback return values.
return sum;
}
test.py
from ctypes import *
CALLBACK = CFUNCTYPE(c_int,c_int)
dll = CDLL('test')
dll.set_callback.argtypes = CALLBACK,
dll.set_callback.restype = c_int
dll.do_callback.argtypes = ()
dll.do_callback.restype = c_int
@CALLBACK
def my_callback(id):
return id + my_callback.my_data # Use the extra callback data.
def init_callback(my_data):
my_callback.my_data = my_data # Simply attach the data as a variable of the callback.
dll.set_callback(my_callback)
init_callback(0)
print(dll.do_callback()) # Expect (0+0)+(1+0)+(2+0)+(3+0)+(4+0) = 10
init_callback(1)
print(dll.do_callback()) # Expect (0+1)+(1+1)+(2+1)+(3+1)+(4+1) = 15
输出
10
15
关于示例代码的注释。 callback(callbackFunc)
被创建并传递给 lib.SetMessageCallback()
但由于在该行执行后不存在引用,回调被销毁。当您尝试使用回调时,这可能会使您的系统崩溃。像我上面那样对回调函数使用装饰器 (@CALLBACK) 相当于 my_callback = CALLBACK(my_callback)
。函数名称是全局级别的,不会超出范围。因此,在生成回调时请记住这一点。将它们存储在一个变量中,并确保它一直在范围内,直到您完成它。