0

我正在使用以下代码在可以将数据表保存到 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 清理解决方案,但它不起作用..

4

3 回答 3

5

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

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

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

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

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

于 2012-06-20T15:46:23.037 回答
1

要创建简单的 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;
    }
}
于 2012-06-20T15:55:16.463 回答
0

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

excel.Quit();
excel = null;

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

于 2012-06-20T15:50:06.007 回答