4

Need to work with Excel Interop. I can successfully open and read from an excel file but while closing it, the background process for that excel does not get killed. Tried using several solutions from previous SO links, but no luck! So my ask is, how to kill the background process???

Below is the UPDATED CODE that I am currently using:

Excel.Application application = new Excel.Application();

var workbooks = application.Workbooks;
Excel.Workbook workbook = workbooks.Open(path);
Excel.Worksheet worksheet = workbook.ActiveSheet;
Excel.Range range = worksheet.UsedRange;
var rows = range.Rows;

// Some business logic  

for (int row = 2; row <= rows.Count; row++)
{
   //Read the data from the excel
}

// Some business logic

//close the excel
rows.Clear();
cell.Clear();
range.Clear();

workbook.Close(false);
application.Quit();

while (Marshal.FinalReleaseComObject(rows) != 0) { }
while (Marshal.FinalReleaseComObject(cell) != 0) { }
while (Marshal.FinalReleaseComObject(range) != 0) { }
while (Marshal.FinalReleaseComObject(worksheet) != 0) { }
while (Marshal.FinalReleaseComObject(workbook) != 0) { }
while (Marshal.FinalReleaseComObject(workbooks) != 0) { }
while (Marshal.FinalReleaseComObject(application) != 0) { }

rows = null;
cell = null;
range = null;
worksheet = null;
workbook = null;
workbooks = null;
application = null;
GC.Collect();
GC.WaitForPendingFinalizers();

By following the above code, I get the below exception in my debugger:

watch 'application' in VS debugger

Any help on this will be appreciated.

IamRuku
  • 158
  • 2
  • 11
  • You are not releasing `range`. Also, if you're manually releasing the RCW through `Marshal.ReleaseComObject`, `GC.Collect` and `GC.WaitForPendingFinalizers` shouldn't be necessary. And last, use `Marshal.FinalReleaseComObject`, it will do the loop for you in one call. – InBetween May 10 '16 at 14:37
  • Also, as a good practice, tend to wrap this sort of code in `try-finally` blocks to ensure you are releasing correctly all COM objects in normal execution and recoverable error scenarios. – InBetween May 10 '16 at 14:40
  • @inBetween: Ya, the code is wrapped within a try-catch, there are a few more things before and after what i've posted here, thought they won't be necessary as they are solely meant for some other BL implementation :) – IamRuku May 10 '16 at 14:41
  • @inBetween tried all that, but with no good result :( m i really being silly and missing something very small?? feeling dumb!! :/ – IamRuku May 10 '16 at 14:46
  • This is probably not it at all, but just in case; when I've used Excel interop I tend to release COM objects from deepest to most shallow. That is, invert the releasing order starting by range -> worksheet -> workbook -> workbooks -> .... -> application. Also consider showing more of your code, maybe you are holding some reference to a COM object you haven't noticed. – InBetween May 10 '16 at 14:49

2 Answers2

0

You are using range.Rows.Count, this might violate the "Never use 2 dots with com objects." rule. See here

You could try including this ;

var rows = range.Rows
for (int row = 2; row <= rows.Count; row++)
{
   //Read the data from the excel
}
rows.Clear(); //rows is itself a range object 
Community
  • 1
  • 1
mark_h
  • 5,233
  • 4
  • 36
  • 52
0

The few times I've had to use Excel interop, I haven't had any issues when following these simple rules:

  1. Always wrap any Excel interop in try-finally blocks. In the finally block put all releasing logic.
  2. Use Marshal.FinalReleaseComObject to release named COM references as its essentially doing the ref count loop for you.
  3. Eagerly release COM objects from deepest to shallowest. In your case I'd start with range then worksheet then workbook and so on.
  4. Correctly release unreferenced COM objects (two dot rule) with GC.Collect() and GC.WaitForPendingFinalizers(). Do this before manually releasing pending COM objects you hold a named reference to.
InBetween
  • 32,319
  • 3
  • 50
  • 90
  • @IamRuku That isn't a runtime exception at all. What seems to be happening is that you are simply attempting to inspect `application` once it has been released. The RCW reference count has reached zero and the runtime has released all its references to the COM object (`application`). – InBetween May 11 '16 at 06:47
  • So if that is the case, then how come the background process still persist in the task manager? because, I can see all the other resources getting cleaned (using VS), and there is no other exception being thrown! – IamRuku May 11 '16 at 08:07
  • @IamRuku I don't know because I can't see all your code. Somewhere something is keeping a reference alive to some COMObject. The fact that you correctly set to zero the reference count to `application` does not mean the object has been released if something else is still referencing it directly or indirectly. You just can't use the `application` reference anymore. – InBetween May 11 '16 at 08:35
  • Check out this little [class](https://github.com/grico1974/WhamoLauncher/blob/master/WhamoLauncher.Charts/XlsWorkbookBuilder.cs) in a project I just uploaded to GitHub. This is the way I normally deal with Excel interop and I've never had any issues. I'm using Excel versions 2007 - 2013 by the way. – InBetween May 11 '16 at 08:39