Ejecutar solo una instancia (C#)


Para prevenir que sea ejecutada más de una instancia de una aplicación Windows o WPF con C# (incluso cuando se realice una copia del archivo ejecutable) podríamos utilizar algo como lo siguiente:

private static bool FirstInstance
{
    get
    {
        bool created;
        string name = Assembly.GetEntryAssembly().FullName;
        // created will be True if the current thread creates and owns the mutex.
        // Otherwise created will be False if a previous instance already exists.
        Mutex mutex = new Mutex(true, name, out created);
        return created;
    }
}

Nota: Para una mayor certidumbre se podría hacer uso de una cadena GUID en ‘name’.

Cuando la primera instancia crea el Mutex pasa a ser su propietario y la variable created se le asigna el valor True. Cuando una nueva instancia se ejecuta intenta tomar posesión del Mutex, pero dado que solo un hilo puede ser propietario de mismo (y primera instancia ya lo es) la nueva no puede tomar posesión del Mutex, por lo cual el valor de created permanece en False, misma que se regresa para indicar si existe (o no) una instancia de la aplicación en ejecución.

Así pues la propiedad FirstInstance la colocaremos en la clase principal de nuestra aplicación WinForm (“Program.cs”) o bien de nuestra aplicación WPF (“App.xaml.cs”) para ser utilizada según corresponda:

WinForm (Program.cs):

[STAThread]
static void Main()
{
    if (FirstInstance)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
    else
    {
        MessageBox.Show("Application is already running.");
        Application.Exit();
    }
}

WPF (App.xaml.cs):

protected override void OnStartup(StartupEventArgs e)
{
    if (FirstInstance)
        base.OnStartup(e);
    else
    {
        MessageBox.Show("Application is already running.");
        Application.Current.Shutdown();
    }
}

Adicionalmente, usando la clase System.Diagnostics.Process se puede obtener la ventana principal y activarla mediante una llamada a la API SetForegroundWindow, tal como se muestra en: Comprobar si hay una instancia previa de nuestra aplicación, escrito en VB.NET por Eduardo Morcillo.

 

Usando WindowsFormsApplicationBase de VB

Otra opción sería recurrir al Modelo de Aplicaciones de Visual Basic (aka My) para crear un gestor de instancias mediante el WindowsFormsApplicationBase (el cual además nos ofrece el evento OnStartupNextInstance) tal como se muestra a continuación para Windows Forms con C#:

Nota: No es necesario traducir el siguiente código para una aplicación Windows Forms con VB. En ese caso solo basta seguir las instrucciones de la segunda mitad del post: Ejecutar solamente una instancia (VB 2005+).

Program.cs

using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;

namespace WinForm1
{
    public static class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            SingleInstanceManager manager = new SingleInstanceManager();
            manager.Run(args);
        }
    }

    // Using VB bits to detect single instances and process accordingly:
    //  * OnStartup is fired when the first instance loads
    //  * OnStartupNextInstance is fired when the application is re-run again
    //    NOTE: it is redirected to this instance thanks to IsSingleInstance
    public class SingleInstanceManager : WindowsFormsApplicationBase
    {
        SingleInstanceApplication app;

        public SingleInstanceManager()
        {
            this.IsSingleInstance = true;
        }

        protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
        {
            // First time app is launched
            app = new SingleInstanceApplication();
            app.Run();
            return false;
        }

        protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
        {
            // Subsequent launches            
            base.OnStartupNextInstance(eventArgs);
            app.Activate();
        }
    }

    public class SingleInstanceApplication
    {
        protected Form mainForm;

        public void Activate()
        {
            // Reactivate application's main window            
            mainForm.Activate();
        }    

        public void Run()
        {
            Application.Run(mainForm = new Form1());
        }
    }
}

Para un ejemplo con WPF usando WindowsFormsApplicationBase tanto con VB como con C# ver: WPF: Single Instance Detection Sample.

Acerca de Willy Mejia

Developer, Techie, Human... http://about.me/willyxoft
Esta entrada fue publicada en .NET y etiquetada , . Guarda el enlace permanente.

9 respuestas a Ejecutar solo una instancia (C#)

  1. johnny IV dijo:

    chévere el artículo, resuelve un problema puntual frecuente, saludos

  2. Sanukode dijo:

    Genial esto me servira mucho jajajjaJAJAJAJA AJAJAJ @_@ WAJAJAJAJ SIIII !!!!

  3. Yelinna dijo:

    Genial artículo!!
    Un Detallito: para usar las clases Mutex y Assembly hay que importar los siguientes espacios de nombres respectivamente:
    using System.Threading;
    using System.Reflection;

  4. JOrge dijo:

    Excelente aporte me sirvió de mucho. Me gustaría saber si me podrías ayudar en actualizaciones automáticas con click one y visual estudio(c#)

  5. wjvelasquez dijo:

    Buen dia.
    TE escribo para ver si me puedes ayudar en una duda.
    Abro una ventana desde otra haciendo la instanciacion
    Windows win = new Windows();
    win.Show();

    El detalle es que quiero que solo se abra una sola ventana. Que al darle al boton no cree una nueva instancia.

    Como lo puedo hacer.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s