简体   繁体   English

释放Interop Excel对象

[英]Release Interop Excel object

I'm currently writting a C#.NET application who use a VBA macro in an Excel file. 我目前正在编写一个在Excel文件中使用VBA宏的C#.NET应用程序。

I run the macro from the c# application when the user click on a button. 当用户单击按钮时,我从c#应用程序运行宏。 I have to wait all data are downloaded that's why this is the VBA code who execute "Application.Quit". 我必须等待所有数据下载完毕,这就是为什么这是执行“ Application.Quit”的VBA代码的原因。

There is my code : 有我的代码:

private void toolStripButton5_Click(object sender, EventArgs e)
    {
        int lastUsedRowFund, lastUsedRowEquity, lastUsedRowBond, lastUsedRowAccount = 0;

        Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
        Excel.Workbook oWB = null;
        Excel.Worksheet oSheetFund = null;
        Excel.Worksheet oSheetEquity = null;
        Excel.Worksheet oSheetBond = null;
        Excel.Worksheet oSheetAccount = null;

        oXL.Visible = false;

        oWB = oXL.Workbooks.Open("C:\\extract.xlsm");

        oSheetFund = oWB.Sheets["Fund"];
        oSheetEquity = oWB.Sheets["Equity"];
        oSheetBond = oWB.Sheets["Bond"];
        oSheetAccount = oWB.Sheets["Account"];

        string[] valuesHeaderFund = {"field1", "field2" };

        string[] valuesHeaderEquity = {"field1", "field2"};

        string[] valuesHeaderBond = {"field1", "field2"};

        string[] valuesHeaderAccount = {"field1", "field2"};

        Excel.Range headerFund = oSheetFund.get_Range("A1", "AA1");
        Excel.Range headerEquity = oSheetEquity.get_Range("A1", "AE1");
        Excel.Range headerBond = oSheetBond.get_Range("A1", "AE1");
        Excel.Range headerAccount = oSheetAccount.get_Range("A1", "AE1");

        headerFund.Value2 = valuesHeaderFund;
        headerEquity.Value2 = valuesHeaderEquity;
        headerBond.Value2 = valuesHeaderBond;
        headerAccount.Value2 = valuesHeaderAccount;

        Excel.Range lastRowFund = oSheetFund.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
        Excel.Range lastRowEquity = oSheetEquity.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
        Excel.Range lastRowBond = oSheetBond.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
        Excel.Range lastRowAccount = oSheetAccount.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);

        lastUsedRowFund = lastRowFund.Row;
        lastUsedRowEquity = lastRowEquity.Row;
        lastUsedRowBond = lastRowBond.Row;
        lastUsedRowAccount = lastRowAccount.Row;

        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
            string[] data = { row.Cells[0].Value.ToString(), row.Cells[1].Value.ToString()};

            if (row.Cells[5].Value.ToString() == "FON")
            {

                lastUsedRowFund += 1;
                oSheetFund.get_Range("A" + lastUsedRowFund, "K" + lastUsedRowFund).Value2 = data;

            }
            else if (row.Cells[5].Value.ToString() == "ACT")
            {

                lastUsedRowEquity += 1;
                oSheetEquity.get_Range("A" + lastUsedRowEquity, "K" + lastUsedRowEquity).Value2 = data;

            }
            else if (row.Cells[5].Value.ToString() == "OBL")
            {

                lastUsedRowBond += 1;
                oSheetBond.get_Range("A" + lastUsedRowBond, "K" + lastUsedRowBond).Value2 = data;

            }
            else if (row.Cells[5].Value.ToString() == "ACCOUNT")
            {

                lastUsedRowAccount += 1;
                oSheetAccount.get_Range("A" + lastUsedRowAccount, "K" + lastUsedRowAccount).Value2 = data;

            }
        }

        RunMacro(oXL, new Object[] { "Main" });

        oXL.UserControl = false;

        //oWB.Close();
        //oXL.Quit();

        releaseObject(lastRowFund);
        releaseObject(lastRowEquity);
        releaseObject(lastRowBond);
        releaseObject(lastRowAccount);
        releaseObject(headerFund);
        releaseObject(headerEquity);
        releaseObject(headerBond);
        releaseObject(headerAccount);
        releaseObject(oSheetFund);
        releaseObject(oSheetEquity);
        releaseObject(oSheetBond);
        releaseObject(oSheetAccount);
        releaseObject(oWB);
        releaseObject(oXL);

    private void RunMacro(object oApp, object[] oRunArgs)
    {
        oApp.GetType().InvokeMember("Run",
            System.Reflection.BindingFlags.Default |
            System.Reflection.BindingFlags.InvokeMethod,
            null, oApp, oRunArgs);
    }

    private void releaseObject(object obj)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
            obj = null;
        }
        catch (Exception ex)
        {
            obj = null;
            MessageBox.Show("Unable to release the Object " + ex.ToString());
        }
        finally
        {
            GC.Collect();
        }
    }

When i click on the toolStripButton5, everything is working. 当我单击toolStripButton5时,一切正常。 But at the end an "EXCEL.EXE" processus still alive in task manager. 但是最后,任务管理器中的“ EXCEL.EXE”进程仍然存在。 When i click again on the button, a new "EXCEL.EXE" is create but when the task is finish, the processus is correctly release. 当我再次单击该按钮时,将创建一个新的“ EXCEL.EXE”,但是当任务完成时,进程将正确释放。 When i quit my application, the first processus is release. 当我退出应用程序时,第一个进程已发布。

Can you help me to correctly release the object at the first click. 您能否帮助我在第一次单击时正确释放对象。

Regards, 问候,

Danny. 丹妮

Unfortunatelly this is not so simple to quit Excel app, because COM objects of Interoop services still exists in memory. 不幸的是,退出Excel应用程序并不是那么简单,因为Interoop服务的COM对象仍然存在于内存中。 That's why Excel.exe process is still running. 这就是Excel.exe进程仍在运行的原因。 Every object can be released using Marshal class. 每个对象都可以使用Marshal类释放。 Sample codes: 样例代码:

Marshal.ReleaseComObject(excelSheets);   //Worksheet
Marshal.ReleaseComObject(excelSheet);    //Sheet

...and so on. ...等等。 Hope this helps. 希望这可以帮助。

Now, it works greatly. 现在,它可以很好地工作了。 When i execute a second extraction with Excel, the first process is correctly release when the new one is created. 当我使用Excel执行第二次提取时,在创建新的过程时正确释放了第一个过程。

I just replace in "releaseObject" System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); 我只是替换为“ releaseObject”中的System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); by Marshal.ReleaseComObject(obj); 通过Marshal.ReleaseComObject(obj);

Maybe because i use "using System.Runtime.InteropServices;" 也许是因为我使用“使用System.Runtime.InteropServices;” in the header. 在标题中。

Thanks a lot. 非常感谢。

Regards 问候

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

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