Поделиться через


Маршалинг различных типов массивов

Обновлен: Ноябрь 2007

В этом примере показан способ передачи массивов следующих типов.

  • Массив целочисленных значений по значению.

  • Массив целочисленных значений по ссылке. Размер массива можно изменять.

  • Многомерный массив (матрица) целочисленных значений по значению.

  • Массив строк по значению.

  • Массив структур с целочисленными значениями.

  • Массив структур со строками.

Если маршалинг по ссылке не выполняется для массива явным образом, по умолчанию выполняется маршалинг массива в виде параметра In. Это поведение можно изменить, явным образом применяя атрибуты InAttribute и OutAttribute.

В этом примере используются следующие неуправляемые функции, показанные со своим исходным объявлением.

  • Функция TestArrayOfInts, экспортированная из PinvokeLib.dll.

    int TestArrayOfInts(int* pArray, int pSize);
    
  • Функция TestRefArrayOfInts, экспортированная из PinvokeLib.dll.

    int TestRefArrayOfInts(int** ppArray, int* pSize);
    
  • Функция TestMatrixOfInts, экспортированная из PinvokeLib.dll.

    int TestMatrixOfInts(int pMatrix[][COL_DIM], int row);
    
  • Функция TestArrayOfStrings, экспортированная из PinvokeLib.dll.

    int TestArrayOfStrings(char** ppStrArray, int size);
    
  • Функция TestArrayOfStructs, экспортированная из PinvokeLib.dll.

    int TestArrayOfStructs(MYPOINT* pPointArray, int size);
    
  • Функция TestArrayOfStructs2, экспортированная из PinvokeLib.dll.

    int TestArrayOfStructs2 (MYPERSON* pPersonArray, int size);
    

PinvokeLib.dll — это пользовательская неуправляемая библиотека, содержащая реализации ранее описанных функций и две переменные структуры, MYPOINT и MYPERSON. Эти структуры содержат следующие элементы:

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

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

В этом примере структуры MyPoint и MyPerson содержат вложенные типы. Атрибут StructLayoutAttribute задается, чтобы гарантировать последовательный порядок членов в памяти, соответствующий порядку их появления.

Класс LibWrap содержит набор методов, вызываемых классом App. Конкретные сведения о передаче массивов см. в комментариях к следующему примеру. Массив, который является ссылочным типом, по умолчанию передается в виде параметра In. Чтобы вызывающий объект мог получать результаты, необходимо явным образом применить атрибуты InAttribute и OutAttributeк аргументу, содержащему массив.

Исходный код для следующих примеров кода см. в разделе Пример технологии вызова неуправляемого кода для .NET Framework.

Объявление прототипов

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

Вызов функций

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

См. также

Основные понятия

Маршалинг массивов типов

Типы данных вызовов неуправляемого кода

Создание прототипов в управляемом коде