下面的代码示例在Excel 2007中运行得很好,但是当我安装Excel 2010(32位)时,除非我添加了GC.Collect(),否则它将使excel.exe进程保持打开状态。我的简单问题是我做错了什么?在我看来,我正在释放我使用的所有内容。
public override void Update()
{
StatusBox.AddStatus("Opening File " + ImportPath);
Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wb = app.Workbooks.Open(ImportPath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
Microsoft.Office.Interop.Excel.Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets[1];
Range rng = ws.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);
int LastRow = rng.Row;
StatusBox.AddStatus(LastRow.ToString() + " Rows Found in File");
StatusBox.AddStatus("Closing File " + ImportPath);
System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
rng = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws);
ws = null;
wb.Close(true, ImportPath, null);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
wb = null;
GC.Collect();
app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
app = null;
}
答案 0 :(得分:1)
您需要同时调用GC.Collect / GC.WaitForPendingFinalizers 和 Marshall.FinalReleaseComObject。
详情请参阅我的答案:
How do I properly clean up Excel interop objects?
请注意,在任何给定命令中“永不使用两个点”的建议(显然是更受欢迎的答案)是有效的,但实际上几乎不可能强制执行。如果您在代码中的任何位置出现任何错误,Excel应用程序将挂起,并且地球上没有可以帮助您的分析工具 - 您必须通过眼睛检查所有代码。对于大型代码库,这基本上是不可能的。
在您的代码中,在调用GC.Collect之后,您没有调用GC.WaitForPendingFinalizers。这是确保垃圾回收调用是同步的必要条件。 (GC.Collect在不同的线程上运行,如果你不等它,那么集合可能就你的subseqent对象版本而无序发生,并且你想要释放次要的COM对象,比如Ranges,首先和主要的最后的工作簿和应用程序等COM对象。)在调用GC.Collect和GC.WaitForPendingFinalizers后,您需要在命名引用上调用Marshall.FinalReleaseComObject。
因此,简而言之,策略是调用GC.Collect和GC.WaitForPendingFinalizers来释放您没有引用的COM对象,并调用Marshall.FinalReleaseComObject来释放您持有命名的COM对象参考
- 迈克