c# - C++ 到 C# 使用联合对嵌套结构进行编组
问题描述
我必须将 C++ .dll 与 C# 代码一起使用。我需要调用一个方法:
THERMALSDK_API short PASCAL GetIRHeaders(HANDLE handle, IRF_IR_FILE_HEADER_T* header, IRF_IR_DATA_HEADER_T* addedInfo, unsigned long *curPos);
为此,我创建了一个简单的包装器:
public class COXAccessor : ICOXAccessor
{
[DllImport("ThermalCamDll", CallingConvention = CallingConvention.StdCall, ExactSpelling = false,
EntryPoint = "GetIRHeaders")]
private static extern ReturnCode GetIRHeaders(out IntPtr handle, out IRF_IR_FILE_HEADER_T header, out IRF_IR_DATA_HEADER_T addedInfo, out uint curPos);
public ReturnCode GetIRHeadersInternal(out IntPtr handle, out IRF_IR_FILE_HEADER_T header,
out IRF_IR_DATA_HEADER_T addedInfo, out uint curPos)
{
return GetIRHeaders(out handle, out header, out addedInfo, out curPos);
}
}
如您所见,此方法需要传入的对象很少。其中最复杂的是 IRF_IR_DATA_HEADER_T 和嵌套结构 IRF_SAVEDATA_T:
/* Structure of IR data header */
typedef struct
{
BYTE dynamic_range; // IRF_DYNAMIC_RANGE_T
IRF_SAVEDATA_T save_data; // Cam data in CAM_DATA
BYTE reserved[460];
} IRF_IR_DATA_HEADER_T;
IRF_SAVEDATA_T(部分):
typedef struct strSAVEDATA
{
union {
struct
{
unsigned int crc; // CRC Data
unsigned char ver; // Setup Data Version ( CG Model : 0x20 )
unsigned char sensor; // Sensor Type ( 0x00 : CX320, 0x01 : CX640, 0x20 : CG QVGA, 0x21 : CG VGA )
unsigned char show_isotherm; // CX Model Only
unsigned char alarm1_duration; // CX Model Only
unsigned char alarm2_duration; // CX Model Only
struct {
unsigned char flag; // ROI Function Mask ( 0x01 : Enable, 0x02 : Exclude )
unsigned short x1; // Position (x2)
unsigned short y1; // Position (x2)
unsigned short x2; // Position (x2)
unsigned short y2; // Position (x2)
} roi[2]; // CX Model Only
};
unsigned char reserved1[128];
};
} IRF_SAVEDATA_T;
我知道 C# 不支持联合,替代它们的方法是使用 FieldOffset 属性。所以我像这样重新创建了这个结构:
[StructLayout(LayoutKind.Explicit)]
public struct IRF_SAVEDATA_T
{
[FieldOffset(0)] public uint crc;
[FieldOffset(0)] public byte ver;
[FieldOffset(0)] public byte sensor;
[FieldOffset(0)] public byte show_isotherm;
[FieldOffset(0)] public byte alarm1_duration;
[FieldOffset(0)] public byte alarm2_duration;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] [FieldOffset(0)] public roi[] roi;
但是当我尝试启动程序时会弹出一个错误:
TypeLoadException:无法加载类型“XXX.IRF_SAVEDATA_T”,因为它包含偏移量 0 处的对象字段,该字段未正确对齐或被非对象字段重叠
我认为错误的来源是:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] [FieldOffset(0)] public roi[] roi;
为了在 C# 中重新创建这个初始化数组 roi 的匿名结构,我创建了新结构:
[StructLayout(LayoutKind.Sequential)]
public struct roi
{
/// <summary>
/// ROI Function Mask ( 0x01 : Enable, 0x02 : Exclude )
/// </summary>
public byte flag;
/// <summary>
/// Position (x2)
/// </summary>
public ushort x1;
/// <summary>
/// Position (x2)
/// </summary>
public ushort y1;
/// <summary>
/// Position (x2)
/// </summary>
public ushort x2;
/// <summary>
/// Position (x2)
/// </summary>
public ushort y2;
}
我认为这是错误的,但我不知道在 C# 结构中获取 roi 字段的另一种方法。
解决方案
忘记联合,在这种情况下它什么都不做,只是在最后添加填充。填充显然很重要,但是您可以通过计算字节数并确保您的结构至少为 128 个字节(这是第二个联合部分将其设置为)来自己填充它。
这将大大简化您的定义,不再FieldOffset
需要任何地方,您可以像平常一样定义您的字段。
推荐阅读
- ios - 多个故事板:它们应该有多小?
- c++ - VS 2017 - 带有版本信息(资源)的 C++ DLL 的 MSBuild 不起作用(致命错误 LNK1158:无法运行“cvtres.exe”)
- python - 我无法理解 keras 中的 skipgrams() 函数
- vba - 运行时错误 91 对象变量或未设置变量
- python - 如何设置numpy并行度?
- c# - C# Make Tree Node text 可下载链接
- java - java中带有hibernate的通用dao
- android - 协程 Android 4.1:阻塞队列后后续启动不起作用
- python - 我的 RunPE 中的 0xC0000005 错误与 python
- redis - 重新启动服务器后,所有密钥都会在 REDIS 中清除