Here’s an example of how to open an Excel file using Excel-Interop, and properly disposing the instance
(source: google)
Application ExcelObj = new Application();
Workbook WB = ExcelObj.Workbooks.Open(fileName,
0, true, 5, "", "", true, XlPlatform.xlWindows, "t",
false, false, 0, true, false, false);
Sheets sheets = WB.Worksheets;
Worksheet WS = (Worksheet)sheets.get_Item(1);
Range excelRange = WS.UsedRange;
... (DO STUFF?)
// Get rid of everything - close Excel
while (Marshal.ReleaseComObject(WB) > 0) { }
WB = null;
while (Marshal.ReleaseComObject(sheets) > 0) { }
sheets = null;
while (Marshal.ReleaseComObject(WS) > 0) { }
WS = null;
while (Marshal.ReleaseComObject(excelRange) > 0) { }
excelRange = null;
GC();
ExcelObj.Quit();
while (Marshal.ReleaseComObject(ExcelObj) > 0) { }
ExcelObj = null;
GC();
public static void GC()
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS
Contact US
Thanks. We have received your request and will respond promptly.
Log In
Come Join Us!
Are you a
Computer / IT professional?
Join Tek-Tips Forums!
- Talk With Other Members
- Be Notified Of Responses
To Your Posts - Keyword Search
- One-Click Access To Your
Favorite Forums - Automated Signatures
On Your Posts - Best Of All, It’s Free!
*Tek-Tips’s functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.
Posting Guidelines
Promoting, selling, recruiting, coursework and thesis posting is forbidden.
Students Click Here
Simple Way to Get Excel.exe Process IDSimple Way to Get Excel.exe Process ID(OP) 15 Dec 03 18:52 Hi, I found a neat little snippit that will let me close any program given the process id, but I need to be able to find out the process id since it’s dynamically generated. Any ideas? Thanks. Red Flag SubmittedThank you for helping keep Tek-Tips Forums free from inappropriate posts. |
Join Tek-Tips® Today!
Join your peers on the Internet’s largest technical computer professional community.
It’s easy to join and it’s free.
Here’s Why Members Love Tek-Tips Forums:
- Talk To Other Members
- Notification Of Responses To Questions
- Favorite Forums One Click Access
- Keyword Search Of All Posts, And More…
Register now while it’s still free!
Already a member? Close this window and log in.
Join Us Close
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
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.
Hi all,
I am looking for a way to get the Process id (or a handle) of an EXCEL
process created from within my code.
For example when the following code is executed:
Dim EXL As Excel.Application = New Excel.Application
a new instance of EXCEL.EXE is created in the task manager.
I am looking for some code (or ideas) of how to identify this
particular instance of EXCEL.EXE AS IT IS CREATED. I know I can use
something like this:
Dim localByName As Process() = Process.GetProcessesByName(«excel»)
but this code will give me ALL instances of EXCEL processes running on
the computer. I know I can also get the users of the processes but
what if I myself had just say 5 instances of EXCEL already running on
my computer?? How do I identify which is the Process Id of EXCEL
created (opened) by my code??
I’m sure some smart people out there have the answers! Appreciate any
help.
PowaGuy
Nov 21 ’05
#1
Как мне получить идентификатор процесса из запущенного объекта?
Dim xlApp As Object = CreateObject("Excel.Application")
Мне нужно использовать позднее связывание, потому что я не могу гарантировать, какую версию получу, поэтому использование Microsoft.Office.Interop.Excel
не сработает.
'do some work with xlApp
xlApp.Quit
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
xlApp = nothing
На данный момент Excel все еще работает в фоновом режиме. Я знаком со всеми рекомендациями по использованию переменных и их выпуску, а затем использую: System.Runtime.InteropServices.Marshal.ReleaseComObject(o)
. Это не работает надежно. Работа, которую я делаю, очень сложная. Я использую для каждого цикла и т.д., используя несколько файлов. Освободить все ресурсы в Excel невозможно. Мне нужен лучший вариант.
Я хотел бы использовать Process.Kill
в Excel, но не знаю, как получить процесс из объекта xlApp. Я не хочу убивать все процессы Excel, потому что у пользователя может быть открыта книга.
Я пробовал использовать Dim xProc As Process = Process.Start(ExcelPath)
, а затем xProc.Kill()
. Иногда это работает, за исключением того, что немного сложно получить правильный объект Excel с помощью XLApp = GetObject("Book1").Application
или XLApp = GetObject("", "Excel.Application")
, если у пользователя уже открыты окна Excel. Мне нужен лучший вариант.
Я не могу использовать GetActiveObject
или BindToMoniker
для получения объекта Excel, потому что они работают с работой только при использовании раннего связывания. Например. Microsoft.Office.Interop.Excel
Как мне получить идентификатор процесса из запущенного объекта?
Изменить: на самом деле меня не очень интересует перефразирование того, как заставить Excel красиво выйти. Многие другие вопросы касались этого. здесь и здесь Я просто хочу убить его; чисто, точно и прямо. Я хочу убить именно тот процесс, который я начал, и никакой другой.
6 ответов
Лучший ответ
На самом деле неважно; Я понял. Это очень чистое, точно нацеленное решение, которое убивает точно запущенный процесс. Это не мешает другим процессам или файлам, которые может открыть пользователь. По моему опыту, прекращение процесса после закрытия файлов и выхода из Excel — это самый быстрый и простой способ справиться с Excel. Вот статья базы знаний с описанием проблемы и рекомендуемым решением Microsoft.
Обратите внимание, что это решение НЕ убивает приложение Excel. Он убивает пустую оболочку процесса только в том случае, если какие-либо указатели не были должным образом удалены. Сам Excel действительно закрывается, когда мы вызываем xlApp.quit()
. Это можно подтвердить, попытавшись подключить работающее приложение Excel, но это не поможет, потому что Excel вообще не запущен.
Многие не рекомендуют убивать процесс; Видеть Как правильно очистить объекты взаимодействия Excel и Общие сведения о сборке мусора в .NET
С другой стороны, многие люди не рекомендуют использовать GC.Collect. См. Что плохого в использовании GC.Collect ()?
Обязательно закройте все открытые книги, выйдите из приложения, отпустите объект xlApp. Наконец, проверьте, жив ли процесс, и если да, то убейте его.
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
Как только я понял, что могу получить дескриптор окна из Excel, мне просто понадобилась функция для получения идентификатора процесса из дескриптора окна. Следовательно, GetWindowThreadProcessId
Если кто-нибудь знает способ получить это на vb.net, я был бы признателен.
9
Community
23 Май 2017 в 12:00
Использование Marshal.ReleaseComObject () или уничтожение процесса Excel.exe некрасиво, подвержено ошибкам и является ненужным средством решения этой проблемы. И очень вредно в долгосрочной перспективе, этот вопрос показывает, что может случиться. Правильный способ сделать это — вызвать GC.Collect (), но прочтите этот ответ, чтобы понять, почему это не так. работать, когда вы отлаживаете свою программу.
Обходной путь прост, вам просто нужно убедиться, что вы вызываете GC.Collect () в другом методе. Это гарантирует, что ваши ссылки на объекты Excel больше не входят в область действия. Итак, приблизительный набросок программы, которая делает это правильно, будет следующим:
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
6
Community
23 Май 2017 в 12:17
Public Declare Function GetWindowThreadProcessId Lib "user32" _
(ByVal hwnd As Long, _
ByRef lpdwProcessId As Long) As Long
Function KillProcess(hwnd As Long)
Dim CurrentForegroundThreadID As Long
Dim strComputer As String
Dim objWMIService
Dim colProcessList
Dim objProcess
Dim ProcIdXL As Long
ProcIdXL = 0
CurrentForegroundThreadID = GetWindowThreadProcessId(hwnd, ProcIdXL)
strComputer = "."
Set objWMIService = GetObject _
("winmgmts:\" & strComputer & "rootcimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where ProcessID =" & ProcIdXL)
For Each objProcess In colProcessList
objProcess.Terminate
Next
End Function
KillProcess (ExcelApplication.hwnd)
2
Jakuje
19 Ноя 2015 в 11:13
Для C # используйте:
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
uint iProcessId = 0;
//Get the process ID of excel so we can kill it later.
GetWindowThreadProcessId((IntPtr)ExcelObj.Hwnd, out iProcessId);
try
{
Process pProcess = Process.GetProcessById((int)iProcessId);
pProcess.Kill();
}
catch (System.Exception)
{
//just ignore any failure.
}
0
JimMoore
15 Май 2014 в 21:36
Я нашел обходной путь (источник на VB):
Private Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
Сначала Marshal.ReleaseComObject () все более детализированные объекты и устанавливают для них значение Nothing.
Переместите окно Excel наверх после закрытия последней книги, а затем подождите 1000 мс (хорошее значение для шансов на работу):
exlBook.Close()
Dim exlProcId As Integer = Nothing
GetWindowThreadProcessId(exlApp.Hwnd, exlProcId)
AppActivate(exlProcId)
Threading.Thread.Sleep(1000)
Marshal.ReleaseComObject(exlBook)
exlBook = Nothing
В конце концов:
exlApp.Quit()
exlApp = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
Я обнаружил это, когда остановил программу после закрытия рабочей книги, затем открыл окно Excel, затем продолжил программу и процесс Excel был закрыт.
С уважением: Торстен, Ганновер, Германия
0
user3756502
30 Дек 2018 в 23:04
Я столкнулся с этой проблемой при разработке автоматического приложения, которое каждый день создает от 50 до 100 книг Excel и отправляет их по электронной почте. Что бы я ни делал, экземпляр Excel зависал в диспетчере задач, иногда даже после GC.WaitForPendingFinalizers ().
Поскольку приложение работает без присмотра, я не могу рисковать, что Excel съест машину, поэтому я объединил все подходы в:
Private Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
Dim XLApp As Excel.Application
Dim XLHwnd As Integer
Dim XLProcID As Integer
Dim XLProc As Process
XLApp = New Excel.Application
XLHwnd = XLApp.Hwnd
GetWindowThreadProcessId(CType(XLHwnd, IntPtr), XLProcID)
XLProc = Process.GetProcessById(XLProcID)
DoStuffWithExcel()
Try
XLApp.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(XLApp)
XLApp = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()
If Not XLProc.HasExited Then
XLProc.Kill()
End If
Catch ex As Exception
XLApp = Nothing
Finally
GC.Collect()
End Try
Я пытаюсь выйти изящно, но если это не удается, я прекращаю процесс, потому что должен!
Пока что вёл себя
0
Yowser
7 Мар 2019 в 19:04