P/Invoke [In,Out]属性是否可选用于编组数组?

Mr.*_*C64 11 c# c++ arrays pinvoke attributes

假设存在一个带有纯C接口的本机函数,如下所示,从本机DLL导出:

// NativeDll.cpp

extern "C" void __stdcall FillArray(
    int fillValue, 
    int count, 
    int* data)
{
    // Assume parameters are OK...

    // Fill the array
    for (int i = 0; i < count; i++)
    {
        data[i] = fillValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下P/Invoke工作正常(使用VS2010 SP1测试):

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)]
public static extern void FillArray(
    int fillValue,
    int count,
    [In, Out] int[] data
);
Run Code Online (Sandbox Code Playgroud)

以及这个P /调用,与上面相同,但没有[In, Out]属性:

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)]
public static extern void FillArray(
    int fillValue,
    int count,
    int[] data
);
Run Code Online (Sandbox Code Playgroud)

那么,这些[In, Out]属性是否可选用于编组数组?他们的目的是什么,如果有的话?可以在我们的P/Invoke声明中省略它们吗?

Han*_*ant 21

不,他们不是完全可选的.它碰巧偶然工作.然而,这是一个非常常见的事故.它的工作原理是因为数组实际上没有被编组.pinvoke marshaller看到C#数组已经与本机数组兼容,因此跳过创建它的副本的步骤.它只是固定数组并将指针传递给本机代码.

这当然是非常有效的,你将不可避免地得到结果,因为本机代码直接写数组元素.因此,[In]和[Out]属性都不重要.

如果数组元素类型不那么简单,那就会变得更加模糊.在编组之后识别不是blittable或布局不匹配的结构或类类型的元素类型并不容易,因此pinvoke marshaller 必须复制该数组.尤其是布局不兼容可能非常难以确定,因为管理布局无法发现.并且可以根据使用的抖动而改变.它可以在x86中工作但不能在x64中工作,当选择AnyCPU时非常讨厌.得到它的修改的副本复制回C#阵列需要[OUT].

不知道该建议什么,除了没有人因为他们的声明明确而被解雇.也许你应该总是在数组元素类型不简单的时候明确,这样你就不会发生意外.