我正在尝试自动执行将数据放入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()
,则该过程立即从任务管理器中消失。谢谢你的帮助!
答案 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);
。