我正在尝试从Python调用DLL。 DLL是用直接的C编写的,并没有什么特别复杂的。这就是ctypes正是为此而制造的东西。但是,我在从DLL函数调用返回的结构中获取正确的值时遇到问题。传递的结构中的第一个值是正确返回的,但其他值则不是。
代码从内存中的缓冲区中读取多条消息。它使用ReadFirst()/ ReadNext()编码范例。传入一个“当前消息”结构来跟踪状态。
这是保存当前ReadFirst()/ ReadNext()状态的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;
这是用ctypes编写的ctypes struct对应物......
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的值是垃圾。 (消息值从指向其他内存的指针解除引用。我认为我还没有那个权利但是我必须保存那个,直到我修复了其他内容。如果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下编译的。我已经在各种C和C ++ .NET程序中使用了这个DLL,没有任何问题。
我已经使用了ctypes和structs来返回其他代码中的值,它似乎工作得很好。由于结构中的第一个值是正常的,但后续的值远离这个“感觉”就像数据对齐问题。我在ctypes结构中设置了 pack = 1,并在已编译的DLL代码中设置了字节对齐。我已经完成了每个结构的打印输出大小,并验证了它们是预期的大小。
我已经在这一段时间里撞到墙上一段时间了,而且我已经没想法了。关于下一步该尝试的任何想法?
答案 0 :(得分:2)
我注意到C struct的第一个元素是unsigned int,但你的python Structure是c_uint32。您确定它们的架构尺寸相同吗?
如果没有任何帮助,我会执行以下操作来追踪问题的根源:
首先,我将从python声明和C源中的任何_pack_
或其他对齐操作中删除#pragma pack
。从一个已知的地方开始,原生对齐。
则...
我会写一个C程序来迭代结构并用offsetof(struct, field)
打印每个成员的偏移量。此外,该程序应调用First()和一些对Next()的调用,并将结构(以二进制形式)写入文件。
接下来,使用struct模块编写一个python脚本,并迭代从C程序中写出的结构,并掌握字段大小和对齐的知识,调用struct.unpack(.. 。)找到正确定义结构的格式字符串。
凭借这些知识,您应该能够正确编码ctypes.Structure