views:

15

answers:

1

For test purpose, I want to compare two structs (of unknown type T) marshaled from unmanaged code.

Because they may contain some packing in unmanaged representation, it is inappropriate to convert whole struct to byte array and then compare byte by byte:

int       size    = Marshal.SizeOf(typeof(T));
IntPtr    buf1    = Marshal.AllocHGlobal(size); // FreeHGlobal omitted for simplicity
IntPtr    buf2    = Marshal.AllocHGlobal(size);
byte[]    array1  = new byte[size];
byte[]    array2  = new byte[size];
Marshal.StructureToPtr(st1, buf1, false);
Marshal.StructureToPtr(st2, buf2, false);
Marshal.Copy(buf1, array1, 0, size);
Marshal.Copy(buf2, array2, 0, size);

// inapropriate
for (int i = 0; i < size; ++i)
{
    if (array1[i] != array2[i]) { return false; }
}
return true;

I think it is necessary to compare field by field.

Thanks to reflection, I can enumerate FieldInfo, and then using Marshal.OffsetOf method I can get offsets of the fields.

Unfortunately, however, I have no idea how to get sizes of the fields. Without it I think I can't compare two fields eliminating the effect of packing.

foreach (var fieldInfo in typeof(T).GetFields())
{
    int offset     = (int)Marshal.OffsetOf(typeof(T), fieldInfo.Name);
    int fieldSize  = ...;        // I need this
    for (int i = offset; i < offset + fieldSize; ++i)
    {
        if (array1[i] != array2[i]) { return false; }
    }
}
return true;

Is there any way to accomplish this? Or Is there better way to compare the unmanaged structs?

Note: Field types are arbitrary (may be primitive integers, arrays, strings, enums, structs, etc).

A: 

Can you use Marshal.SizeOf(fieldInfo.FieldType)?

Also, might the two structs be packed differently? Because if they're not, doesn't the packing become irrelevant? Can you give an example of where packing means that a direct byte-by-byte comparison gives you the wrong answer? I'm assuming that when the memory is allocated, it's zeroed out - so any unused bytes (due to padding) will be zero and thus equal in both arrays.

Jon Skeet