如何在 C++-CLI 中创建全局句柄

问题描述 投票:0回答:6

我尝试在 C++-CLI 项目中使用 C# 类,但 Visual Studio 只允许我在函数内部的本地范围内声明 C# 对象的句柄 (^)。我让它工作的唯一方法是声明一个指向句柄的全局指针:

SUTAdapter::Form1^ *ptForm1;

但是如果我在函数内创建一个对象并将其地址赋予全局指针:

SUTAdapter::Form1^ form1;
form1 = gcnew SUTAdapter::Form1();
ptForm1 = &form1;
(*ptForm1)->incCounter(0);

当函数退出并且我尝试在其他 C++-CLI 函数中使用 incCounter 函数时,该对象似乎消失了(调试器说 this == null)。有没有办法在 C++-CLI 中拥有 C# 代码的全局句柄?我猜由于某种我不明白的原因,全局句柄被禁止,但我没有主意,我需要完成此操作。谢谢你。

编辑:

*ptForm1 = gcnew SUTAdapter::Form1();

给出空引用异常。为什么?

c++-cli
6个回答
4
投票

此限制似乎与其他基于 CLR 的语言一致。例如,C# 没有静态、函数范围变量的概念。 C++/CLI 中缺乏此类功能表明这就是 CLR 的工作方式 - 静态对象必须在类范围内定义。

CLR 是基于对象的,因此这只是面向对象的性质影响其上运行的语言设计的一个例子。

从面向对象的角度来看,无论如何我更喜欢 C#。


2
投票

好的,谢谢你的回答,但我终于解决了,我在谷歌上找到了它:

http://bytes.com/groups/net-vc/473036-how-define-global-com-object-vc-8-a

VS 似乎不允许全局句柄或静态句柄位于函数内部。我对此感到困惑,因为有时需要全局访问托管对象。

解决方案是声明一个“GlobalObjects”类,其中包含静态句柄:

ref class GlobalObjects
{
public:
static SUTAdapter::Form1^ hndForm1;
};

这样我就可以全局访问 C# 表单/类。上一个错误的错误代码是C3145,我还在想为什么VS不允许声明全局句柄。


1
投票

Visual Studio 是否允许您在本地范围内声明 C# 对象的 static 句柄?

SUTAdapter::Form1^ theForm() {
   static SUTAdapter::Form1^ form1 = gcnew SUTAdapter::Form1();
   return form1;
}

1
投票
*ptForm1 = gcnew SUTAdapter::Form1();

给出空引用异常,因为您正在取消引用空指针 - 在这方面它就像指向任何其他类型的指针一样。


0
投票

我认为 - 而且没有测试过 - 你遇到的问题是因为你存储了一个指向本地句柄的指针,这可能会让垃圾收集器有点困惑,因为你正在使用一个指向本地句柄的指针一个自动对象。

您是否尝试过将上面的作业替换为


*ptForm1 = gcnew SUTAdapter::Form1();

而不是通过本地对象引用绕道?


0
投票

进入正题,c++/cli 不允许全局作用域或本机类中的托管对象的原因是因为垃圾收集器的堆压缩功能。 GC 可以在内存中移动对象以避免碎片。然后,此操作会使对托管对象的引用不指向它们应该指向的位置,在 c# 中, (大多数情况下)一切都在GC的监视下发生,这些引用在所述压缩发生后更新为新位置。 然而,gc 不知道在非托管内存上找到的托管引用(发现这一点很困难),因此在本机环境中声明此类引用是不切实际的。 一个简单的解决方法是使用 gcroot<>,它是众所周知的 GCHandle 的包装器。 另外,您的解决方案不起作用的原因是您获得了指向引用的指针,该引用在函数退出时被清除,因此您的指针没有指向。 (PS:抱歉,如果这个回答很古怪,这实际上是我的第一次。)

© www.soinside.com 2019 - 2024. All rights reserved.