2

I would like to better understand the mapping of structs/classes when it comes to deal with unmanaged code.

I have defined the following struct:

   [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;
      }
   }

to be used with the folling method:

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

While it works great as long as ProfileInfo is a struct, LoadUserProfile starts failing when I make ProfileInfo a class.

I just wondered why ?
To me the StructLayout was applied the same way over a class or struct.

What are the possible differences of memory representation of ProfileInfo that makes LoadUserProfile fails when I change it from struct to class ?

John-Philip
  • 3,392
  • 2
  • 23
  • 52
  • 2
    My crystal ball says that you forgot to remove the `ref` keyword from the argument declaration. Required because class objects are always passed by reference. Smartest way to ask a question at SO is by posting the code that *doesn't* work. – Hans Passant Aug 17 '15 at 15:43

1 Answers1

-1

In C++, classes contain a hidden 'this' pointer. I am guessing C# does the same thing.

In the image below, pi is a struct, p2 is a class. You can see from the memory dumps (pi on the left, p2 on the right) that p2 has some extra bytes which is the hidden pointer.

enter image description here

Steve Wellens
  • 20,506
  • 2
  • 28
  • 69