¿Cómo puedo saber si se está ejecutando un proceso?

155

Cuando obtengo una referencia a a System.Diagnostics.Process, ¿cómo puedo saber si un proceso se está ejecutando actualmente?

reshefm
fuente

Respuestas:

252

Esta es una forma de hacerlo con el nombre:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
  MessageBox.Show("nothing");
else
  MessageBox.Show("run");

Puede repetir todo el proceso para obtener la ID para su posterior manipulación:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
Patrick Desjardins
fuente
Esto es exactamente lo que estaba buscando. Aunque esta es una publicación muy antigua, ¿podría explicarme cómo es válida C #? No lo dudo, veo que funciona, pero nunca he visto si más sin {}.
MatthewD
44
@MatthewD: las if/elsedeclaraciones de C # que solo tienen una línea de longitud no necesitan tener llaves para indicar la declaración de bloque. Esto también se aplica a foreachy fordeclaraciones. Se reduce al estilo de codificación.
Hallmanac
También investigué un poco sobre esto, encontré esa información, pero no la vi for. Años de c # .net dev y nunca he visto este estilo. Como dicen, "aprendes algo nuevo todos los días". Gracias por la publicación y la respuesta ..
MatthewD
3
@MatthewD sí, esto va para la mayoría de los idiomas en realidad (como Java). En general, es una buena práctica evitar frases como estas y siempre colocar llaves, ya que siempre existe la posibilidad de que tenga que agregar más declaraciones allí en el futuro, en cuyo caso las llaves ya estarán allí cuando las necesite. Pero para cosas como esta, si está 100% seguro de que solo necesita una declaración, está bien hacerlo y es sintácticamente válido.
David Mordigal
1
Si no puede encontrar el proceso, intente eliminar la extensión. (Ej: .exe)
DxTx
28

Esta es la forma más simple que encontré después de usar el reflector. Creé un método de extensión para eso:

public static class ProcessExtensions
{
    public static bool IsRunning(this Process process)
    {
        if (process == null) 
            throw new ArgumentNullException("process");

        try
        {
            Process.GetProcessById(process.Id);
        }
        catch (ArgumentException)
        {
            return false;
        }
        return true;
    }
}

El Process.GetProcessById(processId)método llama al ProcessManager.IsProcessRunning(processId)método y lanza ArgumentExceptionen caso de que el proceso no exista. Por alguna razón, la ProcessManagerclase es interna ...

reshefm
fuente
Esta fue una muy buena respuesta; sin embargo, no debería tener a través del argumento excepción nula (porque de todos modos se habría lanzado una excepción de referencia nula y no hizo nada con la excepción. Además, obtendrá una InvalidOperationException si no invocó Start () o invocaste el método close ().
Publiqué
16

Solución sincrónica:

void DisplayProcessStatus(Process process)
{
    process.Refresh();  // Important


    if(process.HasExited)
    {
        Console.WriteLine("Exited.");
    }
    else
    {
        Console.WriteLine("Running.");
    } 
}

Solución asincrónica:

void RegisterProcessExit(Process process)
{
    // NOTE there will be a race condition with the caller here
    //   how to fix it is left as an exercise
    process.Exited += process_Exited;
}

static void process_Exited(object sender, EventArgs e)
{
   Console.WriteLine("Process has exited.");
}
Coincoin
fuente
66
Para la primera opción: ¿cómo puedo saber si el proceso se inició en primer lugar?
reshefm
8

reshefm tuvo una muy buena respuesta; sin embargo, no tiene en cuenta una situación en la que el proceso nunca se inició para comenzar.

Aquí hay una versión modificada de lo que publicó.

    public static bool IsRunning(this Process process)
    {
        try  {Process.GetProcessById(process.Id);}
        catch (InvalidOperationException) { return false; }
        catch (ArgumentException){return false;}
        return true;
    }

Eliminé su ArgumentNullException porque en realidad se supone que es una excepción de referencia nula y el sistema la arroja de todos modos y también tomé en cuenta la situación en la que el proceso nunca se inició o el método close () se usó para cerrar el proceso.

Aelphaeis
fuente
Personalmente, preferiría ver una excepción ArgumentNullException al revisar una excepción registrada que una NullReferenceException, ya que ArgumentNullException es mucho más explícito sobre lo que salió mal.
Sean
1
@Sean, normalmente estaría de acuerdo contigo, pero este es un método de extensión. Creo que es más apropiado lanzar una excepción de puntero nulo dada la sintaxis, simplemente se siente más consistente con los métodos de llamada de objetos nulos.
Aelphaeis
Esto activará el controlador de eventos FirstHandledException cada vez. Manera de enviar spam a sus registros allí amigo.
Latencia
6

Esto debería ser de una sola línea:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
guneysus
fuente
3

Depende de qué tan confiable desee que sea esta función. Si desea saber si la instancia de proceso particular que tiene todavía se está ejecutando y está disponible con una precisión del 100%, entonces no tiene suerte. La razón es que desde el objeto de proceso administrado solo hay 2 formas de identificar el proceso.

El primero es el Id. De proceso. Desafortunadamente, los identificadores de proceso no son únicos y pueden reciclarse. Buscar en la lista de procesos un Id. Coincidente solo le indicará que hay un proceso con el mismo id en ejecución, pero no es necesariamente su proceso.

El segundo elemento es el controlador de proceso. Sin embargo, tiene el mismo problema que el Id y es más incómodo trabajar con él.

Si está buscando confiabilidad de nivel medio, entonces es suficiente verificar la lista de procesos actual para un proceso de la misma ID.

JaredPar
fuente
1

Process.GetProcesses()Es el camino a seguir. Pero es posible que necesite usar uno o más criterios diferentes para encontrar su proceso, dependiendo de cómo se esté ejecutando (es decir, como un servicio o una aplicación normal, tenga o no una barra de título).

Jeff Kotula
fuente
Si pone este método en un bucle, le costará muchos ciclos de CPU. Recomiendo usar GetProcessByName () o GetProcessByID ().
Hao Nguyen
0

Tal vez (probablemente) estoy leyendo la pregunta incorrectamente, pero ¿está buscando la propiedad HasExited que le dirá que el proceso representado por su objeto Process ha salido (normalmente o no).

Si el proceso al que tiene una referencia tiene una IU, puede usar la propiedad Respondiendo para determinar si la IU está respondiendo actualmente a la entrada del usuario o no.

También puede establecer EnableRaisingEvents y controlar el evento Exited (que se envía de forma astronómica) o llamar a WaitForExit () si desea bloquear.


fuente
0

Puede crear una instancia de Process una vez para el proceso que desea y seguir rastreando el proceso usando ese objeto de Proceso .NET (seguirá rastreando hasta que llame a Cerrar en ese objeto .NET explícitamente, incluso si el proceso que estaba rastreando ha muerto [Esto es para poder darle tiempo de cierre del proceso, también conocido como ExitTime, etc.])

Citando http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx :

Cuando sale un proceso asociado (es decir, cuando el sistema operativo lo cierra a través de una terminación normal o anormal), el sistema almacena información administrativa sobre el proceso y regresa al componente que había llamado WaitForExit. El componente Proceso puede acceder a la información, que incluye ExitTime, utilizando el controlador para el proceso salido.

Debido a que el proceso asociado ha salido, la propiedad Manejar del componente ya no apunta a un recurso de proceso existente. En cambio, el identificador solo se puede utilizar para acceder a la información del sistema operativo sobre el recurso del proceso. El sistema conoce los manejadores de los procesos salidos que no han sido liberados por los componentes del Proceso, por lo que mantiene la información ExitTime and Handle en la memoria hasta que el componente del Proceso libere específicamente los recursos. Por este motivo, cada vez que llame a Inicio para una instancia de Proceso, llame a Cerrar cuando el proceso asociado haya finalizado y ya no necesite ninguna información administrativa al respecto. Cerrar libera la memoria asignada al proceso salido.

George Birbilis
fuente
0

Probé la solución de Coincoin:
antes de procesar algún archivo, lo copio como un archivo temporal y lo abro.
Cuando termino, cierro la aplicación si aún está abierta y elimino el archivo temporal:
solo uso una variable de proceso y la verifico después:

private Process openApplication;  
private void btnOpenFile_Click(object sender, EventArgs e) {  
    ...
    // copy current file to fileCache  
    ...  
    // open fileCache with proper application
    openApplication = System.Diagnostics.Process.Start( fileCache );  
}

Más tarde cierro la aplicación:

 ...   
openApplication.Refresh(); 

// close application if it is still open       
if ( !openApplication.HasExited() ) {
    openApplication.Kill();  
}

// delete temporary file  
System.IO.File.Delete( fileCache );

Funciona (hasta ahora)

Jack Griffin
fuente
3
En openApplication.HasExited(), HasExited no es una función. La forma correcta sería openApplication.HasExited.
caiosm1005
0

A pesar de la API compatible de los marcos .Net con respecto a la verificación del proceso existente por ID de proceso, esas funciones son muy lentas. Cuesta una gran cantidad de ciclos de CPU ejecutar Process.GetProcesses () o Process.GetProcessById / Name ().

Un método mucho más rápido para verificar un proceso en ejecución por ID es usar API OpenProcess () . Si el identificador de retorno es 0, el proceso no existe. Si el identificador es diferente de 0, el proceso se está ejecutando. No hay garantía de que este método funcione al 100% en todo momento debido a un permiso.

Hao Nguyen
fuente
0

Hay muchos problemas asociados con esto, ya que otros parecen haber abordado parcialmente:

  • No se garantiza que los miembros de la instancia sean seguros para subprocesos. Lo que significa que hay condiciones de carrera que pueden ocurrir con la vida útil de la instantánea al intentar evaluar las propiedades del objeto.
  • El identificador de proceso arrojará Win32Exception para ACCESS DENIED donde no se permiten permisos para evaluar esta y otras propiedades similares.
  • Para el estado NO SE ESTÁ EJECUTANDO, también se generará una ArgumentException al intentar evaluar algunas de sus propiedades.

Si las propiedades que otros han mencionado son internas o no, aún puede obtener información de ellas a través de la reflexión si el permiso lo permite.

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

Puede pinvokear el código Win32 para Snapshot o puede usar WMI, que es más lento.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Otra opción sería OpenProcess / CloseProcess, pero aún se encontrará con los mismos problemas, con las mismas excepciones que antes.

Para WMI - OnNewEvent.Properties ["?"]:

  • "ParentProcessID"
  • "Identificacion de proceso"
  • "Nombre del proceso"
  • "SECURITY_DESCRIPTOR"
  • "ID de sesión"
  • "Sid"
  • "TIME_CREATED"
Latencia
fuente
0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

También puede usar un temporizador para verificar el proceso cada vez

berkay
fuente
3
¿No sería al revés? si longitud == 0 eso significa que no funciona?
Jay Jacobs el
La respuesta es la misma que la de Patrick Desjardins: stackoverflow.com/a/262291/7713750
Rekshino
Al revés longitud> 0 significa que se encuentran procesos.
HaseeB Mir
Esto podría tener un error, ( length == 0debería aparecer Not Working) pero aún así hace el trabajo.
Momoro