Home » excel » c# – Why does this code cause Excel to not close properly?

c# – Why does this code cause Excel to not close properly?

Posted by: admin March 9, 2020 Leave a comment

Questions:

Why does this line of code cause Excel not to exit?

Excel.Range range = (Excel.Range)ws.Cells[1,1];

If it’s because of the casting, then wouldn’t this code cause the same problem?

Excel.Worksheet ws = (Excel.Worksheet)wb.ActiveSheet;

I’ve tried. But this works. Excel will close.

If I use this code. Excel closes.

Excel.Range range = ws.get_Range("A1","A1");

So what’s the difference? Yes I know there’s like a million of “How to close Excel properly” threads. But since this is a question and not an answer, I decided to ask a new one instead of asking in other people’s question.

Here’s my code. But of course there’s another codes in between. I’m just commenting out everything and slowly trying out which lines causes Excel to not close. I realise that even without using Garbage collector, Excel still closes. I do not want to use a sledgehammer to close Excel.

Thanks.

Excel.Application objExcel = new Excel.Application();
Excel.Workbooks wbs = objExcel.Workbooks;
Excel.Workbook wb = wbs.Open(saveFileDialog1.FileName, Type.Missing,  Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
Excel.Worksheet ws = (Excel.Worksheet)wb.ActiveSheet;
//Excel.Range range = (Excel.Range)ws.Cells[1,1];
Excel.Range range = ws.get_Range("A1","A1");

FinalReleaseAnyComObject(range);
FinalReleaseAnyComObject(ws);
wb.Close(Type.Missing, Type.Missing, Type.Missing);
FinalReleaseAnyComObject(wb);
FinalReleaseAnyComObject(wbs);
objExcel.Quit();
FinalReleaseAnyComObject(objExcel);

Currently I’ve tried until objExcel, wbs, wb and ws. These 4 objects does not cause a problem.

private static void FinalReleaseAnyComObject(object o)
{
    Marshal.FinalReleaseComObject(o);
    o = null;
}

I realise that you cannot reuse the variable as well.

Excel.Range range = ws.get_Range("A1","G1");
range = ws.get_Range("A1", "A1");

This will cause Excel not to close properly too. Instead, use this.

Excel.Range range = ws.get_Range("A1","G1");
FinalReleaseAnyComObject(range);
range = ws.get_Range("A1", "A1");
How to&Answers:

There’s a hidden Range interface pointer that you can’t see, the Cells property returns it. You then apply the indexer expression to it, dereferencing the default Item property of that Range. To get another Range.

This is why it is such a bad, bad idea to try to manage COM interface pointers yourself. Trust the garbage collector to always get it right. GC.Collect() and GC.WaitForPendingFinalizers() if you really, really want to make it quit on demand. Be sure to read this answer to understand why this doesn’t always work as expected when you debug your program.