2008-09-18 22 views

Respuesta

118

Usar Mutex. Uno de los ejemplos anteriores que usan GetProcessByName tiene muchas salvedades. Aquí es un buen artículo sobre el tema:

http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx

[STAThread] 
static void Main() 
{ 
    using(Mutex mutex = new Mutex(false, "Global\\" + appGuid)) 
    { 
     if(!mutex.WaitOne(0, false)) 
     { 
     MessageBox.Show("Instance already running"); 
     return; 
     } 

     Application.Run(new Form1()); 
    } 
} 

private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9"; 
+1

El uso de un mutex también funciona para el código nonnet también (aunque la sintaxis podría variar) – crashmstr

+1

Este código debe manejar agandonedmutexexceptions –

+8

Aquí hay una versión un poco más completa, con algunos buenos comentarios: http://stackoverflow.com/ questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c/229567 –

3

En este artículo se explica simplemente cómo se puede crear una aplicación de Windows con el control del número de sus instancias o ejecutar sólo sola instancia. Esta es una necesidad muy típica de una aplicación comercial. Ya hay muchas otras soluciones posibles para controlar esto.

http://www.openwinforms.com/single_instance_application.html

8

Hanselman tiene a post sobre el uso de la clase WinFormsApplicationBase del conjunto Microsoft.VisualBasic para hacer esto.

+0

He estado usando que un par de años, pero ahora estoy buscando para cambiar a una solución basada en la exclusión mutua. Tengo clientes que informan problemas con esto y sospecho que está usando Remoting para hacerlo. –

1

Normalmente se hace con un objeto mutex llamado (uso de las nuevas mutex ("el nombre de la aplicación", true) y compruebe el valor de retorno), pero también hay algunas clases de apoyo en Microsoft.VisualBasic. dll que can do it for you.

17
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1) 
{ 
    AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn); 
    return; 
} 
+1

Creo que debería ver esto: http: //odetocode.com/blogs/scott/archive/2004/08/20/the-misunderstood-mutex.aspx – SubmarineX

+0

@SubmarineX ¿Cómo está seguro de que este artículo es correcto? todavía es controversia entre mutex y http://www.codeproject.com/Articles/4975/Fly-Create-A-Single-Instance-Application –

+0

Increíble Simplemente perfecto gracias por su tiempo y esfuerzos –

4

mediante Visual Studio 2005 o 2008, cuando se crea un proyecto para un ejecutable, en las ventanas de propiedades dentro del panel "Aplicación" hay una casilla de verificación denominada “Hacer aplicación de instancia única” que puede activar para convertir la aplicación en una aplicación de instancia única.

Aquí hay una captura de la ventana de la que estoy hablando: Este es un proyecto de aplicación de Windows Visual Studio 2008.

+3

Busqué esta casilla de verificación que mencionas para mi aplicación C#/WPF, y no hay ninguna. – HappyNomad

+3

No lo veo en mis propiedades de la aplicación VS 2008 C#/WinForms tampoco. –

+0

No en VS2005 también. Debe mencionar el viejo estudio de VB. – nawfal

6

Parece que hay 3 técnicas fundamentales que se han propuesto hasta ahora.

  1. derivados de la clase Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase y establezca la propiedad IsSingleInstance true. (Creo que una advertencia aquí es que esto no funcionará con las aplicaciones de WPF, ¿o sí?)
  2. Use un mutex con nombre y compruebe si ya se ha creado.
  3. Obtenga una lista de procesos en ejecución y compare los nombres de los procesos. (Esto tiene la salvedad de requerir que el nombre de su proceso sea único en relación con cualquier otro proceso que se ejecute en la máquina de un usuario determinado.)

¿Alguna advertencia que me he perdido?

+3

No creo que 3 sea muy eficiente. Yo votaría por el Mutex, lo usé sin problemas muchas veces. Nunca he usado el elemento 1, no estoy seguro de cómo vuela cuando estás en C#. – typemismatch

+2

La opción 1 aún funciona con WPF; es algo más complicada. http://msdn.microsoft.com/en-us/library/ms771662.aspx –

+1

¿Cómo funciona 2 con usuarios de multilínea en un servidor de terminal? – SillyMonkey

15

Aquí está el código que necesita para asegurarse de que solo se está ejecutando una instancia. Este es el método de usar un mutex con nombre.

public class Program 
{ 
    static System.Threading.Mutex singleton = new Mutex(true, "My App Name"); 

    static void Main(string[] args) 
    { 
     if (!singleton.WaitOne(TimeSpan.Zero, true)) 
     { 
      //there is already another instance running! 
      Application.Exit(); 
     } 
    } 
} 
+2

Para una aplicación WPF use Application.Current.Shutdown(); Este método funciona como un encanto. Gracias Terrapin. – Jeff

+0

Aquí lo principal es hacer mutex estático. Al igual que en el otro caso, GC lo recogerá. – Oleksii

4

¡Utilice VB.NET! No: realmente;)

utilizando Microsoft.VisualBasic.ApplicationServices;

WindowsFormsApplicationBase de VB.Net le proporciona una propiedad "SingleInstace", que determina otras instancias y permite que solo se ejecute una instancia.

1
[STAThread] 
static void Main()     // args are OK here, of course 
{ 
    bool ok; 
    m = new System.Threading.Mutex(true, "YourNameHere", out ok); 

    if (! ok) 
    { 
     MessageBox.Show("Another instance is already running."); 
     return; 
    } 

    Application.Run(new Form1()); // or whatever was there 

    GC.KeepAlive(m);    // important! 
} 

Desde: Ensuring a single instance of .NET Application

y: Single Instance Application Mutex

La misma respuesta que @Smink y @Imjustpondering con una peculiaridad:

Jon Skeet's FAQ on C# para averiguar por qué GC.KeepAlive importa

+0

-1, porque no puede usar un bloque de uso con el mutex, lo que haría que KeepAlive sea superfluo. Y sí, creo que John Skeet lo malinterpretó. No explica por qué sería incorrecto deshacerse del mutex en este caso. –

2

Este es el código para VB.Net

Private Shared Sub Main() 
    Using mutex As New Mutex(False, appGuid) 
     If Not mutex.WaitOne(0, False) Then 
       MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error) 
      Return 
     End If 

     Application.Run(New Form1()) 
    End Using 
End Sub 

Este es el código para C#

private static void Main() 
{ 
    using (Mutex mutex = new Mutex(false, appGuid)) { 
     if (!mutex.WaitOne(0, false)) { 
      MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      return; 
     } 

     Application.Run(new Form1()); 
    } 
} 
1

(Nota: esta es una solución de diversión! Funciona pero usa un diseño malo GDI + para lograr esto.)

Pon una imagen con tu aplicación y cárgala al iniciar. Sosténgalo hasta que la aplicación salga. El usuario no podrá iniciar una segunda instancia. (Por supuesto, la solución es mucho más limpio mutex)

private static Bitmap randomName = new Bitmap("my_image.jpg"); 
5

he intentado todas las soluciones aquí y nada funcionó en mi proyecto de C# .NET 4.0. Con la esperanza de ayudar a alguien aquí la solución que funcionó para mí:

Como principales variables de clase:

private static string appGuid = "WRITE AN UNIQUE GUID HERE"; 
private static Mutex mutex; 

Cuando es necesario comprobar si la aplicación ya está en ejecución:

bool mutexCreated; 
mutex = new Mutex(true, "Global\\" + appGuid, out mutexCreated); 
if (mutexCreated) 
    mutex.ReleaseMutex(); 

if (!mutexCreated) 
{ 
    //App is already running, close this! 
    Environment.Exit(0); //i used this because its a console app 
} 

que necesitaba para cerrar otras istancias solo con algunas condiciones, esto funcionó bien para mi propósito

+0

Bien, tuviste éxito. Gracias hombre. –

+0

No necesita adquirir realmente el mutex y liberarlo. Todo lo que necesita saber es si otra aplicación ya creó el objeto (es decir, su recuento de referencia del kernel> = 1). –

1

Esto funcionó para mí en C# puro. el try/catch es cuando posiblemente un proceso en la lista sale durante su ciclo.

using System.Diagnostics; 
.... 
[STAThread] 
static void Main() 
{ 
... 
     int procCount = 0; 
     foreach (Process pp in Process.GetProcesses()) 
     { 
      try 
      { 
       if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0) 
       { 
        procCount++;       
        if(procCount > 1) { 
         Application.Exit(); 
         return; 
        } 
       } 
      } 
      catch { } 
     } 
     Application.Run(new Form1()); 
} 
2

Después de probar múltiples soluciones, la pregunta. Terminé usando el ejemplo de WPF aquí: http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/

public partial class App : Application 
{ 
    private static Mutex _mutex = null; 

    protected override void OnStartup(StartupEventArgs e) 
    { 
     const string appName = "MyAppName"; 
     bool createdNew; 

     _mutex = new Mutex(true, appName, out createdNew); 

     if (!createdNew) 
     { 
      //app is already running! Exiting the application 
      Application.Current.Shutdown(); 
     } 

    }   
} 

En App.xaml:

x:Class="*YourNameSpace*.App" 
StartupUri="MainWindow.xaml" 
Startup="App_Startup" 
3

1 - Crear una referencia en el programa.CS ->

using System.Diagnostics; 

2 - Poner en void Main() como la primera línea de código ->

if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1) 
       return; 

Eso es todo.

+0

¿Cuál es la diferencia de esto a 'Mutex'? Hay una trampa? –

2

Simplemente usando un StreamWriter, ¿qué tal esto?

System.IO.File.StreamWriter OpenFlag = null; //globally 

y

try 
{ 
    OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning"); 
} 
catch (System.IO.IOException) //file in use 
{ 
    Environment.Exit(0); 
} 
0

Asegúrese de considerar la seguridad al restringir una aplicación a una sola instancia:

Artículo completo: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813

Estamos utilizando un mutex llamado con un nombre fijo para detectar si otra copia o f el programa se está ejecutando. Pero eso también significa que un atacante puede crear el mutex primero, impidiendo así que nuestro programa se ejecute. ¿Cómo puedo evitar este tipo de denegación de servicio ataque?

...

Si el atacante está en ejecución en el mismo contexto de seguridad como el programa de es (o sería) que se ejecuta en, entonces no hay nada que puedas hacer. Sea cual sea el "saludo secreto" que se le ocurra para determinar si se está ejecutando otra copia de su programa , el atacante puede imitarlo. Dado que se ejecuta en el contexto de seguridad correcto, puede hacer cualquier cosa que el programa "real" pueda hacer.

...

Es evidente que no puede protegerse de un atacante ejecutar en el mismo privilegio de seguridad, pero todavía se puede protegerse contra atacantes no privilegiados funcionando a otros privilegios de seguridad.

Pruebe a establecer una DACL en el mutex, aquí es la forma en .NET: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx

Cuestiones relacionadas