如何将ctypes指针转换为Python类的实例 [英] How to cast a ctypes pointer to an instance of a Python class

查看:281
本文介绍了如何将ctypes指针转换为Python类的实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您具有以下C代码:

Say you have the following C code:

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

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

和以下Python 3代码:

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))

其中 path / to / lib.dll是C代码的编译二进制文件。

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

如何转换userData参数在回调中返回到PythonClass的实例,因此可以调用函数 foo()?

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

推荐答案

基于 [Python 3.Docs]:ctypes-A Python的外部函数库,为了使它正常工作,我对您的代码做了一些更改。

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()

注释


  • 机智时h Python 类型,使用 ctypes.py_object (这是 PyObject 的包装)而不是 ctypes.c_void_p

  • 始终定义 argtypes (和 Python 调用的 C 函数的> restype ) call_python_func (包装 callPython ))

  • PythonClass.foo()缺少1 st self )参数,因此只是在 PythonClass 内部定义的函数,而不是方法

  • 是否进行了其他非关键更改(大多是重命名)

  • 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)

输出


(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


这篇关于如何将ctypes指针转换为Python类的实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆