元帅的 [In] [Out] 属性

Posted

技术标签:

【中文标题】元帅的 [In] [Out] 属性【英文标题】:Marshal's [In] [Out] Attributes 【发布时间】:2015-06-06 07:29:42 【问题描述】:

我在我的 C# 代码中调用了一个非托管函数。

该函数的声明如下:

int myFun(unsigned char* inputBuffer, unsigned char* &outputBuffer);

我使用这个函数如下:

[DllImport("myDLL.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int myFun([In] byte[] inputBuffer, out IntPtr outputBuffer);

byte[] a = Encoding.ASCII.GetBytes("sampletext!");
IntPtr b;
res = myFun(a, out b);

虽然我提到了[InAttribute]byte[] inputBuffer,但该函数仍然改变了a 的值。似乎 CLR 正在使用自己的默认封送处理行为。 我使用了byte[],因为它与unsigned char* 等效。

当我将 byte[] 替换为 char[] 时,CLR 将遵循我的 In-Out 属性。

非常感谢您的帮助。 如需更多信息,请阅读此msdn page。

【问题讨论】:

也许MarshalAs 就是您要找的东西? pinvoke marshaller 仅在必要时复制数据。它不必使用 byte[],它只是固定数组并将指针传递给第一个元素。因此,本机代码直接在托管数组上进行聚会。非常有效率。与 char[] 不同的是,元素必须从 16 位值转换为 8 位值。您将获得 Encoding.Default 值。 pinvoke marshaller必须复制,没有[Out]就不会复制回来。 【参考方案1】:

来自documentation,我的重点是:

作为一种优化,仅包含 blittable 成员的 blittable 类型和类的数组在编组期间被固定而不是复制。当调用者和被调用者在同一个单元中时,这些类型可以作为 In/Out 参数编组。但是,这些类型实际上是作为 In 参数编组的,如果要将参数编组为 In/Out 参数,则必须应用 InAttribute 和 OutAttribute 属性。

由于 byte 是 blittable,因此您的字节数组被固定而不是复制,因此编组为 In/Out。

当我用 char[] 替换 byte[] 时,CLR 将遵循我的 In-Out 属性。

C# 类型 char 是 not blittable。 char 的数组未固定,因此 [In] char[] 编组为 In 参数。

【讨论】:

C#类型的char不是blittable。如果他使用Charset Unicode呢? @xanatos 我的答案中的文档链接将 System.Char 列为非 blittable @David Heffernan,非常感谢您的回答。这篇文章也很有用。 msdn.microsoft.com/en-us/library/23acw07k%28v=vs.110%29.aspx @DavidHeffernan 今天终于做了一个测试...和C方法外的地址一样,[In]/[Out]是“隐式”的) @xanatos 好的,这似乎是合理的。不过,在问题的代码中,byte[] 是正确的,因为这是二进制数据。

以上是关于元帅的 [In] [Out] 属性的主要内容,如果未能解决你的问题,请参考以下文章

openGL之API学习(一七六)GLSL变量类型uniform attribute varying in out

添加中心性度量作为顶点属性

css3 的过渡效果transition最少需要设置哪两个属性

css动画及权重

Python string 模块

Filter中获取session的属性