구조체 샘플
이 샘플에서는 또 다른 구조체를 가리키는 구조체를 전달하는 방법, 포함된 구조체가 있는 구조체를 전달하는 방법 및 포함된 배열이 있는 구조체를 전달하는 방법을 보여 줍니다.
Structs 샘플에서는 다음의 관리되지 않는 함수를 사용합니다. 이 함수들은 원래의 함수 선언과 함께 표시되어 있습니다.
PinvokeLib.dll에서 내보낸 TestStructInStruct
int TestStructInStruct(MYPERSON2* pPerson2);
PinvokeLib.dll에서 내보낸 TestStructInStruct3
void TestStructInStruct3(MYPERSON3 person3);
PinvokeLib.dll에서 내보낸 TestArrayInStruct
void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
PinvokeLib.dll은 이러한 함수와 네 개의 구조체 MYPERSON, MYPERSON2, MYPERSON3 및 MYARRAYSTRUCT에 대한 구현이 포함된, 관리되지 않는 사용자 지정 라이브러리입니다. 이 구조체에는 다음 요소가 포함되어 있습니다.
typedef struct _MYPERSON
{
char* first;
char* last;
} MYPERSON, *LP_MYPERSON;
typedef struct _MYPERSON2
{
MYPERSON* person;
int age;
} MYPERSON2, *LP_MYPERSON2;
typedef struct _MYPERSON3
{
MYPERSON person;
int age;
} MYPERSON3;
typedef struct _MYARRAYSTRUCT
{
bool flag;
int vals[ 3 ];
} MYARRAYSTRUCT;
관리되는 MyPerson, MyPerson2, MyPerson3 및 MyArrayStruct 구조체에는 다음 특징이 있습니다.
MyPerson에는 문자열 멤버만 포함되어 있습니다. CharSet 필드는 관리되지 않는 함수에 전달될 때 이 문자열을 ANSI 형식으로 설정합니다.
MyPerson2에는 MyPerson 구조체에 대한 IntPtr가 포함되어 있습니다. .NET Framework 응용 프로그램에서는 코드가 unsafe로 표시되지 않은 이상 포인터를 사용하지 않으므로 IntPtr 형식은 관리되지 않는 구조체에 대한 원래 포인터를 대체합니다.
MyPerson3에는 MyPerson이 포함 구조체로 포함되어 있습니다. 다른 구조체 내에 포함된 구조체는 포함 구조체의 요소를 기본 구조체에 직접 포함시키는 방법으로 결합할 수도 있고, 이 샘플에서처럼 포함 구조체 상태로 둘 수도 있습니다.
MyArrayStruct에는 정수 배열이 포함되어 있습니다. MarshalAsAttribute 특성은 UnmanagedType 열거형 값을 ByValArray로 설정합니다. ByValArray는 배열에 있는 요소의 수를 나타내는 데 사용됩니다.
이 샘플의 모든 구조체에는 멤버가 나타나는 순서에 따라 메모리에 순차적으로 정렬되도록 StructLayoutAttribute 특성이 적용됩니다.
LibWrap 클래스에는 App 클래스에서 호출하는 TestStructInStruct, TestStructInStruct3 및 TestArrayInStruct 메서드에 대한 관리되는 프로토타입이 포함되어 있습니다. 각 프로토타입은 다음과 같이 하나의 매개 변수를 선언합니다.
TestStructInStruct - MyPerson2 형식에 대한 참조를 매개 변수로 선언합니다.
TestStructInStruct3 - MyPerson3 형식을 매개 변수로 선언하고 이 매개 변수를 값으로 전달합니다.
TestArrayInStruct - MyArrayStruct 형식에 대한 참조를 매개 변수로 선언합니다.
메서드에 대한 인수 형식의 구조체는 해당 매개 변수에 ref(Visual Basic에서는 ByRef) 키워드가 포함되어 있지 않은 경우 값으로 전달됩니다. 예를 들어, TestStructInStruct 메서드는 MyPerson2 형식의 개체에 대한 참조 즉, 주소 값을 비관리 코드에 전달합니다. MyPerson2가 가리키는 구조체를 조작하기 위해 이 샘플에서는 Marshal.AllocCoTaskMem 메서드와 Marshal.SizeOf 메서드를 함께 사용하여 지정된 크기의 버퍼를 만들고 해당 주소를 반환합니다. 그런 다음에는 관리되는 구조체의 내용을 관리되지 않는 버퍼로 복사합니다. 마지막으로 이 샘플에서는 Marshal.PtrToStructure 메서드를 사용하여 관리되지 않는 버퍼에서 관리되는 개체로 데이터를 마샬링하고 Marshal.FreeCoTaskMem 메서드를 사용하여 관리되지 않는 메모리 블록을 해제합니다.
프로토타입 선언
' Declares a managed structure for each unmanaged structure.
<StructLayout(LayoutKind.Sequential, CharSet := CharSet.Ansi)> _
Public Structure MyPerson
Public first As String
Public last As String
End Structure 'MyPerson
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyPerson2
Public person As IntPtr
Public age As Integer
End Structure 'MyPerson2
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyPerson3
Public person As MyPerson
Public age As Integer
End Structure 'MyPerson3
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyArrayStruct
Public flag As Boolean
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
Public vals As Integer()
End Structure 'MyArrayStruct
Public Class LibWrap
' Declares managed prototypes for unmanaged functions.
Declare Function TestStructInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef person2 As MyPerson2) As Integer
Declare Function TestStructInStruct3 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal person3 As MyPerson3) As Integer
Declare Function TestArrayInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef myStruct As MyArrayStruct) As Integer
End Class 'LibWrap
// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct MyPerson
{
public string first;
public string last;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyPerson2
{
public IntPtr person;
public int age;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyPerson3
{
public MyPerson person;
public int age;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyArrayStruct
{
public bool flag;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
public int[] vals;
}
public class LibWrap
{
// Declares a managed prototype for unmanaged function.
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestStructInStruct(ref MyPerson2 person2);
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestStructInStruct3(MyPerson3 person3);
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestArrayInStruct(ref MyArrayStruct myStruct);
}
// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Ansi)]
public value struct MyPerson
{
public:
String^ first;
String^ last;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyPerson2
{
public:
IntPtr person;
int age;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyPerson3
{
public:
MyPerson person;
int age;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyArrayStruct
{
public:
bool flag;
[MarshalAs(UnmanagedType::ByValArray, SizeConst=3)]
array<int>^ vals;
};
public ref class LibWrap
{
public:
// Declares a managed prototype for unmanaged function.
[DllImport("..\\LIB\\PinvokeLib.dll")]
static int TestStructInStruct(MyPerson2% person2);
[DllImport("..\\LIB\\PinvokeLib.dll")]
static int TestStructInStruct3(MyPerson3 person3);
[DllImport("..\\LIB\\PinvokeLib.dll")]
static int TestArrayInStruct(MyArrayStruct% myStruct);
};
함수 호출
Public Class App
Public Shared Sub Main()
' Structure with a pointer to another structure.
Dim personName As MyPerson
personName.first = "Mark"
personName.last = "Lee"
Dim personAll As MyPerson2
personAll.age = 30
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf( _
personName))
Marshal.StructureToPtr(personName, buffer, False)
personAll.person = buffer
Console.WriteLine(ControlChars.CrLf & "Person before call:")
Console.WriteLine("first = {0}, last = {1}, age = {2}", _
personName.first, personName.last, personAll.age)
Dim res As Integer = LibWrap.TestStructInStruct(personAll)
Dim personRes As MyPerson = _
CType(Marshal.PtrToStructure(personAll.person, _
GetType(MyPerson)), MyPerson)
Marshal.FreeCoTaskMem(buffer)
Console.WriteLine("Person after call:")
Console.WriteLine("first = {0}, last = {1}, age = {2}", _
personRes.first, _
personRes.last, personAll.age)
' Structure with an embedded structure.
Dim person3 As New MyPerson3()
person3.person.first = "John"
person3.person.last = "Evans"
person3.age = 27
LibWrap.TestStructInStruct3(person3)
' Structure with an embedded array.
Dim myStruct As New MyArrayStruct()
myStruct.flag = False
Dim array(2) As Integer
myStruct.vals = array
myStruct.vals(0) = 1
myStruct.vals(1) = 4
myStruct.vals(2) = 9
Console.WriteLine(vbNewLine + "Structure with array before call:")
Console.WriteLine(myStruct.flag)
Console.WriteLine("{0} {1} {2}", myStruct.vals(0), _
myStruct.vals(1), myStruct.vals(2))
LibWrap.TestArrayInStruct(myStruct)
Console.WriteLine(vbNewLine + "Structure with array after call:")
Console.WriteLine(myStruct.flag)
Console.WriteLine("{0} {1} {2}", myStruct.vals(0), _
myStruct.vals(1), myStruct.vals(2))
End Sub 'Main
End Class 'App
public class App
{
public static void Main()
{
// Structure with a pointer to another structure.
MyPerson personName;
personName.first = "Mark";
personName.last = "Lee";
MyPerson2 personAll;
personAll.age = 30;
IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(personName));
Marshal.StructureToPtr(personName, buffer, false);
personAll.person = buffer;
Console.WriteLine("\nPerson before call:");
Console.WriteLine("first = {0}, last = {1}, age = {2}",
personName.first, personName.last, personAll.age);
int res = LibWrap.TestStructInStruct(ref personAll);
MyPerson personRes =
(MyPerson)Marshal.PtrToStructure(personAll.person,
typeof(MyPerson));
Marshal.FreeCoTaskMem(buffer);
Console.WriteLine("Person after call:");
Console.WriteLine("first = {0}, last = {1}, age = {2}",
personRes.first, personRes.last, personAll.age);
// Structure with an embedded structure.
MyPerson3 person3 = new MyPerson3();
person3.person.first = "John";
person3.person.last = "Evans";
person3.age = 27;
LibWrap.TestStructInStruct3(person3);
// Structure with an embedded array.
MyArrayStruct myStruct = new MyArrayStruct();
myStruct.flag = false;
myStruct.vals = new int[3];
myStruct.vals[0] = 1;
myStruct.vals[1] = 4;
myStruct.vals[2] = 9;
Console.WriteLine("\nStructure with array before call:");
Console.WriteLine(myStruct.flag);
Console.WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
LibWrap.TestArrayInStruct(ref myStruct);
Console.WriteLine("\nStructure with array after call:");
Console.WriteLine(myStruct.flag);
Console.WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
}
}
public ref class App
{
public:
static void Main()
{
// Structure with a pointer to another structure.
MyPerson personName;
personName.first = "Mark";
personName.last = "Lee";
MyPerson2 personAll;
personAll.age = 30;
IntPtr buffer = Marshal::AllocCoTaskMem(Marshal::SizeOf(personName));
Marshal::StructureToPtr(personName, buffer, false);
personAll.person = buffer;
Console::WriteLine("\nPerson before call:");
Console::WriteLine("first = {0}, last = {1}, age = {2}",
personName.first, personName.last, personAll.age);
int res = LibWrap::TestStructInStruct(personAll);
MyPerson personRes =
(MyPerson)Marshal::PtrToStructure(personAll.person,
MyPerson::typeid);
Marshal::FreeCoTaskMem(buffer);
Console::WriteLine("Person after call:");
Console::WriteLine("first = {0}, last = {1}, age = {2}",
personRes.first, personRes.last, personAll.age);
// Structure with an embedded structure.
MyPerson3 person3;// = gcnew MyPerson3();
person3.person.first = "John";
person3.person.last = "Evans";
person3.age = 27;
LibWrap::TestStructInStruct3(person3);
// Structure with an embedded array.
MyArrayStruct myStruct;// = new MyArrayStruct();
myStruct.flag = false;
myStruct.vals = gcnew array<int>(3);
myStruct.vals[0] = 1;
myStruct.vals[1] = 4;
myStruct.vals[2] = 9;
Console::WriteLine("\nStructure with array before call:");
Console::WriteLine(myStruct.flag);
Console::WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
LibWrap::TestArrayInStruct(myStruct);
Console::WriteLine("\nStructure with array after call:");
Console::WriteLine(myStruct.flag);
Console::WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
}
};