Comment puis-je obtenir l'ID de processus à partir D'un "Excel créé.L'Application" de l'objet?
Comment obtenir l'identifiant du processus d'un objet en cours d'exécution?
Dim xlApp As Object = CreateObject("Excel.Application")
je dois utiliser la reliure tardive parce que je ne peux pas garantir quelle version je vais obtenir si en utilisant Microsoft.Office.Interop.Excel
ne fonctionnera pas.
'do some work with xlApp
xlApp.Quit
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
xlApp = nothing
à ce point Excel est toujours en cours d'exécution dans l'arrière-plan. Je suis familier avec toutes les recommandations d'utiliser des variables et de les libérer puis d'utiliser: System.Runtime.InteropServices.Marshal.ReleaseComObject(o)
. Ce n'est pas fiable. Le travail que je fais est très compliqué. J'utilise pour chaque boucle etc en utilisant plusieurs fichiers. Il est impossible de libérer toutes les ressources dans Excel. J'ai besoin d'une meilleure option.
j'aimerais utiliser Process.Kill
sur Excel mais je ne sais pas comment obtenir le processus à partir de l'objet xlApp. Je ne veux pas tuer tous les processus Excel parce que l'utilisateur pourrait avoir un classeur ouvert.
j'ai essayé d'utiliser Dim xProc As Process = Process.Start(ExcelPath)
puis d'utiliser xProc.Kill()
qui fonctionne parfois sauf qu'il est un peu délicat de obtenez le bon objet Excel en utilisant XLApp = GetObject("Book1").Application
ou XLApp = GetObject("", "Excel.Application")
si L'Utilisateur a déjà Excel windows ouvert. J'ai besoin d'une meilleure option.
Je ne peux pas utiliser GetActiveObject
ou BindToMoniker
pour obtenir L'objet Excel parce qu'ils ne fonctionnent avec le travail qu'en utilisant la reliure anticipée. Par exemple: Microsoft.Office.Interop.Excel
Comment obtenir l'identifiant du processus d'un objet en cours d'exécution?
Edit: en fait, je ne suis pas vraiment intéressé par une refonte sur la façon D'obtenir Excel à bien sortie. De nombreuses autres questions sont abordées. ici et ici je veux juste le tuer; proprement, précisément et directement. Je veux tuer le processus exact que j'ai commencé et aucun autre.
4 réponses
Avec Marshal.ReleaseComObject () ou tuer L'Excel.processus exe sont laides, sujettes aux erreurs et des pansements inutiles pour ce problème. Et très préjudiciable à long terme, cette question montre ce qui peut arriver. La bonne façon de le faire est d'appeler le GC.Collect (), mais lisez cette réponse pour comprendre pourquoi cela a tendance à ne pas fonctionner lorsque vous déboguez votre programme.
La solution est simple, vous avez juste besoin de faire assurez-vous que vous appelez GC.Collect () dans une méthode différente . Ce qui garantit que vos références D'objet Excel ne sont plus dans la portée. Donc l'ébauche d'un programme qui fait ce droit serait:
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
peu importe, j'ai compris. C'est très propre, précisément solution ciblée qui tue le processus exact qui a été commencé. Il n'interfère avec aucun autre processus ou fichier que l'utilisateur pourrait avoir ouvert. D'après mon expérience, tuer le processus après la fermeture des fichiers et quitter Excel est le moyen le plus rapide et le plus facile de traiter avec Excel. voici un article de base de connaissances décrivant le problème et la solution recommandée par Microsoft.
veuillez noter que cette solution ne tue pas L'application Excel. Il ne tue la couche de processus vide que si des pointeurs n'ont pas été correctement éliminés. Excel lui-même démissionne quand on appelle xlApp.quit()
. Cela peut être confirmé en essayant de joindre L'application en cours D'exécution Excel qui échouera parce Qu'Excel n'est pas en cours d'exécution du tout.
beaucoup de gens ne recommandent pas de tuer le processus; Voir comment nettoyer correctement les objets Excel interop et la Compréhension de la Collecte des Ordures .net
d'un autre côté, beaucoup de gens ne recommandent pas L'utilisation du GC.Recueillir. Voir What is so wrong about using GC.Collecter()?
assurez-vous de fermer tous les classeurs ouverts, quitter l'application, Libérer l'objet xlApp. Vérifiez enfin si le processus est toujours en vie et si oui, tuez-le.
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
une fois que j'ai réalisé que Je pourrais obtenir la poignée de fenêtre D'Excel, alors j'ai juste eu besoin de la fonction pour obtenir L'ID de processus de la poignée de fenêtre. D'où GetWindowThreadProcessId
si quelqu'un connaît un vb.net je vous en serais reconnaissant.
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 & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where ProcessID =" & ProcIdXL)
For Each objProcess In colProcessList
objProcess.Terminate
Next
End Function
KillProcess (ExcelApplication.hwnd)
Pour C# utilisation:
[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.
}