可能重复:
如何在 C# 中正确清理 Excel 互操作对象
假设 ASP.NET Web 应用程序在服务器上生成自动 Excel 报告。一旦处理结束,我们如何杀死服务器端 Excel.EXE。我故意提出这个问题,因为我相信垃圾收集器即使在 Excel 文件关闭后也不会清理 Excel 可执行文件。
任何指针都会有帮助吗?
可能重复:
如何在 C# 中正确清理 Excel 互操作对象
假设 ASP.NET Web 应用程序在服务器上生成自动 Excel 报告。一旦处理结束,我们如何杀死服务器端 Excel.EXE。我故意提出这个问题,因为我相信垃圾收集器即使在 Excel 文件关闭后也不会清理 Excel 可执行文件。
任何指针都会有帮助吗?
很抱歉这么说,我不是想聪明,但是……不要把办公室放在服务器上!!!
如果我理解正确的话!:)
编辑:即使我为此被贬低了,我永远不会提倡在服务器上运行 Office - 过去事实证明这对我来说太痛苦了。
话虽如此,我和水晶报表现在也是如此;-)
我同意不在服务器上运行 Office。并不是说我在这件事上有任何选择:)
使用 taskkill 选项要记住的一件事是,除非您专门为此计划(又名 - 单例),否则您可能有多个 Excel 副本(或任何其他 Office 应用程序)正在运行,并且无意中关闭了错误的实例。
另请注意,根据http://support.microsoft.com/kb/257757
Microsoft 目前不推荐也不支持任何无人值守、非交互式客户端应用程序或组件(包括 ASP、ASP.NET、DCOM 和 NT 服务)的 Microsoft Office 应用程序自动化,因为 Office 可能表现出不稳定的行为和/或在此环境中运行 Office 时出现死锁。
作为替代方案,有一个名为Aspose Cells的产品提供了一种产品,该产品旨在允许您在服务器环境中以编程方式使用 Excel 工作表。作为免责声明,我从未亲自使用过该产品,但我从过去与我共事过的几个人那里听说过。
我有更多时间考虑这个答案,现在建议使用 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 进程将关闭。
我有一个类似的问题。虽然“taskkill excel.exe”或枚举所有“excel”进程并杀死它们确实有效,但这会杀死所有正在运行的 Excel 进程。你最好只杀死你当前正在使用的实例。
这是我用来完成此操作的代码。它使用 PInvoke(参见此处)从 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)。
你在使用 VSTO 吗?完成它对我有用后,您可以关闭 Excel 应用程序excelobject.Quit();
,但我不再在服务器端使用 Excel。
您可以查看 Excel 的 XML 架构来构建没有 Excel 本身的 Excel 文件。查看CarlosAg Excel Writer,它的功能完全相同。
:)。我在这里用 Excel 记下了我的小冲突。它也有一些我经过大量搜索后找到的链接。希望能帮助到你。
基本上 Excel 是一种痛苦,即使它可以自动化。
除了对 mdb 文件的数据访问之外,我也不建议在服务器上使用办公应用程序。
我完全可以理解,有时它是必要的。在那些情况下,我会推荐以下内容:
如果您绝对需要在同一台服务器上执行此操作,那么至少在它自己的应用程序池中实现上述内容。
限制自己保留一个工作队列并且只有一个 Excel 实例(或任何其他办公应用程序)让你用 TaskKill 或 .Kill() 放弃它而不会失去工作。
我相信如果你把它保持在一个线程中,那么你很少需要杀死它。
我使用电子表格工具在服务器上生成 XL 报告,效果非常好。我们不必担心EXCEL过程..
实际上,我不久前有一个与此类似的问题-使用 Office 自动化时检查挂起的 Office 进程-对该问题的一些回答可能对您有用。
此外,我必须同意其他人所说的关于将任何 Office 产品远离服务器的说法;但是,由于您正在使用 Excel,因此生成Excel XML 文档可能是可行的。您可以执行此操作而无需执行任何 Office 自动化,并且该过程相当简单。对于简单的基于网格的电子表格,我发现它比尝试使用 Excel 自动化它要容易一些。Office Open XML非常强大,并且允许更复杂的报告以及更多的工作。
结束工作后,您需要安全地处理所有 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 仍然存在,则必须手动将其杀死。
我遇到了类似的问题并使用了以下代码:
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。
最好的方法是使用专门构建的库,例如 Aspose 的库来生成电子表格或填充模板。下一个最佳方法是在适合您需要的情况下使用 xml 格式进行办公。一种有时适合的轻量级方法是创建一个包含一个表的 HTML 文件,并使用 .xls 扩展名对其进行命名。Excel 会很高兴地阅读它,但它的功能非常有限。
这些是我使用过的选项(但不多)。还有一个叫做 Microsoft Office Sharepoint Server 的东西,但我不知道它真的能让你做多少。
也就是说,您的问题正在发生,因为当您调用常规 Excel 库时,您实际上是在完全独立于 .Net 的情况下启动 Excel,并且实际上只是使用代理库与之对话。这与使用 WCF 和服务的情况几乎相同。您不会期望服务会因为客户端应用程序使用完它而死掉。更糟糕的是,Excel 是一种非托管资源,根本不会被处置/最终确定/垃圾收集。.Net 运行时不知道 Excel,它只知道那些代理。Application.quit 是您需要的,您可能还需要显式释放创建的 com 对象。