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

时间:2009-09-21 15:15:21

标签: c# interop marshalling

我正在做一些C#互操作工作。我有以下结构:

#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;

这是我尝试将其转换为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;
}

但是,每当我初始化struct时,Name,DeviceInfo和Reserved字段都被设置为null。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:7)

对于数组,请尝试使用fixed关键字:

public fixed byte DeviceInfo[MAX_LINK_DEVINFO];
public fixed byte Reserved[40];

答案 1 :(得分:3)

  

每当我初始化结构时   名称,DeviceInfo和保留字段   都被设置为null

这是正确的,你的定义看起来没问题(顺便说一句,你在原始字段上不需要[MarshalAs],默认行为是做你在那里指定的)。因为你的数组字段是null,所以编组器在将你的结构编组到非托管内存时不会对它们做任何事情,但它会在解组时创建字符串和数组。

答案 2 :(得分:1)

Anton Tykhyy所说的是正确的。我只是想用一些例子来澄清。使用“固定”作品,但这也迫使你使用“不安全”。我希望尽可能避免使用不安全的东西。使用Marshal可以解决这个问题。

首先,假设我有一个使用以下定义在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);

在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];
    }
}

由于receiveMessage()中的msg被记录为[out],因此在将结果传递给函数之前,不需要对结构中的数组执行任何特殊操作。即:

my_message msg = new my_message();
receiveMessage(ref msg);
byte payload10 = msg.payload[10];

由于sendMessage()中的msg记录为[in],因此在调用函数之前需要填充数组。在填充数组之前,需要在使用数组之前显式地实例化该数组。即:

my_message msg = new my_message();
msg.initializeArray();
msg.payload[10] = 255;
sendMessage(ref msg);

调用initializeArray()应该在先前为此数组的struct的结构中创建的数组中实例化数组。