无法closuresC#代码中的Excel进程

我意识到许多类似的问题,在这里提出,我已经经历了大多数没有find解决scheme,以满足我的好奇心(我认为我的情况是更具体一点)。
我试图从我的WPF应用程序中的Excel工作簿的命名范围的名称填充集合。 结果是即使在我的应用程序closures后仍在运行的Excel进程。 我已经将问题本地化到以下代码片段中。 没有它,一切工作正常:

foreach (Excel.Name name in names) { namedRanges.Add(name.Name); } 

所以,显然这里的东西不会被释放。 我还没有find像其他Excel对象一样closures/处理/退出“Excel.Name”的方法。 请build议如何做到这一点。 我正在使用的解决方法是杀死特定的进程,但我宁愿了解这背后的问题,并试图提出一个更相关的解决scheme。 以下是完整的代码摘录:

  Excel.Application excel = new Excel.Application(); excel.Visible = false; Excel.Workbooks wbooks = excel.Workbooks; Excel.Workbook wbook = wbooks.Open(Proc.ExpenseFullPath); ObservableCollection<string> namedRanges = new ObservableCollection<string>(); Excel.Names names = wbook.Names; foreach (Excel.Name name in names) { namedRanges.Add(name.Name); } wbook.Close(); wbooks.Close(); excel.Quit(); 

编辑:我发现如何使其工作。 我把有问题的“foreach”replace为:

 for (int i = 1; i <= names.Count; i++) { namedRanges.Add(names.Item(i).Name); Marshal.FinalReleaseComObject(names.Item(i)); } 

这里是一个关于com对象在你的情况下没有得到正确释放的优秀post 。

  1. 将项目的构build模式更改为“Release”(在DEBUG模式下,COM对象很难处理其引用。
  2. 删除了所有的双点expression式(所有的COM对象都应该绑定到一个variables上,这样它们才能被释放)
  3. 在finally块中显式调用GC.Collect(),GC.WaitForPendingFinalizers()和Marshal.FinalReleaseComObject()

你可能想试试这个:

 Marshal.ReleaseComObject(names); 

对不起,我可以留下这个评论,因为我还没有足够的声望。

添加这个:

 Marshal.ReleaseComObject(wbook); Marshal.ReleaseComObject(excel); 

几年前,我遇到了类似的问题,并使用了一些技术来解决这个问题。 我们的用例可能与您的用例有所不同 – 我们有一个长期运行的服务,产生了多个excel实例,在之前(试图)closures它们。

我从这里find了关于Win32的工作api,并且几乎是逐字地拷贝了代码。 它将Excel实例注册到宿主应用程序的PID中,如果你的应用程序死了,那么excel将会死亡 – 即使主机崩溃,我们也会按如下方式使用它:

 uint pid = 0; GetWindowThreadProcessId(new IntPtr(_excel.Hwnd), out pid); _job = new Job(); _job.AddProcess(Process.GetProcessById((int) pid).Handle); 

其次,我们对Excel分配的任何东西运行一个名为“NAR”的函数:

 private static void NAR(object o) { if (o == null) return; try { System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o); } catch { } finally { o = null; } } 

最后还有垃圾收集咒语,你要在closures时执行:

 private static void GcCleanup() { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); } 

我不记得为什么它做了两次,我记得有一个原因。 我不能说这些技术是驯服Excel的好方法,但它对我有用!