让 C 库调用 python 函数与 ctypes
Have C library call python function with ctypes
我在 c 中有一个 DLL,用于 windows 平台,其结构类似于以下内容:
C 结构
typedef struct some_struct {
int (_stdcall *function)(int arg1, int arg2);
...
}SOME_STRUCT;
我定义了一个 python ctypes 结构来模仿下面的结构
Python结构
class SOME_STRUCT(Structure):
_fields_ = [('function', POINTER(CFUNCTYPE(c_int, c_int, c_int))), ...]
C 代码中此结构的要点是注册一个回调函数,该函数在其自己的线程中的某些触发器上执行。如果可能的话,我希望能够做的是将该回调设置为 Python 函数,这样当从 C 代码调用 C 结构中的函数时,它就是 python 函数被执行。
我在 python 中尝试完成此操作(无效)的内容如下:
def func(arg1,arg2):
print('I was called!')
return 0
struct = SOME_STRUCT()
prototype = CFUNCTYPE(c_int, c_int, c_int)
struct.function = byref(prototype(func))
我得到的具体错误(这可能不是我唯一的问题)是它抱怨 struct.function
期待一个 LP_CFunctionType
实例但得到一个 CArgObject
实例。我怎样才能做我想做的事?
这是一个工作示例和测试 DLL 源。奇怪的是,当回调是结构的唯一成员时,我无法让它工作(崩溃)。这似乎是一个错误,因为没有结构包装器或向结构添加第二个成员的回调使其工作。
注意事项:
- 将
WINFUNCTYPE
与 __stdcall
结合使用。 CFUNCTYPE
用于 __cdecl
.
- 您不需要
POINTER
或 byref
即可运行。
@CALLBACK
装饰器相当于func = CALLBACK(func)
.
test.c
#include <stdio.h>
typedef int (__stdcall *CALLBACK)(int arg1, int arg2);
typedef struct some_struct {
CALLBACK function;
int other;
} SOME_STRUCT;
__declspec(dllexport) int func(SOME_STRUCT* pss)
{
printf("%d\n",pss->other);
return pss->function(1,2);
}
test.py
from ctypes import *
CALLBACK = WINFUNCTYPE(c_int,c_int,c_int)
class SOME_STRUCT(Structure):
_fields_ = [('function', CALLBACK),
('other', c_int)]
@CALLBACK
def callback(arg1,arg2):
return arg1 + arg2
dll = CDLL('test')
dll.argtypes = POINTER(SOME_STRUCT),
dll.restype = c_int
struct = SOME_STRUCT(callback,7)
print(dll.func(byref(struct)))
输出
7
3
我在 c 中有一个 DLL,用于 windows 平台,其结构类似于以下内容:
C 结构
typedef struct some_struct {
int (_stdcall *function)(int arg1, int arg2);
...
}SOME_STRUCT;
我定义了一个 python ctypes 结构来模仿下面的结构
Python结构
class SOME_STRUCT(Structure):
_fields_ = [('function', POINTER(CFUNCTYPE(c_int, c_int, c_int))), ...]
C 代码中此结构的要点是注册一个回调函数,该函数在其自己的线程中的某些触发器上执行。如果可能的话,我希望能够做的是将该回调设置为 Python 函数,这样当从 C 代码调用 C 结构中的函数时,它就是 python 函数被执行。
我在 python 中尝试完成此操作(无效)的内容如下:
def func(arg1,arg2):
print('I was called!')
return 0
struct = SOME_STRUCT()
prototype = CFUNCTYPE(c_int, c_int, c_int)
struct.function = byref(prototype(func))
我得到的具体错误(这可能不是我唯一的问题)是它抱怨 struct.function
期待一个 LP_CFunctionType
实例但得到一个 CArgObject
实例。我怎样才能做我想做的事?
这是一个工作示例和测试 DLL 源。奇怪的是,当回调是结构的唯一成员时,我无法让它工作(崩溃)。这似乎是一个错误,因为没有结构包装器或向结构添加第二个成员的回调使其工作。
注意事项:
- 将
WINFUNCTYPE
与__stdcall
结合使用。CFUNCTYPE
用于__cdecl
. - 您不需要
POINTER
或byref
即可运行。 @CALLBACK
装饰器相当于func = CALLBACK(func)
.
test.c
#include <stdio.h>
typedef int (__stdcall *CALLBACK)(int arg1, int arg2);
typedef struct some_struct {
CALLBACK function;
int other;
} SOME_STRUCT;
__declspec(dllexport) int func(SOME_STRUCT* pss)
{
printf("%d\n",pss->other);
return pss->function(1,2);
}
test.py
from ctypes import *
CALLBACK = WINFUNCTYPE(c_int,c_int,c_int)
class SOME_STRUCT(Structure):
_fields_ = [('function', CALLBACK),
('other', c_int)]
@CALLBACK
def callback(arg1,arg2):
return arg1 + arg2
dll = CDLL('test')
dll.argtypes = POINTER(SOME_STRUCT),
dll.restype = c_int
struct = SOME_STRUCT(callback,7)
print(dll.func(byref(struct)))
输出
7
3