Excel Process will not terminate with Excel-Introp

人盡茶涼 提交于 2019-12-11 17:59:46

问题


I have been trying to import data from an excel sheet into a DataTable. The problem is that after i finish, excel would not terminate the process. I do not want to terminate by process name using System.Diagnostics as that approach would terminate all excel instances rather than the one that was created by the application. I know that this question was posted over here before multiple times, but none of the solutions seem to work for me. I am probably missing something and can not see it.

below is my code:

    private void importToolStripMenuItem_Click(object sender, EventArgs e)
{
    openFileDialog1.Filter = "Excel WorkBooks (*.xlsx)|*.xlsx";
    openFileDialog1.FilterIndex = 1;
    openFileDialog1.Multiselect = false;


    if(openFileDialog1.ShowDialog() == DialogResult.OK)
    {
            string empRange = "D4";
            string emptxid = "K4";

            object oMissing = System.Reflection.Missing.Value;
            string path = openFileDialog1.FileName;


            oExcel.Application xlApp;
            oExcel.Workbooks xlWorkBooks;
            oExcel.Workbook xlWorkBook;
            oExcel.Sheets xlSheets;
            oExcel.Worksheet xlWorkSheetDATA;
            oExcel.Worksheet xlWorkSheetEMP;
            oExcel.Range range;

            xlApp = new oExcel.Application();

            xlWorkBooks = xlApp.Workbooks;
            xlWorkBook = xlWorkBooks.Open(path);
            xlSheets = xlWorkBook.Worksheets;


            xlWorkSheetDATA = (oExcel.Worksheet)xlSheets.get_Item(DATASheetName);
            xlWorkSheetEMP = (oExcel.Worksheet)xlSheets.get_Item(EMPSheetName); 
            xlWorkSheetEMP.Activate(); 
            range = xlWorkSheetEMP.get_Range(empRange, empRange); 

            xlWorkSheetDATA.Activate();
            range = xlWorkSheetDATA.get_Range(emptxid, emptxid);

            xlApp.DisplayAlerts = false;


            xlWorkSheetDATA.Columns.ClearFormats();
            xlWorkSheetDATA.Rows.ClearFormats();

            int iTotalColumns = xlWorkSheetDATA.UsedRange.Columns.Count;
            int iTotalRows = xlWorkSheetDATA.UsedRange.Rows.Count;
            xlApp.Visible = true;

            DataTable dt = new DataTable();
            addColumns(iTotalColumns, dt);
            insertIntoDataTable(iTotalRows, dt, path);

            //clean-up
            System.Runtime.InteropServices.Marshal.ReleaseComObject(range);
            range = null;
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkSheetEMP);
            xlWorkSheetEMP = null;
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkSheetDATA);
            xlWorkSheetDATA = null;
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheets);
            xlSheets = null;
            xlWorkBook.Close(false);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkBook);
            xlWorkBook = null;
            xlWorkBooks.Close();
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkBooks);
            xlWorkBooks = null;
            xlApp.Quit();
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
            xlApp = null;

        }  
    }

回答1:


Write a method to release the objects such as this example

    private void ReleaseOfficeObject(object o)
    {
        Marshal.ReleaseComObject(o);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Marshal.FinalReleaseComObject(o);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
    }

then to call it

        ReleaseOfficeObject(range);
        ReleaseOfficeObject(xlWorkSheetDATA);
        ReleaseOfficeObject(xlSheets);
        xlWorkBook.Close(false);
        ReleaseOfficeObject(xlWorkBook);
        xlWorkBook = null;
        xlWorkBooks.Close();
        ReleaseOfficeObject(xlWorkBooks);
        xlWorkBooks = null;
        xlApp.Quit();
        ReleaseOfficeObject(xlApp);



回答2:


You never need to call Marshal.ReleaseComObject in this context. The runtime is perfectly able to keep track of COM objects and release them when they are no longer referenced. Calling Marshal.ReleaseComObject is a confusing anti-pattern that sadly even some Microsoft documentation mistakenly suggests. You also don't have to set local variables to null - the references in local variables will be out of scope when the method completes.

You do have to be careful with this kind of code in debug builds. References in a method are artificially kept alive until the end of the method so that they will still be accessible in the debugger. This means your local xlApp variable might not be cleaned up by calling the GC inside that method.

You should run the garbage collection twice, reference cycles could be broken in the first collection, but you need a second collection to be sure all cleanup is done for those references.

To avoid this issue, you might follow a pattern like this:

private void importToolStripMenuItem_Click(object sender, EventArgs e)
{
    openFileDialog1.Filter = "Excel WorkBooks (*.xlsx)|*.xlsx";
    openFileDialog1.FilterIndex = 1;
    openFileDialog1.Multiselect = false;

    if(openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        string path = openFileDialog1.FileName;

        // Call another method that wraps all the Excel COM stuff
        // That prevents debug builds from confusing the lifetime of COM references
        DoExcelStuff(path);

        // When back here, all the Excel references should be out of scope
        // Run the GC (twice) to clean up all COM references
        // (This can be pulled out into a helper method somewhere)
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

private void DoExcelStuff(string path)
{
    // All your Excel COM interop goes here

    string empRange = "D4";
    string emptxid = "K4";

    object oMissing = System.Reflection.Missing.Value;

    // ... variable declarations
    xlApp = new oExcel.Application();

    // More xlApp, workbooks etc...

    // Done - tell Excel to close
    xlApp.Quit();

    // No need for Marshal.ReleaseComObject(...) 
    // or setting variables to null here! 
}


来源:https://stackoverflow.com/questions/31524103/excel-process-will-not-terminate-with-excel-introp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!