다음을 통해 공유


OutArrayOfStructs 샘플

이 샘플에서는 정수와 문자열이 포함된 구조체 배열을 Out 매개 변수를 통해 관리되지 않는 함수에 전달하는 방법을 보여 줍니다.

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

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

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

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

앞에서 언급한 것처럼 C#에서는 안전하지 않은 코드를 사용할 수 있지만 Visual Basic 2005에서는 사용할 수 없습니다. C# 샘플에서 UsingUnsafePointer는 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);
}
// Declares a class member for each structure element.
[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Ansi)]
public ref class MyStruct
{
public:
    String^ buffer;
    int size;
};

// Declares a structure with a pointer.
[StructLayout(LayoutKind::Sequential)]
public value struct MyUnsafeStruct
{
public:
    IntPtr buffer;
    int size;
};

public ref class LibWrap
{
public:
    // Declares managed prototypes for the unmanaged function.
    [DllImport("..\\LIB\\PInvokeLib.dll")]
    static void TestOutArrayOfStructs(int% size,
        IntPtr% outArray);

    [DllImport("..\\LIB\\PInvokeLib.dll")]
    static void TestOutArrayOfStructs(int% size,
        MyUnsafeStruct** outArray);
};

함수 호출

Public Class App
    Public Shared Sub Main()
        Console.WriteLine( vbNewLine + "Using marshal class" + vbNewLine)
        UsingMarshaling()
        'Visual Basic 2005 cannot use unsafe code.
    End Sub 'Main

    Public Shared Sub UsingMarshaling()
        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");
        UsingMarshaling();
        Console.WriteLine("\nUsing unsafe code\n");
        UsingUnsafePointer();
    }

    public static void UsingMarshaling()
    {
        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 UsingUnsafePointer()
    {
        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);
    }
}
public ref class App
{
public:
    static void Main()
    {
        Console::WriteLine("\nUsing marshal class\n");
        UsingMarshaling();
        Console::WriteLine("\nUsing unsafe code\n");
        UsingUnsafePointer();
    }

    static void UsingMarshaling()
    {
        int size;
        IntPtr outArray;

        LibWrap::TestOutArrayOfStructs(size, outArray);
        array<MyStruct^>^ manArray = gcnew array<MyStruct^>(size);
        IntPtr current = outArray;
        for (int i = 0; i < size; i++)
        {
            manArray[i] = gcnew MyStruct();
            Marshal::PtrToStructure(current, manArray[i]);

            Marshal::DestroyStructure(current, MyStruct::typeid);
            //current = (IntPtr)((long)current + Marshal::SizeOf(manArray[i]));
            current = current + Marshal::SizeOf(manArray[i]);

            Console::WriteLine("Element {0}: {1} {2}", i, manArray[i]->buffer,
                manArray[i]->size);
        }
        Marshal::FreeCoTaskMem(outArray);
    }

    static void UsingUnsafePointer()
    {
        int size;
        MyUnsafeStruct* pResult;

        LibWrap::TestOutArrayOfStructs(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);
    }
};

참고 항목

개념

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

플랫폼 호출 데이터 형식

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