通过.NETclosures时Excel 2007挂起

我有一个Visual Basic .NET程序需要打开和closuresExcel电子表格。 打开并阅读电子表格工作正常,但试图closuresExcel 2007应用程序导致它挂起。 它似乎closures,但如果你看任务pipe理器应用程序仍在运行。 我用来closures它的代码是

wbkData.Close(saveChanges:=False) appExcel.Quit() wbkData = Nothing appExcel = Nothing 

我怎样才能让Excel正常closures?

你的问题的答案已经涵盖在这里我认为: 如何正确清理c中的excel互操作对象

我不能从你的代码示例中看到,但基本上,总是把你的Excel对象分配给局部variables,永远不会“双点”,如下所示:

 //FAIL Workbook wkBook = xlApp.Workbooks.Open(@"C:\mybook.xls"); 

而是分别引用每个obj:

 //WIN Worksheets sheets = xlApp.Worksheets; Worksheet sheet = sheets.Open(@"C:\mybook.xls"); ... Marshal.ReleaseComObject(sheets); Marshal.ReleaseComObject(sheet); 

.NET创build一个你不可见的COM对象的包装器,直到GC编织它的魔法才会被释放。

直到我发现这一点,我每次创build一个新的工作簿,以检查excel.exe进程的年龄,并杀死任何超过一分钟的时间,在ASP.NET应用程序中运行下面的hacky代码:

 //force kill any excel processes over one minute old. try { Process[] procs = Process.GetProcessesByName("EXCEL"); foreach (Process p in procs) { if (p.StartTime.AddMinutes(1) < DateTime.Now) { p.Kill(); } } } catch (Exception) {} 

我写了你在Excel团队博客中提到的post…

我也在StackOverflow上讨论过这个问题, 如何正确清理C#中的Excel互操作对象 。

这个问题的第一个答案被标记为“正确的”,并得到了11票,但我向你保证,在实践中这个政策是非常难以妥善利用的。 如果有人滑过任何地方并使用“双点”,或者通过每个循环迭代单元格,或者任何其他类似的命令,那么你将会有未引用的COM对象,并冒着一个挂起的风险 – 并且将没有办法find代码中的原因。

相反,你正在采取的清理程序绝对是要走的路。

我在MSDN Excel博客find了一个解决scheme,为我工作。 这是解释为

上面有两个问题:

(1)尽pipe代码似乎首先处理了“wbkData”对象,但上面的代码实际上并没有强制执行,因为.NET垃圾收集过程可以以任何顺序处理其对象。 (GC是非确定性的,而不仅仅是非确定性的。)

(2)像“wsh = wbkData.Workssheets.Item(1)”这样的命令 – 或者像这样的命令 – 是非常常见的,并且会创build一个包含“工作表”对象的RCW对象。 你将不会有一个variables持有对它的引用,所以你通常不会考虑它,但是这个RCW对象不会被丢弃,直到下一个垃圾收集。 但是,上面的代码最后调用GC.Collect(),所以当调用appExcel.Quit()时,RCW仍然保存对这个“工作表”对象的引用。 Excel因此挂起。

最终的代码看起来像

 GC.Collect() GC.WaitForPendingFinalizers() wbkData.Close(SaveChanges:=False) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wbkData) : wbkData = Nothing appExcel.Quit() System.Runtime.InteropServices.Marshal.FinalReleaseComObject(appExcel) : appExcel = Nothing