다음을 통해 공유


OutArrayOfStructs 샘플

업데이트: 2007년 11월

이 샘플에서는 정수와 문자열이 포함된 구조체 배열을 Out 매개 변수를 통해 관리되지 않는 함수에 전달하는 방법을 보여 줍니다. 샘플 소스 코드는 Platform Invoke 기술 샘플에 포함되어 있습니다.

이 샘플에서는 Marshal 클래스나 안전하지 않은 코드를 사용하여 네이티브 함수를 호출하는 방법을 보여 줍니다.

이 샘플에서는 PinvokeLib.dll에 정의되어 있고 소스 파일에도 제공된 래퍼 함수와 플랫폼 호출을 사용합니다. 또한 TestOutArrayOfStructs 함수와 MYSTRSTRUCT2 구조체를 사용합니다. 이 구조체에는 다음 요소가 포함되어 있습니다.

typedef struct _MYSTRSTRUCT2
{
   char* buffer;
   UINT size; 
} MYSTRSTRUCT2;

MyStruct 클래스에는 ANSI 문자로 구성된 문자열 개체가 들어 있습니다. CharSet 필드는 ANSI 형식을 지정합니다. MyUnsafeStruct는 문자열 대신 IntPtr 형식이 들어 있는 구조체입니다.

LibWrap 클래스에는 오버로드된 TestOutArrayOfStructs 프로토타입 메서드가 포함되어 있습니다. 메서드에서 포인터를 매개 변수로 선언하는 경우 이 클래스는 unsafe 키워드로 표시되어야 합니다. Visual Basic 2005에서는 안전하지 않은 코드를 사용할 수 없으므로 오버로드된 메서드, 안전하지 않은 한정자 및 MyUnsafeStruct 구조체가 필요하지 않습니다.

App 클래스에서는 배열 전달에 필요한 모든 작업을 수행하는 UsingMarshal 메서드를 구현합니다. 이 배열은 out(Visual Basic의 경우 ByRef) 키워드로 표시되어 데이터가 호출 수신자에서 호출자에게 전달됨을 나타냅니다. 이 구현에서는 다음의 Marshal 클래스 메서드를 사용합니다.

  • PtrToStructure - 관리되지 않는 버퍼에서 관리되는 개체로 데이터를 마샬링합니다.

  • DestroyStructure - 구조체의 문자열용으로 예약된 메모리를 해제합니다.

  • FreeCoTaskMem - 배열용으로 예약된 메모리를 해제합니다.

앞에서 언급한 것처럼 C#에서는 안전하지 않은 코드를 사용할 수 있지만 Visual Basic 2005에서는 사용할 수 없습니다. C# 샘플에서 UsingUnsafe는 Marshal 클래스 대신 포인터를 사용하여 MyUnsafeStruct 구조체가 들어 있는 배열을 다시 전달할 수 있도록 구현된 또 다른 메서드입니다.

프로토타입 선언

' Declares a class member for each structure element.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Ansi )> _
Public Class MyStruct 
   Public buffer As String 
   Public someSize As Integer
End Class 'MyStruct

Public Class LibWrap
' Declares a managed prototype for the unmanaged function.
   Declare Sub TestOutArrayOfStructs Lib "..\\LIB\\PinvokeLib.dll" ( _
      ByRef arrSize As Integer, ByRef outArray As IntPtr )
End Class 'LibWrap
// Declares a class member for each structure element.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MyStruct 
{
   public String buffer;
   public int size;
}
// Declares a structure with a pointer.
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnsafeStruct 
{
   public IntPtr buffer;
   public int size;
}

public unsafe class LibWrap
{
   // Declares managed prototypes for the unmanaged function.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size, 
      out IntPtr outArray );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size, 
   MyUnsafeStruct** outArray );
}

함수 호출

Public Class App
   Public Shared Sub Main()
      Console.WriteLine( ControlChars.CrLf & "Using marshal class" & _
ControlChars.CrLf )
      UsingMarshal()
      'Visual Basic 2005 cannot use unsafe code.
   End Sub 'Main
   
   Public Shared Sub UsingMarshal()   
      Dim arrSize As Integer
      Dim outArray As IntPtr
      LibWrap.TestOutArrayOfStructs( arrSize, outArray )
      Dim manArray(arrSize - 1) As MyStruct
      Dim current As IntPtr = outArray
      Dim i As Integer
      
      For i = 0 To arrSize - 1
      
         manArray(i) = New MyStruct()
         Marshal.PtrToStructure( current, manArray(i))
         
         Marshal.DestroyStructure( current, GetType( MyStruct )) 
         current = IntPtr.op_explicit( current.ToInt64() _
           + Marshal.SizeOf( manArray(i) ))
         
         Console.WriteLine( "Element {0}: {1} {2}", i, manArray(i)._
           buffer, manArray(i).someSize )
      Next i
      Marshal.FreeCoTaskMem( outArray )
   End Sub 'UsingMarshal
End Class 'App
public class App
{
   public static void Main()
   {
      Console.WriteLine( "\nUsing marshal class\n" );
      UsingMarshal();
      Console.WriteLine( "\nUsing unsafe code\n" );
      UsingUnsafe();
   }
   
   public static void UsingMarshal()   
   {
      int size;
      IntPtr outArray;
      LibWrap.TestOutArrayOfStructs( out size, out outArray );
      MyStruct[] manArray = new MyStruct[ size ];
      IntPtr current = outArray;
      for( int i = 0; i < size; i++ )
      {
         manArray[ i ] = new MyStruct();
         Marshal.PtrToStructure( current, manArray[ i ]);
         
         //Marshal.FreeCoTaskMem( (IntPtr)Marshal.ReadInt32( current ));
         Marshal.DestroyStructure( current, typeof(MyStruct) );
         current = (IntPtr)((long)current + 
            Marshal.SizeOf( manArray[ i ] ));
         
         Console.WriteLine( "Element {0}: {1} {2}", i, 
            manArray[ i ].buffer, manArray[ i ].size );
      }
      Marshal.FreeCoTaskMem( outArray );
   }
   
   public static unsafe void UsingUnsafe()
   {
      int size;
      MyUnsafeStruct* pResult;
      LibWrap.TestOutArrayOfStructs( out size, &pResult );
      MyUnsafeStruct* pCurrent = pResult;
      for( int i = 0; i < size; i++, pCurrent++ )
      {
         Console.WriteLine( "Element {0}: {1} {2}", i, 
            Marshal.PtrToStringAnsi( pCurrent->buffer ), pCurrent->size );
         Marshal.FreeCoTaskMem( pCurrent->buffer );
      }
      Marshal.FreeCoTaskMem( (IntPtr)pResult );
   }
}

참고 항목

개념

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

플랫폼 호출 데이터 형식

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