0

DLL にコンパイルする次の C ソースがあります。

int (*pfuncExtB)(int a, int b);

int funcB(int a, int b)
{
    return funcExtB(a, b);
}

int funcExtB(int a, int b)
{
    return pfuncExtB(a, b);
}

私がやりたいことは、 pfuncExtB を Python 関数に「ポイント」させることです。したがって、これは Python で行うことです。

from ctypes import *

def add(a, b):
    return a + b

mutdll = cdll.LoadLibrary("my.dll")

pfuncExtB = (POINTER(CFUNCTYPE(c_int, c_int, c_int))).in_dll(mutdll, 'pfuncExtB')

funcB = mutdll.funcB
funcB.argtypes = [c_int, c_int]
funcB.restype = c_int

pfuncExtB.contents = CFUNCTYPE(c_int, c_int, c_int)(add)

print funcB(3 , 4)

この後、次の呼び出しで 7 が返されることを期待しています

print funcB(3, 4)

しかし、私は得る:

Traceback (most recent call last):
..................
print funcB(3, 4)
WindowsError: exception: access violation reading 0x00000001

それで、私はここで何が間違っていますか?Python関数をctypes関数へのポインタ変数に「割り当て」ることは可能ですか?

編集: Mark Tolonen の回避策 (C で記述された関数変数へのポインターの set 関数) を見た後、試してみたときになぜうまくいかなかったのかがわかりました。

これは動作しません:

set(CFUNCTYPE(c_int,c_int,c_int)(add))
print funcB(2, 3)

これが機能している間:

callback = CFUNCTYPE(c_int,c_int,c_int)(add)
set(callback)
print funcB(2, 3)

set は、マークの回答のように、関数へのポインター引数をグローバルに割り当てるC関数です。彼が指摘したように、答えはドキュメントにあります:

コールバック関数に関する重要な注意事項: C コードから使用されている限り、CFUNCTYPE() オブジェクトへの参照を保持してください。ctypes はそうではありません。そうしないと、ガベージ コレクションが実行され、コールバックが行われたときにプログラムがクラッシュする可能性があります。

4

1 に答える 1

1

Python でのグローバル変数の正しい型はCFUNCTYPE(c_int,c_int,c_int)(no POINTER()) ですが、一度変数の値を変更する方法がわかりません。set 関数を追加できる場合は、次のように機能します。

typedef int (*FUNC)(int,int);

__declspec(dllexport) FUNC pfuncExtB;

__declspec(dllexport) void set(FUNC f)
{
    pfuncExtB = f;
}

int funcExtB(int a, int b)
{
    return pfuncExtB(a, b);
}

__declspec(dllexport) int funcB(int a, int b)
{
    return funcExtB(a, b);
}

パイソン

from ctypes import *

FUNC = CFUNCTYPE(c_int,c_int,c_int)

@FUNC
def add(a, b):
    return a + b

mutdll = cdll.LoadLibrary('x')

mutdll.set.argtypes = [FUNC]
mutdll.set.restype = None

mutdll.set(add) # set the global variable

pfuncExtB = FUNC.in_dll(mutdll,'pfuncExtB')
print(pfuncExtB(1,2)) # -> 3

funcB = mutdll.funcB
funcB.argtypes = [c_int, c_int]
funcB.restype = c_int

print(funcB(3 , 4)) # -> 7

これは機能しないことに注意してください。

pfuncExtB = POINTER(FUNC).in_dll(mutdll,'pfuncExtB')
pfuncExtB.contents(1,2) # exception!
于 2013-03-01T16:57:07.697 に答える