【问题标题】:How can I dispose my Excel Application如何处理我的 Excel 应用程序
【发布时间】:2013-04-11 11:37:01
【问题描述】:

我的代码如下

Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(file);

Excel.Worksheet xlSheet = xlWorkbook.Sheets[1]; // get first sheet
Excel.Range xlRange = xlSheet.UsedRange;

这些是我的函数中使用的唯一变量

foreach (Excel.Worksheet XLws in xlWorkbook.Worksheets)
{
    // do some stuff 

    xlApp.UserControl = false;

    if (xlRange != null)
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlRange);

    if (xlSheet != null)
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlSheet);

    if (xlWorkbook != null)
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlWorkbook);

    xlRange = null;
    xlSheet = null;
    xlWorkbook = null;
    xlApp.Quit();

    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp);
}

但我仍然在任务管理器中得到 EXCEL.EXE

请帮忙?

【问题讨论】:

  • 通常情况下,退出命令会将进程从任务管理器中取出。您确定 Excel.exe 不是在代码测试期间卡在那里的先前进程吗?如果代码不好,你不得不中途停止它,excel应用程序将永远不会退出。
  • 我注意到您正在退出应用程序for each 工作表???听起来很奇怪,只有一个应用程序包含工作表。
  • @Daniel 是的,因为以前我在循环之外尝试过..现在可以说如果它正在读取文件 ABC.xlsx,它会在同一文件夹中创建 ~ABC.xlsx有必要退出它(我不知道任何其他方式)......而且因为它正在循环它试图读取〜ABC.xlsx并生成异常
  • 你在做一些 foreach ".xlsx" 文件吗???如果不是那个~ABC文件没有问题,退出应用程序时它会被删除。我相信在一些调试中你遇到了一个错误,并且在那个运行中,excel 应用程序卡在了管理器中。您运行的任何其他时间都会创建一个新的excel进程,如果它到达quit命令,它将退出管理器。但是以前的过程永远不会在那里完成,必须手动将其关闭。
  • Excel 互操作是一堆垃圾...我最终改用 OpenOfficeXML / EPPlus!

标签: c# excel automation


【解决方案1】:

杀死MainWindowTitle为空值的excel进程。下面是一个示例源代码。

    Microsoft.Office.Interop.Excel.Application oXL;
    Microsoft.Office.Interop.Excel._Workbook oWB;
    Microsoft.Office.Interop.Excel._Worksheet oSheet;
    Microsoft.Office.Interop.Excel.Range oRng;
    object misvalue = System.Reflection.Missing.Value;
    try
    {
        //Start Excel and get Application object.
        oXL = new Microsoft.Office.Interop.Excel.Application();
        oXL.Visible = true;

        //Get a new workbook.
        oWB = (Microsoft.Office.Interop.Excel._Workbook)(oXL.Workbooks.Add(""));
        oSheet = (Microsoft.Office.Interop.Excel._Worksheet)oWB.ActiveSheet;

        //Add table headers going cell by cell.
        oSheet.Cells[1, 1] = "First Name";
        oSheet.Cells[1, 2] = "Last Name";
        oSheet.Cells[1, 3] = "Full Name";
        oSheet.Cells[1, 4] = "Salary";

        //Format A1:D1 as bold, vertical alignment = center.
        oSheet.get_Range("A1", "D1").Font.Bold = true;
        oSheet.get_Range("A1", "D1").VerticalAlignment =
            Microsoft.Office.Interop.Excel.XlVAlign.xlVAlignCenter;

        // Create an array to multiple values at once.
        string[,] saNames = new string[5, 2];

        saNames[0, 0] = "John";
        saNames[0, 1] = "Smith";
        saNames[1, 0] = "Tom";

        saNames[4, 1] = "Johnson";

        //Fill A2:B6 with an array of values (First and Last Names).
        oSheet.get_Range("A2", "B6").Value2 = saNames;

        //Fill C2:C6 with a relative formula (=A2 & " " & B2).
        oRng = oSheet.get_Range("C2", "C6");
        oRng.Formula = "=A2 & \" \" & B2";

        //Fill D2:D6 with a formula(=RAND()*100000) and apply format.
        oRng = oSheet.get_Range("D2", "D6");
        oRng.Formula = "=RAND()*100000";
        oRng.NumberFormat = "$0.00";

        //AutoFit columns A:D.
        oRng = oSheet.get_Range("A1", "D1");
        oRng.EntireColumn.AutoFit();

        oXL.Visible = false;
        oXL.UserControl = false;
        oWB.SaveAs("c:\\test505.xls", Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing,
                false, false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

        oWB.Close(null, null, null);
        oXL.Quit();  //MainWindowTitle will become empty afer being close

        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oXL);
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWB);

        Process[] excelProcesses = Process.GetProcessesByName("excel");
        foreach (Process p in excelProcesses)
        {
            if (string.IsNullOrEmpty(p.MainWindowTitle)) // use MainWindowTitle to distinguish this excel process with other excel processes 
            {
                p.Kill();
            }
        }
    }
    catch (Exception ex2)
    {

    }

【讨论】:

  • 优秀,手动杀死excel进程确认文件已释放
【解决方案2】:

你有一个隐式对象保持打开状态。试试这个

Excel.Application xlApp = new Excel.Application();
Excel.Workbooks xlWorkbooks = xlApp.Workbooks;
Excel.Workbook xlWorkbook = xlWorkbooks.Open(file);
....    

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlWorkbooks);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlWorkbook);
....    

【讨论】:

【解决方案3】:

好的...我希望这会有所帮助...我花了很长时间来调整它以使其正常工作...

这是我的整个函数(VB —— 但复杂的东西的 C# 代码在那里(感谢帮助我走到这一步的太多其他 stackoverflow 巨头!)

Private Function ImportWorksFile() As Integer

    Dim EndofSheet As Boolean
    Dim BlankRowCounter As Integer
    Dim rr As RowResult
    Dim SecCount As Integer = 0
    Dim SecRow As SecurityRow

    Dim uf As New UtilFunctions

    'If this has already been run, the instance of the excel object would have been 'killed' and needs to be reinstantiated
    If blnExcelProcessKilled Then 'Global boolean var
        xlApp = New Excel.Application()
        blnExcelProcessKilled = False
    End If
    Dim excelProcess(0) As Process
    excelProcess = Process.GetProcessesByName("excel")

    Dim tmp As Excel.Workbooks
    Try
        tmp = xlApp.Workbooks
        xlWorkBook = tmp.Open(WorkingFileName)
    Catch ex As Exception
        MessageBox.Show("There was a problem opening the workbook - please try again", CurAFLApp.AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        Return 0
    End Try

    Using dc As New AFLData(CurAFLApp, True)

        Dim cmd As SqlCommand = DefineCommand()
        cmd.CommandType = CommandType.StoredProcedure

        For Each ws As Excel.Worksheet In xlWorkBook.Worksheets

            Dim row As Integer = 1
            EndofSheet = False
            BlankRowCounter = 0

            If ImpCols.ContainsKey(ws.Name) Then
                SecRow = New SecurityRow(ImpCols(ws.Name))

                Do Until EndofSheet
                    Try
                        SecRow.NewRow(ws.Rows(row))
                        rr = SecRow.IsValidRow

                        If rr = RowResult.Valid Then
                            ' read this row and process
                            With cmd
                                .Parameters("@AcctDate").Value = FileDate
                                .Parameters("@NewSub").Value = SecRow.GetStrCell("newsub")
                                RunProcedure(cmd)
                            End With

                            SecCount += 1

                            BlankRowCounter = 0

                        Else
                            BlankRowCounter += rr

                        End If

                    Catch ex As Exception
                        MessageBox.Show("There was a problem with row: " & row & " in workbook " & ws.Name)

                    End Try

                    ' if we've counted 50 blank A column values in a row, we're done.
                    If BlankRowCounter <= -50 Then
                        EndofSheet = True
                    End If

                    row += 1
                Loop
            End If
        Next
    End Using

    Try

        xlWorkBook.Close(SaveChanges:=False)
        xlApp.Workbooks.Close()
        xlApp.Quit()

        '// And now kill the process. C# Version (for reference)
        'if (processID != 0)
        '{
        '    Process process = Process.GetProcessById(processID);
        '    process.Kill();
        '}

        ' Reversed the order of release per  http://stackoverflow.com/questions/12916137/best-way-to-release-excel-interop-com-object


    Catch ex As Exception
        MessageBox.Show("There was a problem CLOSING the workbook - Please double check that the data was imported correctly. ", CurAFLApp.AppName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        Return 0
    Finally

        releaseObject(tmp)
        releaseObject(xlWorkBook)
        releaseObject(xlApp)
        If Not excelProcess(0).CloseMainWindow() Then

            excelProcess(0).Kill()
            blnExcelProcessKilled = True
        End If

    End Try

    Return SecCount

End Function

Public Sub releaseObject(ByVal obj As Object)
    Try
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
        obj = Nothing
    Catch ex As Exception
        obj = Nothing
    Finally
        GC.Collect()
        'Not sure if the following line helps or hinders -- seems to lock things up once in a while
        'GC.WaitForPendingFinalizers()
    End Try
End Sub

【讨论】:

    【解决方案4】:

    试试:

    xlWorkbook.Close(false); // if you Workbook should not be saved
    

    而不是:

    if (xlWorkbook != null)
       System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlWorkbook);
    
    xlWorkbook = null;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-27
      • 2021-07-05
      • 1970-01-01
      • 1970-01-01
      • 2016-04-13
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多