【问题标题】:Ctypes callback function with arguments带参数的 Ctypes 回调函数
【发布时间】:2019-06-26 02:25:02
【问题描述】:

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

我需要使用自定义参数和 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

【问题讨论】:

    标签: python ctypes


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-11
      • 1970-01-01
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      • 2015-04-29
      • 1970-01-01
      相关资源
      最近更新 更多