C COM服务器:
interface IFace1: IUnkNown{ HRESULT CreateOtherInterface([in] REFIID iidFace,[out,iid_is(iidFace)] void** ppOut); }; coclass ClassIFace1 { [default] interface IFace1; };
C#客户端:
ClassIFace1 Face1Obj = new ClassIFace1(); IFace1 Face1Ctrl = (IFace1)Face1Obj; IFace2 Face2Ctrl = null; IntPtr Face2IntPtr = new IntPtr(); Face1Ctrl.CreateOtherInterface(Face2Guid,out Face2IntPtr); Face2Ctrl = (IFace2)Mashal.PtrToStructure(Face2IntPtr); //Consume Face2Ctrl if(Face1Obj != null) { Marshal.ReleaseComObject(Face1Obj); }
由于IFace2,IFace3和IFace4不与IFace1共享相同的coclass,我怀疑Marshal.ReleaseComObject(Face1Obj)行只会破坏ClassIFace1对象而不会破坏ClassIFace2,ClassIFace3,ClassIFace4对象并导致内存泄漏.有什么方法可以解决这个问题吗?或者Marshal.ReleaseComObject(Face1Obj)实际上也会破坏其他COM对象?
解决方法
但是,由于你提到只有1个coclass暴露给客户端,我想象有一些奇怪的原因,客户端使用的TLB文件没有看到其他3个coclasses或其他3个coclass没有正确注册但是由一些专有方式的第一个coclass.我也假设您无法修改服务器端实现.
鉴于所有这些假设,这是我的答案.引用计数独立地保留在4个coclass中.因此,释放第一个coclass上的引用不会减少其他三个coclass中的引用计数.
还有一些事情你需要注意.您正在使用Marshal.ReleaseComObject(Face1Obj)来释放第一个coclass.你可以这样做,因为第一个coclass由Runtime Callable Wrapper(RCW)包装.就像Martin所说,即使你不调用Marshal.ReleaseComObject(),.NET运行时也会在发生garbabge收集时为你做.
但是,Face2Ctrl的获得方式不同.它不是由RCW包裹的.您将返回的指针直接视为结构.这对我来说听起来不对,因为您可能在内存对齐和数据编组方面存在问题.你想要做的可能是调用Marshal.GetobjectForIUnkNown,它会为你返回一个RCW.获得RCW后,您可以调用Marshal.ReleaseComObject()以及时释放您的RCW.
如果CreateOtherInterface的实现类似于QueryInterface,它总是在返回的接口上添加AddRef,那么一旦完成Face2Obj,就应该在返回的接口上调用Marshal.Release. Marshal.ReleaseComObject()是不够的,因为它只释放了RCW添加的引用计数,但在这种情况下,你需要在IUnkNown上调用一次更多.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。