无法在C#代码中关闭Excel进程

时间:2013-11-02 13:59:05

标签: c# excel automation

我知道很多类似的问题,在这里提出并且我已经完成了大部分问题而没有找到解决方案来满足我的好奇心(我认为我的情况有点具体)。
我正在尝试从我的WPF应用程序中的Excel工作簿的命名范围的名称填充集合。结果是即使我的应用程序关闭后Excel运行也会运行。我已将问题本地化为以下代码。没有它,一切正常:

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

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

     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”:

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

3 个答案:

答案 0 :(得分:1)

Here is an excellent post关于com对象在你的情况下没有得到正确释放。

  
      
  1. 将项目的构建模式更改为“Release”(在DEBUG模式下,COM对象很难处理其引用。
  2.   
  3. 删除了所有双点表达式(所有COM对象都应绑定到一个变量,以便它们可以被释放)
  4.   
  5. 在finally块中显式调用GC.Collect(),GC.WaitForPendingFinalizers()和Marshal.FinalReleaseComObject()
  6.   

您可能想尝试一下:

Marshal.ReleaseComObject(names);

对不起,我可以将此留作评论,因为我还没有足够的声誉。

答案 1 :(得分:0)

添加:

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

答案 2 :(得分:0)

几年前,我遇到了类似的问题,并使用了几种技术来对抗它。我们的用例可能与您的用例略有不同 - 我们有一个长期运行的服务,它产生了多个excel实例,以便在关闭它们之前完成工作。

我从这里http://www.xtremevbtalk.com/showpost.php?p=1335552&postcount=22发现了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;
    }
 }

最后有一个垃圾收集咒语,你要在关闭时执行:

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

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