From: Igor R. on 4 May 2010 08:16 Hello, In my C# project I use a COM-based SDK. Some of its COM objects generate events. Assume the following scenario (all the objects below are from the SDK): var child = new SDKLib.Child(); child.onSomeEvent += () => { doSomething() }; someParent.setChild(child); In the above code "child" COM object is held by "someParent" - by design, preventing it from getting disposed. *But*, IUUC, no one holds its RCW, because "child" variable is local. So when "child" goes out of scope, it's GC-ed, which in turn causes it to Unadvise() from the event source. Thus, after a few seconds "onSomeEvent" stops firing. Certainly, I can create a List<Object>, which would hold all these objects - just to prevent their garbage-collection, but maybe there's a more elegant way to workarnoud this issue? Thanks.
From: Alberto Poblacion on 4 May 2010 14:46 "Igor R." <igor.rubinov(a)gmail.com> wrote in message news:8c6244d9-2381-4077-8109-661e5248bd2b(a)s29g2000yqd.googlegroups.com... > In my C# project I use a COM-based SDK. Some of its COM objects > generate events. > Assume the following scenario (all the objects below are from the > SDK): > > var child = new SDKLib.Child(); > child.onSomeEvent += () => { doSomething() }; > someParent.setChild(child); > > In the above code "child" COM object is held by "someParent" - by > design, preventing it from getting disposed. *But*, IUUC, no one holds > its RCW, because "child" variable is local. So when "child" goes out > of scope, it's GC-ed, which in turn causes it to Unadvise() from the > event source. Thus, after a few seconds "onSomeEvent" stops firing. > Certainly, I can create a List<Object>, which would hold all these > objects - just to prevent their garbage-collection, but maybe there's > a more elegant way to workarnoud this issue? Have you actually tried this out? In theory, the Garbage Collector does NOT free objects that are reachable, either directly or indirectly. That is, if someParent has a reference to child, and child has a reference to the RCW, then neither child nor the RCW will be Collected even if child has gone out of scope, because both objects are still reachable (through someParent).
From: Igor R. on 4 May 2010 19:04 > Have you actually tried this out? Sure, I did. I observed a weird situation: the object stopped firing events few seconds after it was created. Then I had to debug the ATL connection-points implementation to realize what actually happened. > In theory, the Garbage Collector does NOT free objects that are reachable, either directly or indirectly. That's the point - the "child" is NOT accessible. The accessible entity is the underlying COM object, but it's not managed by .NET anyway. > That is, if someParent has a reference to child, and child has a reference to the RCW It seems that the child doesn't reference the RCW. IIUC, the reference is one-way: RCW references the COM object, but not vice versa.
From: Alberto Poblacion on 4 May 2010 19:52 "Igor R." <igor.rubinov(a)gmail.com> wrote in message news:4129f13e-51b2-4c6d-9055-ec7a945ca00f(a)i9g2000yqi.googlegroups.com... > That's the point - the "child" is NOT accessible. The accessible > entity is the underlying COM object, but it's not managed by .NET > anyway. But the .Net code never references the COM object. It only references the RCW, which *is* a .Net assembly and is subject to Garbage Collection. When you do this: var child = new SDKLib.Child(); "child" is not the COM object, it is a reference to an instance of the RCW that wraps the COM object.
From: Peter Duniho on 4 May 2010 23:29
Igor R. wrote: > Hello, > > In my C# project I use a COM-based SDK. Some of its COM objects > generate events. > Assume the following scenario (all the objects below are from the > SDK): > > var child = new SDKLib.Child(); > child.onSomeEvent += () => { doSomething() }; > someParent.setChild(child); > > In the above code "child" COM object is held by "someParent" - by > design, preventing it from getting disposed. *But*, IUUC, no one holds > its RCW, because "child" variable is local. So when "child" goes out > of scope, it's GC-ed, which in turn causes it to Unadvise() from the > event source. [...] Frankly, your code example is so sparse and vague, it's hard to know what you're talking about. But, let's assume that the object returned by "SDKLib.Child()" is a COM object wrapped in RCW. Let's further assume that "someParent.setChild(child)" for whatever reason does _not_ retain a reference to the RCW object that was returned by "SDKLib.Child()" (perhaps it itself is an RCW, and thus the only thing it internally is retaining is the unmanaged COM interface reference). If all that's true, then yes�without any references to the wrapper object, it will be GC'ed, and the COM object released when that happens. As for the solution, it's the same as if you had a managed object with an event that you subscribed to. You have to keep a reference to it, otherwise the object with the event will be collected. Why should the RCW be any different? .NET doesn't have any effective way to track the lifetime of the underlying COM object; all it can do is manage the managed object. If you want your managed objects to stay alive, you need to keep references to them. Pete |