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

时间:2017-09-05 01:43:32

标签: c# .net process desktop-application

我有一个启动多个进程的应用程序。此应用程序的目的是监视它们是否在启动时运行,如果没有,则在没有响应时终止该进程,如果它没有运行则重新启动。运行应用程序知道最初启动的每个进程,并检查它们是否由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数据库,我的应用程序会查询该数据库,知道该进程的最后一次报告何时是知道它是否已经锁定"。我告诉你代表我要启动和监控的进程的Aplicacion类。

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

1 个答案:

答案 0 :(得分:0)

按名称杀死进程;

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