Comment puis-je savoir si un processus est en cours d'exécution?

155

Lorsque j'obtiens une référence à un System.Diagnostics.Process, comment puis-je savoir si un processus est en cours d'exécution?

reshefm
la source

Réponses:

252

C'est une façon de le faire avec le nom:

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

Vous pouvez boucler tous les processus pour obtenir l'ID pour une manipulation ultérieure:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
Patrick Desjardins
la source
Ceci est exactement ce que je cherchais. Même s'il s'agit d'un article très ancien, pourriez-vous m'expliquer comment c'est valide C #. Je n'en doute pas, je vois que ça marche, mais je n'ai jamais vu sinon sans {}.
MatthewD
4
@MatthewD: Les instructions C # if/elsequi ne font qu'une seule ligne n'ont pas besoin d'accolades pour indiquer l'instruction de bloc. Cela vaut aussi pour foreachet fordéclarations. Cela se résume au style de codage.
Hallmanac
J'ai aussi fait des recherches à ce sujet, trouvé ces informations, mais je n'ai pas vu les forinformations. Des années de développement c # .net et je n'ai jamais vu ce style. Comme on dit, "vous apprenez quelque chose de nouveau chaque jour". Merci pour le message et la réponse ..
MatthewD
3
@MatthewD ouais, cela vaut pour la plupart des langages (comme Java). C'est généralement une bonne pratique d'éviter les one-liners comme ceux-ci et de toujours mettre des accolades, car il y a toujours une chance que vous ayez à ajouter plus d'instructions à l'avenir, auquel cas les accolades seront déjà là lorsque vous en aurez besoin. Mais pour des choses comme celle-ci, si vous êtes sûr à 100% que vous n'avez besoin que d'une seule instruction, c'est correct et syntaxiquement valide.
David Mordigal
1
Si vous ne trouvez pas le processus, essayez de supprimer l'extension. (Ex: .exe)
DxTx
28

C'est le moyen le plus simple que j'ai trouvé après avoir utilisé un réflecteur. J'ai créé une méthode d'extension pour cela:

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

La Process.GetProcessById(processId)méthode appelle la ProcessManager.IsProcessRunning(processId)méthode et lance ArgumentExceptionau cas où le processus n'existe pas. Pour une raison quelconque, la ProcessManagerclasse est interne ...

reshefm
la source
C'était une très bonne réponse; cependant, vous ne devriez pas avoir via l'argument null exception (car une exception de référence null aurait été levée de toute façon et vous n'avez rien fait avec l'exception. De plus, vous obtiendrez une InvalidOperationException si vous n'avez pas appelé Start () ou vous avez appelé la méthode close (). J'ai publié une autre réponse pour expliquer ces deux situations.
Aelphaeis
16

Solution synchrone:

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


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

Solution asynchrone:

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
la source
6
Pour la première option: comment savoir si le processus a été lancé en premier lieu?
reshefm
8

reshefm a eu une assez bonne réponse; cependant, il ne tient pas compte d'une situation dans laquelle le processus n'a jamais commencé.

Voici une version modifiée de ce qu'il a publié.

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

J'ai supprimé son ArgumentNullException parce qu'il suppose en fait être une exception de référence nulle et qu'il est de toute façon levé par le système et j'ai également pris en compte la situation dans laquelle le processus n'a jamais commencé ou la méthode close () a été utilisée pour fermer le processus.

Aelphaeis
la source
Personnellement, je préférerais de beaucoup voir une ArgumentNullException lors de l'examen d'une exception journalisée qu'une NullReferenceException, car ArgumentNullException est beaucoup plus explicite sur ce qui n'a pas fonctionné.
Sean
1
@Sean Je serais normalement d'accord avec vous, mais c'est une méthode d'extension. Je pense qu'il est plus approprié de lancer une exception de pointeur nul compte tenu de la syntaxe, cela semble juste plus cohérent avec les méthodes d'appel d'objets nuls.
Aelphaeis
Cela déclenchera le gestionnaire d'événements FirstHandledException à chaque fois. Façon de spammer vos journaux là-bas mon pote.
Latence
6

Cela devrait être une seule ligne:

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

Cela dépend de la fiabilité de cette fonction. Si vous voulez savoir si l'instance de processus particulière que vous avez est toujours en cours d'exécution et disponible avec une précision de 100%, vous n'avez pas de chance. La raison en est qu'à partir de l'objet de processus géré, il n'y a que 2 façons d'identifier le processus.

Le premier est l'ID de processus. Malheureusement, les identifiants de processus ne sont pas uniques et peuvent être recyclés. La recherche d'un identifiant correspondant dans la liste des processus vous indiquera uniquement qu'un processus avec le même identifiant est en cours d'exécution, mais ce n'est pas nécessairement votre processus.

Le deuxième élément est le descripteur de processus. Il a le même problème que l'Id et il est plus difficile de travailler avec.

Si vous recherchez une fiabilité de niveau moyen, il suffit de vérifier la liste de processus actuelle pour un processus du même ID.

JaredPar
la source
1

Process.GetProcesses()est la voie à suivre. Mais vous devrez peut-être utiliser un ou plusieurs critères différents pour trouver votre processus, en fonction de la façon dont il s'exécute (c'est-à-dire en tant que service ou application normale, qu'il ait ou non une barre de titre).

Jeff Kotula
la source
Si vous mettez cette méthode en boucle, cela coûte beaucoup de cycles CPU. Je recommande d'utiliser GetProcessByName () ou GetProcessByID ().
Hao Nguyen
0

Peut-être (probablement) que je lis mal la question, mais recherchez-vous la propriété HasExited qui vous dira que le processus représenté par votre objet Process s'est terminé (normalement ou non).

Si le processus auquel vous faites référence possède une interface utilisateur, vous pouvez utiliser la propriété Responding pour déterminer si l'interface utilisateur répond actuellement à l'entrée utilisateur ou non.

Vous pouvez également définir EnableRaisingEvents et gérer l'événement Exited (qui est envoyé de manière asynchrone) ou appeler WaitForExit () si vous souhaitez bloquer.


la source
0

Vous pouvez instancier une instance de processus une fois pour le processus souhaité et continuer à suivre le processus à l'aide de cet objet Process .NET (il continuera à suivre jusqu'à ce que vous appeliez explicitement Close sur cet objet .NET, même si le processus qu'il suivait est mort [ceci afin de pouvoir vous donner l'heure de la fermeture du processus, aka ExitTime etc.])

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

Lorsqu'un processus associé se termine (c'est-à-dire lorsqu'il est arrêté par le système d'exploitation via un arrêt normal ou anormal), le système stocke les informations administratives sur le processus et retourne au composant qui avait appelé WaitForExit. Le composant Process peut ensuite accéder aux informations, qui incluent l'ExitTime, en utilisant le Handle vers le processus quitté.

Étant donné que le processus associé s'est arrêté, la propriété Handle du composant ne pointe plus vers une ressource de processus existante. Au lieu de cela, le handle peut être utilisé uniquement pour accéder aux informations du système d'exploitation sur la ressource de processus. Le système est conscient des descripteurs de processus sortis qui n'ont pas été libérés par les composants Process, il conserve donc les informations ExitTime et Handle en mémoire jusqu'à ce que le composant Process libère spécifiquement les ressources. Pour cette raison, chaque fois que vous appelez Start pour une instance de processus, appelez Close lorsque le processus associé est terminé et que vous n'avez plus besoin d'informations administratives à ce sujet. Close libère la mémoire allouée au processus terminé.

George Birbilis
la source
0

J'ai essayé la solution de Coincoin:
avant de traiter un fichier, je le copie en tant que fichier temporaire et l'ouvre.
Quand j'ai terminé, je ferme l'application si elle est toujours ouverte et
je supprime le fichier temporaire: j'utilise juste une variable Process et je la vérifie ensuite:

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

Plus tard, je ferme l'application:

 ...   
openApplication.Refresh(); 

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

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

Cela fonctionne (jusqu'à présent)

Jack Griffin
la source
3
À openApplication.HasExited(), HasExited n'est pas une fonction. La bonne façon serait openApplication.HasExited.
caiosm1005
0

Malgré l'API prise en charge par les frameworks .Net concernant la vérification des processus existants par ID de processus, ces fonctions sont très lentes. Il en coûte énormément de cycles CPU pour exécuter Process.GetProcesses () ou Process.GetProcessById / Name ().

Une méthode beaucoup plus rapide pour vérifier un processus en cours par ID consiste à utiliser l'API native OpenProcess () . Si le handle de retour est 0, le processus n'existe pas. Si le handle est différent de 0, le processus est en cours d'exécution. Il n'y a aucune garantie que cette méthode fonctionnera à 100% à tout moment grâce à l'autorisation.

Hao Nguyen
la source
0

Il existe de nombreux problèmes associés à cela, car d'autres semblent partiellement résoudre:

  • Les membres d'instance ne sont pas garantis d'être thread-safe. Cela signifie qu'il existe des conditions de concurrence qui peuvent se produire avec la durée de vie de l'instantané tout en essayant d'évaluer les propriétés de l'objet.
  • Le descripteur de processus lèvera Win32Exception pour ACCESS DENIED où les autorisations pour évaluer cela et d'autres propriétés de ce type ne sont pas autorisées.
  • Pour l'état ISN'T RUNNING, une ArgumentException sera également déclenchée lors de la tentative d'évaluation de certaines de ses propriétés.

Que les propriétés que d'autres ont mentionnées soient internes ou non, vous pouvez toujours obtenir des informations de leur part par réflexion si l'autorisation le permet.

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

Vous pouvez épingler du code Win32 pour Snapshot ou vous pouvez utiliser WMI qui est plus lent.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Une autre option serait OpenProcess / CloseProcess, mais vous rencontrerez toujours les mêmes problèmes avec les exceptions levées comme avant.

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

  • "ParentProcessID"
  • "ProcessID"
  • "Nom du processus"
  • "SECURITY_DESCRIPTOR"
  • "ID de session"
  • "Sid"
  • «TIME_CREATED»
Latence
la source
0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

vous pouvez également utiliser une minuterie pour vérifier le processus à chaque fois

Berkay
la source
3
Ne serait-ce pas l'inverse? si longueur == 0 cela signifie ne pas fonctionner?
Jay Jacobs
La réponse est la même que celle de Patrick Desjardins: stackoverflow.com/a/262291/7713750
Rekshino
Son autre chemin autour de la longueur> 0 signifie que des processus sont trouvés.
HaseeB Mir du
Cela peut avoir une erreur ( length == 0devrait s'afficher Not Working), mais le travail est toujours terminé.
Momoro le