[英]C#: marshalling a struct that contains arrays
I am doing some C# interop work.我正在做一些 C# 互操作工作。 I have the following struct:
我有以下结构:
#pragma pack(push,1)
typedef struct
{
unsigned __int64 Handle;
LinkType_t Type;
LinkState_t State;
unsigned __int64 Settings;
signed __int8 Name[MAX_LINK_NAME];
unsigned __int8 DeviceInfo[MAX_LINK_DEVINFO];
unsigned __int8 Reserved[40];
} LinkInfo_t;
This is my attempt to convert it into a C# struct:这是我将其转换为 C# 结构的尝试:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LinkInfo_t
{
[MarshalAs(UnmanagedType.U8)]
public UInt64 Handle;
MarshalAs(UnmanagedType.I4)]
public LinkType_t Type;
[MarshalAs(UnmanagedType.I4)]
public LinkState_t State;
[MarshalAs(UnmanagedType.U8)]
public UInt64 Settings;
[MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_LINK_NAME)]
public string Name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_LINK_DEVINFO, ArraySubType = UnmanagedType.U1)]
public byte[] DeviceInfo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U1)]
public byte[] Reserved;
}
However, whenever I initialize the struct the Name, DeviceInfo, and Reserved fields are all set to null.但是,每当我初始化结构时,Name、DeviceInfo 和 Reserved 字段都设置为 null。 How do I fix this?
我该如何解决?
For the arrays, try to use the fixed
keyword:对于数组,尝试使用
fixed
关键字:
public fixed byte DeviceInfo[MAX_LINK_DEVINFO];
public fixed byte Reserved[40];
whenever I initialize the struct the Name, DeviceInfo, and Reserved fields are all set to null
每当我初始化结构时,Name、DeviceInfo 和 Reserved 字段都设置为 null
This is correct, and your definition looks OK to me (BTW, you don't need [MarshalAs]
on the primitive fields, the default behaviour is to do what you specified there).这是正确的,你的定义对我来说看起来没问题(顺便说一句,原始字段上不需要
[MarshalAs]
,默认行为是执行你在那里指定的操作)。 Because your array fields are null
, the marshaler won't do anything about them when marshaling your struct to unmanaged memory, but it's going to create the strings and arrays when unmarshaling.因为您的数组字段是
null
,所以在将您的结构编组到非托管内存时,封送拆收器不会对它们做任何事情,但它会在解组时创建字符串和数组。
What Anton Tykhyy says is correct. Anton Tykhyy 说的是正确的。 I just want to clarify with some examples.
我只想用一些例子来澄清。 Using 'fixed' works, but that forces you to use 'unsafe' as well.
使用“fixed”是有效的,但这也迫使你使用“unsafe”。 I like to avoid using unsafe wherever possible.
我喜欢尽可能避免使用 unsafe。 Using Marshal is a way to get around that.
使用 Marshal 是解决这个问题的一种方法。
First, let's say that I have a library that was created in C with the following definitions.首先,假设我有一个用 C 创建的库,定义如下。
typedef struct {
int messageType;
BYTE payload[60];
} my_message;
/**
* \param[out] msg Where the message will be written to
*/
void receiveMessage(my_message *msg);
/*
* \param[in] msg The message that will be sent
*/
void sendMessage(my_message *msg);
In C#, the following structure would be equivalent to the one in C.在 C# 中,以下结构等同于 C 中的结构。
[StructLayout(LayoutKind.Sequential, Size = 64), Serializable]
struct my_message
{
int messageType;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 60)]
byte[] payload;
public initializeArray()
{
//explicitly initialize the array
payload = new byte[60];
}
}
Since the msg in receiveMessage() is documented as [out], you don't need to do anything special to the array in the structure before passing it to the function.由于 receiveMessage() 中的 msg 被记录为 [out],因此在将其传递给函数之前,您无需对结构中的数组进行任何特殊处理。 ie:
IE:
my_message msg = new my_message();
receiveMessage(ref msg);
byte payload10 = msg.payload[10];
Since the msg in sendMessage() is documented as [in], you will need to fill the array before calling the function.由于 sendMessage() 中的 msg 被记录为 [in],因此您需要在调用该函数之前填充该数组。 Before filling the array, the array needs to be explicitly instantiated before using it.
在填充数组之前,数组需要在使用前显式实例化。 ie:
IE:
my_message msg = new my_message();
msg.initializeArray();
msg.payload[10] = 255;
sendMessage(ref msg);
Calling initializeArray() should instantiate the array in the previously allocated space created within the struct for this array.调用 initializeArray() 应该在为该数组的结构中创建的先前分配的空间中实例化该数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.