简体   繁体   English

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

[英]C# excel interop process persists after crash

I have just recently started working with the Excel Interop in C# and have run into a problem with Excel processes persisting if my application crashes. 我最近刚开始使用C#语言处理Excel Interop,如果我的应用程序崩溃,Excel进程仍然存在问题。 ( Why the process crashes is a separate issue that I am investigating.) 为什么进程崩溃是我正在调查的另一个问题。)

I think I am releasing the COM objects correctly as everything cleans up fine if my application completes successfully. 认为我正确地释放了COM对象,因为如果我的应用程序成功完成,一切都会正常进行。 It is only if it crashes or if I happen to quit during debugging that the Excel process is left. 只有当它崩溃或在调试过程中碰巧退出时,才剩下Excel进程。

Of course I realize when it crashes, the COM objects aren't cleaned up. 我当然知道,当它崩溃时,COM对象不会被清除。 I am not sure how to handle this. 我不确定如何处理。

Here is a bit of pseudo-code that hopefully demonstrates what I am doing (the real code is rather long.) 这是一些伪代码,希望能演示我在做什么(真正的代码很长。)

It is supposed to 1)Open an existing excel file, 2) access a specific worksheet in the file, 3) insert a lot of rows, 4) add values to those rows, 5) close & save it all. 应该1)打开一个现有的excel文件,2)访问文件中的特定工作表,3)插入很多行,4)向这些行添加值,5)关闭并保存所有内容。

What am I doing wrong? 我究竟做错了什么?

    // 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;

You are releasing the object outside of try-catch blocs. 您要在try-catch之外释放对象。 And in the catch, you create a new exception even with a new message. 并且在捕获中,即使有新消息,您也会创建一个新的异常。 When you are creating a new exception from catch block your original exception is gone. 当您从catch块创建新异常时,原始异常消失了。 Considered as a bad practice. 被视为不良做法。

You have to release objects inside the catch or finally blocks. 您必须释放catch对象或finally阻止。 According to your code, your objects are still persisted after the crash. 根据您的代码,崩溃后对象仍然保留。

BTW, to work with Excel I would recommend the EPPlus library. 顺便说一句,要使用Excel,我建议使用EPPlus库。 It will perform all operation that you need without installing Excel on the server (bad practice again). 它将执行所需的所有操作,而无需在服务器上安装Excel(再次是错误的做法)。

UPDATE UPDATE

To clean-up all the objects: 要清理所有对象:

           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();

In your try catch, you should be closing Excel. 在尝试捕获中,您应该关闭Excel。 Like so 像这样

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

     }

As it stands when it fails it does not close Excel. 按其失败时的状态,它不会关闭Excel。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM