【发布时间】:2021-05-08 21:42:36
【问题描述】:
我必须将 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# struct 中获取 roi 字段的另一种方法。
【问题讨论】:
-
忽略它并手动将其编组到/从原始字节?
-
我不知道该怎么做。这是我第一次尝试从 C# 中使用 C++
-
你知道它是怎么包装的吗?查看您的内部
struct,一个以char开头并具有四个shorts的结构将根据您的打包和对齐方式具有非常不同的布局。看起来您正在将那些shorts映射到bytes。短裤是 16 位,字节是 8 位 -
我已经根据制作的字节更改了 roi 结构 -> ushort。错误仍然存在。
-
我不知道打包,我只有dll和它定义结构的头文件
标签: c# c++ marshalling unmanaged