rrh
rrh

Reputation: 115

Excel process still runs in background

I'm reading some data from a sheet of an excel file using interop library. I get the data just fine by using Microsoft.Office.Interop.Excel and then reading all data in the sheet.

Application ExcelApp = new Excel.Application();
Workbook excelWorkbook = ExcelApp2.Workbooks.Open(excelFileNamePath);
_Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
Range excelRange = excelWorksheet.UsedRange;
//...for loops for reading data
ExcelApp.Quit();

But after my application terminates, I tried to edit my excel file and had some problems while opening. Apparently the excel process keeps on running in the background even though I called ExcelApp.Quit(). Is there a way to properly close the excel file that the application uses? I'm new to c# so i'm probably missing something here.

Edit: Solved! Apparently there's a rule for com objects that discourages using 2 dots.

Excel.Application ExcelApp2 = new Excel.Application();
Excel.Workbooks excelWorkbooks = ExcelApp2.Workbooks;
Excel.Workbook excelWorkbook = excelWorkbooks.Open(excelFileName);
Excel._Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
//...
excelWorkbook.Close();       
Marshal.ReleaseComObject(excelWorkbook);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(excelRange);
ExcelApp2.Quit();

Upvotes: 10

Views: 16805

Answers (8)

Redouane Ayache
Redouane Ayache

Reputation: 1

var Process = Process.GetProcessesByName("excel").Select(x => x.Id.ToString());
Application ExcelApp = new Excel.Application();
Workbook excelWorkbook = ExcelApp2.Workbooks.Open(excelFileNamePath);
_Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
Range excelRange = excelWorksheet.UsedRange;
//...for loops for reading data
foreach (Process pros in Process.GetProcessesByName("excel"))
{
    if (!array1.Contains(pros.Id.ToString()))
    {
        Console.WriteLine(pros.Id.ToString());
        pros.Kill();

    }

}

Upvotes: -1

onoffon
onoffon

Reputation: 103

This code worked on me.

        Excel.Application excelApp = null;
        Excel.Workbooks excelWorkbooks = null;
        Excel.Workbook excelWorkbook = null;
        Excel._Worksheet xlWorkSheet = null;
        Excel.Range range = null;

        excelApp = new Excel.Application();
        excelWorkbooks = excelApp.Workbooks;
        excelWorkbook = excelWorkbooks.Open(excelName);
        xlWorkSheet = (Excel.Worksheet)excelWorkbook.ActiveSheet;

        range = xlWorkSheet.Range["C3"] ;
        range.Value = "Update Data";
        Marshal.ReleaseComObject(range);

        xlWorkSheet.SaveAs(path);
            
        Marshal.ReleaseComObject(xlWorkSheet);
        excelWorkbook.Close();
        Marshal.ReleaseComObject(excelWorkbook);
        excelWorkbooks.Close();
        Marshal.ReleaseComObject(excelWorkbooks);
        excelApp.Quit();
        Marshal.ReleaseComObject(excelApp);

Upvotes: 0

Abhishek Tripathy
Abhishek Tripathy

Reputation: 1

For me this worked : //opening

        var excelFile = new Application();
        Workbook workBook1 = excelFile.Workbooks.Open(goldenCopy_path);
        Workbook workBook2 = excelFile.Workbooks.Open(new_path);

        Worksheet goldWorkSheet, newWorkSheet;
        goldWorkSheet = workBook1.Worksheets[1];
        newWorkSheet = workBook2.Worksheets[1];

//closing //it will release the workbook from visual studio

        goldWorkSheet = null;
        newWorkSheet = null;

        workBook1.Close();
        workBook2.Close();
        workBook1 = null;
        workBook2 = null;

        excelFile.Quit();
        excelFile = null;

Upvotes: 0

TJacken
TJacken

Reputation: 369

For me this worked!

//Initializing
Application excelApp = new Application();
Workbook excelWorkbook = excelApp.Workbooks.Open(pathExcelFile, 0, true, 5, "", "", 
                               true, XlPlatform.xlWindows, "\t", false, false, 0, 
                               true, 1, 0);
Worksheet excelWorksheet = (Worksheet)excelWorkbook.Sheets[1];

//closing
excelWorksheet = null;

excelWorkbook.Close();
excelWorkbook = null;

excelApp.Quit();
excelApp = null;

Upvotes: 1

Rob
Rob

Reputation: 464

Long time no answer but what worked for me was to call the GC.Collect(); from the caller,

i.e. instead of

main()
{
    ...
    doexcelstuff();
    ...
}

void doexcelstuff()
{
    Excel.Application ExApp2 = new Excel.Application();
    Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
    Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
    //...
    excelWb.Close();
    ExApp2.Quit();     
    Marshal.ReleaseComObject(excelWb);
    Marshal.ReleaseComObject(excelWorksheet);
    Marshal.ReleaseComObject(ExApp2);
    excelWb = null;
    excelWorksheet= null;
    ExApp2= null;
    GC.Collect();
}

Using above Excel does not die

but a very small change, to where the GC is called from

main()
{
    ...
    doexcelstuff();
    GC.Collect();      // <<-- moved the GC to here (the caller)
    ...
}

void doexcelstuff()
{
    Excel.Application ExApp2 = new Excel.Application();
    Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
    Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
    //...
    excelWb.Close();
    ExApp2.Quit();     
    Marshal.ReleaseComObject(excelWb);
    Marshal.ReleaseComObject(excelWorksheet);
    Marshal.ReleaseComObject(ExApp2);
    excelWb = null;
    excelWorksheet= null;
    ExApp2= null;
    // removed the GC from here
}

My guess is the garbage collector needs to also quietly clean up internally created temp values (including refs/pointers) from the heap - some of which I guess in this case are pointing to COM objects.

(Just takes a smidgen of understanding of how machines work underneath the source code.)

Upvotes: 5

CJBS
CJBS

Reputation: 15695

There was another similar question - and answer (https://stackoverflow.com/a/17367570/3063884), in which the solution was to avoid using double-dot notation. Instead, define variables for each object used along the way, and individually use Marshal.ReleaseComObject on each one.

Copying straight from the linked solution:

var workbook = excel.Workbooks.Open(/*params*/)

---> instead use -->

var workbooks = excel.Workbooks;
var workbook = workbooks.Open(/*params*/)

Then, when done, release each COM object:

Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excel);

Upvotes: 15

John
John

Reputation: 186

Interop is notoriously buggy... I use the following method after saving my workbook, and no longer have issues with Excel remaining open when I exit my applications:

while (Marshal.ReleaseComObject(wb) > 0);
while (Marshal.ReleaseComObject(xl) > 0);

wb = null;
xl = null;

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

wb is my workbook object, and xl is my Excel.Application object.

Upvotes: 0

Brian English
Brian English

Reputation: 466

You are not closing your workbook. Close it and then release it before quitting the Excel application:

excelWorkbook.close();
Marshal.ReleaseComObject(excelWorkbook);
ExcelApp.Quit();

Upvotes: 1

Related Questions