我们要在x64应用程序中调用C ++函数:https://www.inventcom.net/fanuc-focas-library/misc/cnc_diagnoss
我们需要将ODBDGN结构传递给该函数。此结构中具有联合,因此在c#中我们无法定义联合,我们需要这样做:
[StructLayout(LayoutKind.Explicit, Pack=4)]
public class ODBDGN
{
[FieldOffset(0)]
public short datano; /* data number */
[FieldOffset(2)]
public short type; /* axis number */
[FieldOffset(4),
MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public byte[] cdatas;
[FieldOffset(4),
MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public short[] idatas;
[FieldOffset(4),
MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public int[] ldatas;
}
在32位应用程序中,初始化此结构可以正常工作。
Int 64位应用程序,初始化此结构不起作用并引发此错误:
System.TypeLoadException
HResult=0x80131522
Message=Impossible de charger le type 'ODBDGN' à partir de l'assembly 'CommunicationFanuc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null', car il contient un champ objet à l'offset '4' qui n'est pas correctement aligné ou qui est chevauché par un champ non objet.
Source=CommunicationFanuc
StackTrace:
at CommunicationFanuc.DiagnosticAddress.Read() in D:\Projets\PMM2.0\CommunicationFanuc\Addresses\Channel\Diagnostic\DiagnosticAddress.cs:line 98
at CommunicationFanuc.Tests.PtmFocasEthernet.ReadDiagnostic() in D:\Projets\PMM2.0\CommunicationFanuc.Tests\Ethernet\PtmFocasEthernet.cs:line 809
我了解在x64应用程序中,默认Pack值为8,所以偏移量必须为8而不是4:
[StructLayout(LayoutKind.Explicit)]
public class ODBDGN
{
[FieldOffset(0)]
public short datano; /* data number */
[FieldOffset(2)]
public short type; /* axis number */
[FieldOffset(8),
MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public byte[] cdatas;
[FieldOffset(8),
MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public short[] idatas;
[FieldOffset(8),
MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public int[] ldatas;
}
但是,如果我们调用cnc_diagnoss C ++函数,则在结构中,我们缺少type
和cdatas
之间的2个八位位组
但是当我们这样声明结构时:
[StructLayout(LayoutKind.Sequential)]
public class ODBDGN_Byte
{
public short datano;
public short type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public byte[] cdatas;
}
这有效(不是联合,但如果数据为字节),则type
和cdatas
之间没有任何缺失
在这种情况下,datano
的偏移量为0 type
的偏移量为2,而cdatas
的偏移量为4
那么在这种情况下为什么不能创建显式布局?我不明白这是怎么回事...
答案 0 :(得分:1)
这里的问题很常见。您的基本经验法则是,如果您使用FieldOffset
,则偏移量为0
。换句话说,您将复制C ++联合。这使您可以最紧密地映射到C ++类型的声明方式,并允许p / invoke marsaller正确对齐结构,而无需手动进行。这确实意味着要引入额外的类型,但这是值得的。它是这样的:
[StructLayout(LayoutKind.Explicit)]
public struct ODBDGN_CODE
{
[FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public byte[] cdatas;
[FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public short[] idatas;
[FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public int[] ldatas;
}
[StructLayout(LayoutKind.Sequential)]
public class ODBDGN
{
public short datano;
public short type;
public ODBDGN_CODE code;
}
就我个人而言,尽管我认为在这里使用工会并没有必要。另一种选择是这样声明:
[StructLayout(LayoutKind.Sequential)]
public class ODBDGN
{
public short datano;
public short type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
public byte[] code;
}
然后将帮助程序方法添加到该类,该方法允许用户使用其他基本类型的数组获取并设置代码字段。辅助方法将在short[]
和byte[]
之间以及int[]
和byte[]
之间转换。