使用ctypes编写回调

使用ctypes编写回调

本文介绍了使用ctypes编写回调,该回调将指向指针参数的指针传入,以用作输出参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ctypes将python代码与旧版C DLL接口。
DLL期望我给它一个函数指针用作回调,然后将在DLL内部调用它。

I am using ctypes to interface python code with a legacy C DLL.The DLL expects that I give it a function pointer to be used as a callback, that then will be called from within the DLL.

C的C声明该回调看起来像

The C declaration of that callback looks like

char foo(char **buf)

从理论上讲,DLL希望我让buf指向由回调管理的字符串缓冲区,如果一切正常,则返回0。在C中,这将是一个静态char []变量mybuf,我将使用

Semantically the DLL expects that I let point buf to a string buffer that is managed by the callback and return 0 if everything works fine. In C that would be a static char[] variable mybuf and I would pass the address of that static buf back with code like

*buf = &mybuf[0] ;
return (char)0 ;

mybuf中的字符串需要像往常一样在C中终止为空。我能够传递一个函数指向DLL的指针,现在是python(成员)函数

The string in mybuf needs to be null terminated as usual in C. I was able to pass a function pointer to the DLL and now a python (member) function

def pyfoo(self, char_ptr_ptr)

会被调用。

定义pyfoo的类也会初始化(在 init 中)

The class in which pyfoo is defined also initialises (in init) a field

self.response=create_string_buffer("The Response String")

我如何传递地址,该字符串实际上存储在内存中到DLL?
因为ctypes有时创建副本而不是按地址返回真实引用,所以我尝试了类似的

How do I pass the address, where this string is actually stored in memory to the DLL?Since ctypes sometimes creates copies instead of returning a real reference by address I tried something like

cpointer = c_int.from_address(char_ptr_ptr[0])
cpointer.value = addressof(self.response)
return c_char(0)

它不起作用。
我尝试了其他方法来取消对传递的指针指针的引用并在那里存储内存地址(例如,直接将(我认为是字符串的地址)存储到char-ptr_ptr [0]中),但是回调永远不会做我期望的事情。

It does not work.I tried other ways of dereferencing the passed pointer-pointer and storing a memory address there (e.g. directly storing (what I think is the address of the string) into char-ptr_ptr[0]), but the caller of the callback is never doing what I am expecting it to do.

如果有人解决了在python中创建以null终止的字符串并将该字符串的地址通过**指针传递给用C实现的DLL的问题,在此,我将非常感谢他/她如何解决此问题。谢谢!

If anybody has ever solved the problem to create a null terminated string in python and to pass the address of that string through a **pointer to a DLL implemented in C, I would be very thankful to here about how he/she solved the issue. Thanks!

(编辑)还是我的问题更简单?是

(Edit) Or is my problem much simpler? Is

c_char(0)

实际上将单个字节作为返回值推入堆栈吗?如果没有,那么实现返回一个字节的回调的正确方法是什么?

actually pushing a single byte onto the stack as return value? If not, what would be the right way to implement a callback that shall return a single byte?

推荐答案

我会使用以下函数原型:

I'd use the following function prototype:

CFUNCTYPE(c_byte, POINTER(POINTER(c_char)))

然后像这样写 pyfoo

    def pyfoo(self, char_ptr_ptr):
        char_ptr_ptr[0] = self.response
        return 0

例如:

>>> import os
>>> from ctypes import *

>>> open('tmp.c', 'w').write(r'''
... #include <stdio.h>
... typedef char (*callback_t)(char **buf);
... int test(callback_t foo)
... {
...     char res, *buf;
...     res = foo(&buf);
...     printf("res: %d\n", res);
...     printf("buf: %s\n", buf);
...     return 0;
... }
... ''')
>>> _ = os.system('gcc -shared -fPIC -o tmp.so tmp.c')
>>> lib = CDLL('./tmp.so')

>>> class Test(object):
...   def __init__(self):
...     self.response = create_string_buffer("The Response String")
...     self.callback = CFUNCTYPE(c_byte, POINTER(POINTER(c_char)))(self.pyfoo)
...   def pyfoo(self, char_ptr_ptr):
...     char_ptr_ptr[0] = self.response
...     return 0
...

>>> t = Test()
>>> _ = lib.test(t.callback)
res: 0
buf: The Response String

这篇关于使用ctypes编写回调,该回调将指向指针参数的指针传入,以用作输出参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 05:52