I am in the process of writing an application in C # that will open an Excel spreadsheet (2007, for now) through interop, work a little, and then close. The "magic" part is non-trivial, therefore this application will contain many links to many COM objects generated by Excel.
I wrote this application before (too many times, in fact), but I never found a convenient “good smell” approach for interacting with COM objects. The problem is partly that, despite considerable research, I still do not quite understand COM, and partly that the interaction wrappers hide a lot that probably should not be hidden. The fact that there are many different conflicting suggestions from the community only exacerbates the situation.
If you can’t tell from the name, I did my research. Title refers to this post:
How to clean Excel interaction objects correctly?
First asked in 2008, the advice was really useful and solid at the time (especially “Never use 2 points with COM objects”), but now it seems outdated. In March 2010, the Visual Studio team published a blog article warning computer programmers that Marshal.ReleaseComObject [was considered] dangerous . Two articles are mentioned in the article: cbrumme WebLog> ReleaseComObject and Display between interface pointers and callable wrappers (RCW) , which indicates that people used ReleaseComInterop incorrectly all the time (cbrumme: "If you are a client application using a small amount of COM -objects that are freely distributed in your managed code, you should not use ReleaseComObject ").
Does anyone have an example of a moderately complex application, preferably using multiple threads that can successfully move between memory leaks (Excel continues to run in the background after closing the application) and InvalidComObjectExceptions? I am looking for something that will allow a COM object to be used outside the context in which it was created, but it can be cleared after the application is completed: a hybrid of memory management strategies that can effectively cover managed / unmanaged separation.
Linking to an article or study guide that discusses the correct approach to this problem would be a very valuable alternative. My best google-fu efforts returned the obviously wrong ReleaseComInterop approach.
UPDATE:
(This is not an answer)
I discovered this article shortly after posting:
VSTO and COM Interop by Jake Jinnivan
I was able to implement my strategy of wrapping COM objects in AutoCleanup classes using the extension method, and I am very pleased with the result. Although it does not provide solutions that allow COM objects to cross the boundaries of the context in which they were created, and still uses the ReleaseComObject function, it at least provides a clear and easy to read solution.
Here is my implementation:
class AutoCleanup<T> : IDisposable { public T Resource { get; private set; } public AutoCleanup( T resource ) { this.Resource = resource; } ~AutoCleanup() { this.Dispose(); } private bool _disposed = false; public void Dispose() { if ( !_disposed ) { _disposed = true; if ( this.Resource != null && Marshal.IsComObject( this.Resource ) ) { Marshal.FinalReleaseComObject( this.Resource ); } else if ( this.Resource is IDisposable ) { ( (IDisposable) this.Resource ).Dispose(); } this.Resource = null; } } } static class ExtensionMethods { public static AutoCleanup<T> WithComCleanup<T>( this T target ) { return new AutoCleanup<T>( target ); } }