2011-01-18 22 views
27

¿Cómo puedo verificar si mi aplicación C# Windows se está ejecutando?Comprobando si mi aplicación de Windows se está ejecutando

Sé que puedo verificar el nombre del proceso pero el nombre puede cambiarse si el exe cambia.

¿Hay alguna forma de tener una clave hash o algo para que mi aplicación sea única?

+2

Si desea sólo una instancia echar un vistazo a objeto mutex: http://stackoverflow.com/questions/819773/run-single-instance-of-an-application-using-mutex –

+0

hay un problema con el uso de Mutex de esa manera, además a veces necesito reiniciar mi aplicación usando Application.Restart que entraría en conflicto con el patrón mutex. – Stacker

+0

Así que, básicamente, su pregunta es: "¿Cómo puedo obtener todas las funciones mutex sin crear realmente un mutex"? ¿Por qué no preguntas cómo solucionar los problemas que tienes con el uso de un mutex? –

Respuesta

33
public partial class App : System.Windows.Application 
{ 
    public bool IsProcessOpen(string name) 
    { 
     foreach (Process clsProcess in Process.GetProcesses()) 
     { 
      if (clsProcess.ProcessName.Contains(name)) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 

    protected override void OnStartup(StartupEventArgs e) 
    { 
     // Get Reference to the current Process 
     Process thisProc = Process.GetCurrentProcess(); 

     if (IsProcessOpen("name of application.exe") == false) 
     { 
      //System.Windows.MessageBox.Show("Application not open!"); 
      //System.Windows.Application.Current.Shutdown(); 
     } 
     else 
     { 
      // Check how many total processes have the same name as the current one 
      if (Process.GetProcessesByName(thisProc.ProcessName).Length > 1) 
      { 
       // If ther is more than one, than it is already running. 
       System.Windows.MessageBox.Show("Application is already running."); 
       System.Windows.Application.Current.Shutdown(); 
       return; 
      } 

      base.OnStartup(e); 
     } 
    } 
+5

Esto es frágil: 'IsProcessOpen (" nombre de la aplicación.exe ")'.Un ejecutable puede haber cambiado de nombre entre el momento en que se escribe el código fuente y el momento en que se ejecuta en la máquina del usuario. Mutex no tiene este problema y no hace suposiciones sobre cómo se ejecuta la aplicación. –

+0

¿Hay alguna forma de "cambiar a" o "llevar el proceso al frente" si se está ejecutando otra instancia de la aplicación? – Agent007

+0

Enumera las ventanas del proceso y encuentra el primer plano: EnumWindows. Luego trae esta ventana al frente. – izogfif

0

Pago: What is a good pattern for using a Global Mutex in C#?

// unique id for global mutex - Global prefix means it is global to the machine 
const string mutex_id = "Global\\{B1E7934A-F688-417f-8FCB-65C3985E9E27}"; 

static void Main(string[] args) 
{ 
    using (var mutex = new Mutex(false, mutex_id)) 
    { 
     // edited by Jeremy Wiebe to add example of setting up security for multi-user usage 
     // edited by 'Marc' to work also on localized systems (don't use just "Everyone") 
     var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow); 
     var securitySettings = new MutexSecurity(); 
     securitySettings.AddAccessRule(allowEveryoneRule); 
     mutex.SetAccessControl(securitySettings); 

     //edited by acidzombie24 
     var hasHandle = false; 
     try 
     { 
      try 
      { 
       // note, you may want to time out here instead of waiting forever 
       //edited by acidzombie24 
       //mutex.WaitOne(Timeout.Infinite, false); 
       hasHandle = mutex.WaitOne(5000, false); 
       if (hasHandle == false) return;//another instance exist 
      } 
      catch (AbandonedMutexException) 
      { 
       // Log the fact the mutex was abandoned in another process, it will still get aquired 
      } 

      // Perform your work here. 
     } 
     finally 
     { 
      //edit by acidzombie24, added if statemnet 
      if (hasHandle) 
       mutex.ReleaseMutex(); 
     } 
    } 
} 
+1

-1: como dice el OP, sabe que puede verificar el nombre del proceso, quiere saber qué hacer si se cambia el nombre de la aplicación – djeeg

+0

@djeeg: ¿Leímos la misma pregunta? ¿Puede indicar el punto donde op dice * que quiere saber qué hacer si se cambia el nombre de la aplicación *? –

+4

línea número 2: "Sé que puedo verificar el nombre del proceso, pero el nombre puede cambiarse si el exe cambió". – djeeg

0

Yo manera muy simplista supongo que sería, para cada exe que se está ejecutando, se puede crear/abrir un archivo en el disco en una ubicación conocida (c: \ temp) con un nombre especial " yourapp.lock "y luego solo cuenta cuántos de esos hay.

Una forma más difícil sería abrir algunas comunicaciones entre procesos, por lo que con la lista de procesos podría interrogar cada proceso para ver si era su aplicación.

+0

no es aceptable ya que no creo que deba solicitar acceso para escribir directamente en el disco, y eso traería muchos problemas, pero gracias – Stacker

-1

Introduzca un guid en los datos de su conjunto. Agregue esta guía al registro. Ingrese una clave reg donde la aplicación lea su propio nombre y agregue el nombre como valor allí.

El otro observador de tareas lee la clave de registro y conoce el nombre de la aplicación.

+0

Después de la falla de la aplicación, el reinicio no lo salvará de 'duplicado instancia 'mensaje. No use el registro, tenga cuidado con la salida no limpia cuando se olvide de eliminar este valor – filimonic

+0

Bueno, usar el registro es una opción, lo mismo que hace cuando escribe un archivo .pid en algún lugar del sistema de archivos. Si la aplicación falla, debe limpiar este desastre. Lo mismo con el registro, el código debe manejar esto. – YvesR

18

La forma recomendada es usar un Mutex. Se puede extraer una muestra aquí: http://www.codeproject.com/KB/cs/singleinstance.aspx

En concreto el código:


     /// 
     /// check if given exe alread running or not 
     /// 
     /// returns true if already running 
     private static bool IsAlreadyRunning() 
     { 
      string strLoc = Assembly.GetExecutingAssembly().Location; 
      FileSystemInfo fileInfo = new FileInfo(strLoc); 
      string sExeName = fileInfo.Name; 
      bool bCreatedNew; 

      Mutex mutex = new Mutex(true, "Global\\"+sExeName, out bCreatedNew); 
      if (bCreatedNew) 
       mutex.ReleaseMutex(); 

      return !bCreatedNew; 
     }
+1

Esto funcionará si la aplicación de comprobación es la misma que la aplicación en ejecución. – basarat

+4

Funcionará con cualquier aplicación si usa un GUID en lugar de 'sExeName'. –

0

necesita una manera de decir que "estoy corriendo" de la aplicación,

1) abrir una WCF ping servicio 2) escribir en el registro/archivo en el inicio y eliminar al apagar 3) crear un Mutex

... prefiero la pieza WCF porque no puede limpiar el archivo/registro correctamente y Mutex parece tener sus propios problemas

1

Para mi aplicación WPF he definido la id de la aplicación global y uso el semáforo para manejarla.

public partial class App : Application 
{  
    private const string AppId = "c1d3cdb1-51ad-4c3a-bdb2-686f7dd10155"; 

    //Passing name associates this sempahore system wide with this name 
    private readonly Semaphore instancesAllowed = new Semaphore(1, 1, AppId); 

    private bool WasRunning { set; get; } 

    private void OnExit(object sender, ExitEventArgs e) 
    { 
     //Decrement the count if app was running 
     if (this.WasRunning) 
     { 
      this.instancesAllowed.Release(); 
     } 
    } 

    private void OnStartup(object sender, StartupEventArgs e) 
    { 
     //See if application is already running on the system 
     if (this.instancesAllowed.WaitOne(1000)) 
     { 
      new MainWindow().Show(); 
      this.WasRunning = true; 
      return; 
     } 

     //Display 
     MessageBox.Show("An instance is already running"); 

     //Exit out otherwise 
     this.Shutdown(); 
    } 
} 
Cuestiones relacionadas