tel*_*dor 3 c# c++ clr pinvoke
我使用 P/Invoke 将数据从 C# 代码传递到 C++ 代码,反之亦然。到目前为止效果很好。
最近我读了几篇文章(例如这篇需要固定这些数据的
我查阅了一些微软的文章,但对我来说,它们并不完全清楚何时需要手动完成固定。我对这篇文章的理解是,CLR 确保 GC 收集时不会出现问题。它通过固定数据或将数据复制到 GC 不收集的非托管内存中来实现这一点。所以对我来说这意味着程序员不需要关心固定。本文中的示例也没有显示任何固定。我仍然不确定我的结论是否正确。
进一步挖掘,我发现了我在代码中使用的特定数据类型的更多信息:
int, long:按值传递 - 因此不得固定。但是关于ref int?
IntPtr:我使用 AllocHGlobal() 在非托管内存中分配空间。GC 不涉及这一点。因此无需固定。
byte[]:通过引用传递但自动固定。请参阅此处:作为一种优化,可直接传送类型的数组和仅包含可直接传送成员的类的数组将在封送过程中固定而不是复制。
string:通过引用传递但自动固定。请参阅此处:在对 String 等对象进行封送期间会自动执行固定,但您也可以使用 GCHandle 类手动固定内存。
string[], 'custom struct with strings': 这里我真的不确定。“在对诸如 String [...] 之类的对象进行编组期间自动执行 Pinning ”这句话是否包含字符串数组和自定义结构?
目前我没有固定任何东西,代码工作正常。即使我在 C++ 执行其任务时强制 GC 进行收集。但这当然并不意味着它总是工作得很好。我使用.Net Framework 4.8。
我需要固定上述数据类型吗?
这里的规则取决于您所调用的内容,因此在没有具体示例的情况下只能给出模糊的建议,但是:
如果您通过 P/Invoke 调用的方法仅在该 P/Invoke 调用期间使用指针,那么:在几乎所有情况下,您都可以传递隐式指针,或者在fixed调用周围使用(即,如果P/Invoke 签名只需声明SomeStruct*或IntPtr),就可以正常工作。
如果您通过 P/Invoke 调用的方法在返回之前存储指针,然后期望该指针有意义(可能对于基于回调的异步/完成 API),那么这就是您需要确保的问题场景数据不会被移动:
AllocHGlobal:没有什么必要