使用英语阅读

通过


封送不同类型的数组

数组是包含有一个或多个相同类型的元素的托管代码中的引用类型。 尽管数组是引用类型,但它们却作为 In 参数传递到非托管函数。 此行为与托管数组传递到托管对象的方式不一致,数组作为 In/Out 参数进行传递。 有关其他详细信息,请参阅 复制和锁定

下表列出了数组的封送处理选项,并描述了它们的用法。

数组 描述
通过值传递的整数。 将整数的数组作为 In 参数进行传递。
通过引用传递的整数。 将整数的数组作为 In/Out 参数进行传递。
通过值传递的整数(二维)。 将整数的矩阵作为 In 参数进行传递。
通过值传递的字符串。 将字符串的数组作为 In 参数进行传递。
传递具有整数的结构。 将包含整数的结构数组作为 In 参数进行传递。
传递具有字符串的结构。 将仅包含字符串的结构数组作为 In/Out 参数进行传递。 可以更改数组的成员。

示例

本示例演示如何传递以下类型的数组:

  • 通过值传递的整数数组。

  • 通过引用传递的整数数组(可以调整大小)。

  • 通过值传递的整数多维数组(矩阵)。

  • 通过值传递的字符串数组。

  • 传递具有整数的结构数组。

  • 传递具有字符串的结构数组。

除非数组由引用显式地进行封送处理,否则将以默认行为将数组作为 In 参数封送。 通过显示应用 InAttributeOutAttribute 属性,可以更改此行为。

数组示例使用以下非托管函数,这些函数与其原始函数声明一起显示:

  • 从 PinvokeLib.dll 导出的TestArrayOfInts

    int TestArrayOfInts(int* pArray, int pSize);  
    
  • 从 PinvokeLib.dll 导出的TestRefArrayOfInts

    int TestRefArrayOfInts(int** ppArray, int* pSize);  
    
  • 从 PinvokeLib.dll 导出的TestMatrixOfInts

    int TestMatrixOfInts(int pMatrix[][COL_DIM], int row);  
    
  • 从 PinvokeLib.dll 导出的TestArrayOfStrings

    int TestArrayOfStrings(char** ppStrArray, int size);  
    
  • 从 PinvokeLib.dll 导出的TestArrayOfStructs

    int TestArrayOfStructs(MYPOINT* pPointArray, int size);  
    
  • 从 PinvokeLib.dll 导出的TestArrayOfStructs2

    int TestArrayOfStructs2 (MYPERSON* pPersonArray, int size);  
    

PinvokeLib.dll 是一个自定义的非托管库,它包含之前列出的函数、两个结构变量( MYPOINTMYPERSON)的实现。 此结构包含以下元素:

typedef struct _MYPOINT  
{  
   int x;
   int y;
} MYPOINT;  
  
typedef struct _MYPERSON  
{  
   char* first;
   char* last;
} MYPERSON;  

在此示例中, MyPointMyPerson 结构包含嵌入类型。 设置 StructLayoutAttribute 特性,以确保成员在内存中按照它们出现的顺序进行排列。

NativeMethods 类包含一组 App 类调用的方法。 有关传递数组的特定详细信息,请参阅以下示例中的注释。 默认情况下,一个引用类型的数组将作为 In 参数进行传递。 为使调用方接收结果, InAttributeOutAttribute 必须显式应用于包含该数组的参数。

声明原型

// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind.Sequential)]
public struct MyPoint
{
    public int X;
    public int Y;

    public MyPoint(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyPerson
{
    public string First;
    public string Last;

    public MyPerson(string first, string last)
    {
        this.First = first;
        this.Last = last;
    }
}

internal static class NativeMethods
{
    // Declares a managed prototype for an array of integers by value.
    // The array size cannot be changed, but the array is copied back.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestArrayOfInts(
        [In, Out] int[] array, int size);

    // Declares a managed prototype for an array of integers by reference.
    // The array size can change, but the array is not copied back
    // automatically because the marshaler does not know the resulting size.
    // The copy must be performed manually.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestRefArrayOfInts(
        ref IntPtr array, ref int size);

    // Declares a managed prototype for a matrix of integers by value.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestMatrixOfInts(
        [In, Out] int[,] pMatrix, int row);

    // Declares a managed prototype for an array of strings by value.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestArrayOfstrings(
        [In, Out] string[] stringArray, int size);

    // Declares a managed prototype for an array of structures with integers.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestArrayOfStructs(
        [In, Out] MyPoint[] pointArray, int size);

    // Declares a managed prototype for an array of structures with strings.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestArrayOfStructs2(
        [In, Out] MyPerson[] personArray, int size);
}

调用函数

public class App
{
    public static void Main()
    {
        // array ByVal
        int[] array1 = new int[10];
        Console.WriteLine("Integer array passed ByVal before call:");
        for (int i = 0; i < array1.Length; i++)
        {
            array1[i] = i;
            Console.Write(" " + array1[i]);
        }

        int sum1 = NativeMethods.TestArrayOfInts(array1, array1.Length);
        Console.WriteLine("\nSum of elements:" + sum1);
        Console.WriteLine("\nInteger array passed ByVal after call:");

        foreach (int i in array1)
        {
            Console.Write(" " + i);
        }

        // array ByRef
        int[] array2 = new int[10];
        int size = array2.Length;
        Console.WriteLine("\n\nInteger array passed ByRef before call:");
        for (int i = 0; i < array2.Length; i++)
        {
            array2[i] = i;
            Console.Write(" " + array2[i]);
        }

        IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(size)
           * array2.Length);
        Marshal.Copy(array2, 0, buffer, array2.Length);

        int sum2 = NativeMethods.TestRefArrayOfInts(ref buffer, ref size);
        Console.WriteLine("\nSum of elements:" + sum2);
        if (size > 0)
        {
            int[] arrayRes = new int[size];
            Marshal.Copy(buffer, arrayRes, 0, size);
            Marshal.FreeCoTaskMem(buffer);
            Console.WriteLine("\nInteger array passed ByRef after call:");
            foreach (int i in arrayRes)
            {
                Console.Write(" " + i);
            }
        }
        else
        {
            Console.WriteLine("\nArray after call is empty");
        }

        // matrix ByVal
        const int DIM = 5;
        int[,] matrix = new int[DIM, DIM];

        Console.WriteLine("\n\nMatrix before call:");
        for (int i = 0; i < DIM; i++)
        {
            for (int j = 0; j < DIM; j++)
            {
                matrix[i, j] = j;
                Console.Write(" " + matrix[i, j]);
            }

            Console.WriteLine("");
        }

        int sum3 = NativeMethods.TestMatrixOfInts(matrix, DIM);
        Console.WriteLine("\nSum of elements:" + sum3);
        Console.WriteLine("\nMatrix after call:");
        for (int i = 0; i < DIM; i++)
        {
            for (int j = 0; j < DIM; j++)
            {
                Console.Write(" " + matrix[i, j]);
            }

            Console.WriteLine("");
        }

        // string array ByVal
        string[] strArray = { "one", "two", "three", "four", "five" };
        Console.WriteLine("\n\nstring array before call:");
        foreach (string s in strArray)
        {
            Console.Write(" " + s);
        }

        int lenSum = NativeMethods.TestArrayOfstrings(strArray, strArray.Length);
        Console.WriteLine("\nSum of string lengths:" + lenSum);
        Console.WriteLine("\nstring array after call:");
        foreach (string s in strArray)
        {
            Console.Write(" " + s);
        }

        // struct array ByVal
        MyPoint[] points = { new MyPoint(1, 1), new MyPoint(2, 2), new MyPoint(3, 3) };
        Console.WriteLine("\n\nPoints array before call:");
        foreach (MyPoint p in points)
        {
            Console.WriteLine($"X = {p.X}, Y = {p.Y}");
        }

        int allSum = NativeMethods.TestArrayOfStructs(points, points.Length);
        Console.WriteLine("\nSum of points:" + allSum);
        Console.WriteLine("\nPoints array after call:");
        foreach (MyPoint p in points)
        {
            Console.WriteLine($"X = {p.X}, Y = {p.Y}");
        }

        // struct with strings array ByVal
        MyPerson[] persons =
        {
            new MyPerson("Kim", "Akers"),
            new MyPerson("Adam", "Barr"),
            new MyPerson("Jo", "Brown")
        };

        Console.WriteLine("\n\nPersons array before call:");
        foreach (MyPerson pe in persons)
        {
            Console.WriteLine($"First = {pe.First}, Last = {pe.Last}");
        }

        int namesSum = NativeMethods.TestArrayOfStructs2(persons, persons.Length);
        Console.WriteLine("\nSum of name lengths:" + namesSum);
        Console.WriteLine("\n\nPersons array after call:");
        foreach (MyPerson pe in persons)
        {
            Console.WriteLine($"First = {pe.First}, Last = {pe.Last}");
        }
    }
}

请参阅