从 ctypes 中的回调访问值

Accessing value from callback in ctypes

本文关键字:访问 回调 ctypes      更新时间:2023-10-16

我正在使用Python/ctypes编写基于商业DLL的应用程序。此 DLL 读取平面文件并通过 struct 返回数据。相关的 C struct s 如下所示:

struct System{
    unsigned short       user;
    unsigned short       version;
};
struct Message {
    unsigned short       header;
    unsigned short       data;
    unsigned int         messageType;
};

DLL 附带的 API 提供指向具有以下原型的函数的指针。此函数循环访问平面文件并调用接下来定义的Callback

typedef int (__stdcall *Process) (const char* filename, const char* base, unsigned int flags, int user, Callback stdcallback);

Callback原型(上面的第五个参数)定义为:

typedef int (__stdcall *Callback) (const System* Sys, const Message* Msg);

在我的 python 文件中:

from ctypes import *
# using WinDLL for stdcall
lib = WinDLL('CVO.dll')
class System(Structure):
    _fields_ = [('user', c_ushort),
                ('version', c_ushort)]
class Message(Structure):
    _fields_ = [('header', c_ushort),
                ('data', c_ushort),
                ('messageType', c_uint)]
PROTO = WINFUNCTYPE(c_int, POINTER(System), POINTER(Message))
def py_callbck(Sys, Msg):
    print Msg._type_.messageType
    # return 0 to read the next line in the flatfile
    return 0
Callback = PROTO(py_callbck)
pProcess lib.Process
pProcess.argtypes = [c_char_p,c_char_p,c_uint,c_int,PROTO]
pProcess.restype = c_int
pProcess(c_char_p('flat.ccf'),c_char_p(None),c_uint(0),c_int(0),Callback)

我的问题在于访问 DLL 传递给 Msg 结构的值。代码应该打印一个c_int(0, 1, 2),但返回一个Field类型,如下所示:

<Field type=c_ulong, ofs=136, size=4>

我知道平面文件正在处理中,因为我的 Python 代码打印出数百个 <Field ...> 语句,这是应该做的。

我的问题是我如何访问 DLL 推送到Msg Structure的值而不是返回<Field ...>语句?

注意我对 ctypes 比较陌生,C 也很少,所以如果你发现定义任何东西的问题,请告诉我。例如,我知道返回和对象ctypes.pointer和返回新类型的ctypes.POINTER之间存在差异。当我使用ctypes.pointer时,代码错误。

对于ctypes来说相对较新,你在这里做得很好。指针的 _type_ 属性是对指向数据类型的引用。在这种情况下,它是 Message .类属性messageType是实例使用的数据描述符CField

相反,您要做的是取消引用指针以获取Message实例。您可以使用[0]下标或 contents 属性:

def py_callbck(Sys, Msg):
    print Msg[0].messageType  # Msg.contents.messageType
    # return 0 to read the next line in the flatfile
    return 0

请记住保留对Callback的引用,以防止它被垃圾回收。当前,您将其引用为全局。没关系。

关于你调用pProcess的方式,当你定义了argtypes时,通常没有必要为简单类型手动创建ctypes对象。您可以更简单地使用以下方法:

pProcess('flat.ccf', None, 0, 0, Callback)

但要注意函数是否需要可写字符串缓冲区。在这种情况下,请使用 create_string_buffer .这里没有必要,因为char *参数都是const的。