Excel应用程序不在Interop中退出

我正在使用下面的一段代码在ASP.net表单上dynamic地写入excel文件,可以将数据表保存为excel。

//Create Excel Object Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application(); Microsoft.Office.Interop.Excel.Workbook workbook = excel.Workbooks.Open(target); Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets[1]; worksheet.Name = "Worksheet1"; excel.Visible = false; //Generate Fields Name foreach (DataColumn col in dataTable.Columns) { colIndex++; excel.Cells[1, colIndex] = col.ColumnName; } object[,] objData = new object[rowNo, columnNo]; for (int row = 0; row < rowNo; row++) { for (int col = 0; col < columnNo; col++) { objData[row, col] = dataTable.Rows[row][col]; } } Microsoft.Office.Interop.Excel.Range range; range = worksheet.Range[excel.Cells[2, 1], excel.Cells[rowNo + 1, columnNo]]; range.Value2 = objData; worksheet.Columns.AutoFit(); workbook.Save(); workbook.Close(); IntPtr hwnd = new IntPtr(excel.Hwnd); IntPtr processId; IntPtr foo = GetWindowThreadProcessId(hwnd, out processId); Process proc = Process.GetProcessById(processId.ToInt32()); proc.Kill(); //excel.Quit(); GC.Collect(); GC.WaitForPendingFinalizers(); 

数据被写入excel文件。 但是,当我尝试杀死使用proc.Kill()的过程,我得到以下exception

说明:执行当前Web请求期间发生未处理的exception。 请查看堆栈跟踪,了解有关错误的更多信息以及源代码的来源。

exception详细信息:System.ComponentModel.Win32Exception:访问被拒绝

源错误:

在执行当前Web请求期间生成未处理的exception。 有关exception的来源和位置的信息可以使用下面的exception堆栈跟踪来标识。

堆栈跟踪:

 [Win32Exception (0x80004005): Access is denied] System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited) +1985316 System.Diagnostics.Process.Kill() +49 Faculty_Report1.FetchData_EXCEL(String prog, String cls, String spcln, String fromdate, String todate) +2413 Faculty_Report1.fetchselectedvalues_EXCEL() +1044 System.Web.UI.WebControls.ImageButton.OnClick(ImageClickEventArgs e) +187 System.Web.UI.WebControls.ImageButton.RaisePostBackEvent(String eventArgument) +165 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3707 

而不是使用proc.Kill()方法,我已经尝试使用excel.Quit()方法,但过程不会终止。 当我这样做时,每当用户尝试生成报告时,我都会得到一个新的excel进程。

我有web.config文件中的用户模拟,但这不会改变任何东西。

  <system.web> <identity impersonate="true" userName="xxxxxx" password="xxxxxxxx" /> </system.web> 

任何指针我如何避免exception,并确保Excel过程终止罚款? 我已经尝试了在这里find的COM清理解决scheme,但它不工作..

在服务器上使用Interop(如ASP.NET)不受MS支持 – 请参阅http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257757#kb2

由于Windows Vista MS引入了一些安全相关的措施,防止Windows服务“做类似桌面”的事情…这意味着你将不得不规避一些安全措施,以使其工作(不推荐!)。

要在服务器场景中处理Excel,有几个选项(免费和商业):

我可以推荐Aspose.Cells和Flexcel …没有尝试SpreadsheetGear,但听到很多关于它的好东西…

免费选项(尽pipe只适用于较新的xlsx格式!)例如来自MS和EPPlus的 OpenXML 2 。

为了创build简单的excel数据表,除interop之外还有几个可能有趣的选项,但是有一些方法可以在需要使用interop时帮助excel。

第一件事是第一件事 如果您确定可以重用现有应用程序,则可以使用“oldschool”getactiveobject获取现有实例:

  using System.Runtime.InteropServices; Microsoft.Office.Interop.Excel.Application excel; try { excel = (Microsoft.Office.Interop.Excel)Marshal.GetActiveObject("Excel.Application"); } catch { excel = new Microsoft.Office.Interop.Excel.Application(); } 

为了让excel应用程序成功退出,所有的句柄都必须被销毁,但是我想这就是你所说的COM清理的意思吗? 确保所有的句柄都与marshal.releasecomobject一起释放(这可能在现代互操作中不再需要了),这可能是一个痛苦,这就是为什么我把每个办公室互操作“处理”包括在工作表,工作簿,范围等包装。 代码我没有太多的用途分离,但我会张贴在这里无论如何给一个大致的想法:

 public class WrapperBase<T>: IWrapper { protected T obj; protected internal WrapperBase(IWrapper Owner) { SetOwner(Owner); } protected WrapperBase() { } CultureSwitcher cultswitch; public CultureSwitcher CultureSwitcher { get { if (cultswitch == null) { if (owner != null) return owner.CultureSwitcher; cultswitch = new CultureSwitcher(); } return cultswitch; } } public T Object { get { return obj; } internal set { obj = value; } } //public abstract void Save(); public bool IsDisposed { get { return disposed; } } bool disposed; public void Dispose() { Dispose(false); } void Dispose(bool fromfinalize) { if (disposed) return; disposed = true; if (!fromfinalize) GC.SuppressFinalize(this); CultureSwitcher.Try(OnDisposing); if (obj != null) { while (Marshal.ReleaseComObject(obj) > 0) { } obj = default(T); } if (cultswitch != null) { cultswitch.Dispose(); cultswitch = null; } SetOwner(null); } protected virtual void OnDisposing() { if (children != null) { foreach (var c in children) c.Dispose(); children = null; } } ~WrapperBase() { Dispose(true); } List<IWrapper> children; IWrapper owner; public IWrapper Owner { get { return owner; } } protected void SetOwner(IWrapper Owner) { if (Owner == owner) return; if (owner != null) { owner.DeRegister(this); } owner = Owner; if (owner != null) { owner.Register(this); } } public void Register(IWrapper Child) { if (disposed) throw new ObjectDisposedException("Cannot register children after disposing"); if (children == null) children = new List<IWrapper>(); children.Add(Child); } public void DeRegister(IWrapper Child) { if (disposed) return; children.Remove(Child); } protected IEnumerable<IWrapper> GetChildren() { return children; } } 

过去,我也遇到过使用Interop真正closuresExcel应用程序的问题,但发现解决scheme是释放应用程序的实例。 尝试以下操作:

 excel.Quit(); excel = null; 

这听起来太简单了,但是它成功地阻止了Excel的幽灵实例在我的应用程序的操作系统中徘徊。