简体   繁体   English

使用Python Ctypes将结构指针传递给DLL函数

[英]Using Python Ctypes to pass struct pointer to a DLL function

I am attempting to access a function in a DLL file using Python ctypes. 我正在尝试使用Python ctypes访问DLL文件中的函数。 The provided function description is below. 提供的功能说明如下。

Prototype: Picam_ConnectDemoCamera( PicamModel model,
                                    const pichar* serial_number,
                                    PicamCameraID* id )

Description: Virtually connects the software-simulated 'model' with 'serial_number'
and returns the camera id in `_id_`
Notes: `_id_` is optional and can be null

The function references a few variable types defined in the DLL. 该函数引用DLL中定义的一些变量类型。 These variables are described next 接下来介绍这些变量

PicamModel
Type: enum
Description: The camera model.

PicamCameraID
Type: Struct
- PicamModel model: _model_ is the camera model
- PicamComputerInterface computer_interface: computer_interface is the method of
communication
- pichar sensor_name [PicamStringSize_SensorName]: sensor_name contains the name of
the sensor in the camera
- pichar serial_number [PicamStringSize_SerialNumber]: serial_number contains the
unique serial number of the camera

Note that'pichar' is defined in one of the provided header files as follows: 请注意,在提供的头文件之一中定义了“ pichar”,如下所示:

typedef          char   pichar; /* character native to platform   

This seems straightforward, but isn't working out for me for some reason. 这似乎很简单,但由于某种原因对我而言却没有解决。

My understanding is as follows: I pass the function three variables: 我的理解如下:我向函数传递了三个变量:

1) a model , which is really an enum . 1)一个model ,它实际上是一个enum I'm told that python ctypes doesn't inherently support enums, and so I am passing it an integer, 2, which maps to a particular model type. 有人告诉我python ctypes本质上不支持枚举,因此我将其传递给整数2,该整数映射到特定的模型类型。

2) a pointer to a serial number (I can make this up: an arbitrary string) 2)指向序列号的指针(我可以组成一个:任意字符串)

3) A pointer to PicamCameraID , a variable type defined within the DLL, based on the struct type 3)指向PicamCameraID的指针,该指针是DLL中定义的基于struct类型的变量类型

After reading through SO I found a few good starting points, but am still running out of luck. 读完SO之后,我找到了一些很好的起点,但是仍然运气不佳。 Here's my best shot so far 到目前为止,这是我最好的镜头

def pointer(x):
      PointerToType = ctypes.POINTER(type(x))
      ptr = ctypes.cast(ctypes.addressof(x), PointerToType)
      return ptr

class PicamCameraID(ctypes.Structure):
      pass
PicamCameraID._fields_=[("model",ctypes.c_int),
                    ("computer_interface",ctypes.c_int),
                    ("sensor_name",ctypes.c_char_p),
                    ("serial_number",ctypes.c_char_p)]

myid = PicamCameraID()
model = ctypes.c_int(2)
serialnum = ctypes.c_char_p('asdf')
print picam.Picam_ConnectDemoCamera(model, pointer(serialnum), ctypes.byref(myid))

As you can hopefully see, I'm trying to create the variable type that corresponds to the PicamCameraID struct defined in the DLL. 如您PicamCameraID ,我正在尝试创建与DLL中定义的PicamCameraID结构相对应的变量类型。 My intuition was to use the ctypes.pointer command to reference this when passing the argument to the function, but I found indications to use ctypes.byref instead elsewhere . 我的直觉是在将参数传递给函数时使用ctypes.pointer命令引用此参数,但是我发现在其他地方使用ctypes.byref指示。

The code runs without error (returns 0), however, I get varying results when I try to access the properties of the struct PicamCameraID : 代码运行无错误(返回0),但是,当我尝试访问结构PicamCameraID的属性时,得到的结果却有所不同:

myid.model returns "2" which is great that's what I specified myid.computer_interface returns "1" which is fine myid.model返回“ 2”,这是我指定的值myid.computer_interface返回“ 1”,这很好

BUT the problem is myid.serial_number returns 但是问题是myid.serial_number返回

Traceback (most recent call last):   File "<pyshell#28>", line 1, in
<module>
   myid.serial_number ValueError: invalid string pointer 0x2820303031207820

and myid.sensor_name returns: myid.sensor_name返回:

Traceback (most recent call last):   File "<pyshell#29>", line 1, in
<module>
    myid.sensor_name ValueError: invalid string pointer 0x3034333120563245

For some reason these strings aren't being properly populated? 由于某种原因,这些字符串没有正确填充?

Any ideas would be much appreciated, I am a novice to python ctypes (and c) 任何想法将不胜感激,我是python ctypes(和c)的新手

Kind regards 亲切的问候

Addition June 1 2013 增加2013年6月1日

typedef enum PicamStringSize {
    PicamStringSize_SensorName     =  64,
    PicamStringSize_SerialNumber   =  64,
    PicamStringSize_FirmwareName   =  64,
    PicamStringSize_FirmwareDetail = 256 } PicamStringSize; 

typedef struct PicamCameraID {
    PicamModel             model;
    PicamComputerInterface computer_interface;
    pichar                 sensor_name[PicamStringSize_SensorName];
    pichar                 serial_number[PicamStringSize_SerialNumber];
} PicamCameraID;

Your definition of PicamCameraID structure is incorrect: sensor_name and serial_number are arrays : 您对PicamCameraID结构的定义不正确: sensor_nameserial_numberarrays

"""
struct PicamCameraID {
  PicamModel             model;
  PicamComputerInterface computer_interface;
  pichar                 sensor_name[PicamStringSize_SensorName];
  pichar                 serial_number[PicamStringSize_SerialNumber]; 
};
"""
import ctypes as c

PicamStringSize_SensorName = PicamStringSize_SerialNumber = 64
PicamModel = PicamComputerInterface = c.c_int
pichar = c.c_char

class PicamCameraID(c.Structure):
    _fields_ = [("model", PicamModel),
                ("computer_interface", PicamComputerInterface),
                ("sensor_name", pichar * PicamStringSize_SensorName),
                ("serial_number", pichar * PicamStringSize_SerialNumber)]

It seems the second argument is just a string, so you don't need to apply pointer() to it. 似乎第二个参数只是一个字符串,因此您不需要对其应用pointer() Here's the ctypes prototype for Picam_ConnectDemoCamera() function: 这是Picam_ConnectDemoCamera()函数的ctypes原型:

"""
Picam_ConnectDemoCamera(PicamModel model, const pichar* serial_number,
                        PicamCameraID* id)
"""
pichar_p = c.c_char_p # assume '\0'-terminated C strings
Picam_ConnectDemoCamera.argtypes = [PicamModel, pichar_p,
                                    c.POINTER(PicamCameraID)]
Picam_ConnectDemoCamera.restype = c.c_int # assume it returns C int

To call it: 调用它:

picam_id = PicamCameraID()
rc = Picam_ConnectDemoCamera(2, "serial number here", c.byref(picam_id))
print(rc)
print(picam_id.sensor_name.value) # C string
print(picam_id.sensor_name.raw)   # raw memory

Likely, you're not entering the exact structure fields in the exact same order. 您可能没有以完全相同的顺序输入确切的结构字段。 If you don't, then you usually get random data or segfaults. 如果不这样做,那么通常会得到随机数据或段错误。 To access a library with ctypes, you usually need to look inside the header (.h file) to copy the exact structure definition. 要访问具有ctypes的库,通常需要查看标头(.h文件)的内部,以复制确切的结构定义。 Alternatively, use cffi with ffi.verify() if you don't want to depend on the precise layout. 另外,如果您不想依赖精确的布局, 请将cffi与ffi.verify()结合使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM