元帅的 [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