在服务器上杀死 Excel.EXE [重复]

Posted

技术标签:

【中文标题】在服务器上杀死 Excel.EXE [重复]【英文标题】:Killing Excel.EXE on server [duplicate] 【发布时间】:2008-09-09 09:31:41 【问题描述】:

可能重复:How to properly clean up Excel interop objects in C#

假设 ASP.NET Web 应用程序在服务器上生成自动 Excel 报告。一旦处理结束,我们如何杀死服务器端 Excel.EXE。我故意提出这个问题,因为我相信垃圾收集器即使在 Excel 文件关闭后也不会清理 Excel 可执行文件。

任何指针会有所帮助?

【问题讨论】:

我刚刚在这里回答了这个问题:Killing excel process by its main window hWnd 【参考方案1】:

很抱歉这么说,我也不是想装聪明,但是……不要把office放在服务器上!!!

如果我理解正确的话! :)

编辑:尽管我因此而被贬低,但我永远不会永远主张在服务器上运行 Office - 它已被证明也是如此 过去对我来说非常痛苦。

话虽如此,现在我和 Crystal Reports 也是如此;-)

【讨论】:

我同意一般原则,但在现实世界中,Excel 是业务的关键部分,并且围绕它构建了许多业务流程。当这些需要扩展时,唯一的选择通常是将 Excel 作为服务器端组件运行。 别担心,我们中的一些人对你投了赞成票 :) 我完全同意 - 将 Excel 作为某种数据处理器(服务器或客户端)运行似乎很疯狂。 Excel 是一个(臃肿的)前端用户应用程序,而不是应该用于后端处理的东西。 这实际上是 Joel 的文章“为什么 Microsoft Office 文件格式如此复杂?”中“代码重用”的一个很好的例子 有时候绝对别无选择... +1 完全同意这一点.. :) 服务器上的 Excel 是最大的痛苦.. 我浪费了 5 天时间试图解决我的问题,但没有找到答案..【参考方案2】:

我同意不在服务器上运行 Office。并不是说我在这件事上有任何选择:)

使用 taskkill 选项要记住的一件事是,除非您专门为此计划(又名 - 单例),否则您可能有多个 Excel 副本(或任何其他 Office 应用程序)正在运行,并且无意中关闭了错误的实例.

另请注意,根据http://support.microsoft.com/kb/257757

微软目前没有 推荐,不支持, 微软办公自动化 从任何无人看管的应用程序, 非交互式客户端应用程序或 组件(包括 ASP、ASP.NET、 DCOM 和 NT 服务),因为 Office 可能表现出不稳定的行为和/或 在此运行 Office 时出现死锁 环境。

作为替代方案,有一个名为 Aspose Cells 的产品提供的产品旨在让您在服务器环境中以编程方式使用 Excel 工作表。作为免责声明,我从未亲自使用过该产品,但我从过去合作过的几个人那里听说过。

【讨论】:

【参考方案3】:

我有更多时间考虑这个答案,现在建议使用 XML 方法和 Open XML Office 电子表格格式。

这里有一些很好的链接,可以帮助您开始使用代码构建办公文档。 http://msdn.microsoft.com/en-us/magazine/cc163478.aspx http://msdn.microsoft.com/en-us/library/bb735940(office.12).aspx

只需在 SQL Server 上使用 SSIS。它提供了导出到 Excel 的能力。 不要在服务器上运行office。或者在 aspose 或电子表格设备上浪费金钱。

GC 确实可以工作,您只是没有按照这种模式正确使用它...

   private void killExcel()
        
          xlApp.Quit();
          Marshal.ReleaseCOMObject(xlApp);
          if(xlApp != null)
          
            xlApp = null;
          
          GC.WaitForPendingFinalizers();
          GC.Collect();
          GC.WaitForPendingFinalizers();
          GC.Collect();
        

让你的Excel操作类实现IDisposable,然后在Dispose方法中粘贴killExcel()。

更新:另请注意,有时开发人员仍会看到 Excel.exe 在任务管理器中运行。在假设上述代码不起作用之前,请检查运行代码的进程是否也已关闭。对于 VSTO 或 COM 插件,检查 Word/powerpoint/其他 excel 实例是否也已关闭,因为仍有 GC 根返回到启动过程。关闭后,Excel.exe 进程将关闭。

【讨论】:

SSIS 绝对是一场噩梦,除了基本的简单表格 Excel 报告。我不建议 Excel 报告使用 SSIS,尤其是当您的 Excel 报告使用高级功能(如图形、多个表格布局、多个工作表或数据透视表)时。 是的,我同意这一点。对于需要图形或枢轴的高级场景,有更好的解决方案。然而,对于导出和转储数据表,我不同意这绝对是一场噩梦的说法。仍然是课程的马匹,有大量可用的报告解决方案。【参考方案4】:

您在使用 VSTO 吗?完成excelobject.Quit(); 后,您可以关闭 Excel 应用程序,它对我有用,但我不再在服务器端使用 Excel。

您可以查看 Excel 的 XML 架构来构建没有 Excel 本身的 Excel 文件。查看CarlosAg Excel Writer,它的作用完全相同。

【讨论】:

【参考方案5】:

我也遇到过类似的问题。虽然“taskkill excel.exe”或枚举所有“excel”进程并杀死它们确实有效,但这会杀死所有正在运行的 Excel 进程。你最好只杀死你当前正在使用的实例。

这是我用来完成此操作的代码。它使用 PInvoke(请参阅 here)从 Excel.Application 实例(以下示例中的 Me.ExcelInstance)获取 ProcessID。

Dim ExcelPID As Integer
GetWindowThreadProcessId(New IntPtr(Me.ExcelInstance.Hwnd), ExcelPID)

If ExcelPID > 0 Then
   Dim ExcelProc As Process = Process.GetProcessById(ExcelPID)
   If ExcelProc IsNot Nothing Then ExcelProc.Kill()
End If

请注意,由于 PInvoke,这可能不适用于所有平台...迄今为止,这是我发现的唯一可靠方法。我还尝试通过枚举所有 Excel 进程并将 Process.MainModule.BaseAddress 与 Excel.Application.Hinstance 进行比较来找到正确的 PID。

'DO NOT USE THIS METHOD, for demonstration only    
For Each p as Process in ExcelProcesses
        Dim BaseAddr As Integer = p.MainModule.BaseAddress.ToInt32()
        If BaseAddr = Me.ExcelInstance.Hinstance Then
            p.Kill()
            Exit For
        End If
Next

不是找到正确进程的可靠方法,因为 BaseAddress 有时对于多个进程似乎是相同的(导致终止错误的 PID)。

【讨论】:

【参考方案6】:

你需要的命令是“taskkill”。

http://technet.microsoft.com/en-us/library/bb491009.aspx

> taskkill excel.exe

【讨论】:

我刚刚在 VB.Net 中尝试过,它可以工作 System.Diagnostics.Process.Start("taskkill.exe", "-im excel.exe /f")【参考方案7】:

:)。我用 Excel here 记下了我的小冲突。它也有一些我经过大量搜索后找到的链接。希望对您有所帮助。 基本上 Excel 是一种痛苦,即使它可以自动化。

【讨论】:

【参考方案8】:

我也不建议在服务器上使用办公应用程序,除了对 mdb 文件的数据访问。

我完全可以理解,有些时候是必要的。在那些情况下 我会推荐以下内容:

创建一个单独的服务器,这是唯一的功能。 (让您以最小的影响重新启动)。 让服务器实现请求排队机制 保持一个线程处理队列。这使您能够跟踪办公应用程序、在必要时将其终止并继续运行,而不会影响任何排队的作业或其他应用程序。

如果您绝对需要在同一台服务器上执行此操作,那么至少在它自己的应用程序池中实现上述内容。

限制自己保留一个工作队列并且只有一个 Excel 实例(或任何其他办公应用程序)让您使用 TaskKill 或 .Kill() 放弃它而不会丢失工作。

我相信如果你把它保留在一个线程中,那么你很少需要杀死它。

【讨论】:

【参考方案9】:

我已经使用spreadsheetgear 在服务器上生成 XL 报告,它工作得非常好。我们不用担心EXCEL流程..

【讨论】:

【参考方案10】:

我遇到了类似的问题,使用了以下代码:

System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcesses();
for (int i = 0; i < procs.Length; i++)

  if(procs[i].ProcessName == "EXCEL")
  
    procs[i].Kill();
  

这很好用,但我真的会考虑在服务器上使用 Office。

【讨论】:

【参考方案11】:

实际上,我不久前有一个与此类似的问题 - Check for hung Office process when using Office Automation - 该问题的一些回答可能对您有用。

另外,我必须同意其他人所说的关于将任何 Office 产品远离服务器的说法;但是,由于您正在使用 Excel,因此生成 Excel XML documents 可能是可行的。您可以执行此操作而无需执行任何 Office 自动化操作,并且该过程相当简单。对于简单的基于网格的电子表格,我发现它比尝试使用 Excel 自动化它要容易一些。 Office Open XML 非常强大,可以进行更复杂的报告,也可以付出更多的努力。

【讨论】:

【参考方案12】:

您需要在结束工作后安全地处置所有 COM 互操作对象。 “全部”是指绝对全部:集合属性值等等。我在设置过程中创建了堆栈对象并推送了对象:

Stack<object> comObjectsToRelease = new Stack<object>();
...
Log("Creating VBProject object.");
VBProject vbProject = workbook.VBProject;
comObjectsToRelease.Push(vbProject);
...
finally

    if(excel != null)
    
        Log("Quiting Excel.");
        excel.Quit();
        excel = null;
    
    while (comObjectsToRelease.Count > 0)
    
        Log("Releasing 0 COM object.", comObjectsToRelease.GetType().Name);
        Marshal.FinalReleaseComObject(comObjectsToRelease.Pop());
                   
    Log("Invoking garbage collection.");
    GC.Collect();

如果 Excel 仍然存在,则必须手动将其终止。

【讨论】:

【参考方案13】:

最好的方法是使用专门构建的库(例如 Aspose 的库)来生成电子表格或填充模板。下一个最佳方法是在适合您需要的情况下使用 xml 格式进行办公。一种有时适合的轻量级方法是创建一个包含一个表的 html 文件,并使用 .xls 扩展名对其进行命名。 Excel 会很高兴地读取它,但它的功能非常有限。

这些是我使用过的选项(但不多)。还有一个叫做 Microsoft Office Sharepoint Server 的东西,但我不知道它到底能让你做什么。

也就是说,您的问题正在发生,因为当您调用常规 Excel 库时,您实际上是在完全独立于 .Net 的情况下启动 Excel,并且实际上只是使用代理库与之对话。这与使用 WCF 和服务的情况几乎相同。您不会期望服务会因为客户端应用程序使用过它而死掉。更糟糕的是,Excel 是一种非托管资源,根本不会被处置/最终确定/垃圾收集。 .Net 运行时不知道 Excel,它只知道那些代理。 Application.quit 是您需要的,您可能还需要显式释放创建的 com 对象。

【讨论】:

以上是关于在服务器上杀死 Excel.EXE [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Android服务被杀死[重复]

ADB 和 Genymotion 错误:“adb 服务器已过期。正在杀死...无法绑定 'tcp:5037' ADB 服务器未确认”[重复]

Windows按端口号杀死进程[重复]

从python中杀死一个子进程,包括它的子进程[重复]

powershell 在端口上杀死节点服务器

在 Mac OSX 端口 80 上杀死一个未知的自重启服务器