如果我的本机代码需要一个包含两个字段的结构:
[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调用?
答案 0 :(得分:1)
我不应该工作。甚至更多,您需要添加并正确设置StructLayoutAttribute到结构,正如它解释here
我认为,结果应该是这样的:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
IntPtr First;
IntPtr Second;
}
答案 1 :(得分:1)
如果结构中的总差异是添加到结尾的字段,并且使用StructLayout
来阻止编译器优化结构的内存布局(正如Alex Butenko建议的那样),那么它不太可能存在任何负面影响,除了轻微的速度命中。
当您通过P / Invoke(使用struct
属性)将托管DllImport
传递给外部函数时,会有一个编组阶段将您的结构转换为目标的兼容格式。对于ref
和out
参数,在调用的函数返回时将临时值转换回来,将值复制回struct
实例。所有这些都被抽象掉了,尽管如何为每个成员执行编组操作可以使用正确的属性进行调整。
这就是.NET框架在P / Invoke中处理字符串的方式。因为它不能只发送一个string
实例指针指向期望char *
的API函数(两者不相似),所以必须进行一些翻译。
有趣的是,编组代码并不知道目标所期望的内容,而不是你在C#端告诉它的内容,所以如果你发送的是结构的扩展版本,它将完成整个过程。 。在另一端,本机代码将获得一个指向内存块的指针,该内存块包含它所期望的信息,并且没有任何方法可以告诉结构结束后还有更多信息。
除此之外,没有问题......只要您通过引用传递而不是通过值传递。通过价值传递结构应该会在整个大脑中产生大的红色停止标志。不要这样做,这是邪恶的。