如何在c#中正确配置Excel.interop COM对象?

时间:2015-03-05 13:53:47

标签: c# dispose excel-interop

我正在尝试自动执行将数据放入Excel工作表的任务。一切进展顺利,但当我通过任务管理器查看过程时,#EXCEL.exe"仍然存在。我已经使用Marshal.ReleaseComObject来处理我的excel对象。我做了一些测试,以便隔离使该过程保持不变的线,这里是:

CurrentSheet = ExcelWorkbook.Worksheets.Add();

将新工作表添加到当前工作簿后。即使我在创建后处置它,该过程仍然存在于内存中。我的问题是:为了使其正常工作,我缺少什么?

我建议你不要发布有关进程查杀的内容,因为这是一个糟糕的解决方案,我不确定是否会杀死正确的进程。

这是我的代码:

//Declaration
static object misValue = System.Reflection.Missing.Value;
Excel.Application ExcelApp {get;set;}
Excel.Workbook ExcelWorkbook { get; set; }
protected Excel.Sheets ExcelSheets { get; set; }
protected Excel.Worksheet CurrentSheet { get; set; }

//Constructor
public ExcelLib()
{
      //Open in memory
      ExcelApp = new Excel.Application();
      ExcelWorkbook = ExcelApp.Workbooks.Add(misValue);
      ExcelSheets = ExcelWorkbook.Worksheets;
      CurrentSheet = (Excel.Worksheet)ExcelWorkbook.Worksheets[1];

}
// Add new Excel sheet
public virtual bool CreateNewSheet(String SheetName,DataSet ds)
{
    if (SheetName.Length > 31)
        SheetName = SheetName.Substring(0, 31);
    CurrentSheet = ExcelWorkbook.Worksheets.Add(); //this cause the process remains
    CurrentSheet.Name = SheetName;

    ////// Code below doesn't matter
    SetRange("A1", ds.Tables[0].Rows.Count, ds.Tables[0].Columns.Count);
    SetRangeValue(ds.ToStrArray(true));//ds.Tables[0].Rows;
    return true;
}
//The way I dispose the excel objects
public void Close()
{
    ExcelApp.Quit();
    releaseObject(CurrentSheet);
    releaseObject(ExcelSheets);
    releaseObject(ExcelWorkbook);
    releaseObject(ExcelApp);


}
    //release Object

private void releaseObject(object obj)
{
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
            obj = null;
        }
        catch (Exception ex)
        {
            obj = null;
        }
        finally
        {
            GC.Collect(); //Useless
        }
}

在整个应用程序中,我刚刚创建了一个ExcelLib的新实例,调用方法CreateNewSheet(...)然后调用Close。如果我只执行ExcelLib()Close(),则该过程立即从任务管理器中消失。谢谢你的帮助!

2 个答案:

答案 0 :(得分:0)

我建议拨打Marshal.FinalReleaseComObject而不是Marshal.ReleaseComObject。虽然根据我的经验它可以运行得更好,但Excel仍然有时会运行。

因此,我通常会监视已启动的Excel进程并直接将其终止。显然,这种方法不是很优雅,并且有一些注意事项,例如:当用户同时启动Excel时,我还没有找到更好的解决问题的办法,而不是完全摆脱Office互操作。

// start excel

var before = Process.GetProcessesByName("Excel");
_application = new Excel.Application();
var after = Process.GetProcessesByName("Excel");

_process = after.Where(p => !before.Any(x => x.Id == p.Id)).FirstOrDefault();

// clean up

_application.Quit();
Marshal.FinalReleaseComObject(_application);
_application = null;

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

if (_process != null && !_process.HasExited)
{
    _process.Kill();
}

关于代码的说明:您在obj方法中将null设置为releaseObject,但COM实例仍将保留在属性中。您需要使用obj标记ref参数,并使用显式字段而不是自动属性。

答案 1 :(得分:0)

您在ctor中设置CurrentSheet,不要释放它,然后在导致泄漏的行中再次设置它。在执行导致泄漏的线路之前,您需要执行if(CurrentSheet != null) releaseObject(CurrentSheet);