将非托管数据映射到.NET中的托管结构

ser*_*0ne 7 .net c# pinvoke winapi unmanaged

我花了很多时间处理非托管代码,并在.NET中调用平台.下面的代码说明了一些令我困惑的问题,即如何将非托管数据映射到.NET中的托管对象.

对于这个例子,我将使用RECT结构:

C++ RECT实现(非托管Win32 API)

typedef struct _RECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT;
Run Code Online (Sandbox Code Playgroud)

C#RECT实现(托管.NET/C#)

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

好的,所以我的C#等效应该可以工作,对吧?我的意思是,所有变量的顺序与C++结构相同,并且它使用相同的变量名.

我的假设LayoutKind.Sequential意味着非托管数据以与C++结构中出现的相同顺序映射到托管对象.即数据将被映射,从左侧开始,然后是顶部,然后是右侧,然后是底部.

在此基础上我应该能够修改我的C#结构......

C#RECT实现(更清洁一点)

[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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

那么如果变量以错误的顺序声明会发生什么呢?大概这会搞砸坐标,因为它们将不再映射到正确的东西?

public struct RECT
{
    public int top, right, bottom, left;
}
Run Code Online (Sandbox Code Playgroud)

猜测一下,这会映射如下:

顶部=左边

对=顶部

bottom = right

左=底

所以我的问题很简单,我的假设是正确的,我可以根据每个变量的访问说明符,甚至变量名修改托管结构,但我不能改变变量的顺序?

Bot*_*000 7

如果您确实想要更改成员变量的顺序,可以使用FieldOffsetAttribute.只是让它的可读性稍差一点.

您还需要将自己StructLayout设置LayoutKind.Explicit为表示您自己设置偏移量.

例:

[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;
}
Run Code Online (Sandbox Code Playgroud)