Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use FinalReleaseComObject instead of ReleaseComObject?

Tags:

.net

interop

com

I know the basic difference as ReleaseComObject only decreases some counter by one and FinalReleaseComObject decreases it to zero.

So what I usually hear is, call FinalReleaseComObject because then you are sure that the COM object is really released.

But this makes me wonder, there is a point to this counter right? Aren't you breaking that mechanism if you always call FinalReleaseComObject. If that counter is not one before you call ReleaseComObject, is there not probably a reason for it?

What could cause it to be higher than one when it should not be?

Thanks in advance.

PS: My COM experience only consists of using Excel Interop. Not sure if this question is local to that domain (i.e. outside Office Interop, FinalReleaseComObject is not often used).

Update 1

The article Dan mentioned talks about using ReleaseComObject when you're done. As I understand from the article, this is the normal way. I think that if you do this consistently it should work fine. In a comment to the article the author suggests someone to call ReleaseComObject in a loop until it is really released (the article is from 2006, so this is analogues to calling FinalReleaseComObject). But he also states that this could be dangerous.

If you really want to the RCW to call Release() at a particular point in the code, you can call ReleaseComObject() in a loop until the return value reaches zero. This should ensure the RCW will call Release(). However, if you do that, be warned, when the other managed references try to use that RCW, it will cause an exception."

This leads me to believe that it is indeed not a good idea to always call FinalReleaseComObject, as you can cause exceptions elsewhere. As I see it now, you should only call this if you are absolutely sure that you can.

Still, I have little experience in this matter. I don't know how I can be sure. If the counter is increased when it should not be, is it not better to fix that problem? If so, then I would say FinalReleaseComObject is more of a hack than a best practice.

like image 700
Matthijs Wessels Avatar asked Dec 01 '09 15:12

Matthijs Wessels


1 Answers

Some preamble...

A Runtime Callable Wrapper (RCW) only calls IUnknown.AddRef once on the unmanaged COM interface that it wraps. However, an RCW also maintains a separate count of the number of managed references there are to the RCW itself. It is this separate count of managed references that is decremented by a call to Marshal.ReleaseComObject. When the count of managed references reaches zero, the RCW calls IUnknown.Release once on the unmanaged COM interface.

Marshal.FinalReleaseComObject takes the managed reference count to zero with a single call, and thus invokes the wrapped unmanaged IUnknown.Release method immediately (assuming that the managed reference count was not already zero).

So why have both Marshal.ReleaseComObject and Marshal.FinalReleaseComObject? Calling Marshal.FinalReleaseComObject simply avoids having to write a loop that calls Marshal.ReleaseComObject repeatedly until it returns 0 when you wish to indicate that you've really finished using a COM object now.

Why use either Marshal.ReleaseComObject or Marshal.FinalReleaseComObject? There are two reasons I'm aware of:

The first is to ensure that unmanaged resources (such as file handles, memory etc.) being used by the wrapped COM object are freed as soon as possible as a result of the resulting call to the unmanaged IUnknown.Release() method.

The second is to ensure that the thread calling the unmanaged IUnknown.Release() method is under your control, and not the finalizer thread.

Without calls to either of these Marshal methods, the RCW's finalizer will eventually call the unmanaged IUnknown.Release() method some time after the RCW has been garbage collected.

For corroborative details, see the Visual C++ Team blog entry Mixing deterministic and non-deterministic cleanup

like image 132
Dan Blanchard Avatar answered Oct 08 '22 20:10

Dan Blanchard