Condividi tramite


Esempio di unioni

Aggiornamento: novembre 2007

In questo esempio viene dimostrato come passare le strutture contenenti solo tipi di valore e le strutture contenenti un tipo di valore e una stringa come parametri a una funzione non gestita per la quale è prevista un'unione. L'unione rappresenta un percorso di memoria che può essere condiviso da due o più variabili.

Nell'esempio di unioni viene utilizzata la seguente funzione non gestita, illustrata con la dichiarazione di funzione originale:

  • TestUnion esportata da PinvokeLib.dll.

    void TestUnion(MYUNION u, int type);
    

PinvokeLib.dll è una libreria non gestita personalizzata contenente un'implementazione per la funzione elencata in precedenza e due unioni, MYUNION e MYUNION2. Le unioni contengono i seguenti elementi:

union MYUNION
{
    int number;
    double d;
}

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

Nel codice gestito, le unioni sono definite come strutture. La struttura MyUnion contiene due tipi di valore come membri, ovvero un integer e un double. L'attributo StructLayoutAttribute viene impostato in modo da controllare l'esatta posizione di ciascun membro dati. L'attributo FieldOffsetAttribute fornisce la posizione fisica dei campi all'interno della rappresentazione non gestita di un'unione. Poiché entrambi hanno gli stessi valori di offset, i membri possono definire la stessa porzione di memoria.

MyUnion2_1 e MyUnion2_2 contengono rispettivamente un tipo di valore (integer) e una stringa. Nel codice gestito i tipi di valore e quelli di riferimento non possono sovrapporsi. In questo esempio l'overload dei metodi consente al chiamante di utilizzare entrambi i tipi nella chiamata alla stessa funzione non gestita. Il layout di MyUnion2_1 è esplicito e ha un valore di offset preciso. Al contrario, MyUnion2_2 ha un layout sequenziale, poiché i layout espliciti non sono consentiti con i tipi di riferimento. L'enumerazione UnmanagedType viene impostata dall'attributo MarshalAsAttribute su ByValTStr, che consente di identificare le matrici di caratteri inline a lunghezza fissa presenti nella rappresentazione non gestita di un'unione.

La classe LibWrap contiene i prototipi per i metodi TestUnion e TestUnion2. TestUnion2 viene sottoposto a overload allo scopo di dichiarare MyUnion2_1 o MyUnion2_2 come parametri.

Il codice sorgente per gli esempi di codice riportati di seguito è fornito dall'Esempio di tecnologia di richiamo piattaforma di .NET Framework.

Dichiarazione dei prototipi

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

Chiamata delle funzioni

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

Vedere anche

Concetti

Marshalling di classi, strutture e unioni

Tipi di dati del richiamo piattaforma

Creazione di prototipi nel codice gestito