让C库用ctypes调用python函数

时间:2017-09-29 19:43:00

标签: python c 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个实例。我怎么能做我想做的事呢?

1 个答案:

答案 0 :(得分:1)

这是一个工作示例和测试DLL源代码。奇怪的是,当回调是结构(崩溃)的唯一成员时,我无法使它工作。这似乎是一个错误,因为没有结构包装器的回调或向结构添加第二个成员使它工作。

注意事项:

  • WINFUNCTYPE__stdcall一起使用。 CFUNCTYPE适用于__cdecl
  • 您不需要POINTERbyref才能使其正常运作。
  • @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