다양한 형식의 배열 마샬링
배열은 동일한 형식의 요소를 하나 이상 포함하는 관리 코드의 참조 형식입니다. 배열은 참조 형식이지만 관리되지 않는 함수에 In 매개 변수로 전달됩니다. 이 동작은 관리되는 배열이 관리되는 개체에 전달되는 방식(In/Out 매개 변수로)과 일치하지 않습니다. 자세한 내용은 복사 및 고정을 참조하세요.
다음 표에서는 배열에 대한 마샬링 옵션을 나열하고 사용법을 설명합니다.
Array | 설명 |
---|---|
값 형식 정수. | 정수 배열을 In 매개 변수로 전달합니다. |
참조 형식 정수. | 정수 배열을 In/Out 매개 변수로 전달합니다. |
값 형식 정수(2차원). | 정수 행렬을 In 매개 변수로 전달합니다. |
값 형식 문자열. | 문자열 배열을 In 매개 변수로 전달합니다. |
정수를 포함하는 구조체. | 정수를 포함하는 구조체 배열을 In 매개 변수로 전달합니다. |
문자열을 포함하는 구조체. | 문자열만 포함하는 구조체 배열을 In/Out 매개 변수로 전달합니다. 배열의 멤버를 변경할 수 있습니다. |
예시
이 샘플에서는 다음 형식의 배열을 전달하는 방법을 보여 줍니다.
값 형식 정수 배열
크기를 조정할 수 있는 참조 형식 정수 배열
값 형식 정수의 다차원 배열(행렬)
값 형식 문자열 배열
정수를 포함하는 구조체 배열
문자열을 포함하는 구조체 배열
배열이 참조에 의해 명시적으로 마샬링되지 않은 한 기본 동작은 배열을 In 매개 변수로 마샬링합니다. InAttribute 및 OutAttribute 특성을 명시적으로 적용하면 이 동작을 변경할 수 있습니다.
Arrays 샘플에서는 원래 함수 선언과 함께 표시되는 다음과 같은 관리되지 않는 함수를 사용합니다.
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은 앞에 나열된 함수 및 2개의 구조체 변수 MYPOINT 및 MYPERSON에 대한 구현을 포함하는 관리되지 않는 사용자 지정 라이브러리입니다. 구조체에는 다음과 같은 요소가 포함됩니다.
typedef struct _MYPOINT
{
int x;
int y;
} MYPOINT;
typedef struct _MYPERSON
{
char* first;
char* last;
} MYPERSON;
이 샘플에서 MyPoint
및 MyPerson
구조체에는 포함된 형식이 있습니다. StructLayoutAttribute 특성이 설정되어 멤버가 표시되는 순서대로 순차적으로 메모리에 정렬되게 합니다.
NativeMethods
클래스에는 App
클래스가 호출하는 메서드 집합이 포함됩니다. 배열을 전달하는 방법에 대한 자세한 내용은 다음 샘플의 설명을 참조하세요. 참조 형식인 배열은 기본적으로 In 매개 변수로 전달됩니다. 호출자가 결과를 받으려면 배열을 포함하는 인수에 InAttribute 및 OutAttribute 를 명시적으로 적용해야 합니다.
프로토타입 선언
// 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
참고 항목
.NET