即使在释放资源后也无法closuresExcel

我已经尝试了很多解决scheme,但没有工作请帮我解决这个问题。 以下是在SSIS脚本任务中使用的代码

using Excel = Microsoft.Office.Interop.Excel; Excel.Application xlApp = null; Excel.Workbooks workbooks = null; Excel.Workbook xlWorkbook = null; Excel.Worksheet worksheet = null; Excel.Range xlRange = null; try { xlApp = new Excel.Application(); xlApp.DisplayAlerts = false; xlApp.AskToUpdateLinks = false; workbooks = xlApp.Workbooks; xlWorkbook = workbooks.Open("sample.csv", 2, true); xlWorksheet = xlWorkbook.Sheets[1]; xlRange = xlWorksheet.UsedRange; int rowCount = xlRange.Rows.Count; for (int row = 2; row <= rowCount; row++) { //some logic } } catch (Exception ex) { MessageBox.Show(ex.Message); } finally //releasing all resources { GC.Collect(); GC.WaitForPendingFinalizers(); Marshal.ReleaseComObject(xlRange); Marshal.ReleaseComObject(xlWorksheet); xlRange = null; xlWorksheet = null; xlWorkbook.Close(); Marshal.ReleaseComObject(xlWorkbook); xlWorkbook = null; workbooks = null; xlApp.Quit(); Marshal.ReleaseComObject(xlApp); xlApp=null; } 

即使在释放资源之后,仍然看到一个优秀的过程

有两种方法可以实现这一点:

第一种方法

你可以像下面这样创build一个自定义的ReleaseObject函数:

 private void ReleaseObject(object obj) { try { int intRel = 0; do { intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); } while (intRel > 0); } catch (Exception ex) { obj = null; } finally { GC.Collect(); } } 

并使用下面的代码顺序:

 xlWorkBook.SaveAs("...."); xlWorkBook.Close(); xlApp.Quit(); ReleaseObject(xlRange); ReleaseObject(xlWorkSheet); ReleaseObject(xlWorkBook); ReleaseObject(xlApp); 

第二种方法

在脚本任务中创build一个类,创build一个获取Excel.Application的进程ID的函数并杀死它

 using Excel = Microsoft.Office.Interop.Excel; using System.Runtime.InteropServices; using System.Diagnostics; class Sample { [DllImport("user32.dll")] static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId); Process GetExcelProcess(Excel.Application excelApp) { int id; GetWindowThreadProcessId(excelApp.Hwnd, out id); return Process.GetProcessById(id); } } 

然后你可以使用GetExcelProcess(XlApp).Kill();

看起来你在正确的轨道上。 但是,您目前的ExcelApplication是您将在任务监视器中看到的实际过程以及在WordApplication被终止之前需要closures的ExcelDocument。

看看这个简单的例子:

 public void Foo(string filePath) { var application = new Excel.Application(); // do your stuff here... var document = application.Workbooks.Open(filePath, ReadOnly: true, Visible: false); // this is the magic: clear 'application' and 'document', // once the work is finished if (document != null) document.Close(SaveChanges: false); if (application != null) application.Quit(SaveChanges: false); document = null; application = null; } 

在这里你会看到我们实际上正确地closures()工作簿(文档)和退出()应用程序。 这是在最后一节中你所做的一些事情,但要记住,variables进入try …部分之前已经初始化了。

我的build议是:不要手动调用任何垃圾回收(GC)和元帅的东西。 如果你不确定它的作用,它会在以后带来副作用。 接下来,您可以通过在ExcelApplication和ExcelWorkbook上添加一个很好的using (...)结构来进一步改进示例。

正确清理Interop.Excel对象很困难。 做错了,你可能会陷入一个SQL或SSIS机器与僵尸的Excel实例吨。

在这里输入图像描述

互联网上散布 着关于如何正确Close()Quit()ReleaseObject() Interop.Excel对象的build议。 适合您的build议将取决于您调用对象的顺序以及您调用的方法。 例如,如果你使用双点方法,那么你创build了一个不可closures的对象。 即使你听取了所有的build议,并构build你的代码以避免陷阱,当SSIS包被部署到服务器时,情况就会改变。 微软基本上告诉开发者不要这样做 。

Microsoft目前不推荐并不支持从任何无人参与的非交互式客户端应用程序或组件(包括ASP,ASP.NET,DCOM和NT服务)自动化Microsoft Office应用程序,因为Office可能会出现不稳定的行为和/或在此环境中运行Office时发生死锁。

奇怪的事情发生。 而且,它不会缩放。 包将共享相同的Excel实例。 一个程序包的清理程序可以杀死另一个程序包的飞行操作。

听着,我知道Interop.Excel上有很多如何操作,甚至更多的如何清理它们。 但是,这些文章是针对在自己的机器上运行代码的单个实例的个人。 不build议使用SSIS的企业环境。 是的,这太臭了。

但是,有解决scheme! NetOffice类似于Interop.Excel ,帮助处理closures和处理COM对象。 我非常喜欢EPPlus API,它非常轻便,类似于Interop.Excel ,速度更快10倍,没有清理困难。 除了打印和macros之外,Interop可以做几乎所有的事情。 即使比C#更好,也会开始使用Microsoft提供的内置SSIS Excel组件来执行ETL工作。

祝你好运!