Esempio di strutture

In questo esempio viene dimostrato come passare una struttura che punta a una seconda struttura, una struttura con una struttura incorporata e una struttura con una matrice incorporata. Nell'SDK di Microsoft .NET Framework sono incluse le versioni complete di Visual Basic .NET e C# di questo esempio in Samples\Technologies\Interop\Platform-Invoke.

Nell'esempio di strutture vengono utilizzate le seguenti funzioni non gestite, illustrate con le dichiarazioni di funzione originali:

  • TestStructInStruct esportata da PinvokeLib.dll.

    int TestStructInStruct(MYPERSON2* pPerson2);
    
  • TestStructInStruct3 esportata da PinvokeLib.dll.

    void TestStructInStruct3(MYPERSON3 person3);
    
  • TestArrayInStruct esportata da PinvokeLib.dll.

    void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
    

PinvokeLib.dll è una libreria non gestita personalizzata contenente implementazioni per le funzioni elencate in precedenza e quattro strutture, ovvero MYPERSON, MYPERSON2, MYPERSON3 e MYARRAYSTRUCT, le quali contengono i seguenti elementi:

typedef struct _MYPERSON
{
   char* first; 
   char* last; 
} MYPERSON, *LP_MYPERSON;

typedef struct _MYPERSON2
{
   MYPERSON* person;
   int age; 
} MYPERSON2, *LP_MYPERSON2;

typedef struct _MYPERSON3
{
   MYPERSON person;
   int age; 
} MYPERSON3;

typedef struct _MYARRAYSTRUCT
{
   bool flag;
   int vals[ 3 ]; 
} MYARRAYSTRUCT;

Le strutture gestite MyPerson,MyPerson2, MyPerson3 e MyArrayStruct hanno le seguenti caratteristiche:

  • MyPerson contiene solo membri stringa. Le stringhe vengono impostate sul formato ANSI dal campo CharSet, quando viene passato alla funzione non gestita.
  • MyPerson2 contiene un tipo IntPtr alla struttura MyPerson. Il tipo IntPtr sostituisce il puntatore originale alla struttura non gestita poiché nelle applicazioni .NET Framework non vengono utilizzati i puntatori a meno che il codice non sia contrassegnato come unsafe.
  • MyPerson3 contiene MyPerson come struttura incorporata. È possibile semplificare una struttura incorporata in un'altra struttura posizionandone gli elementi direttamente nella struttura principale oppure mantenerla incorporata, come accade in questo esempio.
  • MyArrayStruct contiene una matrice di integer. Il valore dell'enumerazione UnmanagedType viene impostato dall'attributo MarshalAsAttribute su ByValArray, che consente di indicare il numero di elementi nella matrice.

Per tutte le strutture di questo esempio, l'attributo StructLayoutAttribute è applicato in modo da garantire che i membri vengano inseriti in memoria in sequenza, nell'ordine in cui appaiono.

La classe LibWrap contiene prototipi gestiti per i metodi TestStructInStruct, TestStructInStruct3 e TestArrayInStruct chiamati dalla classe App. Ciascun prototipo dichiara un singolo parametro, come indicato di seguito:

  • TestStructInStruct dichiara un riferimento al tipo MyPerson2 come parametro.
  • TestStructInStruct3 dichiara il tipo MyPerson3 come parametro e passa il parametro per valore.
  • TestArrayInStruct dichiara un riferimento al tipo MyArrayStruct come parametro.

Come argomenti per i metodi, le strutture vengono passate per valore a meno che il parametro non contenga la parola chiave ref (ByRef in Visual Basic). Ad esempio, il metodo TestStructInStruct passa un riferimento, ossia il valore di un indirizzo, a un oggetto di tipo MyPerson2 al codice non gestito. Per modificare la struttura alla quale punta MyPerson2, nell'esempio si crea un buffer di dimensioni specificate e se ne restituisce l'indirizzo combinando i metodi Marshal.AllocCoTaskMem e Marshal.SizeOf. In seguito, il contenuto della struttura gestita viene copiato nel buffer non gestito. Infine, il metodo Marshal.PtrToStructure viene utilizzato per effettuare il marshalling dei dati dal buffer non gestito a un oggetto gestito e il metodo Marshal.FreeCoTaskMem per liberare il blocco di memoria non gestito.

Dichiarazione dei prototipi

' Declares a managed structure for each unmanaged structure.
< StructLayout( LayoutKind.Sequential, CharSet := CharSet.Ansi )> _
Public Structure MyPerson
   Public first As String
   Public last As String
End Structure 'MyPerson

< StructLayout( LayoutKind.Sequential )> _
Public Structure MyPerson2
   Public person As IntPtr
   Public age As Integer
End Structure 'MyPerson2

< StructLayout( LayoutKind.Sequential )> _
Public Structure MyPerson3
   Public person As MyPerson
   Public age As Integer
End Structure 'MyPerson3

< StructLayout( LayoutKind.Sequential )> _
Public Structure MyArrayStruct 
   Public flag As Boolean
   < MarshalAs( UnmanagedType.ByValArray, SizeConst:=3 )> _
   Public vals As Integer()
End Structure 'MyArrayStruct

Public Class LibWrap
   ' Declares managed prototypes for unmanaged functions.
   Declare Function TestStructInStruct Lib "..\LIB\PinvokeLib.dll" ( _
      ByRef person2 As MyPerson2 ) As Integer
   Declare Function TestStructInStruct3 Lib "..\LIB\PinvokeLib.dll" ( _
      ByVal person3 As MyPerson3 ) As Integer
   Declare Function TestArrayInStruct Lib "..\LIB\PinvokeLib.dll" ( _
      ByRef myStruct As MyArrayStruct ) As Integer   
End Class 'LibWrap
[C#]
// Declares a managed structure for each unmanaged structure.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct MyPerson 
{
   public String first; 
   public String last;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyPerson2 
{
   public IntPtr person;
   public int age;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyPerson3 
{
   public MyPerson person;
   public int age;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyArrayStruct 
{
   public bool flag;
   [ MarshalAs( UnmanagedType.ByValArray, SizeConst=3 )] 
   public int[] vals;
}

public class LibWrap
{
   // Declares a managed prototype for unmanaged function.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestStructInStruct( ref MyPerson2 person2 );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestStructInStruct3( MyPerson3 person3 );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestArrayInStruct( ref MyArrayStruct 
   myStruct );
}

Chiamata delle funzioni

Public Class App
   Public Shared Sub Main()
      ' Structure with a pointer to another structure. 
      Dim personName As MyPerson
      personName.first = "Mark"
      personName.last = "Lee"
      
      Dim personAll As MyPerson2
      personAll.age = 30
      
      Dim buffer As IntPtr = Marshal.AllocCoTaskMem( Marshal.SizeOf( _
      personName ))
      Marshal.StructureToPtr( personName, buffer, False )
      
      personAll.person = buffer
      
      Console.WriteLine( ControlChars.CrLf & "Person before call:" )
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", _
      personName.first, personName.last, personAll.age )
      
      Dim res As Integer = LibWrap.TestStructInStruct( personAll )
      
      Dim personRes As MyPerson = _
         CType( Marshal.PtrToStructure( personAll.person, _
         GetType( MyPerson )), MyPerson )
      
      Marshal.FreeCoTaskMem( buffer )
      
      Console.WriteLine( "Person after call:" )
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", _
      personRes.first, _
         personRes.last, personAll.age )
      
      ' Structure with an embedded structure.
      Dim person3 As New MyPerson3()
      person3.person.first = "John"
      person3.person.last = "Evens"
      person3.age = 27
      LibWrap.TestStructInStruct3( person3 )
      
      ' Structure with an embedded array.
      Dim myStruct As New MyArrayStruct()
      
      myStruct.flag = False
      Dim array( 2 ) As Integer
      myStruct.vals = array
      myStruct.vals( 0 ) = 1
      myStruct.vals( 1 ) = 4
      myStruct.vals( 2 ) = 9
      
      Console.WriteLine( ControlChars.CrLf & "Structure with array _
      before call:" )
      Console.WriteLine( myStruct.flag )
      Console.WriteLine( "{0} {1} {2}", myStruct.vals( 0 ), _
         myStruct.vals( 1 ), myStruct.vals( 2 ) )
      
      LibWrap.TestArrayInStruct( myStruct )
      Console.WriteLine( ControlChars.CrLf & "Structure with array _
      after call:" )
      Console.WriteLine( myStruct.flag )
      Console.WriteLine( "{0} {1} {2}", myStruct.vals( 0 ), _
         myStruct.vals( 1 ), myStruct.vals( 2 ) )
   End Sub 'Main
End Class 'App
[C#]
public class App
{
   public static void Main()
   {
      // Structure with a pointer to another structure. 
      MyPerson personName;
      personName.first = "Mark";
      personName.last = "Lee";
      
      MyPerson2 personAll;
      personAll.age = 30;
      
      IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( 
      personName ));
      Marshal.StructureToPtr( personName, buffer, false );
      
      personAll.person = buffer;
      
      Console.WriteLine( "\nPerson before call:" );
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", 
         personName.first, personName.last, personAll.age ); 
      
      int res = LibWrap.TestStructInStruct( ref personAll );
      
      MyPerson personRes = 
         (MyPerson)Marshal.PtrToStructure( personAll.person, 
         typeof( MyPerson ));
      
      Marshal.FreeCoTaskMem( buffer );
      
      Console.WriteLine( "Person after call:" );
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", 
         personRes.first, personRes.last, personAll.age );
      
      // Structure with an embedded structure.
      MyPerson3 person3 = new MyPerson3();
      person3.person.first = "John";
      person3.person.last = "Evens";
      person3.age = 27;
      LibWrap.TestStructInStruct3( person3 );
      
      // Structure with an embedded array.
      MyArrayStruct myStruct = new MyArrayStruct();
      
      myStruct.flag = false;
      myStruct.vals = new int[ 3 ];
      myStruct.vals[ 0 ] = 1;
      myStruct.vals[ 1 ] = 4;
      myStruct.vals[ 2 ] = 9;
      
      Console.WriteLine( "\nStructure with array before call:" );
      Console.WriteLine( myStruct.flag );
      Console.WriteLine( "{0} {1} {2}", myStruct.vals[ 0 ], 
         myStruct.vals[ 1 ], myStruct.vals[ 2 ] );
      
      LibWrap.TestArrayInStruct( ref myStruct );
      Console.WriteLine( "\nStructure with array after call:" );
      Console.WriteLine( myStruct.flag );
      Console.WriteLine( "{0} {1} {2}", myStruct.vals[ 0 ], 
         myStruct.vals[ 1 ], myStruct.vals[ 2 ] );
   }
}

Vedere anche

Marshalling di classi, strutture e unioni | Tipi di dati della chiamata al sistema operativo | Creazione di prototipi nel codice gestito