C#Excel互操作过程在崩溃后仍然存在

时间:2018-06-19 16:59:20

标签: c# excel-interop

我最近刚开始使用C#语言处理Excel Interop,如果我的应用程序崩溃,Excel进程仍然存在问题。 (为什么进程崩溃是我正在调查的另一个问题。)

认为我正确地释放了COM对象,因为如果我的应用程序成功完成,一切都可以正常进行。只有当它崩溃或在调试过程中碰巧退出时,才剩下Excel进程。

我当然知道当它崩溃时,COM对象不会被清理。我不确定如何处理。

这里有一些伪代码,希望能演示我在做什么(真正的代码很长。)

应该:1)打开一个现有的excel文件,2)访问文件中的特定工作表,3)插入很多行,4)向这些行添加值,5)关闭并保存所有。 / p>

我在做什么错了?

    // Open excel file
    try {
        myExcelApp = new Excel.Application();
        myExcelApp.Visible = false;
        myExcelApp.DisplayAlerts = false;
        myExcelWorkbook = (Excel.Workbook)myExcelApp.Workbooks.Open(excelFile);
    } catch (Exception ex) {
        string msg = "Error:Failed opening Excel File " + excelFile + ": " + ex.Message;
        throw new Exception(msg);
    }

    // ---- some other stuff here. ----

    foreach ( var toolWorkSheetName in workSheetsList ){

        // Init
        Excel.Worksheet xlWorksheet = null;
        Excel.Range xlRange = null;

        // Get specific worksheet from workbook
        try {
            xlWorksheet = (Excel.Worksheet)myExcelWorkbook.Worksheets[toolWorkSheetName];
        } catch (Exception ex) {
            string msg = "Error:Could not open worksheet in " + toolWorkSheetName + ": " + ex.Message;
            throw new Exception(msg);
        }

        // First scan existing template for insertion row & number of rows to insert
        xlRange = xlWorksheet.UsedRange;
        object[,] values = (object[,])xlRange.Value2;
        Marshal.ReleaseComObject(xlRange);  // Release local com objects 
        int colCount = values.GetLength(1);
        values = null;

        // ---- Determine the following: -----
        // insertRow =~ 3;
        // nLinesToInsert  =~ 63233;
        // colCount =~ 400;

        // Insert a range of rows for the values
        Excel.Range range = xlWorksheet.Range[xlWorksheet.Cells[insertRow, 1], xlWorksheet.Cells[insertRow + nLinesToInsert - 1, colCount]];
        range.Insert(Excel.XlInsertShiftDirection.xlShiftDown, Excel.XlInsertFormatOrigin.xlFormatFromLeftOrAbove);
        Marshal.ReleaseComObject(range);

        values = new object[nLinesToInsert, colCount];

        // ---- populate the new values array ----

        // Insert the values at the target rows.
        Excel.Range startCell = (Excel.Range)xlWorksheet.Cells[insertRow, 1];
        Excel.Range endCell = (Excel.Range)xlWorksheet.Cells[insertRow + nCsvInsertRows - 1, nColsDo];
        Excel.Range writeRange = xlWorksheet.Range[startCell, endCell];
        writeRange.Value2 = values;
        Marshal.ReleaseComObject(writeRange);
        Marshal.ReleaseComObject(endCell);
        Marshal.ReleaseComObject(startCell);

        // Release local com objects 
        Marshal.ReleaseComObject(xlWorksheet);

    }

    //cleanup (NB: Does this need to be done? Does it need to be done here?)
    GC.Collect();
    GC.WaitForPendingFinalizers();

    // Save
    object misValue = System.Reflection.Missing.Value;
    myExcelWorkbook.SaveAs(outFile, Microsoft.Office.Interop.Excel.XlFileFormat.xlOpenXMLWorkbook, misValue,
                        misValue, misValue, misValue, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive,
                        misValue, misValue, misValue, misValue, misValue);

    myExcelWorkbook.Close();
    myExcelApp.Quit();

    //close and release
    Marshal.ReleaseComObject(myExcelWorkbook);
    myExcelWorkbook = null;

    //quit and release
    Marshal.ReleaseComObject(myExcelApp);
    myExcelApp = null;

2 个答案:

答案 0 :(得分:1)

您要释放try-catch组之外的对象。并且在捕获中,即使有新消息,您也会创建一个新的异常。当您从catch块创建新异常时,原始异常消失了。被视为不良做法。

您必须释放catchfinally块内的对象。根据您的代码,崩溃后对象仍然保留。

顺便说一句,要使用Excel,我建议使用EPPlus库。它将执行所需的所有操作,而无需在服务器上安装Excel(再次是错误的做法)。

更新

要清理所有对象:

           System.Runtime.InteropServices.Marshal.ReleaseComObject(startCell );    
           System.Runtime.InteropServices.Marshal.ReleaseComObject(endCell);             
         System.Runtime.InteropServices.Marshal.ReleaseComObject(writeRange);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange );
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorksheet);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange );
            startCell = null;
            endCell = null;
            writeRange = null;

            myExcelApp.Quit();

          System.Runtime.InteropServices.Marshal.ReleaseComObject(myExcelApp);
            myExcelApp = null;
            myExcelWorkbook = null;

            System.GC.Collect();
            GC.WaitForPendingFinalizers();

答案 1 :(得分:1)

在尝试捕获中,您应该关闭Excel。像这样

      try{
            //Some code
        }
    catch{
       Marshal.ReleaseComObject(xlWorksheet);
        myExcelWorkbook.Close();
         myExcelApp.Quit();

     }

当它失败时,它不会关闭Excel。