Search code examples
.netvb.netwinformsmutexsingle-instance

Limit the maximum process-instances by counting the amount of Mutexes?


I've written the next code that prevents multi-instancing via MUTEX, but I would like to extend its funcionality by allowing to set the maximum number of allowed instances, so I should could decide whether I want to allow only a single instance or a multi-instace of only 3 instances (for example).

I've tried to figure out how to count the amount of mutexes of a process, but I didn't find anything about.

By the other hand I've found a lot of posts in StackOverflow explaining how to count the amount of processes by it's filename, I'm not interested in any of this 'cause I've choosed a MUTEX detection which for me is more secure.

Someone could help me in this whim?.

This is all what I have done:

Namespace My

    Partial Friend Class MyApplication

#Region " Properties "

        ''' <summary>
        ''' Gets the current process mutex identifier.
        ''' </summary>
        ''' <value>The current process mutex identifier.</value>
        ''' <exception cref="System.FormatException">The specified value is not a valid GUID format.</exception>
        Private ReadOnly Property MutexID As String
            Get
                ' Define a Golabl Unique Identifier to name the Mutex.
                Dim Id As String = "b045ce40-2863-4ce7-a7df-8afca8214454"

                If Guid.TryParse(input:=Id, result:=New Guid) Then
                    Return Id
                Else
                    Throw New FormatException("The specified value is not in a valid GUID format.")
                End If

            End Get
        End Property

        ''' <summary>
        ''' Gets the maximum instances allowed for this process.
        ''' </summary>
        ''' <value>The maximum instances allowed for this process.</value>
        Private ReadOnly Property MaxInstances As Integer
            Get
                Return 2
            End Get
        End Property

#End Region

#Region " Private Methods "

        ''' <summary>
        ''' Determines whether this is the unique instance that is running for this process.
        ''' </summary>
        ''' <returns><c>true</c> if this is the unique instance; otherwise, <c>false</c>.</returns>
        Private Function IsUniqueInstance() As Boolean

            Dim mtx As Threading.Mutex = Nothing

            Try
                mtx = Threading.Mutex.OpenExisting(name:=Me.MutexID)
                mtx.Close()
                mtx = Nothing
            Catch
                mtx = New Threading.Mutex(initiallyOwned:=True, name:=Me.MutexID)
            End Try

            Return mtx IsNot Nothing

        End Function

#End Region

#Region " Event-Handlers "

        ''' <summary>
        ''' This occurs when the application starts, before the startup Form is created.
        ''' </summary>
        ''' <param name="sender">The source of the event.</param>
        ''' <param name="e">The <see cref="ApplicationServices.StartupEventArgs"/> instance containing the event data.</param>
        Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As ApplicationServices.StartupEventArgs) _
        Handles Me.Startup

            ' If there is more than one instance running of this process with the same mutex then...
            If Not Me.IsUniqueInstance Then ' Prevent multi-instancing.

                MessageBox.Show("This is a limited demo, to run multiple instances please purchase the program.",
                               Application.Info.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)

                ' Cancel the application execution.
                e.Cancel = True

            End If

        End Sub

#End Region

    End Class ' MyApplication

End Namespace

UPDATE

This is the code that I'm trying, I've tried it in the application events, in the form constructor, in the load and shown event, but the multiinstances are not detected.

    Private Sub test() Handles Me.Startup

        Using semaphore As New Semaphore(3I, 3I, "something")

            If Not semaphore.WaitOne(100I) Then
                MsgBox("Already max instances running")
                End
            Else
                MsgBox("test")
            End If

        End Using

    End Sub

Solution

  • Mutex is for mutual exclusion. It will atmost allow only one thread to proceed. If you need to allow number of threads(process in this case) to proceed you need a Semaphore rather than mutex.

    C# sample:

    private static void Main()
    {
        using (Semaphore semaphore = new Semaphore(3, 3, Assembly.GetExecutingAssembly().GetName().FullName))
        {
            if (!semaphore.WaitOne(100))
            {
                MessageBox.Show("Already max instances running");
                return;
            }
    
            //Start your application here
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
    

    VB.Net sample:

    Private Shared Sub Main()
        Using semaphore As New Semaphore(3, 3, Assembly.GetExecutingAssembly().GetName().FullName)
            If Not semaphore.WaitOne(100) Then
                MessageBox.Show("Already max instances running")
                Return
            End If
    
           'Start your application here
            Application.EnableVisualStyles()
            Application.SetCompatibleTextRenderingDefault(False)
            Application.Run(New Form1())
        End Using
    End Sub
    

    P.S: Code converted with http://converter.telerik.com/ from C# to VB