使 StructLayout 在类上工作,因为它在结构上工作

Posted

技术标签:

【中文标题】使 StructLayout 在类上工作,因为它在结构上工作【英文标题】:Making a StructLayout over a class working as it works over a struct 【发布时间】:2015-11-10 07:39:30 【问题描述】:

在处理非托管代码时,我想更好地理解结构/类的映射。

我定义了以下结构:

   [StructLayout(LayoutKind.Sequential)]
   public struct ProfileInfo
   
      public int dwSize;
      public int dwFlags;
      [MarshalAs(UnmanagedType.LPTStr)] public string lpUserName;
      [MarshalAs(UnmanagedType.LPTStr)] public string lpProfilePath;
      [MarshalAs(UnmanagedType.LPTStr)] public string lpDefaultPath;
      [MarshalAs(UnmanagedType.LPTStr)] public string lpServerName;
      [MarshalAs(UnmanagedType.LPTStr)] public string lpPolicyPath;
      public IntPtr hProfile;

      public ProfileInfo(string userName, string profilepath)
      
         dwFlags = 1;    
         dwSize = Marshal.SizeOf<ProfileInfo>();
         lpUserName = userName;
         lpServerName = null;
         lpProfilePath = string.IsNullOrWhiteSpace(profilepath) ? null : profilepath;
         lpPolicyPath = null;
         lpDefaultPath = null;
         hProfile = IntPtr.Zero;
      
   

与以下方法一起使用:

      [DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "LoadUserProfileW")]
      public static extern bool LoadUserProfile(IntPtr hToken, ref ProfileInfo lpProfileInfo);

虽然只要ProfileInfo 是一个结构,它就可以很好地工作,但当我将ProfileInfo 设为一个类时,LoadUserProfile 开始失败。

我只是想知道为什么? 对我来说,StructLayout 以相同的方式应用于类或结构。

当我将其从 struct 更改为 class 时,导致 LoadUserProfile 失败的 ProfileInfo 的内存表示可能存在哪些差异?

【问题讨论】:

我的水晶球说您忘记从参数声明中删除 ref 关键字。必需,因为类对象总是通过引用传递。在 SO 提出问题的最明智方法是发布不起作用的代码。 【参考方案1】:

在 C++ 中,类包含一个隐藏的“this”指针。我猜 C# 做同样的事情。

在下图中,pi 是一个结构体,p2 是一个类。您可以从内存转储中看到(左侧为 p,右侧为 p2),p2 有一些额外的字节,即隐藏指针。

【讨论】:

以上是关于使 StructLayout 在类上工作,因为它在结构上工作的主要内容,如果未能解决你的问题,请参考以下文章

JPA,Hibernate:在现有工作 DTO 中添加新变量时“无法在类上找到适当的构造函数”

Firestore:在类上找不到要序列化的属性

在类上配置别名有啥需要?

为啥无法在类上找到适当的构造函数

Jquery在类上制作动画

无法在类上找到适当的构造函数