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
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
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
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.
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);