如何检测另一个应用程序启动的进程是否正在执行?

问题描述:

我有一个启动几个进程的应用程序。此应用程序的目的是监视它们是否在启动后运行,如果不启动,则在该进程没有响应的情况下终止进程,或者如果没有运行则重新启动。运行应用程序知道要启动的每个进程,并检查它们是否由ObtenerProceso函数运行(我在启动时拥有每个进程的PID,但不能确保进程已死,而另一进程采用相同的进程PID)。如何检测另一个应用程序启动的进程是否正在执行?

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; 
} 

该函数返回null的情况下,它没有找到该过程。

这种方法对我来说效果很好,问题在于我需要监视的进程数量有点花费时间。时间消耗最高的是select语句,该语句获取有关作为执行进程的用户和发送到可执行文件的命令行的进程的更多详细信息。

有没有更有效的方法来做到这一点?

进一步澄清

从一个可执行的应用程序必须启动多个实例(但具有不同的初始化参数),所以拍摄的名字的过程是不推荐,在这些情况下,仅通过在命令行区分它们与该过程已执行。另外,我检查过程是否有两个标准响应,第一个是属性Process.Responding,第二个每个过程都会不时启动SQLite数据库,我的应用程序会不时询问SQLite数据库是否知道该过程的最后一次报告是何时以及是否为不“锁定”。我让你代表一个我将要启动和监视的进程的类。

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

进程句柄是可等待的对象。 (请参阅https://msdn.microsoft.com/en-us/library/windows/desktop/ms682512(v=vs.85).aspx)。如果您的应用程序创建了这些流程,它可以等待它们终止,就像我在上面粘贴的链接上的示例代码中所做的那样。无需查询进程列表。 – BitTickler

+0

为什么不通过进程名称而不是PID?进程名称将更适合此目的。 –

+0

你如何定义“跑步”和“不回应”?这个过程存在吗?在消耗CPU吗?正在执行I/O?更新数据库?响应活动,例如通过消息队列切换互斥锁还是发送消息? – HABO

按名称杀死进程;

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

这是一个重构代码的想法。

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(); 
     } 
    } 
}