Excel 进程在 VB.net 中关闭后仍然运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11761379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 16:14:36  来源:igfitidea点击:

Excel process still runs after closing in VB.net

vb.netexcelgarbage-collectioninterop

提问by Alex

My question is basically just how to end the Excel.exe process that runs when using excel. In the application I open and use an excel workbook with a couple sheets, then leave them for the user to do as they please, my problem is that my application never lets go of the Excel process.

我的问题基本上只是如何结束使用 excel 时运行的 Excel.exe 进程。在应用程序中,我打开并使用带有几张工作表的 excel 工作簿,然后将它们留给用户随心所欲,我的问题是我的应用程序永远不会放弃 Excel 进程。

If the application is closed before closing excel, the process ends when excel is closed, otherwise if I close my application after closing excel, the process stays running.

如果应用程序在关闭 excel 之前关闭,则进程在 excel 关闭时结束,否则如果我在关闭 excel 后关闭我的应用程序,进程将保持运行。

I've tried a few things I've found around the internet to do with GC.collect and waiting for pending finalizers or something along those lines however neither worked.

我已经尝试了一些我在互联网上发现的与 GC.collect 相关的事情,并等待挂起的终结器或类似的东西,但都没有奏效。

I can also close the excel process happily, the only issue is not knowing whether I'm closing a users important spreadsheet that they have neglected to save yet or mine.

我也可以愉快地关闭 excel 进程,唯一的问题是不知道我是否正在关闭他们忽略保存的用户重要电子表格或我的。

I'm not sure if any of my code will help with an answer but I'm using microsoft.office.interop.excel to get to excel, and I am using a workbook already saved in the application's resources folder.

我不确定我的任何代码是否有助于回答,但我正在使用 microsoft.office.interop.excel 来获得 excel,并且我正在使用已保存在应用程序资源文件夹中的工作簿。

-Edit-

-编辑-

Here's everything I've tried, I know it's a little overkill but sadly it still doesn't end the process

这是我尝试过的一切,我知道这有点矫枉过正,但遗憾的是它仍然没有结束这个过程

Marshal.ReleaseComObject(FirstWorksheet)
Marshal.FinalReleaseComObject(FirstWorksheet)
Marshal.ReleaseComObject(SecondWorksheet)
Marshal.FinalReleaseComObject(SecondWorksheet)
Marshal.ReleaseComObject(ThirdWorksheet)
Marshal.FinalReleaseComObject(ThirdWorksheet)
Marshal.ReleaseComObject(FourthWorkSheet)
Marshal.FinalReleaseComObject(FourthWorkSheet)
Marshal.ReleaseComObject(xlRange)
Marshal.FinalReleaseComObject(xlRange)
Marshal.ReleaseComObject(SecondxlRange)
Marshal.FinalReleaseComObject(SecondxlRange)
Marshal.ReleaseComObject(thirdxlRange)
Marshal.FinalReleaseComObject(thirdxlRange)
Marshal.ReleaseComObject(fourthxlRange)
Marshal.FinalReleaseComObject(fourthxlRange)
Marshal.ReleaseComObject(.activeworkbook)
Marshal.FinalReleaseComObject(.activeworkbook)
Marshal.ReleaseComObject(excelApplication)
Marshal.FinalReleaseComObject(excelApplication)
MSExcelControl.QuitExcel() 'A function made by someone else I work with that was meant to close excel's process
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

-Edit- Here's the quitExcel method

-编辑-这是quitExcel方法

Friend Shared Sub QuitExcel()
    If Not getExcelProcessID = -1 Then
        If Not excelApp Is Nothing Then
            'Close and quit
            With excelApp
                Try
                    Do Until .Workbooks.Count = 0
                        'Close all open documents without saving
                        .Workbooks(1).Close(SaveChanges:=0)
                    Loop
                Catch exExcel As Exception
                    'Do nothing
                End Try
                Try
                    .ActiveWorkbook.Close(SaveChanges:=0)
                Catch ex As Exception
                    'Do nothing
                End Try

                Try
                    .Quit()
                Catch ex As Exception
                    'Do nothing
                Finally
                    myExcelProcessID = -1
                End Try
            End With
            excelApp = Nothing
        End If
    End If
End Sub

He had already tried to do the same thing with the process ID's in his class, the problem was his wasn't working which is why I tried to get the process ID again myself which has worked

他已经尝试用他班上的进程 ID 做同样的事情,问题是他没有工作,这就是为什么我试图自己再次获取进程 ID,这已经奏效了

回答by user1388706

Good solution Alex, we shouldn't have to do this, but we do, EXCEL just won't end. I took your solution and created the code below, I call ExcelProcessInit before my app imports or exports with Excel, then call ExcelProcessKill after it's complete.

很好的解决方案 Alex,我们不应该这样做,但我们这样做了,EXCEL 不会结束。我采用了您的解决方案并创建了下面的代码,在我的应用程序导入或导出 Excel 之前调用 ExcelProcessInit,然后在完成后调用 ExcelProcessKill。

Private mExcelProcesses() As Process

Private Sub ExcelProcessInit()
  Try
    'Get all currently running process Ids for Excel applications
    mExcelProcesses = Process.GetProcessesByName("Excel")
  Catch ex As Exception
  End Try
End Sub

Private Sub ExcelProcessKill()
  Dim oProcesses() As Process
  Dim bFound As Boolean

  Try
    'Get all currently running process Ids for Excel applications
    oProcesses = Process.GetProcessesByName("Excel")

    If oProcesses.Length > 0 Then
      For i As Integer = 0 To oProcesses.Length - 1
        bFound = False

        For j As Integer = 0 To mExcelProcesses.Length - 1
          If oProcesses(i).Id = mExcelProcesses(j).Id Then
            bFound = True
            Exit For
          End If
        Next

        If Not bFound Then
          oProcesses(i).Kill()
        End If
      Next
    End If
  Catch ex As Exception
  End Try
End Sub

Private Sub MyFunction()
  ExcelProcessInit()
  ExportExcelData() 'Whatever code you write for this...
  ExcelProcesKill()
End Sub

回答by Rob K.

I know this is an old thread, but if anyone comes back to this, you actually have to call every Interop.Excel object you touch in the workbook. If you pull in an instantiated class from Excel into your code, when you're done with it, Marshal.ReleaseComObject. Even every cell. It's crazy, but it's the only way I was able to get the same issue resolved.

我知道这是一个旧线程,但如果有人回到这个话题,您实际上必须调用您在工作簿中触摸的每个 Interop.Excel 对象。如果您将 Excel 中的实例化类拉入您的代码中,当您完成它时,Marshal.ReleaseComObject。甚至每个细胞。这很疯狂,但这是我能够解决相同问题的唯一方法。

And make darn sure you don't have a fatal exception and leave something unreleased... Excel will stay open.

并确保您没有致命的异常并留下未发布的内容...... Excel 将保持打开状态。

Excel.Applicaiton? Marshal.ReleaseComObject.

Excel.Applicaiton?Marshal.ReleaseComObject。

Excel.Workbook? Marshal.ReleaseComObject.

Excel.工作簿?Marshal.ReleaseComObject。

Excel.Workshet? Marshal.ReleaseComObject.

Excel.工作表?Marshal.ReleaseComObject。

Excell.Range? Marshal.ReleaseComObject.

Excell.Range?Marshal.ReleaseComObject。

Looping through Rows? Marshal.ReleaseComObject every row and cell you loop through.

循环遍历行?Marshal.ReleaseComObject 循环遍历的每一行和单元格。

Exce.Style? Marshal.ReleaseComObject... At least this is what I had to do...

Exce.Style?Marshal.ReleaseComObject ......至少这是我必须做的......

If you plan on using the PIA to access Excel, from the first line of code you write, plan how you're going to release your objects. The best approach I've had is to make sure that I pull an excel value out of the Excel object and load it into my own internal variable. Then imediately call Marshal.ReleaseComObject you accessed. Looping through excel objects via a list in a Application, Workbook, Sheet, ListObject, Table, etc, tends to be the hardest to release. Hence planning is rather critical.

如果您计划使用 PIA 访问 Excel,请从您编写的第一行代码开始,计划您将如何释放您的对象。我所拥有的最佳方法是确保从 Excel 对象中提取一个 excel 值并将其加载到我自己的内部变量中。然后立即调用您访问的 Marshal.ReleaseComObject。通过应用程序、工作簿、工作表、ListObject、表格等中的列表循环遍历 excel 对象往往是最难发布的。因此,规划是相当关键的。

回答by Alex

It's taken a long time but I've finally solved it, the best way to do it is to record the process ID when you create the excel application, this means that you know the unique ID associated with your process only.

折腾了好久终于解决了

To do this, I looked at all the processes that were already there, recording the excel processes' IDs in an array of IDs

为此,我查看了所有已经存在的进程,将 excel 进程的 ID 记录在一组 ID 中

            msExcelProcesses = Process.GetProcessesByName("Excel")
            'Get all currently running process Ids for Excel applications
            If msExcelProcesses.Length > 0 Then
                For i As Integer = 0 To msExcelProcesses.Length - 1
                    ReDim Preserve processIds(i)
                    processIds(i) = msExcelProcesses(i).Id
                Next
            End If

Then repeat the process straight after opening mine (to try and prevent them opening excel themselves and having 2 new excel processes) record the new IDs, check for an ID that wasn't in the last list and store it as an integer.

然后在打开我的之后直接重复这个过程(以防止他们自己打开 excel 并有 2 个新的 excel 进程)记录新的 ID,检查一个不在最后一个列表中的 ID 并将其存储为一个整数。

Then all you need to do at the end is iterate through the list of processes and kill the one with your ID

然后你最后需要做的就是遍历进程列表并用你的 ID 杀死那个

                Dim obj1(1) As Process
                obj1 = Process.GetProcessesByName("EXCEL")
                For Each p As Process In obj1
                    If p.Id = MSExcelControl.getExcelProcessID Then
                        p.Kill()
                    End If
                Next

回答by Francis Dean

I had the same problem a while ago, try using Marshal.ReleaseComObject on your excel objects. It's located ed in the System.Runtime.InteropServices namespace. Also remember to close down your excel objects beforehand.

不久前我遇到了同样的问题,尝试在您的 excel 对象上使用 Marshal.ReleaseComObject。它位于 System.Runtime.InteropServices 命名空间中。还要记得事先关闭你的 excel 对象。

xlWorkbook.Close();
xlApp.Close();
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);