【问题标题】:Excel Application Not Exiting in InteropExcel 应用程序未在互操作中退出
【发布时间】:2012-06-20 23:55:16
【问题描述】:

我正在使用下面这段代码在可以将数据表保存到excel的ASP.net表单上动态写入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() 终止进程时,我得到以下异常

说明:在执行当前 Web 请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

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

来源错误:

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

堆栈跟踪:

[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>

关于如何避免异常并确保 excel 进程正常终止的任何指示?我已经尝试过在这里找到的 COM 清理解决方案,但它不起作用..

【问题讨论】:

    标签: c# asp.net excel impersonation excel-interop


    【解决方案1】:

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

    由于 Windows Vista MS 引入了一些与安全相关的措施来阻止 Windows 服务执行“类似桌面”的操作...这意味着您必须绕过一些安全措施才能使其正常工作(不推荐!)。

    要在服务器方案中处理 Excel,有几种选择(免费和商业):

    我可以推荐Aspose.CellsFlexcel...没有尝试SpreadsheetGear,但听到+阅读了很多关于它的好东西...

    免费选项(尽管仅适用于较新的 xlsx 格式!)例如 OpenXML 2 from MSEPPlus

    【讨论】:

      【解决方案2】:

      要创建简单的 excel 数据表,除了互操作之外,还有几个可能很有趣的选项,但是当必须使用互操作时,有一些方法可以帮助处理 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;
          }
      }
      

      【讨论】:

        【解决方案3】:

        过去我在使用 Interop 让 Excel 应用程序真正关闭时也遇到过问题,但找到了释放应用程序实例的解决方案。请尝试以下操作:

        excel.Quit();
        excel = null;
        

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

        【讨论】:

        • @user1067334 这很有趣;我总是很幸运。
        猜你喜欢
        • 2013-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-21
        • 1970-01-01
        • 2012-08-29
        • 2019-12-24
        • 1970-01-01
        相关资源
        最近更新 更多