Partager via


Marshaling de différents types de tableaux

Mise à jour : novembre 2007

Cet exemple montre comment passer les types suivants de tableaux :

  • Tableau d'entiers par valeur.

  • Tableau d'entiers par référence qui peut être redimensionné.

  • Tableau multidimensionnel (matrice) d'entiers par valeur.

  • Tableau de chaînes par valeur.

  • Tableau de structures avec entiers.

  • Tableau de structures avec chaînes.

À moins qu'un tableau soit explicitement marshalé par référence, le comportement par défaut marshale le tableau en tant que paramètre en entrée. Vous pouvez changer ce comportement en appliquant explicitement les attributs InAttribute et OutAttribute.

L'exemple Arrays utilise les fonctions non managées suivantes, illustrées avec leur déclaration de fonction d'origine :

  • TestArrayOfInts exportée à partir de PinvokeLib.dll.

    int TestArrayOfInts(int* pArray, int pSize);
    
  • TestRefArrayOfInts exportée à partir de PinvokeLib.dll.

    int TestRefArrayOfInts(int** ppArray, int* pSize);
    
  • TestMatrixOfInts exportée à partir de PinvokeLib.dll.

    int TestMatrixOfInts(int pMatrix[][COL_DIM], int row);
    
  • TestArrayOfStrings exportée à partir de PinvokeLib.dll.

    int TestArrayOfStrings(char** ppStrArray, int size);
    
  • TestArrayOfStructs exportée à partir de PinvokeLib.dll.

    int TestArrayOfStructs(MYPOINT* pPointArray, int size);
    
  • TestArrayOfStructs2 exportée à partir de PinvokeLib.dll.

    int TestArrayOfStructs2 (MYPERSON* pPersonArray, int size);
    

PinvokeLib.dll est une bibliothèque non managée personnalisée qui contient des implémentations pour les fonctions précédemment répertoriées et les deux variables de structure MYPOINT et MYPERSON. Ces structures contiennent les éléments suivants :

typedef struct _MYPOINT
{
   int x; 
   int y; 
} MYPOINT;

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

Dans cet exemple, les structures MyPoint et MyPerson contiennent des types incorporés. L'attribut StructLayoutAttribute est défini afin de garantir que les membres sont disposés en mémoire de manière séquentielle, dans l'ordre de leur apparition.

La classe LibWrap contient un ensemble de méthodes appelées par la classe App. Pour des informations spécifiques relatives au passage de tableaux, consultez les commentaires dans l'exemple suivant. Un tableau, qui est un type référence, est passé comme paramètre en entrée par défaut. Pour que l'appelant reçoive les résultats, InAttribute et OutAttribute doivent être appliqués explicitement à l'argument contenant le tableau.

Le code source pour les exemples de code suivants est fourni par Appel de plate-forme, exemple de technologie du .NET Framework.

Déclaration de prototypes

' Declares a managed structure for each unmanaged structure.
< StructLayout( LayoutKind.Sequential )> _
Public Structure MyPoint
   Public x As Integer
   Public y As Integer
   Public Sub New( x As Integer, y As Integer )
      Me.x = x
      Me.y = y
   End Sub 'New
End Structure 'MyPoint

< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Ansi )> _
Public Structure MyPerson
   Public first As String
   Public last As String
   Public Sub New( first As String, last As String )
      Me.first = first
      Me.last = last
   End Sub 'New
End Structure 'MyPerson

Public Class LibWrap
   ' Declares a managed prototype for an array of integers by value.
   ' The array size cannot be changed, but the array is copied back.
   Declare Function TestArrayOfInts Lib "..\LIB\PinvokeLib.dll" ( _
      <[In], Out> ByVal myArray() As Integer, ByVal size As Integer ) _
      As Integer

   ' Declares managed prototype for an array of integers by reference.
   ' The array size can change, but the array is not copied back 
   ' automatically because the marshaler does not know the resulting size.
   ' The copy must be performed manually.
   Declare Function TestRefArrayOfInts Lib "..\LIB\PinvokeLib.dll" ( _
      ByRef myArray As IntPtr, ByRef size As Integer ) As Integer

   ' Declares a managed prototype for a matrix of integers by value.
   Declare Function TestMatrixOfInts Lib "..\LIB\PinvokeLib.dll" ( _
      <[In], Out> ByVal matrix(,) As Integer, ByVal row As Integer ) _
      As Integer

   ' Declares a managed prototype for an array of strings by value.
   Declare Function TestArrayOfStrings Lib "..\LIB\PinvokeLib.dll" ( _
      <[In], Out> ByVal strArray() As String, ByVal size As Integer ) _
   As Integer
   
   ' Declares a managed prototype for an array of structures with 
   ' integers.
   Declare Function TestArrayOfStructs Lib "..\LIB\PinvokeLib.dll" ( _
      <[In], Out> ByVal pointArray() As MyPoint, _
      ByVal size As Integer ) As Integer
   
   ' Declares a managed prototype for an array of structures with strings.
   Declare Function TestArrayOfStructs2 Lib "..\LIB\PinvokeLib.dll" ( _
      <[In], Out> ByVal personArray() As MyPerson, ByVal size _
      As Integer ) As Integer
End Class 'LibWrap
// Declares a managed structure for each unmanaged structure.
[ StructLayout( LayoutKind.Sequential )]
public struct MyPoint 
{
   public int x; 
   public int y;
   public MyPoint( int x, int y )
   {
      this.x = x;
      this.y = y;
   }
}
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct MyPerson 
{
   public String first; 
   public String last;
   public MyPerson( String first, String last )
   {
      this.first = first;
      this.last = last;
   }
}

public class LibWrap
{
   // Declares a managed prototype for an array of integers by value.
   // The array size cannot be changed, but the array is copied back.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestArrayOfInts([In, Out] int[] array, int size );
   
   // Declares a managed prototype for an array of integers by reference.
   // The array size can change, but the array is not copied back 
   // automatically because the marshaler does not know the resulting size.
   // The copy must be performed manually.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestRefArrayOfInts( ref IntPtr array, 
      ref int size );
   
   // Declares a managed prototype for a matrix of integers by value.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestMatrixOfInts([In, Out] int[,] pMatrix, 
      int row );   
   // Declares a managed prototype for an array of strings by value.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestArrayOfStrings( [In, Out] 
      String[] stringArray, int size );
   
   // Declares a managed prototype for an array of structures with integers.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestArrayOfStructs([In, Out] MyPoint[] 
      pointArray, int size ); 
   
   // Declares a managed prototype for an array of structures with strings.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestArrayOfStructs2( [In, Out] 
      MyPerson[] personArray, int size );
}

Appel de fonctions

Public Class App
   Public Shared Sub Main()
      ' array ByVal
      Dim array1(9) As Integer
      
      Console.WriteLine( "Integer array passed ByVal before call:" )
      Dim i As Integer
      For i = 0 To array1.Length - 1
         array1(i) = i
         Console.Write( " " & array1(i) )
      Next i
      
      Dim sum1 As Integer = LibWrap.TestArrayOfInts( array1, array1._
         Length )
      Console.WriteLine( ControlChars.CrLf & "Sum of elements:" & sum1 )
      Console.WriteLine( ControlChars.CrLf & "Integer array passed _
         ByVal after call:" )
      For Each i In  array1
         Console.Write( " " & i )
      Next i
      
      ' array ByRef
      Dim array2(9) As Integer
      Dim arraySize As Integer = array2.Length
      Console.WriteLine( ControlChars.CrLf & ControlChars.CrLf & _
         "Integer array passed ByRef before call:" )
      For i = 0 To array2.Length - 1
         array2(i) = i
         Console.Write( " " & array2(i) )
      Next i
      Dim buffer As IntPtr = Marshal.AllocCoTaskMem( Marshal.SizeOf( _
         arraySize ) * array2.Length )
      Marshal.Copy( array2, 0, buffer, array2.Length )
      Dim sum2 As Integer = LibWrap.TestRefArrayOfInts( buffer, _
         arraySize )
      Console.WriteLine( ControlChars.CrLf & "Sum of elements:" & sum2 )
      
      If arraySize > 0 Then
         Dim arrayRes( arraySize - 1 ) As Integer
         Marshal.Copy( buffer, arrayRes, 0, arraySize )
         Marshal.FreeCoTaskMem( buffer )
         
         Console.WriteLine( ControlChars.CrLf & "Integer array _
           passed ByRef after call:" )
         For Each i In  arrayRes
            Console.Write( " " & i )
         Next i
      Else
         Console.WriteLine( ControlChars.CrLf & "Array after call _
           is empty" )
      End If
      
      ' matrix ByVal 
      Const [DIM] As Integer = 4
      Dim matrix([DIM], [DIM]) As Integer
      
      Console.WriteLine( ControlChars.CrLf & ControlChars.CrLf & _
         "Matrix before call:" )
      For i = 0 To [DIM]
         Dim j As Integer
         For j = 0 To [DIM]
            matrix(i, j) = j
            Console.Write( " " & matrix(i, j) )
         Next j
         Console.WriteLine( "" )
      Next i

      Dim sum3 As Integer = LibWrap.TestMatrixOfInts( matrix, [DIM] + 1 )
      Console.WriteLine( ControlChars.CrLf & "Sum of elements:" & sum3 )
      Console.WriteLine( ControlChars.CrLf & "Matrix after call:" )
      For i = 0 To [DIM]
         Dim j As Integer
         For j = 0 To [DIM]
            Console.Write( " " & matrix(i, j) )
         Next j
         Console.WriteLine( "" )
      Next i

      ' string array ByVal 
      Dim strArray As String() =  { "one", "two", "three", "four", _
        "five" }
      Console.WriteLine( ControlChars.CrLf & ControlChars.CrLf & _
        "String array before call:" )
      Dim s As String
      For Each s In  strArray
         Console.Write( " " & s )
      Next s 
      Dim lenSum As Integer = LibWrap.TestArrayOfStrings( _
         strArray, strArray.Length )
      Console.WriteLine( ControlChars.CrLf & _
         "Sum of string lengths:" & lenSum )
      Console.WriteLine( ControlChars.CrLf & "String array after call:" )
      For Each s In  strArray
         Console.Write( " " & s )
      Next s

      ' struct array ByVal 
      Dim points As MyPoint() = { New MyPoint(1, 1), New MyPoint(2, 2), _
         New MyPoint(3, 3) }
      Console.WriteLine( ControlChars.CrLf & ControlChars.CrLf & _
         "Points array before call:" )
      Dim p As MyPoint
      For Each p In  points
         Console.WriteLine( "x = {0}, y = {1}", p.x, p.y )
      Next p 
      Dim allSum As Integer = LibWrap.TestArrayOfStructs( points, _
         points.Length )
      Console.WriteLine( ControlChars.CrLf & "Sum of points:" & allSum )
      Console.WriteLine( ControlChars.CrLf & "Points array after call:" )
      For Each p In  points
         Console.WriteLine( "x = {0}, y = {1}", p.x, p.y )
      Next p 
      
      ' struct with strings array ByVal 
      Dim persons As MyPerson() =  { _New MyPerson( "Kim", "Akers" ), _
         New MyPerson( "Adam", "Barr" ), _
         New MyPerson( "Jo", "Brown" )}
      Console.WriteLine( ControlChars.CrLf & ControlChars.CrLf & _
         "Persons array before call:" )
      Dim pe As MyPerson
      For Each pe In  persons
         Console.WriteLine( "first = {0}, last = {1}", pe.first, pe.last )
      Next pe 
      
      Dim namesSum As Integer = LibWrap.TestArrayOfStructs2( persons, _
         persons.Length )
      Console.WriteLine( ControlChars.CrLf & "Sum of name lengths:" & _
         namesSum )
      Console.WriteLine( ControlChars.CrLf & ControlChars._
         CrLf & "Persons array after call:" )
      For Each pe In  persons
         Console.WriteLine( "first = {0}, last = {1}", pe.first, pe.last )
      Next pe
   End Sub 'Main
End Class 'App
public class App
{
   public static void Main()
   {
      // array ByVal 
      int[] array1 = new int[ 10 ];
      Console.WriteLine( "Integer array passed ByVal before call:" );
      for( int i = 0; i < array1.Length; i++ )
      {
         array1[ i ] = i;
         Console.Write( " " + array1[ i ] );
      }
      int sum1 = LibWrap.TestArrayOfInts( array1, array1.Length );
      Console.WriteLine( "\nSum of elements:" + sum1 );
      Console.WriteLine( "\nInteger array passed ByVal after call:" );
      
      foreach( int i in array1 )
      {
         Console.Write( " " + i );
      }   
      
      // array ByRef 
      int[] array2 = new int[ 10 ];
      int size = array2.Length;
      Console.WriteLine( "\n\nInteger array passed ByRef before call:" );
      for( int i = 0; i < array2.Length; i++ )
      {
         array2[ i ] = i;
         Console.Write( " " + array2[ i ] );
      }
      IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( size ) 
         * array2.Length );
      Marshal.Copy( array2, 0, buffer, array2.Length );
      
      int sum2 = LibWrap.TestRefArrayOfInts( ref buffer, ref size );
      Console.WriteLine( "\nSum of elements:" + sum2 );
      if( size > 0 )
      {
         int[] arrayRes = new int[ size ];
         Marshal.Copy( buffer, arrayRes, 0, size );
         Marshal.FreeCoTaskMem( buffer );
         Console.WriteLine( "\nInteger array passed ByRef after call:" );
         foreach( int i in arrayRes )
         {
            Console.Write( " " + i );
         }
      }
      else
         Console.WriteLine( "\nArray after call is empty" );
         
      // matrix ByVal 
      const int DIM = 5;
      int[,] matrix = new int[ DIM, DIM ];
      
      Console.WriteLine( "\n\nMatrix before call:" );
      for( int i = 0; i < DIM; i++ )
      {
         for( int j = 0; j < DIM; j++ )
         {
            matrix[ i, j ] = j;
            Console.Write( " " + matrix[ i, j ] );
         }
         Console.WriteLine( "" );
      }
      int sum3 = LibWrap.TestMatrixOfInts( matrix, DIM );
      Console.WriteLine( "\nSum of elements:" + sum3 );
      Console.WriteLine( "\nMatrix after call:" );
      for( int i = 0; i < DIM; i++ )
      {
         for( int j = 0; j < DIM; j++ )
         {
            Console.Write( " " + matrix[ i, j ] );
         }
         Console.WriteLine( "" );
      }
      
      // string array ByVal 
      String[] strArray = { "one", "two", "three", "four", "five" };
      Console.WriteLine( "\n\nString array before call:" );
      foreach( String s in strArray )
         Console.Write( " "+ s );
      int lenSum = LibWrap.TestArrayOfStrings( strArray, strArray.Length );
      Console.WriteLine( "\nSum of string lengths:" + lenSum );
      Console.WriteLine( "\nString array after call:" );
      foreach( String s in strArray )
      {
         Console.Write( " " + s );
      }   
      
      // struct array ByVal 
      MyPoint[] points = { new MyPoint(1,1), new MyPoint(2,2), new MyPoint(3,3) };
      Console.WriteLine( "\n\nPoints array before call:" );
      foreach( MyPoint p in points )
         Console.WriteLine( "x = {0}, y = {1}", p.x, p.y );
      int allSum = LibWrap.TestArrayOfStructs( points, points.Length );
      Console.WriteLine( "\nSum of points:" + allSum );
      Console.WriteLine( "\nPoints array after call:" );
      foreach( MyPoint p in points )
         Console.WriteLine( "x = {0}, y = {1}", p.x, p.y );      
         
      // struct with strings array ByVal 
      MyPerson[] persons = { new MyPerson( "Kim", "Akers" ), 
      new MyPerson( "Adam", "Barr" ), new MyPerson( "Jo", "Brown" )};
      
      Console.WriteLine( "\n\nPersons array before call:" );
      foreach( MyPerson pe in persons )
        Console.WriteLine( "first = {0}, last = {1}", pe.first, pe.last );
      int namesSum = LibWrap.TestArrayOfStructs2( persons, persons.Length );
      Console.WriteLine( "\nSum of name lengths:" + namesSum );
      Console.WriteLine( "\n\nPersons array after call:" );
      foreach( MyPerson pe in persons )
        Console.WriteLine( "first = {0}, last = {1}", pe.first, pe.last );
   }
}

Voir aussi

Concepts

Marshaling des tableaux de types

Types de données d'appel de plate-forme

Création de prototypes dans du code managé