1

ctypes を使用して、python コードをレガシー C DLL とインターフェースします。DLL は、DLL 内から呼び出されるコールバックとして使用される関数ポインターを渡すことを期待しています。

そのコールバックの C 宣言は次のようになります。

char foo(char **buf)

意味的に、DLL は、buf がコールバックによって管理される文字列バッファーを指すようにし、すべてが正常に機能する場合は 0 を返すことを期待しています。C では、静的 char[] 変数 mybuf になり、その静的 buf のアドレスを次のようなコードで返します。

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

mybuf の文字列は、C では通常どおり null で終了する必要があります。関数ポインターを DLL に渡すことができ、Python (メンバー) 関数になりました。

def pyfoo(self, char_ptr_ptr) 

呼ばれます。

pyfoo が定義されているクラスは、( initで) フィールドを初期化します

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

この文字列が実際にメモリに格納されているアドレスを DLL に渡すにはどうすればよいですか? ctypes は、アドレスで実際の参照を返す代わりにコピーを作成することがあるので、次のようなものを試しました

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

それは動作しません。渡されたポインターポインターを逆参照し、そこにメモリアドレスを保存する他の方法を試しました(たとえば、(文字列のアドレスだと思う)をchar-ptr_ptr [0]に直接保存します)が、コールバックの呼び出し元は決して行いません私が期待していること。

Python で null で終了する文字列を作成し、その文字列のアドレスを ** ポインターを介して C で実装された DLL に渡すという問題を解決したことがある人がいれば、彼/彼女が問題をどのように解決したかについてここに非常に感謝しています。 . ありがとう!

(編集)または私の問題はもっと単純ですか?は

c_char(0) 

実際に1バイトを戻り値としてスタックにプッシュしますか? そうでない場合、1 バイトを返すコールバックを実装する正しい方法は何でしょうか?

4

1 に答える 1

0

次の関数プロトタイプを使用します。

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
于 2013-04-03T14:00:10.917 に答える