具有参数的Ctypes回调函数

时间:2019-06-26 02:25:02

标签: python ctypes

不确定我在这里问的是一种正确的方法(找不到任何类似的问题),但是可以了。

我需要使用自定义参数和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返回的参数,但是如何在myData期间传递initMessageCallback,以便可以在callbackFunc内部访问它而又不使其成为全局变量?

def callbackFunc(ID):
    # need to access myData here

1 个答案:

答案 0 :(得分:0)

有两种方法可以做到这一点。您的回调可以是类中的方法,并且可以访问实例化类的实例数据,也可以仅将数据附加到回调本身。这是后者的示例和一些示例回调代码:

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)。函数名称在全局级别,不会超出范围。因此,在生成回调时请记住这一点。将它们存储在变量中,并确保它在作用域内,直到您完成操作为止。