How to cast a ctypes pointer to an instance of a Python class

Sossisos

Say you have the following C code:

typedef void (*PythonCallbackFunc)(void* userData);

void cb(PythonCallbackFunc pcf, void* userData)
{
    pcf(userData);
}

and the following Python 3 code:

import ctypes

class PythonClass():
    def foo():
        print("bar")

CALLBACK_TYPE = ctypes.CFUNCTYPE(None, ctypes.c_void_p)

def callback(userData):
    instanceOfPythonClass = ???(userData) # <-- this part right here
    instanceOfPythonClass.foo()

lib = ctypes.cdll.LoadLibrary("path/to/lib.dll")

pc = PythonClass()

lib.cb(ctypes.byref(pc), CALLBACK_TYPE(callback))

Where "path/to/lib.dll" is a compiled binary of the C code up top.

How would one go about casting the userData parameter in "callback" back to an instance of PythonClass, so one could call the function "foo()"?

CristiFati

Based on [Python 3.Docs]: ctypes - A foreign function library for Python, I did some changes to your code in order to make it work.

dll.c:

#include <stdio.h>

#if defined(_WIN32)
#  define DLL_EXPORT __declspec(dllexport)
#else
#  define DLL_EXPORT
#endif

#define C_TAG "From C"
#define PRINT_MSG_0() printf("%s - [%s] (%d) - [%s]\n", C_TAG, __FILE__, __LINE__, __FUNCTION__)


typedef void (*PythonCallbackFuncPtr)(void *userData);


DLL_EXPORT void callPython(PythonCallbackFuncPtr callbackFunc, void *userData)
{
    PRINT_MSG_0();
    callbackFunc(userData);
}

code.py:

import sys
from ctypes import CDLL, CFUNCTYPE, \
    py_object


CallbackFuncType = CFUNCTYPE(None, py_object)

dll_dll = CDLL("./dll.dll")
call_python_func = dll_dll.callPython
call_python_func.argtypes = [CallbackFuncType, py_object]


class PythonClass():
    def foo(self):
        print("Dummy Python method")


def callback(userData):
    print("From Python: {:s}".format(callback.__name__))
    userData.foo()


def main():
    instance = PythonClass()
    call_python_func(CallbackFuncType(callback), instance)


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Notes:

  • When dealing with Python types, use ctypes.py_object (which is a wrapper over PyObject) rather than ctypes.c_void_p
  • Always define argtypes (and restype) for C functions that you call from Python (e.g. call_python_func (which wraps callPython))
  • PythonClass.foo() was missing the 1st (self) argument and thus being just a function defined inside PythonClass instead of a method
  • Did other non critical changes (mostly renames)

Output:

(py35x64_test) e:\Work\Dev\StackOverflow\q052053434>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64

(py35x64_test) e:\Work\Dev\StackOverflow\q052053434>dir /b
code.py
dll.c

(py35x64_test) e:\Work\Dev\StackOverflow\q052053434>cl /nologo /DDLL dll.c  /link /DLL /OUT:dll.dll
dll.c
   Creating library dll.lib and object dll.exp

(py35x64_test) e:\Work\Dev\StackOverflow\q052053434>dir /b
code.py
dll.c
dll.dll
dll.exp
dll.lib
dll.obj

(py35x64_test) e:\Work\Dev\StackOverflow\q052053434>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

From C - [dll.c] (18) - [callPython]
From Python: callback
Dummy Python method

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

how to specify a JNR Pointer like that of python ctypes

How to copy a class instance in python?

How to make type cast for python custom class

How to get the pointer address of a ctypes.c_char_p instance

In C++ how could I cast a sub class instance from one base class pointer to another without dynamic_cast?

How to "cast" an instance to a subclass?

expected LP_SHFILEOPSTRUCTW instance instead of pointer to SHFILEOPSTRUCTW (python ctypes)

Python Ctypes passing pointer for data

OCaml Ctypes - How to make the pointer to pointer

How to dynamic_cast a pointer of a class with no virtual method?

how to cast a const base class pointer into the derived class

How to get value of char pointer from Python code wtih ctypes

How to initialize a class in python, not an instance

Scala: Cast to a runtime Class instance

how to create an instance of class python

How to persist instance of a class in Python

How to dereference pointer to a class instance?

How do I cast to a constant in ctypes?

Turning ctypes.POINTER(instance) into an actual instance?

How to cast a class instance to an interface while cannot instantiate the interface?

class array, cast pointer in operator[]

python ctypes - wrap void pointer

How to cast a pointer to a Python cffi struct to System.IntPtr (.NET)?

How to use a method of a class from a pointer on an instance of this class?

How to cast a python list into a pointer of type void in C

Python ctypes pointer and allocated memory

Pointer argument passing in python ctypes

Python ctypes: how to define a callback having a buffer pointer and a length in argument?

Python Bytes to CTypes Void Pointer