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.