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 ...
Get C# in a Nutshell, Second Edition 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.