1

So its pretty simple issue

[StructLayout(LayoutKind.Sequential)]
public struct test
{
    public uint a;
}

^ This marshals to size of 4

[StructLayout(LayoutKind.Sequential)]
public struct test
{
    public IntPtr b;
}

^ This marshals to size of 8

[StructLayout(LayoutKind.Sequential)]
public struct test
{
    public uint a;
    public IntPtr b;
}

^ This marshals to size of 16

Now I'm not sure if my calculator is broken or something but I'm pretty sure 8+4 isnt 16..... Is there any reason this nonsense is taking place?

I need it to produce the correct size for use with windows API calls

Well I'm trying to call "NtQueryInformationThread" and my struct is invalid for that here is the structure:

    [StructLayout(LayoutKind.Sequential)]
    public struct TbiClientId
    {
        public IntPtr UniqueProcess;
        public IntPtr UniqueThread;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct ThreadBasicInformation
    {
        public uint ExitStatus;
        public IntPtr TebBaseAdress;
        public int ProcessId;
        public TbiClientId ClientId;
        public UIntPtr AffinityMask;
        public uint Priority;
        public uint BasePriority;
    }

Under marshal.sizeof this comes out as 56 yet the API only accepts 48 if I pass 48 to the API it returns a success and fills the struct....

UberFoX
  • 43
  • 5
  • 1
    The compiler uses alignment. – Vlad from Moscow Feb 11 '21 at 22:25
  • 16 is the correct size for winapi calls. Google "structure member alignment" and "structlayoutattribute.pack" to learn more. – Hans Passant Feb 11 '21 at 22:25
  • Correct maybe but NtQueryInformationThread is not accepting 56 of the marshal size... only 48 as which is the number of my struct values directly. When I add "Pack = 1" to the struct then its accepted is this API just odd? – UberFoX Feb 11 '21 at 22:42
  • Not a duplicate of the question marked duplicate. Related topic, answers cover a lot of the same points, but very different questions. – Kevin Krumwiede Feb 11 '21 at 22:47
  • int ProcessId is not actually present in this undocumented struct. Delete it and you'll get 48. – Hans Passant Feb 11 '21 at 22:59

1 Answers1

3

A uint is a 32-bit type. An IntPtr is platform-dependent, and will be 64-bit on 64-bit platforms.

For the 3rd example, struct members are aligned to certain boundaries to make memory access more efficient, which in this case appears to be on 8-byte boundaries. You can modify this using the Pack attribute.

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct test
{
    public uint a;
    public IntPtr b;
}
geofftnz
  • 9,954
  • 2
  • 42
  • 50