How do I get the process ID from a & ldquo; Excel.Application & rdquo created? object?

advertisements

How do I get the Process ID from a running object?

Dim xlApp As Object  = CreateObject("Excel.Application")

I need to use late binding because I can't guarantee which version I will get so using Microsoft.Office.Interop.Excel won't work.

'do some work with xlApp

xlApp.Quit
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
xlApp = nothing

At this point Excel is still running in the background. I am familiar with all the recommendations to use variables and release them then use: System.Runtime.InteropServices.Marshal.ReleaseComObject(o). This does not work reliably. The work that I'm doing is very complicated. I use for each loops etc using multiple files. It is impossible to release all of the resources in Excel. I need a better option.

I'd like to use Process.Kill on Excel but I don't know how to get the process from the xlApp object. I don't want to kill all Excel processes because the user might have a workbook open.

I tried using Dim xProc As Process = Process.Start(ExcelPath) then using xProc.Kill() That works sometimes except it's a little tricky to get the correct Excel object using XLApp = GetObject("Book1").Application or XLApp = GetObject("", "Excel.Application") if the user already has Excel windows open. I need a better option.

I can't use GetActiveObject or BindToMoniker to get the Excel object because they only work with work when using early binding. E.g. Microsoft.Office.Interop.Excel

How do I get the Process ID from a running object?

Edit: Actually I'm not really interested in a rehash on how to get Excel to nicely exit. Many other questions have addressed that. here and here I just want to kill it; cleanly, precisely and directly. I want to kill the exact process that I started and no other.


Using Marshal.ReleaseComObject() or killing the Excel.exe process are ugly, error prone and unnecessary band-aids for this problem. And highly detrimental in the long run, this question shows what can happen. The proper way to do it is by calling GC.Collect(), but read this answer to understand why this tends to not work when you debug your program.

The workaround is simple, you just need to make sure that you call GC.Collect() in a different method. Which ensures that your Excel object references are no longer in scope. So the rough outline of a program that does this right would be:

Sub Main()
    DoOfficeStuff()
    GC.Collect()
    GC.WaitForPendingFinalizers()
    '' Excel.exe will now be gone
    '' Do more work
    ''...
End Sub

Sub DoOfficeStuff()
    Dim xlApp As Object = CreateObject("Excel.Application")
    '' etc..
End Sub