Reputation: 168
I am trying to design class with callback function which is transferred to some C library. Need to grant access to object of this class without changing callback arguments. How to do this?
from ctypes import *
...
lib = CDLL('mylibname.so')
...
class A(object):
def __init__(self):
CALLBACK = CFUNCTYPE(c_uint32, c_void_p)
self.callback_func = CALLBACK(A.message_callback)
self.param = None
def message_callback(data):
... #here need access to self.param
return 0
def set_param(self, param):
self.param = param
...
a = A()
lib.lib_func(param1, param2, a.callback_func)
EDIT: I've changed callback method in the class with wrapper function:
from ctypes import *
...
lib = CDLL('mylibname.so')
class struct_t(Structure):
pass
struct_t._fields_ = [('next', POINTER(value_pair_t)),
('key', c_char_p),
('value', c_char_p)]
...
class A(object):
def __init__(self):
self.param = None
def wrapper(self):
CALLBACK = CFUNCTYPE(c_uint32, POINTER(struct_t))
def message_callback(data):
... # now I have access to self here
return 0
return CALLBACK(message_callback)
def set_param(self, param):
self.param = param
...
a = A()
lib.lib_func(param1, param2, a.wrapper())
It works in python2, but I still have issues with python3:
Traceback (most recent call last): File "_ctypes/callbacks.c", line 260, in 'calling callback function' TypeError: 'LP_struct_t' object is not callable
Here is link with same issue: Weird bug?
Upvotes: 2
Views: 1922
Reputation: 34270
Just define message_callback(self, data)
and use self.callback_func = A.CALLBACK(self.message_callback)
. Note I used A.CALLBACK
. Set it as a class attribute. Defining it for each instance is a waste of time.
For example:
C:
typedef int (*callback_t)(void *data);
int test(const char *data, callback_t f) {
f((void *)data);
return 0;
}
Python:
from ctypes import *
class A(object):
CALLBACK = CFUNCTYPE(c_uint32, c_void_p)
def __init__(self):
self.callback_func = A.CALLBACK(self.message_callback)
self.param = None
def message_callback(self, data):
self.param = cast(data, c_char_p).value
return 0
Demo:
>>> lib = CDLL('./lib.so')
>>> a = A()
>>> lib.test.argtypes = [c_char_p, A.CALLBACK]
>>> lib.test("updated", a.callback_func)
0
>>> a.param
'updated'
Upvotes: 3