我正在将一个应用程序从VB.NET转换为Python 3.4,并且遇到了使用ctypes调用DLL文件中的函数的问题。对于该特定函数,两个结构由inref传递。对于一种结构,字段偏移不能根据需要进行。最后一个字段的偏移最终关闭。这使得该结构中的所有字段都具有不正确的值。
对于下面的PPNChartList结构,字段偏移量应为0,8,12和76(基于工作的VB.NET代码),但最终为0,8,12和72.那么,我该如何将最后一个字段移位或以其他方式获得该结构的正确值?
任何指导都将不胜感激。
以下是Python代码:
import os
from ctypes import *
_sFile = 'ppn.dll'
_sPath = os.path.join(*(os.path.split(__file__)[:-1] + (_sFile,)))
_ppn = windll.LoadLibrary(_sPath)
class PPNChartSpec(Structure):
_fields_ = [("dStructVer", c_double),
("iNumLanes", c_long),
("iNumCars", c_long),
("iNumRounds", c_long),
("iOptHeatCountEven", c_long),
("iOptAvoidConsecRaces", c_long),
("iOptAvoidRepeatLanes", c_long)]
class PPNChartList(Structure): # This is the problem structure
_fields_ = [("dStructVer", c_double),
("iUsedAlts", c_long),
("aiChartType", c_long * 15),
("audtChartSpec", PPNChartSpec * 15)] # The offset for this last field is off by 4
class PPNChart(Structure):
_fields_ = [("dStructVer", c_double),
("udtSpec", PPNChartSpec),
("iChartType", c_long),
("iNumLanes", c_long),
("iNumHeats", c_long),
("aiCar", c_long * 2399)]
makePPNChart = _ppn.makePPNChart
ptrChartSpec = POINTER(PPNChartSpec)
ptrChart = POINTER(PPNChart)
makePPNChart.argtypes = [ptrChartSpec, ptrChart]
makePPNChart.restype = c_int
altCharts = _ppn.altCharts
ptrChartSpec = POINTER(PPNChartSpec)
ptrChartList = POINTER(PPNChartList)
altCharts.argtypes = [ptrChartSpec, ptrChartList]
altCharts.restype = c_int
编辑:如果它有帮助,下面是显示结构和函数定义的工作VB.NET代码的适用部分。这显示了结构的适当偏移。在Python中,我能够调用makePPNChart()函数并将它传递给它需要的两个结构byref。结构应该回归。所以,我在Python中部分工作。
<StructLayout(LayoutKind.Explicit)> _
Friend Structure PPNChartSpec
<FieldOffset(0)> Dim dStructVer As Double
<FieldOffset(8)> Dim iNumLanes As Integer
<FieldOffset(12)> Dim iNumCars As Integer
<FieldOffset(16)> Dim iNumRounds As Integer
<FieldOffset(20)> Dim iOptHeatCountEven As Integer
<FieldOffset(24)> Dim iOptAvoidConsecRaces As Integer
<FieldOffset(28)> Dim iOptAvoidRepeatLanes As Integer
End Structure
<StructLayout(LayoutKind.Explicit)> _
Friend Structure PPNChartList
<FieldOffset(0)> Dim dStructVer As Double
<FieldOffset(8)> Dim iUsedAlts As Integer
<FieldOffset(12)> <MarshalAs(UnmanagedType.ByValArray, SizeConst:=15)> _
Dim aiChartType() As Integer
<FieldOffset(76)> <MarshalAs(UnmanagedType.ByValArray, SizeConst:=15)> _
Dim audtChartSpec() As PPNChartSpec
End Structure
<StructLayout(LayoutKind.Explicit)> _
Friend Structure PPNChart
<FieldOffset(0)> Dim dStructVer As Double
<FieldOffset(8)> Dim udtSpec As PPNChartSpec
<FieldOffset(40)> Dim iChartType As Integer
<FieldOffset(44)> Dim iNumLanes As Integer
<FieldOffset(48)> Dim iNumHeats As Integer
<FieldOffset(52)> <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2399)> _
Dim aiCar() As Integer
End Structure
<DllImport("ppn.dll")> _
Friend Shared Function makePPNChart(<MarshalAs(UnmanagedType.Struct)> ByRef spec As PPNChartSpec, <MarshalAs(UnmanagedType.Struct)> ByRef Chart As PPNChart) As Short
End Function
<DllImport("ppn.dll")> _
Friend Shared Function altCharts(<MarshalAs(UnmanagedType.Struct)> ByRef spec As PPNChartSpec, <MarshalAs(UnmanagedType.Struct)> ByRef List As PPNChartList) As Short
End Function
编辑#2:我使用下面的循环检查偏移量。在该结构的定义中添加一个额外的c_long字段,我认为这会使事情恰到好处。但是,如下所示,audtChartSpec结构的偏移量跳至80,而不是预期的76.
for f, t in ppn.PPNChartList._fields_:
a = getattr(ppn.PPNChartList, f)
print(f, a)
dStructVer <Field type=c_double, ofs=0, size=8>
iUsedAlts <Field type=c_long, ofs=8, size=4>
aiChartType <Field type=c_long_Array_15, ofs=12, size=60>
unknown <Field type=c_long, ofs=72, size=4>
audtChartSpec <Field type=PPNChartSpec_Array_15, ofs=80, size=480>
答案 0 :(得分:0)
12 + 15 * 4 72,因此VB.NET结构跳过这4个字节,可能是为了保证数组为空终止。在不知道被调用库的实际结构定义的情况下,很难说。您可以添加一个额外的4字节填充字段。
要控制成员的对齐方式,您可以设置_pack_ = 4
以使它们对齐4字节(the equivalent of #pragma pack(4)
):
class PPNChartList(Structure):
_pack_ = 4
_fields_ = [("dStructVer", c_double),
("iUsedAlts", c_long),
("aiChartType", c_long * 15),
("padding", c_long),
("audtChartSpec", PPNChartSpec * 15)]
现在你应该得到预期的结果,至少在c_long是32位的系统上。