2013-11-02 38 views
1

我知道很多类似的问题,在这里提出,我已经通过其中大部分都没有找到解决方案来满足我的好奇心(我认为我的案例有点多具体)。
我想从我的WPF应用程序中的Excel工作簿的命名范围的名称填充集合。结果是即使在我的应用程序关闭后仍在运行的Excel进程。我已将问题本地化为以下代码片段。没有它,一切正常:无法关闭C#代码中的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)); 
} 
+0

有一个COM迭代器在你的foreach循环中使用。你不能到达它,excel.Quit()不会停止运行Excel,直到迭代器被垃圾回收。当你的程序退出时,肯定会发生这种情况,这迫使最后一次通过所有终结器。你需要找出你的程序为什么没有正常退出。例如,不要使用Debug + Stop Debugging。 –

+0

感谢您的想法。我必须照顾每个Excel.Name,因为它们也是COM。不知道为什么,但ReleaseComObject不起作用,而FinalReleaseComObject没有工作。 – Hoodahelll

回答

0

补充一点:

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

Here is an excellent post约没有得到正确释放在你们这样的情况下COM对象。该项目的

  1. 更改的构建模式,以“释放”(在调试模式下,COM对象有一个困难时期他们引用的处置。
  2. 删除了所有双点表达式(所有的COM对象应挂钩一个变量,这样他们可以被释放)
  3. 调用GC.Collect的(),GC.WaitForPendingFinalizers(),和Marshal.FinalReleaseComObject()明确地在finally块

你可能想试试这个:

Marshal.ReleaseComObject(names); 

对不起,我可以离开这个作为一个评论,因为我没有足够的声誉呢。

0

几年前,我遇到过类似的问题,并使用了一些技术来对付它。我们的用例可能与您的用例有所不同 - 我们有一个长期运行的服务,它产生了多个excel实例,以便在之前(尝试)关闭它们。

我从这里发现了有关Win32作业api的信息http://www.xtremevbtalk.com/showpost.php?p=1335552&postcount=22,并且几乎将代码逐字复制。它的Excel实例注册到你的主机应用程序的PID,如果您的应用程序死了那么Excel中与它死 - 即使主机崩溃,我们使用它,如下所示:

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

其次,我们运行一个名为“NAR功能“对用Excel分配的任何东西:

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的好方法,但它对我有用!