viernes, 29 de mayo de 2009

Limitar la cantidad de instancias de una aplicación con VB.NET

He aquí una clase para limitar la cantidad de instancias que pueden correrse de una aplicación.

- Funciona si se cambia el nombre del ejecutable o si se ejecuta desde diferentes ejecutables.
- Funciona si la aplicación se cierra de forma anormal.
- Es configurable por Máquina o por Sesión (útil para limitar por usuario cuando se utilizan Terminal Services).

'The-Pirat 2009
Imports System.Threading

''' <summary>
''' Enumerador para inicar el tipo de bloqueo
''' </summary>
Public Enum eTipo As Integer
  POR_SESION = 0
  [GLOBAL] = 1
End Enum

''' <summary>
''' Clase para implementar un máximo M de instancias de la aplicación por cada usuario o por cada máquina
''' </summary>
Public Class InstanciaPrevia
  Private Shared _mutex As Mutex
  ''' <summary>
  ''' Función que devuelve TRUE si ya se rebasó el límite de instancias del programa corriendo
  ''' </summary>
  ''' <param name="Tipo">Tipo del bloqueo. Por usuario o global.</param>
  Public Shared Function RebasaLimite(ByVal Tipo As eTipo, ByVal Max As Integer) As Boolean
    Dim NombreAssembly As String = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
    For i As Integer = 0 To Max - 1
      If CrearMutex(NombreAssembly, i, Tipo) Then
        Return False
      End If
    Next
    Return True
  End Function

  ''' <summary>
  ''' Intenta crear un nuevo mutex, devuelve true si NO existía previamente y se creó ahora
  ''' </summary>
  Private Shared Function CrearMutex(ByVal Nombre As String, ByVal Index As Integer, ByVal Tipo As eTipo) As Boolean
    'Nombre del mutex según Tipo (visibilidad)
    Dim mutexName As String = If(Tipo = eTipo.GLOBAL, "Global\", "Local\") & Nombre & Index.ToString()
    Dim newMutexCreated As Boolean
    Try
      'Abro/Creo mutex con nombre único
      _mutex = New System.Threading.Mutex(False, mutexName, newMutexCreated)
      If Not newMutexCreated Then
        _mutex.Close()
      End If
      Return newMutexCreated
    Catch ex As Exception
      Return False
    End Try
  End Function
End Class


La forma de utilizar esta clase es:


'Sólo se corre la aplicación si no se rebasa el límite, en este caso, de 3 instancias
Sub main()
  If Not InstanciaPrevia.RebasaLimite(eTipo.GLOBAL, 3) Then
    Application.Run(Form1)
  Else
    MessageBox.Show("Se pasó del límite")
    Application.Exit()
  End If
End Sub

Puedes bajar este ejemplo aquí



Suerte