简体   繁体   English

尽管释放了对象,Excel 仍未关闭

[英]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.所以,我写了一个 class 来处理打开 excel 文件,但是即使我调用关闭 function,excel 也没有关闭。这在我开始使用多个工作簿之前就起作用了,所以我认为它与此有关,但我有不知道如何解决这个问题。 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.我试过使用GC.Collect()GC.WaitForPendingFinalizers()但这似乎也不起作用。

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.简要说明:我删除了 NAR function 和它被调用的任何地方,在我的所有 excel 代码执行后添加了GC.Collect()GC.WaitForPendingFinalisers ,并确保在调用 GC.* 函数之前将所有变量设置为 null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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