如何在c++中传递c#对象引用

本文关键字:对象引用 c++ | 更新日期: 2023-09-27 18:08:59

是否有任何方法通过本地互操作将c#对象引用(类类型,而不是结构)传入和传出c++ ?

这是我的用例:

我试图在c#中编写一个游戏引擎,但想使用本地(c++)物理库。物理库维护所有物理体的内部状态,并允许用户将少量数据(指针)与每个体相关联。在物理模拟标记之后,库提供了所有移动的物理物体的列表。我想遍历这个列表,并将所有更改传递给相应的c#对象。

问题是:将c#中的对象与c++中相应的物理实体相关联的最佳方式是什么?

我可以想到几个方法:

  1. 给每个物理实体一个某种类型的ID,在c++中将ID与物理实体关联起来,并在c#中维护ID到相应对象的映射。在我看来,这似乎是不必要的间接,即使有一个优化的映射机制。利用将c#委托(可以隐式引用c#对象实例)编组到c++函数指针中的能力。这可能是最好的方法;我不知道c#是如何实现委托的,也不知道这会带来什么样的开销。
  2. 在c++中找到引用c#对象的其他方法,并将该引用与每个本地物理实体相关联。

有没有类似选项3的机制是我不知道的?c++/CLI不是一个选择,因为我想支持没有它的平台。

如何在c++中传递c#对象引用

我建议使用专门为这种情况设计的工具,即System.Runtime.InteropServices.GCHandle

使用

:

  1. GCHandleType.NormalGCHandleType.Weak为CLR对象分配GCHandle
  2. 通过GCHandle.ToIntPtrGCHandle转换为IntPtr
  3. IntPtr作为您提到的userdata指针传递给c++端。

:

  1. 从c++端返回IntPtr
  2. 通过GCHandle.FromIntPtrIntPtr转换回GCHandle
  3. 使用GCHandleTarget属性来获取原始CLR对象

当CLR对象不再从c++端被引用时(要么是因为c++对象被销毁,要么是因为你将userdata指针重置为例如IntPtr.Zero),通过调用GCHandle.Free来释放GCHandle

应该分配哪种类型的GCHandle取决于您是否希望GCHandle保持对象存活(GCHandleType.Normal)或不存活(GCHandleType.Weak)。

  1. 映射唯一标识符将允许您将托管代码与非托管代码隔离开来。如果非托管端不对托管对象做任何事情可能会更好,因为你真的无法控制对象的生命周期。
  2. 委托作为函数指针是可能的。您所需要做的就是定义委托类型并创建实例。然后,您可以使用Marshal.GetFunctionPointerForDelegate获取一个地址以传递给非托管端。唯一需要注意的是,你必须确保回调是使用__stdcall
  3. 直接访问类成员和函数是可能的,但是如果没有c++/CLI包装器,你就是在玩火。
  4. 在c#端分配一块内存并将其传递给c++。在托管端的类中,使用属性以适当的偏移量访问该内存。
  5. 使COM对象可见。

另外,请记住,AccessViolationException通常在。net中是不可捕获的。