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

后端 未结 1 1421
囚心锁ツ
囚心锁ツ 2021-01-24 15:21

Say you have the following C code:

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

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


        
相关标签:
1条回答
  • 2021-01-24 15:31

    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
    
    0 讨论(0)
提交回复
热议问题