From: Igor R. on
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
"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
>     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
"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
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