【问题标题】:Release Interop Excel object释放互操作 Excel 对象
【发布时间】:2016-08-14 06:02:56
【问题描述】:

我目前正在编写一个在 Excel 文件中使用 VBA 宏的 C#.NET 应用程序。

当用户单击按钮时,我从 c# 应用程序运行宏。我必须等待下载所有数据,这就是为什么这是执行“Application.Quit”的 VBA 代码。

这是我的代码:

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

当我单击 toolStripButton5 时,一切正常。但最后一个“EXCEL.EXE”进程在任务管理器中仍然存在。当我再次单击按钮时,会创建一个新的“EXCEL.EXE”,但是当任务完成时,进程会正确释放。 当我退出我的应用程序时,第一个进程是发布。

你能帮我在第一次点击时正确释放对象吗?

问候,

丹尼。

【问题讨论】:

    标签: c# .net vba interop


    【解决方案1】:

    不幸的是,退出 Excel 应用程序并不是那么简单,因为 Interoop 服务的 COM 对象仍然存在于内存中。这就是 Excel.exe 进程仍在运行的原因。每个对象都可以使用 Marshal 类释放。示例代码:

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

    ...等等。 希望这会有所帮助。

    【讨论】:

    • 这是我目前在“releaseObject”void 中使用的。我用这个 void 释放所有对象
    • 第一次单击“excel.exe”仍在内存中,但是当我进行其他提取时,新的“excel.exe”正确释放。第一个仍然在内存中,直到我退出我的应用程序
    【解决方案2】:

    现在,它非常有效。当我使用 Excel 执行第二次提取时,第一个进程在创建新进程时正确释放。

    我只是在“releaseObject”中替换 System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);经过 Marshal.ReleaseComObject(obj);

    也许是因为我使用“使用 System.Runtime.InteropServices;”在标题中。

    非常感谢。

    问候

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-09
      • 1970-01-01
      相关资源
      最近更新 更多