1

我知道这里提出了许多类似的问题,并且我已经解决了大多数问题,但没有找到满足我好奇心的解决方案(我认为我的案例更具体一些)。
我正在尝试从我的 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));
}
4

3 回答 3

1

这是一篇关于 com 对象在像你这样的情况下没有被正确释放的优秀帖子。

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

你可能想试试这个:

Marshal.ReleaseComObject(names);

抱歉,我可以将此作为评论留下,因为我还没有足够的声誉。

于 2013-11-02T14:09:56.117 回答
0

添加这个:

Marshal.ReleaseComObject(wbook);
Marshal.ReleaseComObject(excel);
于 2013-11-02T14:08:39.040 回答
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 的好/正确的方法,但它对我有用!

于 2013-11-02T14:27:48.447 回答