tags:

views:

431

answers:

1

Hello,

In my form I am doing something as simple as

private void btnPrintPickList_Click(object sender, EventArgs e)
{
    using (var salesRpt = new SalesOrder(CurrentItem()))
    {
        salesRpt.CreateSpreadSheet();
        salesRpt.Dispose();
    }
}

I have followed the "no 2 dots rule for excel interop".

protected ExcelSheet(bool documentVisible, XlPageOrientation orientation)
{
    ExcelApplication = new Application {Visible = documentVisible};
    WorkBooks = ExcelApplication.Workbooks;
    WorkBook = WorkBooks.Add(XlSheetType.xlWorksheet);
    SheetList = WorkBook.Worksheets;
    Orientation = orientation;
    WorkSheet = (Worksheet) ExcelApplication.ActiveSheet;
}

public Application ExcelApplication { get; private set; }
public Workbook WorkBook { get; private set; }
public Workbooks WorkBooks { get; private set; }
public Worksheet WorkSheet { get; private set; }
public Sheets SheetList { get; private set; }
public XlPageOrientation Orientation { get; private set; }

the dispose method does the following.

    public void Dispose()
    {
        for (int i = 1; i <= SheetList.Count; i++)
        {
            Marshal.FinalReleaseComObject(SheetList[i]);
        }
        //Marshal.FinalReleaseComObject(WorkSheet);
        Marshal.FinalReleaseComObject(SheetList);
        Marshal.FinalReleaseComObject(WorkBook);
        WorkBooks.Close();
        Marshal.FinalReleaseComObject(WorkBooks);
        ExcelApplication.Quit();
        Marshal.FinalReleaseComObject(ExcelApplication);
        WorkSheet = null;
        SheetList = null;
        WorkBook = null;
        WorkBooks = null;
        ExcelApplication = null; 
    }

In my testing, the EXCEL.exe process does not consistently get removed from the current processes in the taskbar once the Excel spreadsheet is printed.

What am I doing wrong?

+2  A: 

Have you tried calling GC.Collect()?

Alternatively, you could use using{} if you don't want to force an immediate garbage collection of all generations

David Relihan
I have used the "using " statement and the Dispose method does get called and completes but the EXCEl.exe does not go out of the task manager until I close out the form.I will try GC.collect() at the very end of dispose.
CF_Maintainer
Adding GC.Collect(); at the end of the Dispose() removed the EXCEl.exe from the task manager.One point though. I had heard it is not advisable to call GC.Collect().Is it valid in case of interop?
CF_Maintainer
Unfortunately, I don't think there is another option for this scenario!
David Relihan
CF_Maintainer, other than leaving off the 'GC.Collect' and 'GC.WaitForPendingFinalizers' call, your code looks *very* good. In addition, you don't need to set your references to 'null' once you have called 'Marshal.FinalReleaseComObject' because 'Marshal.FinalReleaseComObject' already decrements the COM reference count to zero for you, so the COM object will be released even if your variable still holds a reference to the Runtime Callable Wrapper (RCW). For for a bit more on this, see: http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects-in-c/159419#159419
Mike Rosenblum