2017-09-05 1 views
0

Ich habe eine Anwendung, die mehrere Prozesse startet. Der Zweck dieser Anwendung besteht darin, zu überwachen, ob sie nach dem Start ausgeführt wird. Ist dies nicht der Fall, beenden Sie den Prozess, wenn er nicht reagiert, oder führen Sie ihn erneut aus, wenn er nicht ausgeführt wird. Ausführen aller Prozesse, von denen die Anwendung weiß, dass sie gestartet werden sollen, und Prüfung, ob sie von der ObtenerProceso-Funktion ausgeführt werden (ich habe die PIDs jedes Prozesses beim Start, aber das stellt nicht sicher, dass der Prozess beendet ist und ein anderer Prozess das gleiche ausgeführt hat PID).Wie erkennt man, ob ein von einer anderen Anwendung gestarteter Prozess ausgeführt wird?

public static Process ObtenerProceso(int pid, string ubicacion, string argumentos = "", string dominio = "", string usuario = "") 
{ 
    Process proceso = null; 
    Process procesoAux = null; 

    if (Process.GetProcesses().Any(x => x.Id == pid)) 
    { 
     procesoAux = Process.GetProcessById(pid); 
     if (procesoAux.MainModule.FileName.ToUpper() == ubicacion.ToUpper()) 
     { 
      ManagementObjectSearcher mos = new ManagementObjectSearcher($"select * from Win32_Process where ProcessId = {procesoAux.Id}"); 
      foreach (ManagementObject mo in mos.Get()) 
       if (mo["CommandLine"] != null && mo["CommandLine"].ToString().ToUpper().Replace($"\"{ubicacion.ToUpper()}\"", string.Empty).Trim() == argumentos.ToUpper().Trim()) 
       { 
        if (dominio.Trim() != string.Empty && usuario.Trim() != string.Empty) 
        { 
         string[] argList = new string[] { string.Empty, string.Empty }; 
         int respuesta = Convert.ToInt32(mo.InvokeMethod("GetOwner", argList)); 
         if (respuesta == 0 && $"{argList[1]}\\{argList[0]}".ToUpper() == $"{dominio}\\{usuario}".ToUpper()) 
          proceso = procesoAux; 
        } 
        else 
         proceso = procesoAux; 
       } 
     } 

    } 

    return proceso; 
} 

Die Funktion gibt null, falls es den Prozess nicht finden.

Diese Methode hat für mich gut funktioniert, das Problem ist, dass es für die Anzahl der Prozesse, die ich überwachen muss, ein wenig zeitaufwendig ist. Die höchsten Zeitverbräuche wurden in der select-Anweisung ausgegeben, die detailliertere Informationen zum Prozess erhält, als der Benutzer, der den Prozess ausgeführt hat, und die Befehlszeile, die an die ausführbare Datei gesendet wurde.

Gibt es eine effektivere Methode, dies zu tun?

Zusätzliche Klärung

Aus einer einzigen ausführbaren Datei muss die Anwendung mehrere Instanzen starten (aber mit unterschiedlichen Initialisierung Argumente), so dass der Prozess mit Namen Erfassung wird nicht empfohlen, in diesen Fällen nur, um sie durch den Zeilenbefehl unterscheiden, mit denen Der Prozess wurde ausgeführt. Außerdem überprüfe ich, ob der Prozess nach zwei Kriterien antwortet, zuerst mit der Eigenschaft Process.Responding und zweitens jedem Prozess, der von Zeit zu Zeit aktualisiert wird, eine SQLite-Datenbank, die meine Anwendung fragt, wann der letzte Bericht des Prozesses war und ob sie es ist nicht verschlossen". Ich lasse Sie die Aplicacion Klasse, die einen Prozess darstellt, den ich starten und überwachen werde.

using System; 
using System.Data; 
using System.Diagnostics; 
using System.Globalization; 
using System.IO; 
using System.Security; 

namespace Yggdrasil 
{ 
    /// <summary> 
    /// Represents an Application to be monitored. 
    /// </summary> 
    internal class Aplicacion 
    { 
     #region Definition of private variables. 
     private int id; 
     private int idMaquina; 
     private int pid = -999999999; 
     private string nombre; 
     private string descripcion; 
     private string ubicacion; 
     private string argumentos; 
     private string dominio; 
     private string usuario; 
     private SecureString clave; 
     private bool activa; 
     private DateTime fechaCreacion; 
     #endregion 

     #region Properties. 
     /// <summary> 
     /// Gets the Application ID. This property can not be set. 
     /// </summary> 
     public int Id 
     { 
      get 
      { 
       return id; 
      } 
     } 

     /// <summary> 
     /// Gets the identification of the process of the Application. This property can not be set. 
     /// </summary> 
     public int PID 
     { 
      get 
      { 
       return pid; 
      } 
     } 

     /// <summary> 
     /// Gets the identification of the Machine where the Application is executed. This property can not be set. 
     /// </summary> 
     public int IdMaquina 
     { 
      get 
      { 
       return idMaquina; 
      } 
     } 

     /// <summary> 
     /// Gets the name of the Application. This property can not be set. 
     /// </summary> 
     public string Nombre 
     { 
      get 
      { 
       return nombre; 
      } 
     } 

     /// <summary> 
     /// Gets the description of the Application. This property can not be set. 
     /// </summary> 
     public string Descripcion 
     { 
      get 
      { 
       return descripcion; 
      } 
     } 

     /// <summary> 
     /// Gets the location of the Application executable. This property can not be set. 
     /// </summary> 
     public string Ubicacion 
     { 
      get 
      { 
       return ubicacion; 
      } 
     } 

     /// <summary> 
     /// Gets the start arguments for the application. This property can not be set. 
     /// </summary> 
     public string Argumentos 
     { 
      get 
      { 
       return argumentos; 
      } 
     } 

     /// <summary> 
     /// Determines whether the Application is active or inactive. This property can not be set. 
     /// </summary> 
     public bool Activa 
     { 
      get 
      { 
       return activa; 
      } 
     } 

     /// <summary> 
     /// Gets the user with which the application is executed. This property can not be set. 
     /// </summary> 
     public string Usuario 
     { 
      get 
      { 
       return usuario; 
      } 
     } 

     /// <summary> 
     /// Gets the domain in which the application runs. This property can not be set. 
     /// </summary> 
     public string Dominio 
     { 
      get 
      { 
       return dominio; 
      } 
     } 

     /// <summary> 
     /// Gets the password of the user with whom the application is running. This property can not be set. 
     /// </summary> 
     public SecureString Clave 
     { 
      get 
      { 
       return clave; 
      } 
     } 

     /// <summary> 
     /// Gets the last date the application responded. This property can not be set. 
     /// </summary> 
     public DateTime FechaResponde 
     { 
      get 
      { 
       return ObtenerUltimoRespondeProceso(); 
      } 
     } 

     /// <summary> 
     /// Gets the last date the application reported activity. This property can not be set. 
     /// </summary> 
     public DateTime FechaReporte 
     { 
      get 
      { 
       return ObtenerUltimoReporteProceso(); 
      } 
     } 

     /// <summary> 
     /// Gets the date of creation of the application record. This property can not be set. 
     /// </summary> 
     public DateTime FechaCreacion 
     { 
      get 
      { 
       return fechaCreacion; 
      } 
     } 
     #endregion 

     #region implementación de constructores. 
     /// <summary> 
     /// Initializes an object from the Application class. 
     /// </summary> 
     /// <param name="id">Identification of the application.</param> 
     public Aplicacion(int id) 
     { 
      Inicializar(id); 
     } 

     /// <summary> 
     /// Initializes an object from the Application class. 
     /// </summary> 
     /// <param name="id">Identification of the application.</param> 
     /// <param name="idMaquina">Identification of the machine where the application is running.</param> 
     /// <param name="nombre">Name of the application.</param> 
     /// <param name="descripcion">Description of the application.</param> 
     /// <param name="ubicacion">Location of the application executable.</param> 
     /// <param name="argumentos">Arguments with which the application is executed.</param> 
     /// <param name="dominio">User domain of the application.</param> 
     /// <param name="usuario">User with which the application is executed.</param> 
     /// <param name="clave">Password of the user with which the application is executed.</param> 
     /// <param name="activa">Indicates whether the application is active or inactive.</param> 
     /// <param name="fechaCreacion">Creation date of the application record.</param> 
     public Aplicacion(int id, int idMaquina, string nombre, string descripcion, string ubicacion, string argumentos, string dominio, string usuario, string clave, int pid, bool activa, DateTime fechaCreacion) 
     { 
      this.id = id; 
      this.idMaquina = idMaquina; 
      this.nombre = nombre; 
      this.descripcion = descripcion; 
      this.ubicacion = ubicacion; 
      this.argumentos = argumentos; 
      this.activa = activa; 
      this.fechaCreacion = fechaCreacion; 
      this.dominio = dominio; 
      this.usuario = usuario.ToUpper(); 
      this.clave = Utilidades.String2SecureString(clave); 
      this.pid = pid; 
     } 
     #endregion 

     #region Implementación de métodos privados. 
     /// <summary> 
     /// Initializes an object of the Application class knowing its identification. 
     /// </summary> 
     /// <param name="id">Identification of the Application.</param> 
     private void Inicializar(int id) 
     { 
      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
       { 
        DataTable dtAplicacion = controladorBD.EjecutarLector($"SELECT * FROM aplicacion WHERE id_aplicacion = {id}"); 
        foreach (DataRow drAplicacion in dtAplicacion.Rows) 
        { 
         this.id = id; 
         idMaquina = Convert.ToInt32(drAplicacion["id_maquina"]); 
         nombre = drAplicacion["nombre_aplicacion"].ToString(); 
         descripcion = drAplicacion["descripcion"].ToString(); 
         ubicacion = drAplicacion["ubicacion"].ToString(); 
         argumentos = drAplicacion["argumentos"].ToString(); 
         dominio = drAplicacion["dominio"].ToString(); 
         usuario = drAplicacion["usuario"].ToString().ToUpper(); 
         clave = Utilidades.String2SecureString(drAplicacion["clave"].ToString()); 
         if (drAplicacion["activa"].ToString() == "S") 
          activa = true; 
         else 
          activa = false; 
         pid = Convert.ToInt32(drAplicacion["pid"]); 
         fechaCreacion = (DateTime)drAplicacion["fecha_creacion"]; 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al inicializar un objeto Aplicacion. {ex.Message}"); 
      } 
     } 

     /// <summary> 
     /// Updates the PID of the Application. 
     /// </summary> 
     /// <param name="pid">New process identification for the Application.</param> 
     private void ActualizarPID(int pid) 
     { 
      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
       { 
        controladorBD.Ejecutar($"UPDATE aplicacion SET pid = {pid} WHERE id_aplicacion = {id}"); 
        this.pid = pid; 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al intentar actualizar el PID. {ex.Message}"); 
      } 
     } 

     /// <summary> 
     /// Gets the date of the last report of the process. 
     /// </summary> 
     /// <returns></returns> 
     private DateTime ObtenerUltimoReporteProceso() 
     { 
      DateTime fecha = DateTime.Now; 
      Process proceso = ObtenerProcesoActual(); 

      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
       { 
        int cantidad = Convert.ToInt32(controladorBD.EjecutarLector($"SELECT COUNT(*) AS cantidad FROM reporte_proceso WHERE id_proceso = {proceso.Id} AND UPPER(ubicacion) = '{ubicacion.ToUpper()}'").Rows[0]["cantidad"]); 
        if (cantidad > 0) 
        { 
         if (cantidad > 1000) 
          controladorBD.Ejecutar($"DELETE FROM reporte_proceso WHERE id_proceso = {proceso.Id} AND UPPER(ubicacion) = '{ubicacion.ToUpper()}'"); 

         fecha = DateTime.ParseExact(controladorBD.EjecutarLector($"SELECT STRFTIME('%d-%m-%Y %H:%M:%S', DATETIME(x.fecha)) AS fecha FROM (SELECT MAX(fecha_creacion) AS fecha FROM reporte_proceso WHERE id_proceso = {proceso.Id} AND UPPER(ubicacion) = '{ubicacion.ToUpper()}') x").Rows[0]["fecha"].ToString(), "dd-MM-yyyy HH:mm:ss", CultureInfo.InvariantCulture); 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al intentar obtener la fecha del último reporte de una aplicación. {ex.Message}"); 
      } 

      return fecha; 
     } 

     /// <summary> 
     /// Gets the date of the last time the application replied. 
     /// </summary> 
     /// <returns></returns> 
     private DateTime ObtenerUltimoRespondeProceso() 
     { 
      DateTime fecha = DateTime.Now; 

      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
       { 
        object obj_fecha = controladorBD.EjecutarLector($"SELECT STRFTIME('%d-%m-%Y %H:%M:%S', DATETIME(fecha_responde)) AS fecha FROM aplicacion WHERE id_aplicacion = {id}").Rows[0]["fecha"]; 
        if (obj_fecha != null) 
         fecha = DateTime.ParseExact(Convert.ToString(obj_fecha), "dd-MM-yyyy HH:mm:ss", CultureInfo.InvariantCulture); 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al intentar obtener la última fecha de respuesta de una aplicación {ex.Message}"); 
      } 

      return fecha; 
     } 

     /// <summary> 
     /// Gets the current application process. 
     /// </summary> 
     /// <returns></returns> 
     private Process ObtenerProcesoActual() 
     { 
      return Utilidades.ObtenerProceso(pid, ubicacion, argumentos, dominio, usuario); 
     } 
     #endregion 

     #region Implementation of public methods 
     /// <summary> 
     /// Inactiva el proceso. 
     /// </summary> 
     public void Inactivar() 
     { 
      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
        controladorBD.Ejecutar($"UPDATE aplicacion SET activa = 'N' WHERE id_aplicacion = {id} AND activa = 'S'"); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al intentar inactivar una aplicación. {ex.Message}"); 
      } 
     } 

     /// <summary> 
     /// Activate the process. 
     /// </summary> 
     public void Activar() 
     { 
      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
        controladorBD.Ejecutar($"UPDATE aplicacion SET activa = 'S' WHERE id_aplicacion = {id} AND activa = 'N'"); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al intentar activar una aplicación. {ex.Message}"); 
      } 
     } 

     /// <summary> 
     /// Updates the last date the application responded. 
     /// </summary> 
     public void ActualizarRespuesta() 
     { 
      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
        controladorBD.Ejecutar($"UPDATE aplicacion SET fecha_responde = CURRENT_TIMESTAMP WHERE id_aplicacion = {id}"); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al intentar actualizar la fecha de respuesta de una aplicación. {ex.Message}"); 
      } 
     } 

     /// <summary> 
     /// Deletes the configuration application. 
     /// </summary> 
     public void Eliminar() 
     { 
      try 
      { 
       using (ControladorSQLite controladorBD = new ControladorSQLite(Controlador.UbicacionBDLocal)) 
        controladorBD.Ejecutar($"DELETE FROM aplicacion WHERE id_aplicacion = {id}"); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception($"Error al intentar eliminar una aplicaión. {ex.Message}"); 
      } 
     } 

     /// <summary> 
     /// Checks if the application is running. 
     /// </summary> 
     /// <returns></returns> 
     public bool EnEjecucion() 
     { 
      return ObtenerProcesoActual() != null; 
     } 

     /// <summary> 
     /// Determines whether the application is responding. 
     /// </summary> 
     /// <returns></returns> 
     public bool EstaRespondiendo() 
     { 
      return ObtenerProcesoActual().Responding; 
     } 

     /// <summary> 
     /// Run the application. 
     /// </summary> 
     public void Ejecutar() 
     { 
      Process proceso = new Process() 
      { 
       StartInfo = new ProcessStartInfo() 
       { 
        FileName = ubicacion, 
        ErrorDialog = true, 
        UseShellExecute = false, 
        RedirectStandardOutput = true, 
        RedirectStandardError = true, 
        WorkingDirectory = Path.GetDirectoryName(ubicacion), 
        Arguments = argumentos, 
        Domain = dominio, 
        UserName = usuario, 
        Password = clave 
       } 
      }; 

      proceso.Start(); 
      ActualizarPID(proceso.Id); 
     } 

     /// <summary> 
     /// Kills the current application process. 
     /// </summary> 
     public void Matar() 
     { 
      ObtenerProcesoActual().Kill(); 
     } 
     #endregion 
    } 
} 
+0

Prozesshandles sind nützliche Objekte. (Siehe zum Beispiel https://msdn.microsoft.com/en-us/library/windows/desktop/ms682512(v=vs.85).aspx). Wenn Ihre Anwendung die Prozesse erstellt, kann sie darauf warten, dass sie beendet werden, genau wie im Beispielcode auf dem Link, den ich oben eingefügt habe. Keine Notwendigkeit, die Prozessliste abzufragen. – BitTickler

+0

Warum gehst du nicht durch den Prozessnamen anstelle von PID? Der Prozessname wird für diesen Zweck besser geeignet sein. –

+0

Wie definieren Sie "läuft" und "antwortet nicht"? Der Prozess existiert? Verbraucht CPU? Führt ich I/O? Aktualisiert eine Datenbank? Reagiert auf Aktivität, z.B. Umschalten eines Mutex oder Senden einer Nachricht über die Nachrichtenwarteschlange? – HABO

Antwort

0

Um einen Prozess mit Namen zu beenden;

private void TerminateAll() 
    { 
     foreach (var process in Process.GetProcessesByName("exenamewithoutext")) 
     { 
      process?.Kill(); 
     } 
    } 

Hier ist eine Idee, Ihren Code zu refaktorieren.

public class ProcessRunner 
{ 
    /// <summary> 
    /// Gets or sets the running process. 
    /// </summary> 
    private Process RunningProcess { get; set; }  

    /// <summary> 
    /// The exepath of the process. 
    /// </summary> 
    private readonly string exePath; 

    public ProcessRunner(string exePath) 
    { 
     this.exePath = exePath; 
    } 

    /// <summary> 
    /// Runs the specified executable path. 
    /// </summary> 
    /// <param name="exePath">The executable path.</param> 
    public void Run() 
    { 
     var processInfo = new ProcessStartInfo { Arguments = "<Your Args>", FileName = exePath, WindowStyle = ProcessWindowStyle.Normal }; 
     try 
     { 
      this.RunningProcess = Process.Start(processInfo); 
     } 
     catch (Exception exception) 
     { 
      throw new ProcessRunnerException(exception.Message); 
     } 
    } 

    /// <summary> 
    /// Terminates this instance. 
    /// </summary> 
    public void Terminate() 
    { 
     if (this.RunningProcess != null) 
     {    
      this.RunningProcess.Kill(); 
      this.RunningProcess.Dispose(); 
     } 
    } 
} 


public class ProcessManager 
{ 
    private readonly IList<ProcessRunner> MyProcessors{ get; } 

    public ProcessManager() 
    { 
     MyProcessors = new List<ProcessRunner>(); 
     MyProcessors.Add(new ProcessRunner("myexe.exe")); // Add as many as you want. 
    } 

    public void RunAll() 
    { 
     foreach(var proc in MyProcessors) 
     { 
      proc.Run(); 
     } 
    } 

    public void KillAll() 
    { 
     foreach(var proc in MyProcessors) 
     { 
      proc.Terminate(); 
     } 
    } 
} 
Verwandte Themen