Marshalling di diversi tipi di matrici
Una matrice è un tipo di riferimento nel codice gestito che contiene uno o più elementi dello stesso tipo. Anche se le matrici sono tipi di riferimento, vengono passate come parametri in alle funzioni non gestite. Questo comportamento non è coerente con il modo in cui le matrici gestite vengono passate agli oggetti gestiti, ovvero come parametri in/out. Per altri dettagli, vedere Copia e blocco.
La tabella seguente elenca le opzioni di marshalling per le matrici e ne descrive l'utilizzo.
Matrice | Descrizione |
---|---|
Di Integer in base al valore. | Passa una matrice di Integer come un parametro in. |
Di Integer in base al riferimento. | Passa una matrice di Integer come un parametro in/out. |
Di Integer in base al valore (bidimensionale). | Passa una matrice di Integer come un parametro in. |
Di stringhe in base al valore. | Passa una matrice di stringhe come un parametro in. |
Di strutture con Integer. | Passa una matrice di strutture che contengono Integer come un parametro in. |
Di strutture con stringhe. | Passa una matrice di strutture che contengono solo stringhe come parametro In/Out. È possibile modificare i membri della matrice. |
Esempio
Questo esempio illustra come passare i tipi di matrice seguenti:
Matrice di Integer in base al valore.
Matrice di Integer in base al riferimento, che è possibile ridimensionare.
Matrice multidimensionale di Integer in base al valore.
Matrice di stringhe in base al valore.
Matrice di strutture con Integer.
Matrice di strutture con stringhe.
A meno che non venga eseguito il marshalling esplicito di una matrice per riferimento, il comportamento predefinito esegue il marshalling della matrice come un parametro in. È possibile modificare questo comportamento applicando in modo esplicito gli attributi InAttribute e OutAttribute .
Nell'esempio di matrici vengono usate le seguenti funzioni non gestite, illustrate con le dichiarazioni di funzione originali:
TestArrayOfInts esportata da PinvokeLib.dll.
int TestArrayOfInts(int* pArray, int pSize);
TestRefArrayOfInts esportata da PinvokeLib.dll.
int TestRefArrayOfInts(int** ppArray, int* pSize);
TestMatrixOfInts esportata da PinvokeLib.dll.
int TestMatrixOfInts(int pMatrix[][COL_DIM], int row);
TestArrayOfStrings esportata da PinvokeLib.dll.
int TestArrayOfStrings(char** ppStrArray, int size);
TestArrayOfStructs esportata da PinvokeLib.dll.
int TestArrayOfStructs(MYPOINT* pPointArray, int size);
TestArrayOfStructs2 esportata da PinvokeLib.dll.
int TestArrayOfStructs2 (MYPERSON* pPersonArray, int size);
PinvokeLib.dll è una libreria non gestita personalizzata contenente implementazioni per le funzioni elencate in precedenza e due variabili di struttura, ovvero MYPOINT e MYPERSON. Le strutture contengono gli elementi seguenti:
typedef struct _MYPOINT
{
int x;
int y;
} MYPOINT;
typedef struct _MYPERSON
{
char* first;
char* last;
} MYPERSON;
In questo esempio, le strutture MyPoint
e MyPerson
contengono tipi incorporati. L'attributo StructLayoutAttribute è impostato in modo da garantire che i membri vengano inseriti in memoria in sequenza, nell'ordine in cui appaiono.
La classe NativeMethods
contiene un set di metodi chiamati dalla classe App
. Per informazioni specifiche sul passaggio di matrici, vedere i commenti nell'esempio seguente. Una matrice, che è un tipo di riferimento, viene passata come un parametro in per impostazione predefinita. Per permettere al chiamante di ricevere i risultati, InAttribute e OutAttribute devono essere applicati in modo esplicito all'argomento contenente la matrice.
Dichiarazione dei prototipi
// 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
Funzioni chiamanti
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