Share via


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

请参见

概念

封送类、结构和联合

平台调用数据类型

在托管代码中创建原型