Marshaling Classes and Structs
Passing a
class or struct to a C function requires marking the struct or class with
the StructLayout
attribute:
// InteropFun.cs - compile with /nowarn:649 or add "=0;" default // initializers to the fields in SystemTime to avoid warnings using System; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] class SystemTime { public ushort wYear; public ushort wMonth; public ushort wDayOfWeek; public ushort wDay; public ushort wHour; public ushort wMinute; public ushort wSecond; public ushort wMilliseconds; } class InteropFun { [DllImport("kernel32.dll")] static extern void GetSystemTime(SystemTime t); static void Main() { SystemTime t = new SystemTime(); GetSystemTime(t); Console.WriteLine(t.wYear); } }
In both C and C#, fields in an object are located at n number
of bytes from the address of that object. The difference is that in a C# program,
the CLR finds this offset by looking it up using the field name; C field names
are compiled directly into offsets. For instance, in C, wDay
is just a token
to represent whatever is at the address of a SystemTime
instance plus 24 bytes.
For access speed and future widening of a data type, these offsets are
usually in multiples of a minimum width, called the pack
size. For .NET types, the pack size is usually set at the discretion
of the runtime, but by using the StructLayout
attribute, field offsets can be controlled. When using this attribute, the default pack size is 8 bytes, but it can be ...
Get C# in a Nutshell now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.