none
Disposing COM objects.

    Question

  • Hi

     

    When I add reference to COM lib and I use some objects to I have to some how call dispose/destructor on those objects? Or GC will handle this automatically?

     

    Regards


    kicaj
    Tuesday, January 25, 2011 7:15 PM

Answers

  • As opposed to the opinion of Reed Copsey, I personally don't liked the idea that the CG will eventually clean up my COM objects. In the past this gave me all sorts of trouble e.g. Out-Of-Proc server still running after my application finished, documents still locked (in use) after using it in the COM server, ...

    Unfortunatelly Microsoft didn't implement the dispose pattern for the RCW (runtime callable wrapper) so I did my own helper class:

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    
    
    	public class ComDisposer : IDisposable
    	{
    		private List<Object> _comObjs;
    
    		public ComDisposer()
    		{
    			_comObjs = new List<Object>();
    		}
    
    		~ComDisposer()
    		{
    			Dispose(false);
    		}
    
    		public T Add<T>(T o)
    		{
    			if ( o != null && o.GetType().IsCOMObject )
    				_comObjs.Add(o);
    			return o;
    		}
    
    		public void Clear()
    		{
    			Dispose(true);
    		}
    
    		protected virtual void Dispose(bool disposing)
    		{
    			if ( disposing )
    			{
    				for ( int i = _comObjs.Count - 1; i >= 0; --i )
    					Marshal.FinalReleaseComObject( _comObjs[i] );
    				_comObjs.Clear();
    			}
    		}
    
    		void IDisposable.Dispose()
    		{
    			Dispose(true);
    			GC.SuppressFinalize(this);
    		}
    	}
    
    

    The usage is quite simple, just add all COM objects to an instance of the class and dispose it afterwards:

    using ( ComDisposer cd = new ComDisposer() )
    {
     Excel.Application app = cd.Add( new Excel.Application() );
     Excel.Workbooks wbs = cd.Add( app.Workbooks );
     Excel.Workbook wb = cd.Add( wbs.Open(...) );
     ...
    }
    // all COM objects are released at this point
    
    Hope it helps.

    • Marked as answer by kicaj Wednesday, January 26, 2011 9:21 PM
    Wednesday, January 26, 2011 6:28 AM

All replies

  • You rarely need to do this, as the GC will (eventually) clean it up.  However, if the COM object represents a large resource, you may want to call Marshal.ReleaseComObject on the  instance explicitly to force the release of it immediately.

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Tuesday, January 25, 2011 7:31 PM
    Moderator
  • As opposed to the opinion of Reed Copsey, I personally don't liked the idea that the CG will eventually clean up my COM objects. In the past this gave me all sorts of trouble e.g. Out-Of-Proc server still running after my application finished, documents still locked (in use) after using it in the COM server, ...

    Unfortunatelly Microsoft didn't implement the dispose pattern for the RCW (runtime callable wrapper) so I did my own helper class:

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    
    
    	public class ComDisposer : IDisposable
    	{
    		private List<Object> _comObjs;
    
    		public ComDisposer()
    		{
    			_comObjs = new List<Object>();
    		}
    
    		~ComDisposer()
    		{
    			Dispose(false);
    		}
    
    		public T Add<T>(T o)
    		{
    			if ( o != null && o.GetType().IsCOMObject )
    				_comObjs.Add(o);
    			return o;
    		}
    
    		public void Clear()
    		{
    			Dispose(true);
    		}
    
    		protected virtual void Dispose(bool disposing)
    		{
    			if ( disposing )
    			{
    				for ( int i = _comObjs.Count - 1; i >= 0; --i )
    					Marshal.FinalReleaseComObject( _comObjs[i] );
    				_comObjs.Clear();
    			}
    		}
    
    		void IDisposable.Dispose()
    		{
    			Dispose(true);
    			GC.SuppressFinalize(this);
    		}
    	}
    
    

    The usage is quite simple, just add all COM objects to an instance of the class and dispose it afterwards:

    using ( ComDisposer cd = new ComDisposer() )
    {
     Excel.Application app = cd.Add( new Excel.Application() );
     Excel.Workbooks wbs = cd.Add( app.Workbooks );
     Excel.Workbook wb = cd.Add( wbs.Open(...) );
     ...
    }
    // all COM objects are released at this point
    
    Hope it helps.

    • Marked as answer by kicaj Wednesday, January 26, 2011 9:21 PM
    Wednesday, January 26, 2011 6:28 AM