Disable Winform application cache - c#

I developed winform application that read from excel and transform it to text files.
I used Microsoft.Office.Interop.Excel library in order to work with Excel.
Here is my code:
private Excel.Application excel = null;
private Excel.Sheets sheets = null;
private Excel.Workbook excelWorkbook = null;
private Excel.Workbooks excelWorkbooks = null;
private Excel._Worksheet worksheet = null;
private Excel.Range usedRange = null;
public ExcelFacade() { }
public ExcelFacade(string fileName)
{
excel = new Excel.Application();
excelWorkbooks = excel.Workbooks;
excelWorkbook = excelWorkbooks.Open(fileName, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
sheets = excelWorkbook.Sheets;
}
After I finished work with Excel I call next method (from here):
public void Dispose()
{
foreach (Microsoft.Office.Interop.Excel.Worksheet sheet in sheets)
{
while (Marshal.ReleaseComObject(sheet) != 0) { }
}
excelWorkbook.Close();
excelWorkbooks.Close();
excel.Quit();
var chromeDriverProcesses = Process.GetProcesses().
Where(pr => pr.ProcessName.ToLower().Contains("excel"));
foreach (var process in chromeDriverProcesses)
{
process.Kill();
}
//while (Marshal.ReleaseComObject(usedRange) != 0) { }
//while (Marshal.ReleaseComObject(worksheet) != 0) { }
while (Marshal.ReleaseComObject(sheets) != 0) { }
while (Marshal.ReleaseComObject(excelWorkbook) != 0) { }
while (Marshal.ReleaseComObject(excelWorkbooks) != 0) { }
//while (Marshal.ReleaseComObject(excel.Application) != 0)
//{ }
while (Marshal.ReleaseComObject(excel) != 0) { }
usedRange = null;
worksheet = null;
excelWorkbook = null;
excelWorkbooks = null;
sheets = null;
excel = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
However, if I change excel and rerun my application, the updated excel is not taken by application and it looks like it read from old excel. Such behavior is look like caching and I have no idea how to disable it.
The aforementioned is strengthened by the fact that if I change something in my code, e.g. white space, and rebuild the application, it works brilliant and take right Excel file.
Any suggestions?

As #vbnet3d said, using ClosedXML library solves all problems

Related

C# application terminates when writing data to excel worksheet

I am trying to write data in excel work sheet using .Net. However, for some reason whole application terminates (No exception, no warning, no message) when row counter increases to around 900. Whereas, there could be up to 10000 entries.
Furthermore it also terminates if i put a sleep statement, when filling contents. I suspect that there is some sort of timeout associated with excel objects?
Any Ideas what could be causing this? Thanks
Here is the main function -
public void ProduceExcelReport(string reportDirPath, List<MedlineRecord> medlineRecords, List<AccessionRecord> accessionRecords,
List<string> dataBanksOfInterest, bool overwrite)
{
Excell.Application excelApp = null;
Excell.Workbooks excelWorkBooks = null;
Excell.Workbook excelWorkBook = null;
Excell.Sheets worksheets = null;
Excell.Worksheet overAllWorkSheet = null;
Excell.Worksheet parsingWorkSheet = null;
Excell.Worksheet errorWorkSheet = null;
Excell.Worksheet noCitationsSheet = null;
Excell.Worksheet outOfScopeWorksheet = null;
try
{
excelApp = new Excell.Application();
string fullReportPath = Path.Combine(reportDirPath, ReportName);
if (File.Exists(fullReportPath))
{
if (!overwrite)
{
Logger.Warning(string.Format("File {0} already exists. Skipping report production." +
"You can change behaviour by editing OverwriteFilesWithNameConflict tag in settings",
fullReportPath));
return;
}
Logger.Warning(string.Format("File {0} already exists. Overwritting old report." +
"You can change behaviour by editing OverwriteFilesWithNameConflict tag in settings",
fullReportPath));
}
// Initialise
excelApp.DisplayAlerts = false;
object misValue = System.Reflection.Missing.Value;
excelWorkBooks = excelApp.Workbooks;
excelWorkBook = excelWorkBooks.Add(misValue);
worksheets = excelWorkBook.Worksheets;
overAllWorkSheet = (Excell.Worksheet) worksheets.Item[1];
parsingWorkSheet = (Excell.Worksheet) worksheets.Item[2];
errorWorkSheet = (Excell.Worksheet) worksheets.Item[3];
noCitationsSheet = (Excell.Worksheet) worksheets.Add();
outOfScopeWorksheet = (Excell.Worksheet)worksheets.Add();
// Filling contents
FillOverallReportContents(ref overAllWorkSheet, accessionRecords);
FillMedlineParsingReportContents(ref parsingWorkSheet, medlineRecords, dataBanksOfInterest); // <- Terminates when writting contents
FillErrorReportContents(ref errorWorkSheet, medlineRecords);
FillNoCitationReportContents(ref noCitationsSheet, medlineRecords);
FillOutOfScopeReportContents(ref outOfScopeWorksheet, medlineRecords, dataBanksOfInterest);
excelWorkBook.SaveAs(fullReportPath);
excelWorkBook.Close(true, misValue, misValue);
excelApp.Quit(); // Quiting excel app
Logger.Info(string.Format("Excel report at {0} was successfully created", fullReportPath));
}
catch (Exception e)
{
Logger.ExceptionError("Exception occured when trying to write Excel Report", e);
}
finally
{
if (overAllWorkSheet != null) Marshal.ReleaseComObject(overAllWorkSheet);
if (parsingWorkSheet != null) Marshal.ReleaseComObject(parsingWorkSheet);
if (noCitationsSheet != null) Marshal.ReleaseComObject(noCitationsSheet);
if (errorWorkSheet != null) Marshal.ReleaseComObject(errorWorkSheet);
if (outOfScopeWorksheet != null) Marshal.ReleaseComObject(outOfScopeWorksheet);
if (worksheets != null) Marshal.ReleaseComObject(worksheets);
if (excelWorkBook != null) Marshal.ReleaseComObject(excelWorkBook);
if (excelWorkBooks != null) Marshal.ReleaseComObject(excelWorkBooks);
if (excelApp != null) Marshal.ReleaseComObject(excelApp);
}
}
Here is one of the functions that fills worksheet contents
private void FillMedlineParsingReportContents(ref Excell.Worksheet excelWorkSheet, List<MedlineRecord> medlineRecords, List<string> dataBanksOfInterest)
{
// Write the worksheet contents
AddFirstRow(ref excelWorkSheet);
excelWorkSheet.Name = "Medline XML Parsing Summary";
excelWorkSheet.Cells[2, 6] = string.Format("Total articles: {0}", medlineRecords.Count);
excelWorkSheet.Cells[3, 6] = string.Format("Total number dataBank list tags: {0}", (from element in medlineRecords
where element.DataBanksDict.Count > 0
select element).Count());
excelWorkSheet.Cells[4, 6] = string.Format("Total number dataBank tags: {0}", (from element in medlineRecords
select element.DataBanksDict.Count).Sum());
excelWorkSheet.Cells[5, 6] = string.Format("Total number accession tags: {0}", (from element in medlineRecords
select element.GetAccessionRecords().Count).Sum());
int i = 2;
foreach (MedlineRecord record in Utilities.FilterOutMedlineRecords(medlineRecords, dataBanksOfInterest))
{
foreach (AccessionRecord accessionRecord in record.GetAccessionRecords())
{
excelWorkSheet.Cells[i, 1] = accessionRecord.BankName;
excelWorkSheet.Cells[i, 2] = accessionRecord.AccessionId;
excelWorkSheet.Cells[i, 3] = accessionRecord.PMID;
excelWorkSheet.Cells[i, 4] = accessionRecord.FileName;
i++;
// Terminates when I reaches around 800-900
Console.WriteLine(i);
}
}
}

Quickly read data from Excel

I have the code below reading data from an Excel worksheet and converting it to a pipe delimited text file. It works. The problem is it's quite slow as I have to read 1 cell at a time in order to add in the pipe.
I wondered if there was a better way to do this i.e. read the data into memory/array in one step and act on it there.
public string Process(string filename)
{
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
Excel.Range range;
string str = "";
int rCnt = 0;
int cCnt = 0;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(filename, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1); //Use the 1st worksheet
StreamWriter sw = new StreamWriter(destpath);
range = xlWorkSheet.UsedRange;
for (rCnt = 1; rCnt <= range.Rows.Count; rCnt++)
{
if ((rCnt % 1000) == 0)
{
txtProgress.Text = "Rows processed: "+ rCnt;
}
for (cCnt = 1; cCnt <= range.Columns.Count; cCnt++)
{
str = str + ToStr((range.Cells[rCnt, cCnt] as Excel.Range).Value2) + "|";
}
sw.WriteLine(str);
str = "";
}
xlWorkBook.Close(true, null, null);
xlApp.Quit();
sw.Close();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
MessageBox.Show("Complete","Status");
return "Success";
}
public static string ToStr(object readField)
{
if ((readField != null))
{
if (readField.GetType() != typeof(System.DBNull))
{
return Convert.ToString(readField);
}
else
{
return "";
}
}
else
{
return "";
}
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
If you plan on only performing a read on the excel file content, I suggest you use the ExcelDataReader library Link, which extracts the worksheetData into a DataSet object.
static void Main(string[] args)
{
IExcelDataReader reader = null;
string FilePath = "PathToExcelFile";
//Load file into a stream
FileStream stream = File.Open(FilePath, FileMode.Open, FileAccess.Read);
//Must check file extension to adjust the reader to the excel file type
if (System.IO.Path.GetExtension(FilePath).Equals(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else if (System.IO.Path.GetExtension(FilePath).Equals(".xlsx"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
if (reader != null)
{
//Fill DataSet
System.Data.DataSet result = reader.AsDataSet();
try
{
//Loop through rows for the desired worksheet
//In this case I use the table index "0" to pick the first worksheet in the workbook
foreach (DataRow row in result.Tables[0].Rows)
{
string FirstColumn = row[0].ToString();
}
}
catch
{
}
}
}
you can use LinqToExcel nuget package
https://www.nuget.org/packages/LinqToExcel/1.10.1
sample code:
string path = #"Users.xlsx";
var excel = new ExcelQueryFactory(path);
return (from c in excel.Worksheet<User>()
select c).OrderBy(a => a.Name).ToList();

Issue writing to spreadsheet using EPPlus

I'm simply trying to edit a spreadsheet that has text already written into to change the text to be blank.
However it's not working. The method seems to do nothing.
My code is:
public static void ClearCells(string SpreadsheetFilePath)
{
var SpreadsheetPath = new FileInfo(SpreadsheetFilePath);
var package = new ExcelPackage(SpreadsheetPath);
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
ExcelWorksheet currentWorksheet = workBook.Worksheets.First();
currentWorksheet.SetValue(1, 1, "hello123");
}
}
}
There is no runtime error. It runs, completes and the spreadsheet is unchanged. I don't know why.
Just call package.Save(); after you are done editing your file.
var SpreadsheetPath = new FileInfo(#"C:\temp\abc.xlsx");
var package = new ExcelPackage(SpreadsheetPath);
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
ExcelWorksheet currentWorksheet = workBook.Worksheets.First();
currentWorksheet.SetValue(1, 1, "hello123");
}
}
package.Save(); // <========= MISSING IN YOUR CODE
Try something like this:
public static void ClearCells(string SpreadsheetFilePath)
{
var excelFile = new FileInfo(SpreadsheetFilePath);
var excelPack = ExcelPackage(excelFile);
var workSheet = excelPack.Workbook.Worksheets.Add("Content"); // New worksheet
workSheet.Cells[1, 1].Value = "hello123";
excelPack.Save();
}
How about using SetCellValue instead of SetValue?
public static void ClearCells(string SpreadsheetFilePath)
{
var SpreadsheetPath = new FileInfo(SpreadsheetFilePath);
var package = new ExcelPackage(SpreadsheetPath);
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
ExcelWorksheet currentWorksheet = workBook.Worksheets.First();
currentWorksheet.SetCellValue(1, 1, "hello123");
}
}
}

C# Interop print and close Excel file

have problem with interop and editing existing excel file. Excel app doesn't want to close. If I set code, when I edit cells, as comment, rest of code work as I need - Excel open and after print dialog close.
Excel.Application excelApp = null;
Excel.Workbook excelWorkbook = null;
Excel.Worksheet excelWorksheet = null;
string workbookPath = "";
if (RBType1.Checked == true) { workbookPath = Path.GetFullPath("Excel/Mesto.xls"); }
else if (RBType2.Checked == true) { workbookPath = Path.GetFullPath("Excel/Ulehly.xls"); }
else if (RBType3.Checked == true) { workbookPath = Path.GetFullPath("Excel/Spolecenstvi.xls"); }
else if (RBType4.Checked == true) { workbookPath = Path.GetFullPath("Excel/Vlastnici.xls"); }
excelApp = new Excel.Application();
excelApp.Visible = true;
excelWorkbook = excelApp.Workbooks.Open(workbookPath, 0, false, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
excelWorksheet = (Excel.Worksheet)excelWorkbook.Worksheets.get_Item(1);
excelWorksheet.Cells[4, "J"] = RequisitionNumberBox.Text;
excelWorksheet.Cells[9, "C"] = ApplicantBox.Text;
excelWorksheet.Cells[9, "G"] = StreetBox.Text;
excelWorksheet.Cells[9, "J"] = CPBoxC.Text;
excelWorksheet.Cells[10, "J"] = CBBox.Text;
excelWorksheet.Cells[11, "D"] = CTBox.Text;
excelWorksheet.Cells[11, "G"] = ContactPersonBox.Text;
excelWorksheet.Cells[14, "B"] = RepairBox.Text;
excelWorksheet.Cells[20, "B"] = ItemBox.Text;
if (PMOption1.Checked == true) { excelWorksheet.Cells[23, "D"] = "X"; }
if (PMOption2.Checked == true) { excelWorksheet.Cells[24, "D"] = "X"; }
excelWorksheet.Cells[23, "F"] = IssueDate.Text;
excelApp.Dialogs[Excel.XlBuiltInDialog.xlDialogPrint].Show();
excelWorkbook.Close(false, Type.Missing, Type.Missing);
excelApp.Quit();
releaseObject(excelWorksheet);
releaseObject(excelWorkbook);
releaseObject(excelApp);
releaseObject code (found this on internet)
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
How I should edit this code, that it close Excel when program edits cells?

Excel process doesn't get closed

I am not able to get my EXCEL (32) process closed once I am done using it.
As you can see in the code below, once ProcessRFAFData function finishes its execution, the EXCEL process doesn't get closed (I can still see EXCEL.EXE*32 in the task manager).
For this reason, when SaveErrors starts its execution, I get the following exception:
System.Runtime.InteropServices.COMException (0x800A03EC):
Microsoft Office Excel cannot open or save any more documents because there is not enough available memory or disk space.
• To make more memory available, close workbooks or programs you no longer need.
• To free disk space, delete files you no longer need from the disk you are saving to.
at Microsoft.Office.Interop.Excel.Workbooks.Add(Object Template)
at NextG.RFAFImport.Layouts.NextG.RFAFImport.RFAFDataImporter.<>c__DisplayClass9.b__6()
at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass4.b__2()
at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param)
at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode)
at NextG.RFAFImport.Layouts.NextG.RFAFImport.RFAFDataImporter.SaveErrors()
Here is the code that executes the Excel processes:
try {
ProcessRFAFData(FileName);
} catch (Exception ex) {
Status = "ERROR: " + ex.ToString();
}
if (Errors.Count() > 0) {
SaveErrors();
}
Here are all the functions interacting with Excel:
private void ReleaseObject(object obj) {
try {
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
} catch (Exception) { } finally {
GC.Collect();
}
}
private void ProcessRFAFData(string FileName) {
Microsoft.Office.Interop.Excel.Application XLA = null;
Microsoft.Office.Interop.Excel.Workbook XLW = null;
Microsoft.Office.Interop.Excel.Worksheet XLS = null;
bool error = false;
try {
SPSecurity.RunWithElevatedPrivileges(delegate() {
XLA = new Microsoft.Office.Interop.Excel.Application();
XLW = XLA.Workbooks.Open(FileName, 0, true,
Type.Missing, null, null, true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
Type.Missing, false, false, Type.Missing, false, Type.Missing, Type.Missing);
int index = RFAFTabExists(ref XLW);
if (index == 0) return;
XLS = (Microsoft.Office.Interop.Excel.Worksheet)XLW.Worksheets.get_Item(index);
if (!ValidProjectID(ref XLS)) return;
ParseData(ref XLS);
XLW.Close(true, Type.Missing, Type.Missing);
XLA.Quit();
ReleaseObject(XLS);
ReleaseObject(XLW);
ReleaseObject(XLA);
});
} catch (SP.ServerException ex) {
// output error
} catch (Exception ex) {
// output error
}
}
private int RFAFTabExists(ref Microsoft.Office.Interop.Excel.Workbook XLW) {
int index = 0;
foreach (Microsoft.Office.Interop.Excel.Worksheet w in XLW.Worksheets) {
if (w.Name.Equals(settings.Collection["RFAFTabName"])) index++;
}
return index;
}
private bool ValidProjectID(ref Microsoft.Office.Interop.Excel.Worksheet XLS) {
using (SP.ClientContext CTX = new SP.ClientContext(SiteURL)) {
var projectId = XLS.Cells.get_Range(settings.Collection["ProjectIDCell"], Type.Missing).Text.ToString();
var project = // getting list of projects from SharePoint
if (project.Count() > 0) {
ProjectID = XLS.Cells.get_Range(settings.Collection["ProjectIDCell"], Type.Missing).Text.ToString();
return true;
}
}
return false;
}
private void ParseData(ref Microsoft.Office.Interop.Excel.Worksheet XLS) {
ListData.Add("HID", GetHID(XLS.Cells.get_Range(settings.Collection["HIDCell"],
Type.Missing).Text.ToString()));
if (ListData["HID"].Equals("0")) Errors.Add(new ImportError {
Reason = "Hub ID does not exist in this project workspace.",
Reference = string.Format("Hub ID: {0}", XLS.Cells.get_Range(settings.Collection["HIDCell"],
Type.Missing).Text.ToString())
});
int row = Int32.Parse(settings.Collection["StartRow"]);
while (!NoMoreData(ref XLS, row)) {
string PRSIN = XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["PRSIN"], row), Type.Missing).Text.ToString();
string NOC = ValidateNumber(XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["NOC"], row), Type.Missing).Text.ToString());
string UEIRP = ValidateNumber(XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["UEIRP"], row), Type.Missing).Text.ToString());
string LAT = ValidateLatLon(XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["LAT"], row), Type.Missing).Text.ToString());
string LON = ValidateLatLon(XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["LON"], row), Type.Missing).Text.ToString());
string PJ = GetPJ(XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["JurisdictionCol"], row), Type.Missing).Text.ToString(),
XLS.Cells.get_Range(string.Format("{0}{1}", settings.Collection["StateCol"], row),
Type.Missing).Text.ToString());
string ST = GetState(XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["JurisdictionCol"], row), Type.Missing).Text.ToString(),
XLS.Cells.get_Range(string.Format("{0}{1}", settings.Collection["StateCol"], row),
Type.Missing).Text.ToString());
ListItemData.Add(new ListItem {
ProposedRemoteSiteItemNumber = PRSIN,
NumberOfCarriers = NOC,
UsableEIRP = UEIRP,
Latitude = LAT,
Longitude = LON,
PrimaryJurisdiction = PJ,
State = ST
});
row++;
}
}
private bool NoMoreData(ref Microsoft.Office.Interop.Excel.Worksheet XLS, int row) {
return string.IsNullOrEmpty(XLS.Cells.get_Range(string.Format("{0}{1}",
settings.Collection["ProposedRemoteSiteItemNumberCol"], row), Type.Missing).Text.ToString());
}
private void SaveErrors() {
Microsoft.Office.Interop.Excel.Application XLA = null;
Microsoft.Office.Interop.Excel.Workbook XLW = null;
Microsoft.Office.Interop.Excel.Worksheet XLS = null;
object MissingValue = System.Reflection.Missing.Value;
try {
try {
SPSecurity.RunWithElevatedPrivileges(delegate() {
XLA = new Microsoft.Office.Interop.Excel.Application();
XLW = XLA.Workbooks.Add(MissingValue);
XLS = (Microsoft.Office.Interop.Excel.Worksheet)XLW.Worksheets.get_Item(1);
XLS.Cells[1, 1] = "Reason for error";
XLS.Cells[1, 2] = "Reference";
XLS.get_Range("A1").Font.Bold = true;
XLS.get_Range("B1").Font.Bold = true;
int row = 2;
foreach (ImportError e in Errors) {
XLS.Cells[row, 1] = e.Reason;
XLS.Cells[row, 2] = e.Reference;
row++;
}
XLW.SaveAs(ErrorLogFileName, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal,
MissingValue, MissingValue, MissingValue, MissingValue,
Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, MissingValue,
MissingValue, MissingValue, MissingValue, MissingValue);
XLW.Close(true, MissingValue, MissingValue);
XLA.Quit();
ReleaseObject(XLS);
ReleaseObject(XLW);
ReleaseObject(XLA);
});
} catch (Exception ex) {
Status = "ERROR: " + ex.ToString();
}
// Uploading excel file to SharePoint document library
} catch (Exception) { }
}
You may have to go ridiculously explicit:
excelWorkbook.Close (false, System.Reflection.Missing.Value,System.Reflection.Missing.Value) ;
excelWorkbooks.Close();
excelApp.Quit();
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(excelSheets);
Marshal.ReleaseComObject(excelWorkbooks);
Marshal.ReleaseComObject(excelWorkbook);
Marshal.ReleaseComObject(excelApp);
excelWorksheet = null;
excelSheets = null;
excelWorkbooks = null;
excelWorkbook = null;
excelApp = null;
GC.GetTotalMemory(false);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.GetTotalMemory(true);
I've encountered situations where even that did not do it. I resorted to hunting down the Excel process and called Kill() on it.
Release your Excel objects in a finally block, in case of exceptions.
try
{
...
}
catch
{
...
}
finally
{
ReleaseObject(XLS);
ReleaseObject(XLW);
ReleaseObject(XLA);
}
First suggestion: http://code.google.com/p/excellibrary This is a great library that I have used with a lot of success.
Second suggestion: If you absolutely MUST close Excel
/// <summary>
/// Gets all currently running instances of Excel, so we don't kill active windows.
/// </summary>
private void GetInstancesToSave()
{
if (_instancesToSaveList != null)
{
_instancesToSaveList.Clear();
}
_instancesToSaveList = Process.GetProcesses().ToList<Process>();
_instancesToSaveList = _instancesToSaveList.FindAll(proc => proc.ProcessName == "EXCEL");
}
/// <summary>
/// Kills any instances of Excel that were created by the program.
/// </summary>
/// <param name="zInstancesToSave">Instances that were not </param>
private static void KillExcel(List<Process> zInstancesToSave)
{
List<Process> xProcesslist = Process.GetProcesses().ToList<Process>();
xProcesslist = xProcesslist.FindAll(proc => proc.ProcessName == "EXCEL");
foreach (Process xTheprocess in xProcesslist)//read through all running programs
{
bool killit = true;
foreach (Process proc in zInstancesToSave)//read through all running programs
{
if (xTheprocess.Id == proc.Id)
{
killit = false;
}
}
if (killit)
{
xTheprocess.Kill();
}
}
}
You can use these 2 methods to keep track of which instances of excel are running when you start and then find any instances of Excel that your app opened and then kill them. It's certainly not a great solution but sometimes you just have to bite the bullet.
If you don't care about prior instances you can also just do:
/// <summary>
/// Kills any instances of Excel that were created by the program.
/// </summary>
/// <param name="zInstancesToSave">Instances that were not </param>
private static void KillExcel(List<Process> zInstancesToSave)
{
List<Process> xProcesslist = Process.GetProcesses().ToList<Process>();
xProcesslist = xProcesslist.FindAll(proc => proc.ProcessName == "EXCEL");
foreach(Proc process in xProcesslist)
{
process.Kill();
}
}
I would look into using EPPlus from Code Plex.
This example shows how to read data. You are always better on a server going this route - only issue is if you need call formulas - then this approach will not work.
Most of your code will be very similar to your current code, so I would estimate a few hours for moving to this library.
In my case, the Excel add-in lived in a separate AppDomain that I had created earlier on but when the Add-in was unloaded, I never called:
childDomain.Unload();
Once called, the Excel Zombie process was no longer there...
In addition to the above solutions and here is my LOGICALsolution.
I was thinking why do I have so many EXCEL.EXE applications and handled this way.
Here i am checking for conditions while creating New Excel application.
if (_masterApp == null)
_masterApp = new EXCEL.Application();
Only create New Instances of Excel application if the variable you want to create is Null, else reassign the existing variable.
and Use the Solutions mentioned in this blog to CLOSE the _masterApp.
Benefits: This way you will only close the EXCEL application you opened through Solution and not close Manually opened Excel Application.
Look at this link
Kill Process Excel C#
Thanks to KD7 for the solution.
One minor modification is that if your excelapp is not visible your mainwindowtitle will be blank. eg. ""
private void KillSpecificExcelFileProcess(string excelFileName)
{
var processes = from p in Process.GetProcessesByName("EXCEL")
select p;
foreach (var process in processes)
{
MessageBox.Show(process.MainWindowTitle);
if (process.MainWindowTitle == excelFileName)
{
process.Kill();
}
}
}
and to kill all zombie excel background process'
KillSpecificExcelFileProcess("");
This gave me no end of trouble in solving so I will be posting it on each zombie excel process thread.

Categories

Resources