简体   繁体   中英

How to reserve an array of memory type for pinvoke

I need to use this Kernel32 structure: NUMA_NODE_RELATIONSHIP

But the Reserved field is declared as: BYTE Reserved[20];

To declare the structure properly, is there a better way than declaring:

public struct NUMA_NODE_RELATIONSHIP
{
    public UInt16 NodeNumber;
    public BYTE Reserved1;
    public BYTE Reserved2;
    ...
    public BYTE Reserved20;
    public GROUP_AFFINITY GroupMask;
}

or using:

[StructLayout(LayoutKind.Explicit)]
public struct NUMA_NODE_RELATIONSHIP2
{
    [FieldOffset(0)]
    public UInt16 NodeNumber;
    // [FieldOffset(2)] // **
    // public byte Reserved;
    [FieldOffset(22)] 
    public GROUP_AFFINITY GroupMask;
}

** I'm not sure my code is ok... Here FieldOffset is a byte offset or multiple of OS word size (32 or 64 bits)? Does the WIN32 API pad align struct fields and if so, how? If both are padded or both are not padded, I'm fine, otherwise my code is bugged. That is not my main question. That insert is there only to mention that my code is not necessarily working as it is written. My main question is this one:

What is the best way to declare a pinvoke struct with an array in it? I wonder if both will be fine, which one is preferred and/or if there is a better way of declaring that struct because both way I used add artifacts that make it long to write and/or harder to understand.

The WinAPI aligns most small types at their natural size, so WORD at 16 bits and DWORD at 32 bits. BYTE, being one byte, isn't aligned. Padding is inserted where needed to achieve the proper alignment for the next member.

What makes it tricky here is the aligment of GROUP_AFFINITY . I think it's 2 bytes because all its members are WORD .

The second reason I think that it's 2 byte aligned is because Microsoft tends to name its padding (!). If there was 2 bytes of unnamed padding after Reserved , Microsoft would have made it BYTE reserved[22] instead.

And yes, .Net field offsets are in bytes too.

Declare it like this:

[StructLayout(LayoutKind.Sequential)]
public struct NUMA_NODE_RELATIONSHIP
{
    public uint NodeNumber;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public byte[] Reserved;
    public GROUP_AFFINITY GroupMask;
}

There's no need for explicit layout. It makes more sense to let the marshaler lay out the struct using the same rules as the C++ compiler. Especially as GROUP_AFFINITY has alignment of 4 or 8 bytes depending on the machine pointer size. Obviously the above relies on you getting GROUP_AFFINITY right.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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