[英]How to cast a ctypes pointer to an instance of a Python class
假设您有以下 C 代码:
typedef void (*PythonCallbackFunc)(void* userData);
void cb(PythonCallbackFunc pcf, void* userData)
{
pcf(userData);
}
以及以下 Python 3 代码:
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))
其中“path/to/lib.dll”是 C 代码的编译二进制文件。
如何将“回调”中的 userData 参数转换回 PythonClass 的实例,以便调用函数“foo()”?
基于[Python.Docs]: ctypes - A foreign function library for Python ,我对您的代码做了一些更改以使其工作。
dll00.c :
#include <stdio.h>
#if defined(_WIN32)
# define DLL00_EXPORT_API __declspec(dllexport)
#else
# define DLL00_EXPORT_API
#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);
DLL00_EXPORT_API void callPython(PythonCallbackFuncPtr callbackFunc, void* userData)
{
PRINT_MSG_0();
callbackFunc(userData);
}
代码00.py :
#!/usr/bin/env python
import ctypes as ct
import sys
DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
CallbackFuncType = ct.CFUNCTYPE(None, ct.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(*argv):
dll = ct.CDLL(DLL_NAME)
callPython = dll.callPython
callPython.argtypes = [CallbackFuncType, ct.py_object]
callPython.rettype = None
instance = PythonClass()
callPython(CallbackFuncType(callback), instance)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
注意事项:
在处理Python类型时,使用ctypes.py_object (它是PyObject的包装器)而不是ctypes.c_void_p
始终为从Python调用的C函数定义argtypes (和restype )(例如call_python_func (包装callPython ))。 检查[SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer)了解更多细节
PythonClass.foo缺少第一个( self )参数,因此只是在PythonClass中定义的函数而不是方法
是否进行了其他非关键更改(主要是重命名)
输出:
(py35x64_test) e:\Work\Dev\StackOverflow\q052053434>sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> "c:\Install\pc032\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64 [prompt]> dir /b code00.py dll00.c [prompt]> cl /nologo /DDLL dll00.c /link /DLL /OUT:dll00.dll dll.c Creating library dll00.lib and object dll00.exp [prompt]> dir /b code00.py dll00.c dll00.dll dll00.exp dll00.lib dll00.obj [prompt]> "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)] 064bit on win32 From C - [dll00.c] (18) - [callPython] From Python: callback Dummy Python method
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.