Unions Sample

This sample demonstrates how to pass structures containing only value types, and structures containing a value type and a string as parameters to an unmanaged function expecting a union. A union represents a memory location that can be shared by two or more variables. The Microsoft .NET Framework SDK includes the complete Visual Basic .NET and C# versions of this sample in Samples\Technologies\Interop\Platform-Invoke.

The Unions sample uses the following unmanaged function, shown with its original function declaration:

  • TestUnion exported from PinvokeLib.dll.

    void TestUnion(MYUNION u, int type);
    

PinvokeLib.dll is a custom unmanaged library that contains an implementation for the previously listed function and two unions, MYUNION and MYUNION2. The unions contain the following elements:

union MYUNION
{
    int number;
    double d;
}

union MYUNION2
{
    int i;
    char str[128];
};

In managed code, unions are defined as structures. The MyUnion structure contains two value types as its members: an integer and a double. The StructLayoutAttribute attribute is set to control the precise position of each data member. The FieldOffsetAttribute attribute provides the physical position of fields within the unmanaged representation of a union. Notice that both members have the same offset values, so the members can define the same piece of memory.

MyUnion2_1 and MyUnion2_2 contain a value type (integer) and a string, respectively. In managed code, value types and reference types are not permitted to overlap. This sample uses method overloading to enable the caller to use both types when calling the same unmanaged function. The layout of MyUnion2_1 is explicit and has a precise offset value. In contrast, MyUnion2_2 has a sequential layout, because explicit layouts are not permitted with reference types. The MarshalAsAttribute attribute sets the UnmanagedType enumeration to ByValTStr, which is used to identify the inline, fixed-length character arrays that appear within the unmanaged representation of the union.

The LibWrap class contains the prototypes for the TestUnion and TestUnion2 methods. TestUnion2 is overloaded to declare MyUnion2_1 or MyUnion2_2 as parameters.

Declaring Prototypes

' Declares managed structures instead of unions.
< StructLayout( LayoutKind.Explicit )> _
Public Structure MyUnion
   < FieldOffset( 0 )> Public i As Integer
   < FieldOffset( 0 )> Public d As Double
End Structure 'MyUnion

< StructLayout( LayoutKind.Explicit, Size := 128 )> _
Public Structure MyUnion2_1
   < FieldOffset( 0 )> Public i As Integer
End Structure 'MyUnion2_1

< StructLayout( LayoutKind.Sequential )> _
Public Structure MyUnion2_2
   < MarshalAs( UnmanagedType.ByValTStr, SizeConst := 128 )> _
   Public str As String
End Structure 'MyUnion2_2

Public Class LibWrap
   ' Declares managed prototypes for unmanaged function.
   Declare Sub TestUnion Lib "..\LIB\PinvokeLib.dll" ( _
      ByVal u As MyUnion, ByVal type As Integer )
   Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
      ByVal u As MyUnion2_1, ByVal type As Integer )
   Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
      ByVal u As MyUnion2_2, ByVal type As Integer )
End Class 'LibWrap
[C#]// Declares managed structures instead of unions.
[ StructLayout( LayoutKind.Explicit )]
public struct MyUnion 
{
   [ FieldOffset( 0 )]
   public int i;
   [ FieldOffset( 0 )]
   public double d;
}
[ StructLayout( LayoutKind.Explicit, Size=128 )]
public struct MyUnion2_1 
{  
   [ FieldOffset( 0 )]
   public int i;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnion2_2 
{  
   [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )] 
   public String str;
}

public class LibWrap
{
   // Declares managed prototypes for unmanaged function.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestUnion( MyUnion u, int type );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestUnion2( MyUnion2_1 u, int type );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestUnion2( MyUnion2_2 u, int type );
}

Calling Functions

Public Class App
   Public Shared Sub Main()
      Dim mu As New MyUnion()
      mu.i = 99
      LibWrap.TestUnion( mu, 1 )
      
      mu.d = 99.99
      LibWrap.TestUnion( mu, 2 )
      
      Dim mu2_1 As New MyUnion2_1()
      mu2_1.i = 99
      LibWrap.TestUnion2( mu2_1, 1 )
      
      Dim mu2_2 As New MyUnion2_2()
      mu2_2.str = "*** string ***"
      LibWrap.TestUnion2( mu2_2, 2 )
   End Sub 'Main
End Class 'App
[C#]public class App
{
   public static void Main()
   {
      MyUnion mu = new MyUnion();
      mu.i = 99;
      LibWrap.TestUnion( mu, 1 );
      
      mu.d = 99.99;
      LibWrap.TestUnion( mu, 2 );
      
      MyUnion2_1 mu2_1 = new MyUnion2_1();
      mu2_1.i = 99;
      LibWrap.TestUnion2( mu2_1, 1 );
      
      MyUnion2_2 mu2_2 = new MyUnion2_2();
      mu2_2.str = "*** string ***";
      LibWrap.TestUnion2( mu2_2, 2 );
   }
}

See Also

Marshaling Classes, Structures, and Unions | Platform Invoke Data Types | Creating Prototypes in Managed Code