我想從Python調用一個DLL。該DLL是直寫C,沒有什麼非常複雜的。這是ctypes正是爲之而設計的。但是,我無法在從DLL函數調用返回的結構中獲取正確的值。傳遞的結構中的第一個值會正確返回,但其他值不會。Python ctypes不正確地返回通過引用傳遞的一些值
該代碼從內存中的緩衝區中讀取多條消息。它使用ReadFirst()/ ReadNext()編碼範例。有一個「當前消息」結構被傳入以跟蹤狀態。
這裏是C結構,其保持當前ReadFirst()/ ReadNext()狀態......
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;
這裏是ctypes的結構對應寫入的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)]
我將在下面提供更多細節,但問題的關鍵是對ReadFirst()/ ReadNext()的調用正確返回MsgNum的值,但其他值是垃圾。下面是一個示例輸出...
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是正確的並且ReadFirst()/ ReadNext()迭代的次數的正確數目。然而,CurrOffset和DataLen的值是垃圾。 (Messages值是從指向其他內存的引用中取消引用的,我認爲我沒有那個權限,但是我必須保存那個,直到我修復了其他的東西,如果CurrOffset和DataLen錯誤,那麼指向pChanSpec可能是錯也。)
下面是功能的接口...
EnI106Status enI106_Decode_First1553F1
(SuI106Ch10Header * psuHeader,
void * pvBuff,
Su1553F1_CurrMsg * psuMsg);
EnI106Status enI106_Decode_Next1553F1
(Su1553F1_CurrMsg * psuMsg);
這些DLL函數被調用(連同調試打印語句)由...
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
C DLL是在Visual Studio 2005下編譯的。我已經使用了這個DLL與各種C和C++ .NET程序沒有任何問題。
我已經使用ctypes和結構來返回其他代碼中的值,它似乎工作得很好。由於結構中的第一個值是確定的,但隨後的值是不正確的,所以「感覺」就像是數據對齊問題。我已經在ctypes結構中設置了包 = 1,並在編譯的DLL代碼中設置了字節對齊。我已經完成每個結構的sizeof打印輸出,並驗證它們是預期的大小。
我已經在我的頭上撞過牆了一段時間了,現在已經沒有想法了。關於接下來要做什麼的任何想法?
在Python代碼,您通過按地址(self.CurrMsg),但你打印從Decode1553.CurrMsg領域。你不應該從self.CurrMsg打印字段嗎? –