I know the basic difference as ReleaseComObject
only decreases some counter by one and FinalReleaseComObject
decreases it to zero.
So what
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