Маршалинг различных типов массивов
Обновлен: Ноябрь 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 );
}
}