Permitir sólo una instancia en ejecución de una aplicación (How to run a single instance of an application)

Filed under .NET Development

Para esto, pueden utilizar la siguiente clase:

using System;
using System.Threading;

namespace NicolasFerreira.Utilities
{
    //* **************************************************
    //* Author: Nicolás Ferreira (http://nicolasferreira.com/)
    //* **************************************************
    /// <summary>
    /// This class uses EventWaitHandle. It lets you know if another instance of your application is already running. Also, if there is already a running instance of your application and someone try to start another, the main one will be notified.
    /// </summary>
    public static class SingleInstanceApplication
    {
        private static EventWaitHandle _EventWaitHandle;
        private static object _lock = new object();
        private static bool _Opened;
        private static Thread _WaitOneHandlerThread;
        private static bool _RaiseAnotherTriedToRunEvent;
        public delegate void AnotherTriedToRunEventHandler();
        public static event AnotherTriedToRunEventHandler AnotherTriedToRun;
        /// <summary>
        /// Gets a value that indicates whether single instance application monitor is open.
        /// </summary>
        public static bool Opened
        {
            get
            {
                return _Opened;
            }
        }
        /// <summary>
        /// Opens the single instance application monitor.
        /// </summary>
        /// <param name="uniqueInstanceName">A name that identifies your application as unique.</param>
        /// <returns>true if the system-wide EventWaitHandle could be created (the calling instance is single). false if the calling instance should terminate.</returns>
        public static bool Open(string uniqueInstanceName)
        {
            return Open(uniqueInstanceName, false);
        }
        /// <param name="local">true if each terminal server session can run an instance of your application. Otherwise, false.</param>
        public static bool Open(string uniqueInstanceName, bool local)
        {
            if (string.IsNullOrEmpty(uniqueInstanceName))
                throw new ArgumentException("uniqueInstanceName cannot be blank.");
            else if (_Opened)
                throw new InvalidOperationException("Single instance application monitor is open.");
            lock (_lock)
            {
                bool createdNew;
                _EventWaitHandle = new EventWaitHandle(
                    false,
                    EventResetMode.AutoReset,
                    string.Concat(local ? "Local\\" : "Global\\", uniqueInstanceName),
                    out createdNew);
                if (createdNew)
                {
                    _Opened = true;
                    _RaiseAnotherTriedToRunEvent = true;
                    _WaitOneHandlerThread = new Thread(new ThreadStart(EventWaitHandleHandler));
                    _WaitOneHandlerThread.Start();
                }
                else
                {
                    _Opened = false;
                    _RaiseAnotherTriedToRunEvent = false;
                    _EventWaitHandle.Set();
                    _EventWaitHandle.Close();
                    _EventWaitHandle = null;
                }
            }
            return _Opened;
        }
        private static void EventWaitHandleHandler()
        {
            if (_EventWaitHandle != null)
            {
                while (_Opened)
                {
                    _EventWaitHandle.WaitOne();
                    if ((_RaiseAnotherTriedToRunEvent) && (AnotherTriedToRun != null))
                        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
                        {
                            AnotherTriedToRun();
                        }));
                }
            }
        }
        /// <summary>
        /// Closes the single instance application monitor and frees resources.
        /// </summary>
        public static void Close()
        {
            lock (_lock)
            {
                if (!_Opened)
                    throw new InvalidOperationException("Single instance application monitor is not open.");
                _Opened = false;
                _RaiseAnotherTriedToRunEvent = false;
                _EventWaitHandle.Set();
                _EventWaitHandle.Close();
                _EventWaitHandle = null;
            }
        }
    }
}

Ejemplo en una aplicación consola:

        static void Main(string[] args)
        {
            SingleInstanceApplication.AnotherTriedToRun += new SingleInstanceApplication.AnotherTriedToRunEventHandler(SingleInstanceApplication_AnotherTriedToRun);
            if (!SingleInstanceApplication.Open("{63BAA9C4-849C-4b4a-8B9C-FC1D640F09E2}"))
            {
                Console.WriteLine("Another instance of this application is currently running.");
            }
            else
            {
                Console.WriteLine("This is the main instance of your application.");
                Console.ReadLine();
                if (SingleInstanceApplication.Opened)
                {
                    SingleInstanceApplication.Close();
                }
            }
        }
        static void SingleInstanceApplication_AnotherTriedToRun()
        {
            Console.WriteLine(string.Format("{0}: Another instance of this application tried to run.",
                DateTime.Now.ToString()));
        }

Ejemplo en una aplicación Windows Forms:

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            if (SingleInstanceApplication.Open("{4C8C7928-55FD-45e8-A13E-895C5EE4D0C3}"))
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
                if (SingleInstanceApplication.Opened)
                {
                    SingleInstanceApplication.Close();
                }
            }
            else
            {
                MessageBox.Show("Another instance of this application is currently running.");
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            SingleInstanceApplication.AnotherTriedToRun += new SingleInstanceApplication.AnotherTriedToRunEventHandler(SingleInstanceApplication_AnotherTriedToRun);
        }

        void SingleInstanceApplication_AnotherTriedToRun()
        {
            MessageBox.Show(string.Format("{0}: Another instance of this application tried to run.",
                DateTime.Now.ToString()));
        }

Descargar el código.

One Comment

  1. Jorge Garcell
    Posted March 10, 2009 at 10:28 am | Permalink

    Excellent, it worked fine, soft and easy.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*