简体   繁体   中英

Excel doesn't close despite objects being released

So, I have a class that I wrote to handle opening excel files, however excel doesn't close even though I call the close function. This worked before I started using multiple workbooks so I presume that its something to do with that but I have no idea how to fix this. Any help appreciated!

This is the code:

public class ExcelReaderClass
    {
        public Excel.Application? excelApp = null; // create a null excell object that will later be used to store the reference to the open excel app
        public Excel.Workbooks? excelBooks = null; // create a null object collection that will contain all workbooks
        public Excel.Workbook? excelBook = null; // create a null object that will contain a workbook (excel file)
        public Excel.Worksheet? curWorksheet = null; // create a null worksheet object that will contain the reference to the current worksheet that is open
        public Excel.Range? curWorksheetRange = null; // create a range object that will contain the data from the currently open worksheet

        // function that opens excel file and opens excel if it isnt already open
        public void openExcelFile(string filePath) // filePath = filepath for the worksheet that is to be opened
        {
            if(excelApp == null) // if excel isnt open
            {
                excelApp = new Excel.Application(); // create a new instance of excel

                excelApp.DisplayAlerts = false; // prevents "do you want to save" popups, which we want because we are only looking at files not changing them

                excelBooks = excelApp.Workbooks; // create a new instance of workbook object collection
            }

            excelBook = excelBooks.Add(filePath); // add the workbook to the collection
        }

        // function that closes all instances of excel opened by this program
        public void closeExcelFile(bool save, bool closeAll) // bool that controls whether only the worksheet is closed or the whole instance of excel
        {
            //excelBook.Save(); // save function not needed in this instance but might be useful later

            GC.Collect();
            GC.WaitForPendingFinalizers();

            foreach (Excel.Workbook workbook in excelBooks)
            {
                workbook.Close(save, System.Reflection.Missing.Value, System.Reflection.Missing.Value); // close the workbook 
                NAR(workbook);
            }

            NAR(excelBooks); ; // release the workbook collection from Com
            NAR(excelBook);
            NAR(curWorksheet);
            NAR(curWorksheetRange);

            if (closeAll) // if close all is true, we want to close the excel instance too
            {
                excelApp.Quit(); // quit out of excel

                NAR(excelApp); // release excel from Com
            }
        }

        public List<object[,]> readExcelFile(string[] filePaths) // 
        {
            List<object[,]> rangeList = new List<object[,]>(); // list of objects that will contain the data from the excel sheets

            foreach (var filePath in filePaths) // for each file
            {
                openExcelFile(filePath); // open the file in excel
            }

            foreach (var workbook in excelBooks) // iterate through workbooks 
            {
                var book = workbook as Excel.Workbook; // set book as a reference to the workbook

                curWorksheet = book.Worksheets[1]; // set this variable to the first sheet in the workbook
                curWorksheetRange = curWorksheet.UsedRange; // set this variable to the workbook range

                object[,]? range = (object[,])curWorksheetRange.Value2;

                rangeList.Add(range);
            }

            closeExcelFile(false,true);

            return (rangeList);
        }

        //function to kill object and release it from COM
        private void NAR(object o)
        {
            try
            {
                Marshal.FinalReleaseComObject(o);
            }
            catch { }
            finally
            {
                o = null;
            }
        }
    }

I've tried using GC.Collect() and GC.WaitForPendingFinalizers() but that doesn't seem to work either.

Update, this is what I did to fix the code. Feel free to use it. (Doesn't work in Debug mode though)

public class ExcelReaderClass
    {
        public Excel.Application? excelApp = null; // create a null excell object that will later be used to store the reference to the open excel app
        public Excel.Workbooks? excelBooks = null; // create a null object collection that will contain all workbooks
        public Excel.Workbook? excelBook = null; // create a null object that will contain a workbook (excel file)
        public Excel.Worksheet? curWorksheet = null; // create a null worksheet object that will contain the reference to the current worksheet that is open
        public Excel.Range? curWorksheetRange = null; // create a range object that will contain the data from the currently open worksheet

        // function that opens excel file and opens excel if it isnt already open
        public void openExcelFile(string filePath) // filePath = filepath for the worksheet that is to be opened
        {
            if(excelApp == null) // if excel isnt open
            {
                excelApp = new Excel.Application(); // create a new instance of excel

                excelApp.DisplayAlerts = false; // prevents "do you want to save" popups, which we want because we are only looking at files not changing them

                excelBooks = excelApp.Workbooks; // create a new instance of workbook object collection
            }

            excelBook = excelBooks.Add(filePath); // add the workbook to the collection
        }

        // function that closes all instances of excel opened by this program
        public void closeExcelFile(bool save, bool closeAll) // bool that controls whether only the worksheet is closed or the whole instance of excel
        {
            foreach (Excel.Workbook workbook in excelBooks)
            {
                workbook.Close(save, System.Reflection.Missing.Value, System.Reflection.Missing.Value); // close the workbook 
            }

            excelBooks = null; // clear the reference to the workbook collection
            excelBook = null; // clear the reference to the active workbook
            curWorksheet = null; // clear the reference to the current worksheet
            curWorksheetRange = null; // clear the reference to the range of the current worksheet

            if (closeAll) // if close all is true, we want to close the excel instance too
            {
                excelApp.Quit(); // quit out of excel
                excelApp = null;
            }
        }

        public List<object[,]> readExcelFile(string[] filePaths)
        {
            List<object[,]> rangeList = new List<object[,]>();

            foreach (var filePath in filePaths)
            {
                openExcelFile(filePath);
            }

            Console.WriteLine();

            foreach (var workbook in excelBooks) // done to select the first workbook because other methods have failed but this works
            {
                var book = workbook as Excel.Workbook; // set book as a reference to the workbook

                curWorksheet = book.Worksheets[1]; // set this variable to the first sheet in the workbook
                curWorksheetRange = curWorksheet.UsedRange; // set this variable to the workbook range

                object[,]? range = (object[,])curWorksheetRange.Value2;

                rangeList.Add(range);
            }

            closeExcelFile(false,true);

            GC.Collect();
            GC.WaitForPendingFinalizers();

            return (rangeList);
        }
    }

Quick Rundown: I deleted the NAR function and any places it was called, added GC.Collect() and GC.WaitForPendingFinalisers after all my excel code is executed, and made sure all variables are set to null before GC.* functions are called.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM