Excel process still runs after closing in VB.net

2019-01-26 16:02发布

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.

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.

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.

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.

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.

-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

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

4条回答
来,给爷笑一个
2楼-- · 2019-01-26 16:19

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.

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

Excel.Applicaiton? Marshal.ReleaseComObject.

Excel.Workbook? Marshal.ReleaseComObject.

Excel.Workshet? Marshal.ReleaseComObject.

Excell.Range? Marshal.ReleaseComObject.

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

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

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.

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-01-26 16:21

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.

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
查看更多
相关推荐>>
4楼-- · 2019-01-26 16:38

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

            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.

Then all you need to do at the end is iterate through the list of processes and kill the one with your 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
查看更多
乱世女痞
5楼-- · 2019-01-26 16:39

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.

xlWorkbook.Close();
xlApp.Close();
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
查看更多
登录 后发表回答