Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping unmanaged data to a managed structure in .NET

I have spent many hours working with unmanaged code, and platform invoke in .NET. The code below illustrates something that is puzzling me regarding how unmanaged data is mapped to a managed object in .NET.

For this example I am going to use the RECT structure:

C++ RECT implementation (unmanaged Win32 API)

typedef struct _RECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT;

C# RECT implementation (managed .NET/C#)

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int left, top, right, bottom;
}

Okay, so my C# equivalent should work, right? I mean, all of the variables are in the same order as the C++ struct, and it's using the same variable names.

My assumption of LayoutKind.Sequential means that the unmanaged data is mapped to the managed object in the same sequence it appears in the C++ structure. i.e. the data will be mapped, starting with left, then top, then right, then bottom.

On this basis I should be able to modify my C# structure...

C# RECT implementation (a bit cleaner)

[StructLayout(LayoutKind.Sequential)]
public struct Rect //I've started by giving it a .NET compliant name
{
    private int _left, _top, _right, _bottom; // variables are no longer directly accessible.

    /* I can now access the coordinates via properties */
    public Int32 Left
    {
        get { return _left; }
        set { this._left = value; }
    }

    public Int32 Top
    {
        get { return _top; }
        set { this._top = value; }
    }

    public Int32 Right
    {
        get { return _right; }
        set { this._right = value; }
    }

    public Int32 Bottom
    {
        get { return _bottom; }
        set { this._bottom = value; }
    }
}

So what happens if the variables are declared in the wrong order? Presumably this screws up the coordinates because they will no longer be mapped to the correct thing?

public struct RECT
{
    public int top, right, bottom, left;
}

At a guess, this would map like so:

top = left

right = top

bottom = right

left = bottom

So my question is simply, Am I correct in my assumption that, I can modify the managed structure in terms of the access specifier of each variable, and even the variable name, but I cannot alter the order of the variables?

like image 352
Matthew Layton Avatar asked Apr 15 '13 10:04

Matthew Layton


1 Answers

If you really want to change the order of your member variables, you can do it by using the FieldOffsetAttribute. Just makes it a little bit less readable.

You'll also need to set your StructLayout to LayoutKind.Explicit to indicate you are setting the offsets yourself.

Example:

[StructLayout(LayoutKind.Explicit)]
public struct RECT
{
    [FieldOffset(4)]  public int top;
    [FieldOffset(8)]  public int right;
    [FieldOffset(12)] public int bottom;
    [FieldOffset(0)]  public int left;
}
like image 109
Botz3000 Avatar answered Nov 11 '22 08:11

Botz3000