在 C 库调用中保留 .NET 对象的C++/CLI 句柄

本文关键字:C++ CLI 句柄 对象 NET 调用 保留 | 更新日期: 2023-09-27 18:30:49

我有一个C#库,需要用作直接C Win32应用程序的一部分。 我正在尝试在 C++/CLI 中编写一个可以处理 C# .NET 对象的包装器。 唯一的问题是整个项目不能用C++编译,它必须停留在C中。

为了解决这个问题,我想不透明地将 C# 对象的实例传递回 C 代码,以便它们可以传入并在包装库调用中使用,但我不知道该怎么做。 例如,我想做这样的事情:

C++/CLI 包装器:

void * ReturnObject(char *name){
  return (void *)gcnew MyObject(gcnew String(name));
}
void UseObject (void *object){
  MyObject ^handle = (MyObject ^)object;
  object -> use();
}

使用 C++ 静态库的本机 C 代码:

int main (char **argv){
  void *obj = ReturnObject("foobar");
  UseObject(obj);
}

所以C代码从不关心obj的内容是什么,甚至不知道CLR类型MyObject,它只是传递数据来维护对象持久性。 我认为这应该用void指针来完成,但C++编译器不想做强制转换。 我不知道这是因为托管内存和非托管内存之间的差异,还是我只是没有正确执行此操作,但我当然希望得到任何帮助。

所以,回顾一下:我正在尝试在 C++/CLI 包装器库中实例化 .net 对象,并将这些对象保留在直接的 C 代码中,以便它们可以在我尚未编写的其他 C++/CLI 库调用中再次使用。

有什么建议吗?

在 C 库调用中保留 .NET 对象的C++/CLI 句柄

您不能将句柄存储在 void* 中,因为垃圾回收器可以移动对象,使指针比无用更糟糕(它现在将指向其他一些随机对象)。

您需要使用 C++/CLI 提供的gcroot模板。 然后,您可以将gcroot<MyObject>*存储到void*中,并将其传递给 C 代码。 不要忘记在完成gcroot后正确释放它,以便运行析构函数。

还可以查看 GCHandle 类,该类是 .NET 类库的一部分。 但建议在 C++/CLI 代码中使用gcroot(它在内部使用 GCHandle)。