views:

32

answers:

1

I am trying to properly Marshal some structs for a P/Invoke, but am finding strange behavior when testing on a 64 bit OS.

I have a struct defined as:

/// <summary>http://msdn.microsoft.com/en-us/library/aa366870(v=VS.85).aspx&lt;/summary&gt;
[StructLayout(LayoutKind.Sequential)]
private struct MIB_IPNETTABLE
{
    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dwNumEntries;
    public IntPtr table; //MIB_IPNETROW[]
}

Now, to get the address of the table, I would like to do a Marshal.OffsetOf() call like so:

IntPtr offset = Marshal.OffsetOf(typeof(MIB_IPNETTABLE), "table");

This should be 4 - I have dumped the bytes of the buffer to confirm this as well as replacing the above call with a hard coded 4 in my pointer arithmetic, which yielded correct results.

I do get the expected 4 if I instantiate MIB_IPNETTABLE and perform the following call:

IntPtr offset = (IntPtr)Marshal.SizeOf(ipNetTable.dwNumEntries);

Now, in a sequential struct the offset of a field should be sum of the sizes of preceding fields, correct? Or is it the case that when it is an unmanaged structure the offset really is 8 (on an x64 system), but becomes 4 only after Marshalling magic? Is there a way to get the OffsetOf() call to give me the correct offset? I can limp along using calls to SizeOf(), but OffsetOf() is simpler for larger structs.

+2  A: 

In a 64-bit C/C++ build the offset of your table field would be 8 due to alignment requirements (unless you forced it otherwise). I suspect that the CLR is doing the same to you:

The members of the object are laid out sequentially, in the order in which they appear when exported to unmanaged memory. The members are laid out according to the packing specified in StructLayoutAttribute.Pack, and can be noncontiguous.

you may wnat to use that attribute or use the LayoutKind.Explicit attribute along with the FieldOffset attribute on each field if you need that level of control.

Michael Burr
Thank you for confirming my suspicions on unmanaged alignment. Explicit Layout with FieldOffset is what I am looking for.
Mike S