Могу ли я передать Python «сам» объект функции C как c_void_p и привести к исходному типу для использования в обратном вызове? - PullRequest
1 голос
/ 14 февраля 2020

Использование ctypes для взаимодействия моего python3 кода с C API. Одна из функций C регистрирует функцию обратного вызова, т. Е. Она принимает указатель функции на обратный вызов и void* userdata, который должен быть доступен в этом обратном вызове.

// typedef and C function in myClibrary.so
typedef void(__cdecl *callback_function_type)(void*);
int RegCallback(callback_function_type callback_function, void* userbdata);

Я успешно определил требуемый обратный вызов наберите в python функцию, используя CFUNCTYPE(), передайте ее экземпляр функции C и убедитесь, что моя функция обратного вызова выполняется при желании.

Я также успешно отправил простой тип (т.е. int) как userdata и доступ к нему в обратном вызове. Однако отправка сложных типов (то есть пользовательских классов) ускользает от меня.

Мне нужна помощь, чтобы понять, как 1) привести мой объект self к c_void_p (как аргумент userdata), а затем 2) восстановить или вернуть аргумент userdata, доступный в обратном вызове, к исходному типу self для использования в обратном вызове. (Как и в C ++, что можно сделать, приведя указатель this объекта к void* и затем приведя обратно к его исходному типу в обратном вызове.)

Может кто-нибудь помочь мне получить правильный синтаксис для " связать "self как c_void_p и затем" разделить "обратно до его типа класса в обратном вызове?

from ctypes import *
myClibrary = CDLL("myClibrary.so")
callback_t = CFUNCTYPE(None, c_void_p)           # define type of callback function
RegisterCallback = myClibrary.RegCallback        # RegCallback is a C library function
RegisterCallback.argtypes = [callback_t, c_void_p]     # define its argument types
RegisterCallback.restype = c_int                       # define its result type

# define my callback function
def callback_fn(pArg):
    print('Hello from the callback function!')
    # I NEED TO BE ABLE TO ACCESS pArg as an instance of myClass type here in the callback

# construct global instance of the callback function which can be passed as argument to RegisterCallback
_callback_fn = callback_t(callback_fn)

# define custom class, instance of which needs to be passed to callback function
class myClass
    def __init__(self):
        userdata = c_void_p.from_buffer(py_object(self)).    # I think this is correct, but maybe not?
        retval = RegisterCallback(_callback_fn, userdata).   # register the callback function

Эти связанные вопросы близки, но не совсем получить ответ, который я специально ищу с помощью объекта self. Общая рекомендация, похоже, заключается в том, чтобы использовать лямбда-захват вместо c_void_p, но я тоже не могу этого понять.

Пропустить Python объект через void * и вернуться обратно обратный вызов

Python объекты в качестве пользовательских данных в функциях обратного вызова ctypes

...