4

I've a C# application that displays a login form when launched and displays the main form after users are authenticated. I used Mutex to restrict that only one instance of my application runs. And, this works fine for only the Login form. Once the main form is displayed, it doesn't restrict users from reopening the Login form. I was looking for a solution by which the Login screen couldn't be displayed once the main form is already opened.

Here is my Program.cs

 [STAThread]
    static void Main()
    {
        bool mutexCreated=true;

        using (Mutex mutex = new Mutex(true, "eCS", out mutexCreated))
        {
            if (mutexCreated)
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Login());
            }
            else
            {
                Process current = Process.GetCurrentProcess();
                foreach (Process process in Process.GetProcessesByName(current.ProcessName))
                {
                    if (process.Id != current.Id)
                    {
                        XtraMessageBox.Show("Another instance of eCS is already running.", "eCS already running", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        SetForegroundWindow(process.MainWindowHandle);
                        break;
                    }
                }
            }
        }
    }
3
  • So you have no control over what you can allow users to do and what not? I assume there must be some button or other means by which a user can reopen the login screen. Why don't you just remove those? Commented Sep 9, 2012 at 14:50
  • Move your code from the Login form to the Main() method in Program.cs Commented Sep 9, 2012 at 17:46
  • Hans Passant, my Program.cs is supposed to launch the Login window. And my code is already in the Program.cs but not working. Here the code: Commented Sep 9, 2012 at 17:55

4 Answers 4

7

I've made some small changes:


namespace CSMutex
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            bool mutexCreated=true;
            using(Mutex mutex = new Mutex(true, "eCS", out mutexCreated))
            {
                if (mutexCreated)
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Login loging = new Login();
                    Application.Run(loging);
                    Application.Run(new Main() { UserName = loging.UserName });
                }
                else
                {
                    Process current = Process.GetCurrentProcess();
                    foreach (Process process in Process.GetProcessesByName(current.ProcessName))
                    {
                        if (process.Id != current.Id)
                        {
                            MessageBox.Show("Another instance of eCS is already running.", "eCS already running", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            //SetForegroundWindow(process.MainWindowHandle);
                            break;
                        }
                    }
                }
            }
        }
    }
}

That works as expected - i.e. even when Login form is closed (and the main application form is started) it doesn't let user run the application once again. I've decided not to create Main from within Login (this is I believe how you application works) and instead I am passing parameter to Main. I have also made some small change to Login so it has UserName propert (same as Main).

Sign up to request clarification or add additional context in comments.

1 Comment

I'm curious why you are using a for loop to check the processes in the else statement, why not just show the info message ?
0

If you are ok with a reference to Microsoft.VisualBasic, you can use its SingleInstance processing.

    [STAThread]
    static void Main(string[] args)
    {
        using (System.Threading.Mutex mutex = new System.Threading.Mutex(true, "MyApp.SingleInstance.Mutex", out createdNew))
        {
            MainForm = new MainDlg();
            SingleInstanceApplication.Run(MainForm, StartupNextInstanceEventHandler);
        }
    }

    public static void StartupNextInstanceEventHandler(object sender, StartupNextInstanceEventArgs e)
    {
        MainForm.Activate();
    }

public class SingleInstanceApplication : WindowsFormsApplicationBase
{
    private SingleInstanceApplication()
    {
        base.IsSingleInstance = true;
    }

    public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
    {
        SingleInstanceApplication app = new SingleInstanceApplication();
        app.MainForm = f;
        app.StartupNextInstance += startupHandler;
        app.Run(Environment.GetCommandLineArgs());
    }
}

4 Comments

will this still keep the Login form to be displayed first?
This is your main method, so it would prevent whatever startup object you are using from being loaded on the second instance.
is this only applicable on VB? am using c# WinForms
I use this technique in my C# programs. You need to add a reference to the Microsoft.VisualBasic assembly.
-1

if you want limit to only one instance for a Form, you can do something like this:

public static class LoginForm 
{
    private static Form _loginForm = new Form();


    public static bool ShowLoginForm(){

        if(_loginForm.Visible)
             return false;

        _loginForm.Show();
        return true;
    }
}

So if more then one clients will call this method, which is only possible method to show login form, in case when its already visible, it will not be executed.

3 Comments

Thanks Tigran for the quick response. The login form (for the first time) works fine. The problem is restricting the login not to open after the main form is already running. How can i do that?
@user758961: if you use kind of wrapper presented in answer you can achieve that actually. Call ShowLoginForm(..) when it's appropriate.
@user758961: you can extend this to CloseLoginForm(..) or use this trick inside login form itself.
-3
private bool IsSingleInstance()
    {
        string szCurrentProcessName = this.ProductName;
        Process[] processlist = Process.GetProcesses();
        foreach(Process theprocess in processlist)
        {
            string szProcessName = theprocess.MainModule.ModuleName.ToString();
            if (szProcessName.Contains(szCurrentProcessName))
                return false;
        }
        return true;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.