Duplicate instances of my application

Sandallic

Newcomer
Joined
Dec 10, 2004
Messages
11
Hello, here comes another question.

Isnt there any easy way to disable my application to start twice?
I cant accept that there are running two instances of my application at the same time..

I think there is a way withing VS.net where you can turn this off..

Any1 knows ?

Thx, Sandallic
 
I have this solution that works perfectly well for me...
Maybe Mutex is a better option but I leave you to choose...

Visual Basic:
Module Global
    Declare Function ShowWindow Lib "user32" (ByVal hWnd As IntPtr, ByVal nCmdShow As Long) As Long

    Public Sub main()

        'Evaluate if this application is already running on this computer
        Const SW_MAXIMIZE = 3
        Const SW_SHOWMINIMIZED = 2
        Const SW_RESTORE = 9
        Const SHOWNORMAL = 1
        Const SW_SHOW = 5
        Dim processes() As Diagnostics.Process = Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName)
        If processes.Length > 1 Then

            Dim mProcess As Diagnostics.Process
            For Each p As Diagnostics.Process In processes
                If mProcess Is Nothing Then
                    mProcess = p
                Else
                    If p.StartTime < mProcess.StartTime Then mProcess = p
                End If
            Next

            Dim hwnd As IntPtr = mProcess.MainWindowHandle

            Call ShowWindow(hwnd, SW_SHOWMINIMIZED)
            Call ShowWindow(hwnd, SHOWNORMAL)
            Call ShowWindow(hwnd, SW_SHOW)

            Exit Sub
        End If

        Application.EnableVisualStyles()
        Application.DoEvents()

        Application.Run(New StartForm)
    End Sub

End Module

This code not only block a second instance but also shows the application...

Alex :p
 
AlexCode, your code can be easily modified to use mutexes and show the previous instance. That way, there is no chance for your app to be shown twice, and you eliminate the need to loop through all the processes on the first run, which results in a (slightly?) quicker startup time:
Visual Basic:
Module Global
    Declare Function ShowWindow Lib "user32" (ByVal hWnd As IntPtr, ByVal nCmdShow As Long) As Long
    Dim MyMutex As Threading.Mutex

    Public Sub main()
        'declare constants
        Const SW_MAXIMIZE = 3
        Const SW_SHOWMINIMIZED = 2
        Const SW_RESTORE = 9
        Const SHOWNORMAL = 1
        Const SW_SHOW = 5

        'Evaluate if this application is already running on this computer
        Dim NoPrevInstance As Boolean
        'I changed the string here to make it more obvious that it needs to be changed when this code is used:
        MyMutex = New Threading.Mutex(True, "Some String that's specific to your app", NoPrevInstance)
        If Not NoPrevInstance Then

            'if this application is already running, show it
            Dim processes() As Diagnostics.Process = Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName)
            If processes.Length > 1 Then

                Dim mProcess As Diagnostics.Process
                For Each p As Diagnostics.Process In processes
                    If mProcess Is Nothing Then
                        mProcess = p
                    Else
                        If p.StartTime < mProcess.StartTime Then mProcess = p
                    End If
                Next

                Dim hwnd As IntPtr = mProcess.MainWindowHandle

                'Why did you have these two lines in here:
                'Call ShowWindow(hwnd, SW_SHOWMINIMIZED)
                'Call ShowWindow(hwnd, SHOWNORMAL)
                Call ShowWindow(hwnd, SW_SHOW)

                Exit Sub
            End If
        End If

        Application.EnableVisualStyles()
        Application.DoEvents()

        Application.Run(New StartForm)
    End Sub

End Module

By the way, why did you have those two extra ShowWindow lines?
 
Hi...

1st - When I did that code I din't knew about Mutex, and after knowing about it I didn't had much intetntion to modify it, since the performance increse shounldn't be "felt"... But shure it's more "clean" and "correct" code...

2nd - Those 2 extra line you queried about...
At least on my combuter (try it on yours to see if it's "universially" true), if the windows isn't minimized (if it's only behind others), the SHOW doesn't activate the window as expected, only shows it...
The correct behaviour only ocurres when the window is minimized... so, I minimize it (Call ShowWindow(hwnd, SW_SHOWMINIMIZED)), then I show the window with its last size and location (Call ShowWindow(hwnd, SHOWNORMAL)) and finally I call the show to make shure it gets active (Call ShowWindow(hwnd, SW_SHOW)).

Like I said, try it if the same behaviour error ocurres with you... if not, just use the last line...

By the way... thanks for the code "facelift"... :D

Alex :p
 
Although the performance differrence is probably not a reason to use the mutex based code, try running both on a terminal server based system when multiple sessions want to run the same application multiple times.
 
Hummmm great hint Plausy...

I didn't tested it in that environment... what hapens?
It gets confused with the instances or just doesn't work?

Alex :p
 
On my computer, the performance difference is noticable. Skipping the search through the processes seems to save at least a good couple seconds.

After working with the code a bit, I see what you mean about needing those three calls. However, I've always done it with SetForeGroundWindow, anyway. You do still need one call to ShowWindow in case it's minimized. Also, while adding the Declare for SetForegroundWindow, I noticed that ShowWindow had Long's instead of Int32's. Is there a reason why that even still worked? Whatever the case, I changed them to Int32's:
Visual Basic:
Module Global
    Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As IntPtr) As Int32
    Declare Function ShowWindow Lib "user32" (ByVal hWnd As IntPtr, ByVal nCmdShow As Int32) As Int32
    Dim MyMutex As Threading.Mutex

    Public Sub main()
        'declare constants
        Const SW_MAXIMIZE = 3
        Const SW_SHOWMINIMIZED = 2
        Const SW_RESTORE = 9
        Const SHOWNORMAL = 1
        Const SW_SHOW = 5

        'Evaluate if this application is already running on this computer
        Dim NoPrevInstance As Boolean
        MyMutex = New Threading.Mutex(True, "Some String that's specific to your app", NoPrevInstance)
        If Not NoPrevInstance Then

            'if this application is already running, show it
            Dim processes() As Diagnostics.Process = Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName)
            If processes.Length > 1 Then

                Dim mProcess As Diagnostics.Process
                For Each p As Diagnostics.Process In processes
                    If mProcess Is Nothing Then
                        mProcess = p
                    Else
                        If p.StartTime < mProcess.StartTime Then mProcess = p
                    End If
                Next

                Dim hwnd As IntPtr = mProcess.MainWindowHandle

                'The way I would do it:
                Call ShowWindow(hwnd, SW_RESTORE)
                SetForegroundWindow(hwnd)

                Exit Sub
            End If
        End If

        Application.EnableVisualStyles()
        Application.DoEvents()

        Application.Run(New StartForm)
    End Sub

End Module
 
I got this error :

Code:
Additional information:
It is invalid to start a second message loop on a single thread.
Use Application.RunDialog or Form.ShowDialog instead.

with a break on the line
Visual Basic:
 Application.Run(New frmMain)
 
When you look at all the codes out there for making your app only start up once, you might've noticed that they are all in Subs called Main. This is for a reason. You are supposed to put a Sub Main in a Module (alternatively, you can put a Shared Sub Main in a Class, but I prefer the module). Then go to Project -> Properties. In the window that comes up, change "Startup Object" from your form to the Sub Main that you put in.
 
Hey I was reading this post and I was wondering if yall could tell me how to do this in C# or if there was a tutorial I could look at.
 
Last edited:
RampagePS said:
Hey I was reading this post and I was wondering if yall could tell me how to do this in C# or if there was a tutorial I could look at.

Translate it yourself... It's not that hard and sooner or later you'll have to learn a little vb.net... at least to understand the code examples aroud the web... :p
 
I think it would be something like this

[CS]
using System.Diagnostics;
using Microsoft.VisualBasic;
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.Runtime.InteropServices;

namespace Only_One_Instance
{
sealed class Global
{
[DllImport("user32", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
public static extern int SetForegroundWindow(IntPtr hwnd);
[DllImport("user32", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]
public static extern int ShowWindow(IntPtr hWnd, int nCmdShow);
static System.Threading.Mutex MyMutex;

public static void main ()
{
//declare constants
const int SW_MAXIMIZE = 3;
const int SW_SHOWMINIMIZED = 2;
const int SW_RESTORE = 9;
const int SHOWNORMAL = 1;
const int SW_SHOW = 5;

//Evaluate if this application is already running on this computer
bool NoPrevInstance = false;
bool temp_bool = NoPrevInstance;
MyMutex = new System.Threading.Mutex(true, "Some String that's specific to your app", out temp_bool);
if (! NoPrevInstance)
{

//if this application is already running, show it
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(System.Diagnostics.Process.GetCurrentProcess().ProcessName);
if (processes.Length > 1)
{

System.Diagnostics.Process mProcess = null;
foreach (System.Diagnostics.Process p in processes)
{
if (mProcess == null)
{
mProcess = p;
}
else
{
if (p.StartTime < mProcess.StartTime)
{
mProcess = p;
}
}
}

IntPtr hwnd = mProcess.MainWindowHandle;

//The way I would do it :
ShowWindow(hwnd, SW_RESTORE);
SetForegroundWindow(hwnd);

return;
}
}

Application.EnableVisualStyles();
Application.DoEvents();

Application.Run(new Form1());
}

}
}
[/CS]
 
Hey man thanks for the code, im at school know so no time to test it out, :eek: But I will repost when I get home and let you know if it worked.
 
You can try this (VB.Net) :

If (UBound(Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName)) > 0) Then
MsgBox(" Application is already running in another window")
End
End If
 
DarkKai said:
You can try this (VB.Net) :

If (UBound(Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName)) > 0) Then
MsgBox(" Application is already running in another window")
End
End If

Read the complete thread and THEN you'll figure out why that code shouln't be used...

Alex :p
 
Back
Top