4

我看过很多关于如何确保 Excel 在您想要的时候真正退出并且该过程不会继续存在的文章和问题。这是描述问题和 Microsoft 推荐的解决方案的知识库文章。本质上:

'close files

'Quit Excel
xlApp.quit()

'Release and collect garbage
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp)
GC.Collect()
GC.WaitForPendingFinalizers()

很多人不建议杀掉进程;请参阅 如何正确清理 Excel 互操作对象了解 .net 中的垃圾收集

另一方面,很多人不推荐使用 GC.Collect。请参阅使用 GC.Collect() 有什么问题?

根据我的经验,终止该过程是确保 Excel 消失的最快和最简单的方法。我的代码只杀死它启动的确切进程,没有其他。我确保关闭所有打开的工作簿,退出应用程序并释放 xlApp 对象。最后,我检查该进程是否仍然存在,如果存在,则将其杀死。

<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
ByRef lpdwProcessId As Integer) As Integer
    End Function

Sub testKill()

    'start the application
    Dim xlApp As Object = CreateObject("Excel.Application")

    'do some work with Excel

    'close any open files

    'get the window handle
    Dim xlHWND As Integer = xlApp.hwnd

    'this will have the process ID after call to GetWindowThreadProcessId
    Dim ProcIdXL As Integer = 0

    'get the process ID
    GetWindowThreadProcessId(xlHWND, ProcIdXL)

    'get the process
    Dim xproc As Process = Process.GetProcessById(ProcIdXL)

    'Quit Excel
    xlApp.quit()

    'Release
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp)

    'set to nothing
    xlApp = Nothing

    'kill the process if still running
    If Not xproc.HasExited Then
        xproc.Kill()
    End If

End Sub

我看到很多人说杀死进程是不好的,但我还没有看到任何关于为什么的定性答案。特别是在确保文件已关闭之后,Excel 已退出,我们只会终止我们开始的确切进程。我的问题是杀死 Excel 进程的潜在问题是什么。对性能有影响吗?它会损害 Excel 吗?

许多人还会说,通过良好的编码,我不必终止进程。也许吧,但这并不能回答“为什么终止进程不好?”的问题。关闭文件后,退出 Excel 并释放对象;为什么绝对确定该过程已经消失会是一件坏事?

编辑:Excel退出后实际上还剩下什么?如果 Excel 可见,它似乎正常退出,从视图和任务栏中消失。Excel实际上退出了还是没有退出。在我看来,Excel 实际上确实退出了,而且我们只有一个空的进程 shell 正在运行。任何人都可以对此发表评论吗?

编辑:有趣的是我注意到通过 GC.Collect() GC.WaitForPendingFinalizers() 的 GC(又名垃圾收集)实际上会释放 Excel 退出后留下的进程 shell。这是否支持我的假设,即空进程外壳毕竟真的是垃圾?

编辑:刚刚找到一个关于这个问题的优秀网站:50 种杀死 Excel的方法

4

3 回答 3

6

看,事实是,如果可能的话,您应该始终让应用程序正常退出。杀死应用程序是最后的手段。我了解您确信在这种情况下您认为这样做没有任何问题,也许您是正确的。即使杀死它对您的系统绝对没有负面影响,但这并不能改变这样做是错误的事实。这就像违法,因为你知道你不会被抓到,而且无论如何这是一种没有受害者的犯罪。

但是,您可能没有意识到潜在的副作用。例如,当您强制终止应用程序时,操作系统可能会为其保留崩溃数据。或者它可能会向 Microsoft 发送崩溃遥测数据。您实际上是在告诉 Microsoft,应用程序崩溃的频率比实际情况要高,导致其崩溃统计数据略有偏差。

另一个可能的副作用是注册表配置单元可能无法正确卸载。您可能不时在事件日志中看到此错误。当应用程序被强制关闭并且没有正确关闭注册表句柄时,通常会发生这种情况。

即使这些事情都没有发生,您也无法知道操作系统的未来版本可能会做什么。今天行得通的,明天可能行不通。这就是为什么您应该始终遵循记录在案的 API 和指南的原因,因为他们通常会非常努力地支持他们已发布的内容,但通常不会非常努力地支持他们明确告诉您不要做的事情。

于 2013-07-22T07:38:33.987 回答
4

当您使用自动化从另一个应用程序控制 Office 应用程序时,您有时必须像您一样终止 Office 进程以避免“泄漏”不可见的 Office 应用程序。这是 Office 应用程序尝试既充当最终用户应用程序又充当自动化服务器的不幸结果。

在服务器端使用 Word 时,我或多或少地采用了与您相同的解决方案(不要问为什么)。无论我们为正确关闭 Word 付出了多少努力,服务器上都会积累越来越多的“不可见”Word 进程。唯一好的解决方案是杀死那些在被指示退出后不会终止的进程。

当一个 Windows 进程被杀死时,该进程使用的所有资源都被操作系统清理,例如文件和其他操作系统句柄(如注册表句柄)被关闭,内存被释放等。从操作系统的角度来看,当一个进程终止。

但是,应用程序可能会创建要在正常关机期间删除的临时文件。随着时间的推移,这些孤立文件可能会使用越来越多的磁盘空间。此外,如果用户在应用程序中打开了其他文件,则这些文件可能会在进程终止时处于不一致的状态,并且未保存的更改可能会丢失。基本上,被杀死的应用程序可以“泄漏”的是它打算在关闭时清理或删除的文件。“泄漏”的另一个来源是在网络上获取的资源(例如,在共享上打开的文件)。但是,当进程终止时,网络句柄最终将变得“陈旧”并被网络服务器回收。

另外,我想指出,如果进程被杀死,Watson 博士将不会收集任何故障转储数据。这仅在进程意外崩溃时发生(例如,有未处理的异常)。

底线:如果你小心杀死 Excel 可能是避免随着时间的推移“泄漏”不可见的 Excel 进程的最佳方法。在系统重新启动之前让它们使用越来越多的系统资源运行的替代方法是不可行的。如果有的话,成本应该只是临时文件夹中留下的一些小文件。


作为自动化 Office 的替代方法,您可以使用Open XML SDK打开和修改 Office 文件。最初它可能会稍微复杂一些,但您可以完全避免在此过程中启动繁重的 Office 应用程序。

于 2013-07-22T08:04:47.900 回答
0

根据我的经验,程序在关闭时会做一些事情:

  1. 释放所有内存引用
  2. 删除任何临时文件或工作文件
  3. 保存任何状态数据

由于这些原因,以 API 描述的方式关闭 Excel至关重要app.Quit(),使用. 这个例子偏离规范的地方在于 API 没有释放所有的COM对象。这导致步骤 1) 不完整。无法确保应用程序在所有情况下都有效关闭,因为您可能无法始终控制创建的 COM 对象。

我发现使用 Excel(以及其他办公程序)的最佳方法是使用以下过程:

  1. 获取名称包含 Excel 的进程 ID 列表
  2. 打开 Excel
  3. 重复步骤 1。使用它来确定您创建的新 Excel 实例的进程 ID
  4. 使用 Excel
  5. 退出 Excel,释放您创建并终止的所有对象Application.Quit()
  6. 杀死进程

这使 Excel 有机会在进程终止之前释放任何对象、删除任何临时文件并保存任何状态数据。我通常创建一个负责管理 excel 实例的单例类。它实现了 IDisposable,并且在 Disposal 时,它将退出所有剩余的 Excel 应用程序。

于 2013-07-22T22:09:03.793 回答