How to dispose of a NET COM interop object on Release()(如何在 Release() 上处理 NET COM 互操作对象)
问题描述
我有一个用托管代码 (C++/CLI) 编写的 COM 对象.我在标准 C++ 中使用该对象.
当 COM 对象被释放时,如何强制我的 COM 对象的析构函数立即被调用?如果这不可能,请调用我的 COM 对象上的 Release() 调用 MyDispose() 方法?
我声明对象的代码(C++/CLI):
<上一页>[Guid("57ED5388-blahblah")][接口类型(ComInterfaceType::InterfaceIsIDispatch)][ComVisible(真)]公共接口类 IFoo{无效 Doit();};[Guid("417E5293-blahblah")][ClassInterface(ClassInterfaceType::None)][ComVisible(真)]公共参考类 Foo : IFoo{上市:无效我的处置();~Foo() {MyDispose();}//这永远不会被调用!Foo() {MyDispose();}//这由垃圾收集器调用.virtual ULONG Release() {MyDispose();}//这永远不会被调用虚空 Doit();};我使用对象的代码(原生 C++):
<上一页>#import "..\Debug\Foo.tlb"...Bar::IFoo setup(__uuidof(Bar::Foo));//这个对象来自 .tlb.设置.Doit();设置->释放();//显式释放,实际上没有必要,因为 Bar::IFoo 的析构函数将调用 Release().如果我在我的 COM 对象上放置一个析构方法,它就永远不会被调用.如果我放置一个终结器方法,它会在垃圾收集器处理它时被调用.如果我明确调用我的 Release() 覆盖,它永远不会被调用.
我真的很喜欢这样,当我的原生 Bar::IFoo 对象超出范围时,它会自动调用我的 .NET 对象的处置代码.我想我可以通过重写 Release() 来做到这一点,如果对象计数 = 0,则调用 MyDispose().但显然我没有正确覆盖 Release(),因为我的 Release() 方法从未被调用过.
显然,我可以通过将 MyDispose() 方法放在接口中并要求使用我的对象的人在 Release() 之前调用 MyDispose() 来实现这一点,但如果 Release() 只是清理了对象.
是否可以在释放 COM 对象时强制立即调用 .NET COM 对象的析构函数或其他方法?
在这个问题上谷歌搜索让我得到很多点击,告诉我调用 System.Runtime.InteropServices.Marshal.ReleaseComObject(),但当然,这就是你告诉 .NET 释放 COM 对象的方式.我希望 COM Release() 处理一个 .NET 对象.
实际上,当最后一个引用被释放时,无论是 Dispose(或者我应该说 ~Foo)还是 Release 都不会从 COM 客户端调用.它根本没有实施.这里有一些想法如何做到这一点.
http://blogs.msdn.com/oldnewthing/archive/2007/04/24/2252261.aspx#2269675
但即使作者也不建议使用该方法.
如果你也实现了 COM 客户端,最好的选择是查询 IDisposable 并显式调用 Dispose,要请求的 iid 是:
{805D7A98-D4AF-3F0F-967F-E5CF45312D2C}
我能想到的其他选择是实现某种自己的COM 垃圾收集器".COM 创建的每个对象都将放在一个列表中(前提是您的类型的对象只能由 COM 创建 - 我想不出任何方法来区分对象的创建位置).然后您必须定期检查列表,并在每个对象上调用如下内容:
IntPtr iUnk = Marshal.GetIUnknownForObject(@object);int refCount = Marshal.Release(iUnk);如果(参考计数 == 0)@object.Dispose();
但这是一个疯狂的想法.
I have a COM object written in managed code (C++/CLI). I am using that object in standard C++.
How do I force my COM object's destructor to be called immediately when the COM object is released? If that's not possible, call I have Release() call a MyDispose() method on my COM object?
My code to declare the object (C++/CLI):
[Guid("57ED5388-blahblah")] [InterfaceType(ComInterfaceType::InterfaceIsIDispatch)] [ComVisible(true)] public interface class IFoo { void Doit(); }; [Guid("417E5293-blahblah")] [ClassInterface(ClassInterfaceType::None)] [ComVisible(true)] public ref class Foo : IFoo { public: void MyDispose(); ~Foo() {MyDispose();} // This is never called !Foo() {MyDispose();} // This is called by the garbage collector. virtual ULONG Release() {MyDispose();} // This is never called virtual void Doit(); };
My code to use the object (native C++):
#import "..\Debug\Foo.tlb" ... Bar::IFoo setup(__uuidof(Bar::Foo)); // This object comes from the .tlb. setup.Doit(); setup->Release(); // explicit release, not really necessary since Bar::IFoo's destructor will call Release().
If I put a destructor method on my COM object, it is never called. If I put a finalizer method, it is called when the garbage collector gets around to it. If I explicitly call my Release() override it is never called.
I would really like it so that when my native Bar::IFoo object goes out of scope it automatically calls my .NET object's dispose code. I would think I could do it by overriding the Release(), and if the object count = 0 then call MyDispose(). But apparently I'm not overriding Release() correctly because my Release() method is never called.
Obviously, I can make this happen by putting my MyDispose() method in the interface and requiring the people using my object to call MyDispose() before Release(), but it would be slicker if Release() just cleaned up the object.
Is it possible to force the .NET COM object's destructor, or some other method, to be called immediately when a COM object is released?
Googling on this issue gets me a lot of hits telling me to call System.Runtime.InteropServices.Marshal.ReleaseComObject(), but of course, that's how you tell .NET to release a COM object. I want COM Release() to Dispose of a .NET object.
Actually neither the Dispose (or should i say ~Foo) not the Release will be called from the COM client when the last reference is released. It simply is not implemented. Here is some idea how such a thing could be done.
http://blogs.msdn.com/oldnewthing/archive/2007/04/24/2252261.aspx#2269675
But the method is not advised even by author.
If you implement the COM Client as well the best option would be to query for IDisposable and call Dispose explicitly, iid to request is:
{805D7A98-D4AF-3F0F-967F-E5CF45312D2C}
Other option I can think of is to implement some sort of own "COM Garbage Collector". Each object created by COM would be placed in a list (Provided that objects of your type are only creatable by COM - I cannot think of any method to distinguish from where the object is created). And then you would have to periodically check the list, and on each object call something like this:
IntPtr iUnk = Marshal.GetIUnknownForObject(@object);
int refCount = Marshal.Release(iUnk);
if (refCount == 0)
@object.Dispose();
but this is some crazy idea.
这篇关于如何在 Release() 上处理 NET COM 互操作对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在 Release() 上处理 NET COM 互操作对象
基础教程推荐
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01