It’s hard to get rid of all the links, since you need to guess if the calls are:
var workbook = excel.Workbooks.Open("")
Creates an instance of Workbooks that you are not referencing.
Even links like:
targetRange.Columns.AutoFit()
Creates an instance of .Columns() if you do not know and do not release it correctly.
I ended up writing a class containing a list of references to objects that could dispose of all objects in reverse order.
The class has a list of objects and Add() functions for everything that you reference when using the Excel interaction, which returns the object itself:
public List<Object> _interopObjectList = new List<Object>(); public Excel.Application add(Excel.Application obj) { _interopObjectList.Add(obj); return obj; } public Excel.Range add(Excel.Range obj) { _interopObjectList.Add(obj); return obj; } public Excel.Workbook add(Excel.Workbook obj) { _interopObjectList.Add(obj); return obj; } public Excel.Worksheet add(Excel.Worksheet obj) { _interopObjectList.Add(obj); return obj; } public Excel.Worksheets add(Excel.Worksheets obj) { _interopObjectList.Add(obj); return obj; } public Excel.Sheets add(Excel.Sheets obj) { _interopObjectList.Add(obj); return obj; } public Excel.Workbooks add(Excel.Workbooks obj) { _interopObjectList.Add(obj); return obj; }
Then, to unregister the objects, I used the following code:
//Release all registered interop objects in reverse order public void unregister() { //Loop object list in reverse order and release Office object for (int i=_interopObjectList.Count-1; i>=0 ; i -= 1) { ReleaseComObject(_interopObjectList[i]); } //Clear object list _interopObjectList.Clear(); } /// <summary> /// Release a com interop object /// </summary> /// <param name="obj"></param> public static void ReleaseComObject(object obj) { if (obj != null && InteropServices.Marshal.IsComObject(obj)) try { InteropServices.Marshal.FinalReleaseComObject(obj); } catch { } finally { obj = null; } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); }
Then the principle is to create a class and write the links as follows:
//Create helper class xlsHandler xlObj = new xlsHandler(); .. //Sample - Capture reference to excel application Excel.Application _excelApp = xlObj.add(new Excel.Application()); .. //Sample - Call .Autofit() on a cell range and capture reference to .Columns() xlObj.add(_targetCell.Columns).AutoFit(); .. //Release all objects collected by helper class xlObj.unregister();
Unbelievable code of great beauty, but can inspire something useful.
flodis Nov 27 '14 at 18:02 2014-11-27 18:02
source share