如何在 C++-CLI 中创建全局句柄
我尝试在 C++-CLI 项目中使用 C# 类,但 Visual Studio 只允许我在函数内部的本地范围内声明 C# 对象的句柄 (^)。 我让它工作的唯一方法是声明一个指向句柄的全局指针:
SUTAdapter::Form1^ *ptForm1;
但是如果我在函数内创建一个对象并将其地址赋予全局指针:
SUTAdapter::Form1^ form1;
form1 = gcnew SUTAdapter::Form1();
ptForm1 = &form1;
(*ptForm1)->incCounter(0);
当函数退出并且我尝试在其他函数中使用 incCounter 函数时C++-CLI 函数,对象似乎消失了(调试器说 this == null)。 有没有办法在 C++-CLI 中拥有 C# 代码的全局句柄? 我猜由于某种我不明白的原因,全局句柄被禁止,但我没有主意,我需要完成此操作。 谢谢。
编辑:
*ptForm1 = gcnew SUTAdapter::Form1();
给出空引用异常。 为什么?
I am trying to use a C# class in a C++-CLI project, but Visual Studio will only let me declare a handle (^) to a C# object in a local scope, just inside a function. The only way I got it working was declaring a global pointer to a handle:
SUTAdapter::Form1^ *ptForm1;
But if then I create an object inside a function and give its address to the global pointer:
SUTAdapter::Form1^ form1;
form1 = gcnew SUTAdapter::Form1();
ptForm1 = &form1;
(*ptForm1)->incCounter(0);
When the function exits and I try to use the incCounter function inside some other C++-CLI function, the object seems gone (debugger says this == null). Is there a way to have a global handle of a C# code in C++-CLI? I guess global handles are forbidden for some reason I don't understand but I am out of ideas and I need this done. Thank you.
edit:
*ptForm1 = gcnew SUTAdapter::Form1();
Gives a null reference exception. Why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
此限制似乎与其他基于 CLR 的语言一致。 例如,C# 没有静态、函数范围变量的概念。 C++/CLI 中缺乏此类功能表明这就是 CLR 的工作方式 - 静态对象必须在类范围内定义。
CLR 是基于对象的,因此这只是面向对象性质影响其上运行的语言设计的一个例子。
从面向对象的角度来看,无论如何我更喜欢 C#。
This restriction seems consistent with the other CLR-based languages. C# has no concept of a static, function-scoped variable for example. The lack of such functionality in C++/CLI suggests that is the way the CLR works - static objects must be defined at the class scope.
The CLR is object based, so this is just a case of that object-oriented nature influencing the design of languages that run on top of it.
From an OO view point, I like the C# way better anyway.
好的,谢谢您的回答,但我终于解决了它,我在谷歌上发现了它:
http://bytes.com/groups/net-vc/473036-how-define-global-com-object-vc-8-a
看来VS没有不要让全局句柄或静态句柄位于函数内部。 我对此感到困惑,因为有时需要全局访问托管对象。
解决方案是声明一个“GlobalObjects”类,其中包含静态句柄:
这样我就可以全局访问 C# 表单/类。 上一个错误的错误代码是C3145,我仍然想知道为什么VS不允许声明全局句柄。
Ok thanks for your answers but I finally solved it, I found it googling:
http://bytes.com/groups/net-vc/473036-how-define-global-com-object-vc-8-a
It seems that VS doesn't let global handles or static handles inside functions. I am puzzled about this because sometimes it is necessary to access managed objects globally.
The solution is to declare a "GlobalObjects" class with static handles inside it:
This way I can access the C# form/class globally. The error code of the previoous error is C3145, I am still wondering why does not VS allow the declaration of global handles.
Visual Studio 是否允许您在本地范围内声明 C# 对象的静态句柄?
Will Visual Studio let you declare a static handle to a C# object in a local scope?
给出空引用异常,因为您正在取消引用空指针 - 在这方面它就像指向任何其他类型的指针一样。
Gives a null reference exception because you are dereferncing a null pointer - it is just like a pointer to any other type in that regard.
我认为 - 而且没有测试它 - 你遇到的问题是因为你存储了一个指向本地句柄的指针,这可能会让垃圾收集器有点困惑,因为你正在使用一个指向自动对象。
代替上述分配?
您是否尝试过通过本地对象引用来
I think - and that's without testing it - that the problem you're having is because you're storing a pointer to a local handle, which might confuse the garbage collector a little due to the fact that you're taking a pointer to an automatic object.
Have you tried to replace the above assignment with
instead of the detour via the local object reference?
进入主题,C++/CLI 不允许全局范围或本机类中的托管对象的原因是垃圾收集器的堆压缩功能。 GC 可以在内存中移动对象以避免碎片。
然后,此操作会使对托管对象的引用不再指向它们应该指向的位置。 在 C# 中,(大部分)所有事情都在 GC 的监视下发生,这些引用会在所述压缩发生后使用新位置进行更新。
但是,GC 不知道在非托管内存上找到的托管引用(这是很难找到的),因此在本机环境中声明此类引用是不切实际的。
一个简单的解决方法是使用
gcroot<>
,它是众所周知的GCHandle
的包装器。另外,您的解决方案不起作用的原因是您获得了一个指向引用的指针,该引用在函数退出时被清除,因此您的指针没有指向。
To put you into the topic, the reason C++/CLI does not allow managed objects in the global scope or in native classes is because of the heap compaction function of the garbage collector. The GC can move objects around in memory to avoid fragmentation.
This action then makes references to your managed objects not point where they should. In C#, where (mostly) everything is happening under the watch of the GC, these references get updated with the new locations after said compaction happened.
However, the GC is not aware of the managed references found on unmanaged memory (found this the hard way), making it unpractical to declare such a reference in native environments.
A simple workaround this, is to use
gcroot<>
which is a wrapper for the well knownGCHandle
.Also, the reason your solution doesn't work is because you get a pointer to the reference, this reference is cleaned on function exit, so your pointer isn't pointing.