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
demandé sur Community 2013-07-20 09:42:03

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
6
répondu Hans Passant 2017-05-23 12:17:08

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.

2
répondu D_Bester 2017-05-23 12:00:13
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)
1
répondu ajsco 2015-11-19 11:13:11

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.
    }
0
répondu JimMoore 2014-05-15 21:36:27