Compartir a través de


Ejemplo Unions

Actualización: noviembre 2007

En este ejemplo se demuestra cómo pasar estructuras que sólo contienen tipos de valor y estructuras que contienen un tipo de valor y una cadena como parámetros a una función no administrada que espera recibir una unión. Una unión representa una ubicación de memoria que puede ser compartida por dos o más variables.

En el ejemplo Unions se utiliza la siguiente función no administrada, que se muestra con su declaración de función original:

  • TestUnion exportada desde PinvokeLib.dll.

    void TestUnion(MYUNION u, int type);
    

PinvokeLib.dll es una biblioteca personalizada no administrada que contiene una implementación para la función enumerada anteriormente y dos uniones: MYUNION y MYUNION2. Las uniones contienen los elementos siguientes:

union MYUNION
{
    int number;
    double d;
}

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

En código administrado, las uniones se definen como estructuras. La estructura MyUnion contiene dos tipos de valor como miembros: entero y doble. El atributo StructLayoutAttribute se establece para controlar la posición exacta de cada miembro de datos. El atributo FieldOffsetAttribute proporciona la posición física de los campos dentro de la representación no administrada de una unión. Observe que ambos miembros tienen los mismos valores de desplazamiento, por lo que pueden definir la misma parte de la memoria.

MyUnion2_1 y MyUnion2_2 contienen un tipo de valor (entero) y una cadena, respectivamente. En código administrado no se permite que los tipos de valor y los tipos de referencia se superpongan. En este ejemplo se utiliza la sobrecarga de métodos para permitir que el llamador utilice ambos tipos al llamar a la misma función no administrada. El diseño de MyUnion2_1 es explícito y tiene un valor de desplazamiento preciso. Por el contrario, el diseño de MyUnion2_2 es secuencial, porque no se permiten diseños explícitos con los tipos de referencia. El atributo MarshalAsAttribute establece la enumeración UnmanagedType en ByValTStr, que se utiliza para identificar las matrices de caracteres de longitud fija insertadas que aparecen en la representación no administrada de la unión.

La clase LibWrap contiene los prototipos para los métodos TestUnion y TestUnion2. TestUnion2 se sobrecarga para declarar MyUnion2_1 o MyUnion2_2 como parámetro.

El código fuente de los ejemplos de código siguientes lo proporciona el Ejemplo de tecnología de invocación de plataformas de .NET Framework.

Declaración de prototipos

' 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
// 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 );
}

Llamadas a funciones

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

Vea también

Conceptos

Calcular referencias de clases, estructuras y uniones

Tipos de datos de invocación de plataforma

Crear prototipos en código administrado