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 はそうではありません。そうしないと、ガベージ コレクションが実行され、コールバックが行われたときにプログラムがクラッシュする可能性があります。