Please let me suggest that "FinalReleaseComObject" is not the way to go. If you write structured code, you should never need it.
Strictly following Microsoft Patterns & Practices:
1) Declare & instantiate COM objects at the last moment possible.
2) ReleaseComObject(obj) for ALL objects, at the soonest moment possible.
3) Always ReleaseComObject in the opposite order of creation.
4) NEVER call GC.Collect() except when required for debugging.
All of these things are documented on MSDN. Upon following these simple rules, .NET will optimize garbage collection along the way, minimizing memory/garbage load, and improving your overall application performance.
WARNING:
GC.Collect will stop all .NET process in the OS to collect garbage. With each call to GC.Collect, you may promote garbage from Generation 0 to Generation 1 and then to Generation 2. Once your garbage reaches Generation 2, you must terminate your process to recover memory.
Finally, your code may require calling GC.Collect to get around leaky code. You can unknowingly leak hidden COM objects into garbage just by taking legitimate coding shortcuts. For example:
Imagine a COM function that does work, and returns a COM object.
(comClass.comObject) myCom.ProcessError(errorNumber);
Your code doesn't want the resulting object, it just wants to process the error:
myCom.ProcessError(5);
Marshal.ReleaseComObject(myCom);
The returned COM object is sent to .NET garbage, keeping a handle to myCom from garbage.
Until GC naturally occurs, myCom will not be fully released. This is why so many people need to force object destruction using FinalReleaseComObject() and GC.Collect().
Both are required for dirty Interop code.
A CLEAN version of this code:
Marshal.ReleaseComObject( myCom.ProcessError (5) );
Marshal.ReleaseComObject( myCom);
There are many other shortcuts where you ignore items in collections, and when you follow certain COM objects chains where you can leak intermediate objects. Again, please refer to Microsoft Patterns and Practices.