带参数的Ctypes回调函数 [英] Ctypes callback function with arguments

查看:85
本文介绍了带参数的Ctypes回调函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Not sure what I am asking here is a proper way to do it (can't find any similar question), but here goes.

我需要使用自定义参数和ctypes参数来启动回调函数.

I need to initiate a callback function with custom arguments alongside with the ctypes arguments.

功能

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 ?

I can access the parameter returned by SetMessageCallback but how can I pass myData during initMessageCallback so that I can access it inside callbackFunc without making it a global variable?

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

推荐答案

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

There's a couple ways to do this. Your callback could be a method in a class and can access the instance data of the instantiated class, or you can just attach the data to the callback itself. Here's an example of the latter and some sample callback code:

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

A note about your sample code. callback(callbackFunc) is created and passed to lib.SetMessageCallback() but since no reference exists after that line executes the callback is destroyed. That can crash your system when you try to use the callback. Using a decorator (@CALLBACK) against the callback function like I've done above is the equivalent of my_callback = CALLBACK(my_callback). The function name is at the global level and won't go out of scope. So keep that in mind when generating callbacks. Store them in a variable and make sure it stays in scope until you're done with it.

这篇关于带参数的Ctypes回调函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆