2012-11-15 41 views
5

Tôi đang cố gắng gọi một DLL từ Python. DLL được viết thẳng C và không có gì phức tạp về nó. Đây là loại điều mà ctypes chính xác thực hiện. Tuy nhiên tôi gặp khó khăn khi nhận được các giá trị chính xác trong một cấu trúc trả về từ các cuộc gọi hàm DLL. Giá trị đầu tiên trong cấu trúc đã truyền được trả về chính xác nhưng các giá trị khác thì không.Python ctypes không trả lại chính xác một số giá trị được chuyển bởi tham chiếu

Mã đọc nhiều thư từ bộ đệm trong bộ nhớ. Nó sử dụng một mô hình mã hóa ReadFirst()/ReadNext(). Có một cấu trúc "thông báo hiện tại" được truyền vào để theo dõi trạng thái.

Đây là struct C chứa ReadFirst hiện tại()/ReadNext() nhà nước ...

typedef struct 
    { 
    unsigned int   uMsgNum; 
    uint32_t    ulCurrOffset; 
    uint32_t    ulDataLen; 
    Su1553F1_ChanSpec  * psuChanSpec; 
    Su1553F1_Header  * psu1553Hdr; 
    SuCmdWordU   * psuCmdWord1; 
    SuCmdWordU   * psuCmdWord2; 
    uint16_t    * puStatWord1; 
    uint16_t    * puStatWord2; 
    uint16_t    uWordCnt; 
    uint16_t    * pauData; 
    } Su1553F1_CurrMsg; 

Đây là ctypes struct đối viết bằng ctypes ...

class CurrMsg_1553F1(ctypes.Structure): 
    ''' Data structure for the current 1553 message info structure ''' 
    _pack_ = 1 
    _fields_ = [("MsgNum",  ctypes.c_uint32), 
       ("CurrOffset", ctypes.c_uint32), 
       ("DataLen",  ctypes.c_uint32), 
       ("pChanSpec", ctypes.POINTER(ChanSpec_1553F1)), 
       ("p1553Hdr", ctypes.c_void_p), 
       ("pCmdWord1", ctypes.POINTER(CmdWord)), 
       ("pCmdWord2", ctypes.POINTER(CmdWord)), 
       ("pStatWord1", ctypes.c_void_p), 
       ("pStatWord2", ctypes.c_void_p), 
       ("WordCnt",  ctypes.c_uint16), 
       ("pData",  ctypes.c_void_p)] 

Tôi sẽ cung cấp thêm chi tiết bên dưới, nhưng điểm mấu chốt của vấn đề là các cuộc gọi đến ReadFirst()/ReadNext() trả lại chính xác các giá trị cho MsgNum nhưng các giá trị khác là rác. Đây là một đầu ra mẫu ...

MsgNum 0 CurrOffset 40912728 DataLen 40912732 Messages = 3664897 
MsgNum 1 CurrOffset 40912728 DataLen 40912748 Messages = 60417 
MsgNum 2 CurrOffset 40912728 DataLen 40912748 Messages = 60417 
etc. 

MsgNum là đúng và ReadFirst()/ReadNext() lặp chính xác số lần. Tuy nhiên, các giá trị cho CurrOffset và DataLen là rác. (Giá trị tin nhắn được dereferenced từ con trỏ đến bộ nhớ khác.Tôi không nghĩ rằng tôi có quyền nhưng tôi sẽ phải lưu rằng một cho đến khi tôi nhận được công cụ này khác cố định. có lẽ là sai cũng có.)

Dưới đây là các giao diện cho các chức năng ...

EnI106Status enI106_Decode_First1553F1 
    (SuI106Ch10Header * psuHeader, 
    void    * pvBuff, 
    Su1553F1_CurrMsg * psuMsg); 

EnI106Status enI106_Decode_Next1553F1 
    (Su1553F1_CurrMsg * psuMsg); 

những chức năng DLL được gọi (cùng với báo cáo gỡ lỗi in) bằng cách ...

def __init__(self, PacketIO): 
    self.CurrMsg = CurrMsg_1553F1() 

def Decode_First1553F1(self): 
    Status = self.PacketIO._IrigDataDll.enI106_Decode_First1553F1(ctypes.byref(self.PacketIO.Header), ctypes.byref(self.PacketIO.Buffer), ctypes.byref(self.CurrMsg)) 
    print "MsgNum %d CurrOffset %d DataLen %d Messages = %d" % \ 
     (Decode1553.CurrMsg.MsgNum, Decode1553.CurrMsg.CurrOffset, Decode1553.CurrMsg.DataLen, Decode1553.CurrMsg.pChanSpec.contents.MsgCnt) 
    return Status 

def Decode_Next1553F1(self): 
    Status = self.PacketIO._IrigDataDll.enI106_Decode_Next1553F1(ctypes.byref(self.CurrMsg)) 
    print "MsgNum %d CurrOffset %d DataLen %d Messages = %d" % \ 
     (Decode1553.CurrMsg.MsgNum, Decode1553.CurrMsg.CurrOffset, Decode1553.CurrMsg.DataLen, Decode1553.CurrMsg.pChanSpec.contents.MsgCnt) 
    return Status 

DLL C được biên dịch theo Visual Studio 2005. Tôi đã sử dụng DLL này rất nhiều với các chương trình C và C++ .NET khác nhau mà không gặp vấn đề gì.

Tôi đã sử dụng các mẫu và cấu trúc để trả về các giá trị trong mã khác và dường như nó hoạt động tốt. Kể từ khi giá trị đầu tiên trong cấu trúc là OK nhưng các giá trị tiếp theo là cách này "cảm thấy" như một vấn đề liên kết dữ liệu. Tôi đã đặt gói = 1 trong cấu trúc ctypes và đã đặt căn chỉnh byte trong mã DLL đã biên dịch. Tôi đã thực hiện sizeof bản in của mỗi cấu trúc và xác minh họ là kích thước dự kiến.

Tôi đã đánh đầu vào tường trên cái này một lúc và không có ý tưởng. Bạn có suy nghĩ gì về việc thử tiếp theo không?

+0

Trong đoạn mã Python, bạn vượt qua ByRef (self.CurrMsg), nhưng bạn in các lĩnh vực từ Decode1553.CurrMsg. Không nên bạn in các lĩnh vực từ self.CurrMsg thay vào đó? –

Trả lời

2

Tôi lưu ý phần tử đầu tiên của cấu trúc C là không dấu int, nhưng cấu trúc python của bạn là c_uint32. Bạn chắc chắn chúng có cùng kích thước với kiến ​​trúc của bạn?

Nếu đó không phải là bất kỳ sự giúp đỡ, tôi sẽ làm như sau để truy nguyên nguồn gốc của vấn đề:

Trước tiên, tôi sẽ loại bỏ _pack_ từ việc kê khai python và bất kỳ #pragma pack hoặc thao tác liên kết khác từ nguồn C . Bắt đầu từ một địa điểm đã biết, căn chỉnh gốc.

Sau đó ...

Tôi muốn viết chương trình C để lặp lại cấu trúc và in số bù của mỗi thành viên bằng offsetof(struct, field). Ngoài ra, chương trình này sẽ thực hiện cuộc gọi đến First() và một số cuộc gọi đến Next() và viết các cấu trúc, như là, trong nhị phân, vào một tập tin.

Tiếp theo, viết kịch bản python sử dụng mô-đun cấu trúc và lặp lại các cấu trúc bạn đã viết từ chương trình C và trang bị kiến ​​thức về kích thước và sắp xếp trường, thực hiện cuộc gọi tới struct.unpack (...) chuỗi định dạng xác định đúng cấu trúc.

Với kiến ​​thức mà bạn nên có khả năng mã đúng ctypes.Structure bạn

Các vấn đề liên quan