Hoy he aprendido una nueva forma de evitar que se ejecute más de una instancia de tu software usando un mutex con nombre en .NET. El código en este caso es para VB.NET pero como sabéis es trivial pasarlo a C#.
Hasta ahora, para evitar múltiples instancias utilizaba la función Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName). La idea consiste en comprobar si existe algún proceso con el nombre de tu programa ejecutándose en ese momento, y en caso afirmativo, terminar la ejecución de la nueva instancia que se intenta iniciar. A primera vista (puede que haya más), comentaré un par de puntos débiles de este método. En primer lugar, si el usuario cambia el nombre del ejecutable, adiós protección, el nombre del proceso cambia. Y en segundo lugar, si pretendes ejecutar tu programa en Windows Vista, la llamada a la función requiere permisos de administrador, y si no los tiene el programa (Botón derecho, ejecutar como administrador, por ejemplo) saltará una excepción bastante fea. Es una pena que tengamos que obligar al usuario a ejecutar nuestro programa en un nivel de confianza superior cuando realmente no es necesario. ¿La solución? Un mutex con nombre.
Un mutex con nombre es un objeto global (Objeto Kernel) que puede ser verificado desde cualquier programa. La idea consiste en comprobar si somos el “owner” de dicho mutex. Si somos la primera instancia, como lo estaremos creando seremos en efecto los propietarios. Cualquier intento de iniciar otra instancia de la aplicación, podrá comprobar que ese mutex ya está creado y que por lo tanto, otra instancia de la aplicación se está ejecutando.
Os copio aquí el código en VB.Net. No le he pasado el FxCop asi que es posible que no se ajuste perfectamente a la guía de diseño de clases de Microsoft para .Net.
Public Class MutexInstancia Private Shared m_EsPrimeraInstancia As Boolean = False Private Shared m_Mutex As System.Threading.Mutex = Nothing Public Shared ReadOnly Property ExistePrograma() As Boolean Get If m_Mutex Is Nothing Then m_Mutex = New System.Threading.Mutex(True, "MiMutexGlobal", m_EsPrimeraInstancia) End If Return Not m_EsPrimeraInstancia End Get End Property Private Sub New() End Sub End Class
If MutexInstancia.ExistePrograma Then MessageBox.Show("El programa ya está abierto.", "Atención", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) End End If
Como podéis ver la clase es un simple contenedor de métodos estáticos, así que sacar la funcionalidad de aquí e incorporarla en otro lado si lo necesitáis. Eso sí, aseguraros de que el Mutex está vivo (No es null) durante toda la ejecución de la aplicación. Por último:
No sé si a alguien le será de utilidad, pero quien sabe.
De lectura recomendada. Me ha gustado mucho la temática…¿Cómo reconocer a los buenos desarrolladores?
También via VariableNotFound encontré este interesante post sobre las pruebas de nivel para trabajar en Mono.
Y ya en otro orden de cosas, los 7 hábitos de las personas altamente innovadoras:
1. Trabajar duro
2. Evitar inhibiciones
3. Asumir riesgos, cometer errores
4. Escapar
5. Anotar las ideas
6. Encontrar patrones y combinarlos
7. Ser curioso
Un saludo


