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.
CREATE "Excel. Application" hExcel. RUN GetWindowThreadProcessId (hExcel:Hwnd, OUTPUT processIdForExcel). DISPLAY processIdForExcel.
The Application object contains: Application-wide settings and options. Methods that return top-level objects, such as ActiveCell, ActiveSheet, and so on.
To create an ActiveX object, assign the object returned by CreateObject to an object variable. This code starts the application creating the object, in this case, a Microsoft Excel spreadsheet. After an object is created, you reference it in code by using the object variable you defined.
Actually never mind; I figured it out. This is a very clean, precisely targeted solution that kills the exact process that was started. It doesn't interfere with any other process or file that the user might have open. In my experience killing the process after closing files and quitting Excel is the fastest and easiest way to deal with Excel. Here is a knowledge Base article describing the problem and Microsoft's recommended solution.
Please note that this solution does NOT kill the Excel application. It only kills the empty process shell if any pointers have not been properly disposed. Excel itself DOES actually quit when we call xlApp.quit()
. This can be confirmed by trying to attach the running Excel application which will fail because Excel is not running at all.
Many people don't recommend killing the process; See How to properly clean up Excel interop objects and Understanding Garbage Collection in .net
On the other hand many people don't recommend using GC.Collect. See What's so wrong about using GC.Collect()?
Be sure to Close any open workbooks, Quit the application, Release the xlApp object. Finally check to see if the process is still alive and if so then kill it.
Private Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As IntPtr, _
ByRef lpdwProcessId As Integer) As Integer
Sub testKill()
'start the application
Dim xlApp As Object = CreateObject("Excel.Application")
'do some work with Excel
'close any open files
'get the window handle
Dim xlHWND As Integer = xlApp.hwnd
'this will have the process ID after call to GetWindowThreadProcessId
Dim ProcIdXL As Integer = 0
'get the process ID
GetWindowThreadProcessId(xlHWND, ProcIdXL)
'get the process
Dim xproc As Process = Process.GetProcessById(ProcIdXL)
'Quit Excel
xlApp.quit()
'Release
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
'set to nothing
xlApp = Nothing
'kill it with glee
If Not xproc.HasExited Then
xproc.Kill()
End If
End Sub
Once I realized that I could get the window handle from Excel, then I just needed the function to get the process ID from the window handle. Hence GetWindowThreadProcessId
If anyone knows a vb.net way to get that I would be grateful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With