封送處理不同型別的陣列
更新:2007 年 11 月
這個範例示範如何傳遞下列陣列型別:
以傳值方式的整數陣列
以傳址方式的整數陣列,其大小可以調整
以傳值方式之整數的多維陣列 (矩陣)
以傳值方式的字串陣列
具有整數的結構陣列
具有字串的結構陣列
除非陣列是以傳址方式明確地封送處理,否則預設行為會將陣列當成 In 參數封送處理。您可以明確套用 InAttribute 和 OutAttribute 屬性,來改變此行為。
陣列範例使用下列 Unmanaged 函式,顯示其原始函式宣告:
從 PinvokeLib.dll 匯出 TestArrayOfInts。
int TestArrayOfInts(int* pArray, int pSize);
從 PinvokeLib.dll 匯出 TestRefArrayOfInts。
int TestRefArrayOfInts(int** ppArray, int* pSize);
從 PinvokeLib.dll 匯出 TestMatrixOfInts。
int TestMatrixOfInts(int pMatrix[][COL_DIM], int row);
從 PinvokeLib.dll 匯出 TestArrayOfStrings。
int TestArrayOfStrings(char** ppStrArray, int size);
從 PinvokeLib.dll 匯出 TestArrayOfStructs。
int TestArrayOfStructs(MYPOINT* pPointArray, int size);
從 PinvokeLib.dll 匯出 TestArrayOfStructs2。
int TestArrayOfStructs2 (MYPERSON* pPersonArray, int size);
PinvokeLib.dll 是自訂的 Unmanaged 程式庫,包含先前列示的函式和兩個結構變數 (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 );
}
}