Partilhar via


Amostra de OutArrayOfStructs

Este exemplo mostra como passar uma matriz de estruturas que contém números inteiros e seqüências de caracteres como parâmetros para uma função não gerenciada.

Este exemplo demonstra como chamar uma função nativa usando o Marshal de classe e usando código não seguro.

Este exemplo utiliza a funções de wrapper e platform invokes definido em PinvokeLib.dll, também é fornecida em arquivos de origem. Ele usa o TestOutArrayOfStructs função e o MYSTRSTRUCT2 estrutura. A estrutura contém os seguintes elementos:

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

O MyStruct classe contém um objeto de seqüência de caracteres de ANSI. O CharSet campo especifica o formato de ANSI. MyUnsafeStruct, é uma estrutura que contém um IntPtr tipo em vez de uma seqüência de caracteres.

O LibWrap classe contém o sobrecarregado TestOutArrayOfStructs método de protótipo. Se um método declara um ponteiro como um parâmetro, a classe deve ser marcada com o unsafe palavra-chave. Porque Visual Basic 2005 não é possível usar o código não seguro, o método sobrecarregado, modificador inseguro e o MyUnsafeStruct estrutura são desnecessários.

O App classe implementa o UsingMarshaling método, que executa todas as tarefas necessárias para passar o array. A matriz é marcada com o out (ByRef em Visual Basic) passa de palavra-chave para indicar que os dados do chamador para o chamador. A implementação usa a seguinte Marshal métodos de classe:

  • PtrToStructurepara empacotar dados no buffer não gerenciado em um objeto gerenciado.

  • DestroyStructurePara liberar a memória reservada para seqüências de caracteres na estrutura.

  • FreeCoTaskMemPara liberar a memória reservada para a matriz.

Como mencionado anteriormente, C# permite que o código não seguro e Visual Basic 2005 faz não. No exemplo de C#, UsingUnsafePointer é uma implementação do método alternativo que usa ponteiros em vez da Marshal classe para passar de volta a matriz que contém o MyUnsafeStruct estrutura.

A declaração de protótipos

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

Chamando funções

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

Consulte também

Conceitos

O empacotamento de Classes, estruturas e uniões

Tipos de dados de invocação de plataforma

A criação de protótipos em código gerenciado