다음을 통해 공유


구조체 샘플

업데이트: 2007년 11월

이 샘플에서는 또 다른 구조체를 가리키는 구조체를 전달하는 방법, 포함된 구조체가 있는 구조체를 전달하는 방법 및 포함된 배열이 있는 구조체를 전달하는 방법을 보여 줍니다.

다음 코드 예제의 소스 코드는 .NET Framework Platform Invoke 기술 샘플을 통해 제공됩니다.

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, MYPERSON3MYARRAYSTRUCT에 대한 구현이 포함된, 관리되지 않는 사용자 지정 라이브러리입니다. 이 구조체에는 다음 요소가 포함되어 있습니다.

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 );
}

함수 호출

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 = "Evens"
      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( ControlChars.CrLf & "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( ControlChars.CrLf & "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 = "Evens";
      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 ] );
   }
}

참고 항목

개념

클래스, 구조체 및 공용 구조체 마샬링

플랫폼 호출 데이터 형식

관리 코드에서 프로토타입 만들기