简体   繁体   English

C#:编组包含数组的结构

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM