2013-06-01 137 views
4

我正在嘗試使用Python ctypes訪問DLL文件中的函數。提供的功能描述如下。使用Python Ctypes將結構指針傳遞給DLL函數

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 

該函數引用了DLL中定義的幾個變量類型。這些變量描述未來

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 

注that'pichar」中提供的頭文件中的一個定義如下:

typedef   char pichar; /* character native to platform 

這看起來簡單,但不工作對我來說有些原因。

我的理解如下:我通過功能三個變量:

1)model,這實在是一個enum。我被告知python ctypes本質上不支持枚舉,所以我傳遞一個整數2,它映射到一個特定的模型類型。

2)的指針,一個序列號(I可以使這件事:任意字符串)

3)的指針,PicamCameraID,該DLL內定義的變量的類型,基於所述struct類型

通過閱讀後我發現了一些很好的起點,但仍然運氣不佳。這是我最好的拍攝到目前爲止

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)) 

正如你可以看到希望,我試圖創建一個對應於DLL中定義的PicamCameraID結構變量類型。我的直覺是在將參數傳遞給函數時使用ctypes.pointer命令來引用此參數,但我發現使用ctypes.byref而不是elsewhere

代碼運行而不會出現錯誤(返回0),不過,我得到不同的結果,當我嘗試訪問結構PicamCameraID的屬性:

myid.model返回「2」,這是偉大的,是我指定什麼 myid.computer_interface返回 「1」,這是細

BUT問題是myid.serial_number返回

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

myid.sensor_name回報:

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

出於某種原因,這些字符串沒有被正確填充?

任何想法,將不勝感激,我是新手到Python ctypes的(和c)

親切的問候

加入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; 
+0

什麼是'pichar'?字符串的大小是如何確定的?如果您不通過'pointer()'調用直接傳遞'serialnum',會發生什麼? – jfs

+0

J.F. - 感謝您的回覆。我的頭文件告訴我以下內容: typedef char pichar;/*字符原生平臺 換句話說,我相信它只是重新映射char? – Joe

回答

7

你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)] 

看來第二個參數只是一個字符串,所以你不需要申請pointer()它。下面是​​原型Picam_ConnectDemoCamera()功能:

""" 
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 

要叫它:

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 
+0

謝謝J.F. - 這非常有幫助 – Joe

0

可能的是,你不進入確切的結構字段完全相同的順序。如果你不這樣做,那麼你通常會得到隨機數據或段錯誤。要使用ctypes訪問庫,通常需要查看頭文件(.h文件)以複製確切的結構定義。或者,如果您不想依賴精確的佈局,請使用cffi和ffi.verify()。

+0

嗨Armin - 我只是從頭文件中添加了一些我認爲能夠解決您的建議的文本。難道說我的'sensor_name'字符串沒有被指定到正確的長度,因此我的兩個字符串基本上都被擠在一起,數據丟失了? 我看到頭文件確實爲這些變量定義了一個字符串大小,但是我不清楚當我使用ctypes定義變量時如何解釋這個字符串的大小 – Joe

+0

你錯誤地聲明瞭它,而ctypes會只是盲目地使用你錯誤的聲明。 J.F.塞巴斯蒂安給出了更準確的答案。 –