Reputation: 42340
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?
Upvotes: 7
Views: 1686
Reputation: 613322
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?
Yes, that is correct. Neither the access specifier, nor the variable name has any impact on the way the struct is laid out.
Upvotes: 0
Reputation: 39630
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;
}
Upvotes: 7
Reputation: 6698
The default mapping of a struct
in C# is LayoutKind.Sequential
. This prevents the compiler from optimizing memory by rearranging the variables and assure correct mapping.
You may however tell the compiler a different order of the variables by using LayoutKind.Explicit
, and FieldOffsetAttribute
:
[StructLayout(LayoutKind.Explicit)]
public struct Rect
{
[FieldOffset(8)]
public int right;
[FieldOffset(4)]
public int top;
[FieldOffset(0)]
public int left;
[FieldOffset(12)]
public int bottom;
}
The value of the FieldOffsetAttribute
indicates the byte position in the struct of the start of the variable.
Upvotes: 1
Reputation: 3379
Yes, it seems that your thinking is OK. StructLayout(LayoutKind.Sequential)
is the default value applied to C# struct
so you don't even need to do this. But if you would like to have different order of fields you can do this by using StructLayout(LayoutKind.Explicite)
and then apply FieldOffset
attribute to each field - this is much better approach since you make explicite what is implicite and no longer are you depending on something that can easly be changed like field definition order.
Take a look at MSDN sample: StructLayoutAttribute Class
and it should be clearer. Also - create sample application in C++ and C# and play with it to get a hang of it - it will benefit you greatly.
Upvotes: 2