P / Invoke传递结构比本机代码期望的更长

时间:2016-01-07 00:24:40

标签: c# .net pinvoke

如果我的本机代码需要一个包含两个字段的结构:

[DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern int my_method(ref MyStruct myStruct);

// this is what native code expects
public struct MyStruct {
    IntPtr First;
    IntPtr Second;
}

但是我将另一个结构传递给它,是否有效 - 无论是设计还是偶然?

[DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern int my_method(ref MyLongerStruct myLongerStruct);

// this is what I want to pass to it
public struct MyLongerStruct {
    IntPtr First;
    IntPtr Second;
    object ObjectPointer;
}

将对象引用添加到C#侧结构的末尾会不会影响P / Invoke调用?

2 个答案:

答案 0 :(得分:1)

我不应该工作。甚至更多,您需要添加并正确设置StructLayoutAttribute到结构,正如它解释here

我认为,结果应该是这样的:

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
    IntPtr First;
    IntPtr Second;
}

答案 1 :(得分:1)

如果结构中的总差异是添加到结尾的字段,并且使用StructLayout来阻止编译器优化结构的内存布局(正如Alex Butenko建议的那样),那么它不太可能存在任何负面影响,除了轻微的速度命中。

当您通过P / Invoke(使用struct属性)将托管DllImport传递给外部函数时,会有一个编组阶段将您的结构转换为目标的兼容格式。对于refout参数,在调用的函数返回时将临时值转换回来,将值复制回struct实例。所有这些都被抽象掉了,尽管如何为每个成员执行编组操作可以使用正确的属性进行调整。

这就是.NET框架在P / Invoke中处理字符串的方式。因为它不能只发送一个string实例指针指向期望char *的API函数(两者不相似),所以必须进行一些翻译。

有趣的是,编组代码并不知道目标所期望的内容,而不是你在C#端告诉它的内容,所以如果你发送的是结构的扩展版本,它将完成整个过程。 。在另一端,本机代码将获得一个指向内存块的指针,该内存块包含它所期望的信息,并且没有任何方法可以告诉结构结束后还有更多信息。

除此之外,没有问题......只要您通过引用传递而不是通过值传递。通过价值传递结构应该会在整个大脑中产生大的红色停止标志。不要这样做,这是邪恶的。