Search code examples
c#.netexcelcomoffice-interop

Excel COM Interop, process not finishes if I edit cells


I am trying to work with Excel via COM interop. It works fine but Excel process is still hanging after DoStuff method is finished (though it disappears when my program finishes).

If I remove the code that fills cell I do not have this issue.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

namespace ConsoleApplication13
{
    class Program
    {
        static void DoStuff()
        {
            string workbookPath = @"C:\....xlsx";

            var excelApp = new Excel.Application();

            excelApp.Visible = true;

            var workbooks = excelApp.Workbooks;

            var workbook = workbooks.Open(workbookPath,
                0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
                true, false, 0, true, false, false);

            var workheets = workbook.Worksheets;

            var mainWorksheet = (Excel.Worksheet) workheets.Item[1];

            var cell = (Excel.Range)mainWorksheet.Cells[4, "U"];

            cell.set_Value(Missing.Value, 99);

            ReleaseObject(cell);

            ReleaseObject(mainWorksheet);
            ReleaseObject(workheets);

            workbook.Close(false, Missing.Value, Missing.Value);

            ReleaseObject(workbook);
            ReleaseObject(workbooks);

            excelApp.Quit();

            ReleaseObject(excelApp);

        }

        private static void ReleaseObject(object obj)
        {
            if (obj != null && Marshal.IsComObject(obj))
            {
                Marshal.ReleaseComObject(obj);
            }
        }

        static void Main(string[] args)
        {
            DoStuff();

            Console.ReadKey();
        }
    }
}

I am trying to store all references to COM objects and release it as was suggested here How do I properly clean up Excel interop objects? but it doesn't work for Cells and I don't understand why.


Solution

  • I ended up doing something like this with the GC approach. Looks like it works fine.

    using System;
    using System.Reflection;
    using Excel = Microsoft.Office.Interop.Excel;
    
    namespace ConsoleApplication13
    {
        class ExcelWorker : IDisposable
        {
            private Excel.Application _excelApp;
    
            private Excel.Workbook _workbook;
            private Excel.Worksheet _mainWorksheet;
    
            private readonly string _workbookPath;
    
            public ExcelWorker(string workbookPath)
            {
                _workbookPath = workbookPath;
            }
    
            public void Start()
            {
                _excelApp = new Excel.Application();
    
                _excelApp.Visible = true;
    
                var workbooks = _excelApp.Workbooks;
    
                _workbook = workbooks.Open(_workbookPath,
                    0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
                    true, false, 0, true, false, false);
    
                var workheets = _workbook.Worksheets;
    
                _mainWorksheet = (Excel.Worksheet) workheets.Item[1];
            }
    
            public void DoStuff()
            {
                var cell = (Excel.Range)_mainWorksheet.Cells[4, "U"];
    
                cell.set_Value(Missing.Value, 99);
            }
    
            public void Stop()
            {
                if (_workbook != null)
                {
                    _workbook.Close(false, Missing.Value, Missing.Value);
    
                    _workbook = null;
                    _mainWorksheet = null;
                }
    
                if (_excelApp != null)
                {
                    _excelApp.Quit();
    
                    _excelApp = null;
                }
    
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
    
            public void Dispose()
            {
                Stop();
            }
        }
    
        class Program
        {
    
            static void Main(string[] args)
            {
                using (var excelWorker = new ExcelWorker(@"C:\.....xlsx"))
                {
                    excelWorker.Start();
    
                    excelWorker.DoStuff();
    
                    excelWorker.DoStuff();
                }
    
                Console.ReadKey();
            }
        }
    }