陣列是受控代碼中的參考型別,包含一個或多個相同類型的元素。 雖然陣列是參考型別,但它們會以輸入參數的形式傳遞至非受控函式。 此行為與 Managed 陣組傳遞至 Managed 物件的方式不一致,也就是 In/Out 參數。 如需其他詳細數據,請參閱 複製和釘選。
下表列出陣列的封送處理選項,並描述其用法。
| 陣列 | 說明 |
|---|---|
| 依值排序的整數。 | 傳遞整數陣組做為 In 參數。 |
| 依據參考方式的整數。 | 傳遞整數陣組做為 In/Out 參數。 |
| 依值 (二維) 的整數。 | 傳遞整數矩陣做為 In 參數。 |
| 依值排序的字串。 | 傳遞字串陣列做為 In 參數。 |
| 具有整數的結構。 | 傳遞結構陣列,其中包含整數做為In參數。 |
| 具有字串的結構。 | 傳遞只包含字串做為 In/Out 參數的結構陣列。 陣列的成員可以變更。 |
範例
這個範例示範如何傳遞下列類型的陣列:
依值排列的整數陣列。
依參考的整數陣列,可以重設大小。
以傳值為單位之整數的多維度陣列(矩陣)。
依值儲存的字串陣列
具有整數的結構陣列。
具有字串的結構陣列。
除非陣列明確地以參考傳遞方式封送,否則預設行為會將陣列封送為 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 屬性被設定為確保成員根據其出現的順序,在記憶體中順序排列。
類別 NativeMethods 包含一組由類別 App 呼叫的方法。 如需傳遞陣列的特定詳細數據,請參閱下列範例中的批注。 陣列,這是參考型別,預設會以In參數的形式傳遞。 呼叫者要接收結果, InAttributeOutAttribute 必須明確套用到 包含陣列的參數。
宣告原型
// 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;
}
}
internal static class NativeMethods
{
// 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", CallingConvention = CallingConvention.Cdecl)]
internal 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", CallingConvention = CallingConvention.Cdecl)]
internal 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", CallingConvention = CallingConvention.Cdecl)]
internal 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", CallingConvention = CallingConvention.Cdecl)]
internal 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", CallingConvention = CallingConvention.Cdecl)]
internal 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", CallingConvention = CallingConvention.Cdecl)]
internal static extern int TestArrayOfStructs2(
[In, Out] MyPerson[] personArray, int size);
}
' 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
End Structure
<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
End Structure
Friend Class NativeMethods
' 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", CallingConvention:=CallingConvention.Cdecl)>
Friend Shared Function TestArrayOfInts(
<[In], Out> ByVal myArray() As Integer, ByVal size As Integer) _
As Integer
End Function
' 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.
<DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
Friend Shared Function TestRefArrayOfInts(
ByRef myArray As IntPtr, ByRef size As Integer) As Integer
End Function
' Declares a managed prototype for a matrix of integers by value.
<DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
Friend Shared Function TestMatrixOfInts(
<[In], Out> ByVal matrix(,) As Integer, ByVal row As Integer) _
As Integer
End Function
' Declares a managed prototype for an array of strings by value.
<DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
Friend Shared Function TestArrayOfStrings(
<[In], Out> ByVal strArray() As String, ByVal size As Integer) _
As Integer
End Function
' Declares a managed prototype for an array of structures with
' integers.
<DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
Friend Shared Function TestArrayOfStructs(
<[In], Out> ByVal pointArray() As MyPoint, ByVal size As Integer) _
As Integer
End Function
' Declares a managed prototype for an array of structures with strings.
<DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
Friend Shared Function TestArrayOfStructs2(
<[In], Out> ByVal personArray() As MyPerson, ByVal size As Integer) _
As Integer
End Function
End Class
呼叫函式
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 = NativeMethods.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 = NativeMethods.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 = NativeMethods.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 = NativeMethods.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 = {p.X}, Y = {p.Y}");
}
int allSum = NativeMethods.TestArrayOfStructs(points, points.Length);
Console.WriteLine("\nSum of points:" + allSum);
Console.WriteLine("\nPoints array after call:");
foreach (MyPoint p in points)
{
Console.WriteLine($"X = {p.X}, Y = {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 = {pe.First}, Last = {pe.Last}");
}
int namesSum = NativeMethods.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 = {pe.First}, Last = {pe.Last}");
}
}
}
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 = NativeMethods.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 = NativeMethods.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 = NativeMethods.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 = NativeMethods.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 = {p.x}, y = {p.y}")
Next p
Dim allSum As Integer = NativeMethods.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 = {p.x}, y = {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 = {pe.first}, last = {pe.last}")
Next pe
Dim namesSum As Integer = NativeMethods.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 = {pe.first}, last = {pe.last}")
Next pe
End Sub
End Class