繁体   English   中英

如何将 ctypes 指针转换为 Python 类的实例

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM