【问题标题】:Why does Microsoft.Office.Interop.Excel.Application.Quit() leave the background process running?为什么 Microsoft.Office.Interop.Excel.Application.Quit() 让后台进程继续运行?
【发布时间】:2015-01-13 19:47:38
【问题描述】:

以下代码使 Microsoft Excel 后台进程一直运行,直到我的程序退出:

var excelApplication = new Application();
var workbooks = excelApplication.Workbooks;
var workbook = excelApplication.Workbooks.Open(file.FullName);

workbook.Close();
excelApplication.Workbooks.Close();
excelApplication.Quit();

Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApplication);

为什么?我错过了什么?

【问题讨论】:

  • 您是否尝试删除 // do stuff 中的所有内容?造成这种情况的主要原因是一些剩余的引用、分配的对象等等。
  • 在我的测试中,除了评论之外什么都没有。我发布的代码是完整/准确的代码。
  • 我已经更新了问题。我刚刚意识到我最初的测试产生了欺骗性的结果。

标签: c# excel office-interop excel-interop


【解决方案1】:

知道了!

application.Workbooks != application.Workbooks

此属性不公开变量,它生成一个值。所以每次我访问 Workbooks 属性时,我都会创建一个新的 COM 对象。

我修复了代码,一切都很好。谢谢大家。

var excelApplication = new Application();
var workbooks = excelApplication.Workbooks;
var workbook = workbooks.Open(pathToExcelWorkbook); // Fixed

workbook.Close();
workbooks.Close();
excelApplication.Quit();

Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApplication);

【讨论】:

  • 嗨@eugene - 你的回答确实让我朝着正确的方向前进,但我发现它不够具体,无法解决整个问题。如果您比较我的两个代码示例中的第 3 行,您会发现问题在于我未能理解 Workbooks 属性将始终返回一个新对象。
  • 对!如果人使用工作表,人也应该释放这个对象!
  • 你做了什么不同的事情?上面的答案没有什么不同
  • @Fandango68 - 如评论所述,修复位于第 3 行。
【解决方案2】:

这是 Office 应用程序中普遍存在的问题。所有 Excel 插件/自动化应用程序都应在不再需要时系统地释放它们对 Excel 对象的引用。未能系统地释放对 Excel 对象的引用可能会阻止 Microsoft Office Excel 正确关闭。请参阅Systematically Releasing Objects 了解更多信息。它与 Outlook 相关,但相同的原则可以应用于所有 Office 应用程序。

使用 System.Runtime.InteropServices.Marshal.ReleaseComObject 在您使用完 Excel 对象后释放它。然后在 Visual Basic 中将变量设置为 Nothing(在 C# 中为 null)以释放对对象的引用。

【讨论】:

  • 似乎是一个合理的回应,不知道你为什么被否决
  • 在较新的 Office 版本中仍然是这种情况吗?您发布的链接指向 2007 年信息的链接。如果我更改文档的版本(“其他版本”下拉菜单),则没有关于 2010 年或 2013 年的 System.Runtime.InteropServices.Marshal.ReleaseComObject 的信息。
  • 同样适用于较新的 Office 版本。
  • 这仍将对象留在任务列表中。将其设置为 NULL 没有帮助(在 C# 中)
【解决方案3】:

这样做是错误的,但这是解决问题的最简单方法

    [DllImport("user32.dll")]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    private Application _excelApp;
    private Workbook _excelWorkBook;
    private Worksheet _excelSheet;

    private void CloseExcelApp()
    {
        int hWnd = _excelApp.Application.Hwnd;
        uint processID;

        GetWindowThreadProcessId((IntPtr)hWnd, out processID);
        Process.GetProcessById((int)processID).Kill();

        _excelWorkBook = null;
        _excelApp = null;
        _excelSheet = null;
    }

您只需要在需要使用它时初始化所有未初始化的变量,并在需要关闭应用程序时调用 CloseExcelApp()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 2019-11-25
    • 2015-11-09
    • 1970-01-01
    相关资源
    最近更新 更多