Why won't excel instances not quit

0

I am trying to delete named ranges from a bunch of excel files.

Getting the following exception throws when the code is running:

"Invalid index. (Exception from HRESULT: 0x8002000B (DISP_E_BADINDEX))"

Tried everything thing I could think of but excel instances just won't quit!

Please see the code pasted below. Interop is no less than a horrible nightmare! :(

enter image description here

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Excel = Microsoft.Office.Interop.Excel;
    using System.IO;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    namespace excel_delete_nr
    {
        class Program
        {
            static void Main(string[] args)
            {

                String tp_folder = @"C:\tp";
                String[] tps = Directory.GetFiles(tp_folder);

                foreach (String m in tps)
                {

                   var xlApp = new Excel.Application();
                   var xlWorkbooks = xlApp.Workbooks;
                   var xlWorkbook = xlWorkbooks.Open(m);


                    var ranges = xlWorkbook.Names;
                    int leftoveritems = ranges.Count;


                    while (leftoveritems > 0)
                    {
                        int i = 1;
                        try
                        {
                            while (i <= leftoveritems)
                            {
                                xlWorkbook.Names.Item(i).Delete();
                                //System.Windows.Forms.MessageBox.Show(i + " deleted.");
                                i++;
                            }
                        }
                        catch (Exception ex)
                        {
                             Console.WriteLine(ex.Message);
                        }

                        ranges = xlWorkbook.Names;
                        leftoveritems = ranges.Count;
                    }



                    xlWorkbook.Save();
                    xlWorkbook.Close();
                    xlWorkbooks.Close();
                    xlApp.Quit();

                    Marshal.ReleaseComObject(ranges);
                    Marshal.ReleaseComObject(xlWorkbook);
                    Marshal.ReleaseComObject(xlWorkbooks);
                    Marshal.ReleaseComObject(xlApp);

                }
            }
        }
    }
c#
excel-interop
asked on Stack Overflow Feb 20, 2019 by user3289968

1 Answer

1

I got it working with the below code. You must be really careful when working with Interop.
But if you have such simple task and if you know all your files will be the new format (understand Open XML) than I would use OpenXML solution where you don't need to use Excel at all and it significantly faster. Check it below

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

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Which solution to use?\n1  - for running Excel or \n2 - for using OpenXML");
            var result = Console.ReadLine();
            if (string.IsNullOrWhiteSpace(result)) return;

            String tp_folder = @"c:\tp\";
            String[] tps = Directory.GetFiles(tp_folder);

            if (result == "1")
            {
                DeleteNamesWithExcelApp(tps);
            }
            else if (result == "2")
            {
                var cls = new OpenXmlSolution();
                foreach (String m in tps)
                {
                    cls.RemoveNames(m);
                }
            }

            Console.WriteLine("Done");
            Console.ReadLine();
        }

        public static void DeleteNamesWithExcelApp(String[] tps)
        {

            Excel.Workbooks xlWorkbooks = null;
            Excel.Workbook xlWorkbook = null;
            Excel.Names ranges = null;

            var xlApp = new Excel.Application();
            try
            {
                foreach (String m in tps)
                {
                    xlWorkbooks = xlApp.Workbooks;
                    xlWorkbook = xlWorkbooks.Open(m);
                    ranges = xlWorkbook.Names;
                    int leftoveritems = ranges.Count;

                    Excel.Name name = null;
                    try
                    {
                        for (int i = leftoveritems; i >= 1; i--)
                        {
                            name = xlWorkbook.Names.Item(i);
                            name.Delete();
                            if (name != null) Marshal.ReleaseComObject(name);
                            name = null;
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        if (name != null) Marshal.ReleaseComObject(name);
                    }
                    if (xlWorkbook != null)
                    {
                        xlWorkbook.Close(true);
                        Marshal.ReleaseComObject(xlWorkbook);
                        xlWorkbook = null;
                    }
                    if (xlWorkbooks != null) Marshal.ReleaseComObject(xlWorkbooks);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if (ranges != null) Marshal.ReleaseComObject(ranges);
                if (xlWorkbook != null) Marshal.ReleaseComObject(xlWorkbook);
                if (xlWorkbooks != null) Marshal.ReleaseComObject(xlWorkbooks);
                if (xlApp != null)
                {
                    xlApp.Quit();
                    Marshal.ReleaseComObject(xlApp);
                    xlApp = null;
                }
            }
        }
    }
}

Here is the OpenXML solution I'd prefer. I really don't know how it behaves with old xls files.

using DocumentFormat.OpenXml.Packaging;
using System.Linq;

namespace ConsoleApp3
{
    public class OpenXmlSolution
    {
        public void RemoveNames(string fullPathToFile)
        {            
            using (SpreadsheetDocument document = SpreadsheetDocument.Open(fullPathToFile, true))
            {
                WorkbookPart wbPart = document.WorkbookPart;
                var numOfNames = wbPart.Workbook.DefinedNames.Count();
                if (numOfNames == 0) return;
                for (int i = numOfNames -1 ; i >= 0; i--)
                {
                    wbPart.Workbook.DefinedNames.ChildElements[i].Remove();
                }                
                wbPart.Workbook.Save();                
            }
        }
    }
}
answered on Stack Overflow Feb 20, 2019 by PetLahev

User contributions licensed under CC BY-SA 3.0