2008-09-09 11 views
24

J'ai une application winforms C# qui a besoin de démarrer un exe externe de temps en temps, mais je ne souhaite pas démarrer un autre processus si un est déjà en cours d'exécution, mais plutôt passer à celui-ci.Comment puis-je savoir si un processus est déjà en cours d'exécution avec C#?

Alors, comment en C# serait-je ainsi dans l'exemple ci-dessous?

using System.Diagnostics; 

... 

Process foo = new Process(); 

foo.StartInfo.FileName = @"C:\bar\foo.exe"; 
foo.StartInfo.Arguments = "Username Password"; 

bool isRunning = //TODO: Check to see if process foo.exe is already running 


if (isRunning) 
{ 
    //TODO: Switch to foo.exe process 
} 
else 
{ 
    foo.Start(); 
} 

Répondre

29

Cela devrait le faire pour vous.

Check Processes

//Namespaces we need to use 
using System.Diagnostics; 

public bool IsProcessOpen(string name) 
{ 
    //here we're going to get a list of all running processes on 
    //the computer 
    foreach (Process clsProcess in Process.GetProcesses()) { 
     //now we're going to see if any of the running processes 
     //match the currently running processes. Be sure to not 
     //add the .exe to the name you provide, i.e: NOTEPAD, 
     //not NOTEPAD.EXE or false is always returned even if 
     //notepad is running. 
     //Remember, if you have the process running more than once, 
     //say IE open 4 times the loop thr way it is now will close all 4, 
     //if you want it to just close the first one it finds 
     //then add a return; after the Kill 
     if (clsProcess.ProcessName.Contains(name)) 
     { 
      //if the process is found to be running then we 
      //return a true 
      return true; 
     } 
    } 
    //otherwise we return a false 
    return false; 
} 

 
+0

Ne serait-il pas préférable d'utiliser Equals à la place de contains, votre commentaire ne reflète pas comment il se comportera.
Si je spesifc nom pour être "notepad" son va trouver notepad.exe et tout autre processus qui a le bloc-notes dans son nom. – EKS

+0

La ligne 'foreach (Processus clsProcess dans Process.GetProcesses) {' devrait lire 'foreach (Processus clsProcess dans Process.GetProcesses() {' –

+0

@John M - Bons yeux! Fixé – DaveK

1

Je pense que la réponse complète à votre problème nécessite de comprendre ce qui se passe lorsque votre application détermine qu'une instance de foo.exe est déjà en cours d'exécution i.e qu'est-ce que '// TODO: Passer au processus foo.exe'?

6

J'ai utilisé la fonction AppActivate dans l'environnement d'exécution VB pour activer un processus existant. Vous devrez importer la DLL Microsoft.VisualBasic dans le projet C#.

using System; 
using System.Diagnostics; 
using Microsoft.VisualBasic; 

namespace ConsoleApplication3 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Process[] proc = Process.GetProcessesByName("notepad"); 
      Interaction.AppActivate(proc[0].MainWindowTitle); 
     } 
    } 
} 
21

Vous pouvez utiliser LINQ ainsi,

var processExists = Process.GetProcesses().Any(p => p.ProcessName.Contains("<your process name>")); 
1

Dans un projet passé, je devais éviter de multiples exécution d'un processus, alors j'ai ajouté un code dans la section init de ce processus qui crée un mutex nommé. Ce mutext a été créé et acquis avant de continuer le reste du processus. Si le processus peut créer le mutex et l'acquérir, c'est le premier qui s'exécute. Si un autre processus contrôle déjà le mutex, alors celui qui échoue n'est pas le premier, donc il sort immédiatement. J'essayais juste d'empêcher une deuxième instance de s'exécuter, en raison de dépendances sur des interfaces matérielles spécifiques. En fonction de ce dont vous avez besoin avec cette ligne «passer à», vous pouvez avoir besoin d'une solution plus spécifique, telle qu'un identifiant de processus ou un handle.

En outre, j'ai eu l'accès de code source au processus que j'essayais de démarrer. Si vous ne pouvez pas modifier le code, l'ajout du mutex n'est évidemment pas une option.

0

Mnebuerquo a écrit:

Aussi, j'avais accès au code source au processus je tentais de commencer. Si vous ne pouvez pas modifier le code, l'ajout du mutex n'est évidemment pas une option.

Je n'ai pas accès au code source pour le processus que je veux courir.

J'ai fini par utiliser la MainWindowHandle proccess pour passer au processus une fois que je l'ai trouvé est alread fonctionnement:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
public static extern bool SetForegroundWindow(IntPtr hWnd); 
1

Deux préoccupations à garder à l'esprit:

  1. Votre exemple impliqué placer un mot de passe sur une ligne de commande. Que la représentation en clair d'un secret pourrait être une faille de sécurité.

  2. Lors de l'énumération des processus, demandez vous-même les processus que vous souhaitez vraiment énumérer. Tous les utilisateurs, ou juste l'utilisateur actuel? Que se passe-t-il si l'utilisateur actuel est connecté deux fois (deux postes de travail )?

2

J'ai découvert que Mutex ne fonctionne pas comme dans l'application Console. L'utilisation de WMI pour interroger les processus visibles à l'aide de la fenêtre Gestionnaire des tâches résoudra donc votre problème.

Utilisez quelque chose comme ceci:

static bool isStillRunning() { 
    string processName = Process.GetCurrentProcess().MainModule.ModuleName; 
    ManagementObjectSearcher mos = new ManagementObjectSearcher(); 
    mos.Query.QueryString = @"SELECT * FROM Win32_Process WHERE Name = '" + processName + @"'"; 
    if (mos.Get().Count > 1) 
    { 
     return true; 
    } 
    else 
     return false; 
} 

NOTE: Ajouter référence d'assemblage "System.Management" pour activer l'IntelliSense type.

+0

Cette approche permet l'inspection de la ligne de commande args (mo [ "Ligne de commande"]); – crokusek