【问题标题】:How to run one instance of a c# WinForm application?如何运行一个 c# WinForm 应用程序实例?
【发布时间】:2012-09-09 14:44:04
【问题描述】:

我有一个 C# 应用程序,它在启动时显示登录表单,并在用户通过身份验证后显示主表单。我使用 Mutex 来限制我的应用程序只能运行一个实例。而且,这仅适用于登录表单。显示主表单后,它不会限制用户重新打开登录表单。我正在寻找一种解决方案,一旦主窗体已经打开,登录屏幕就无法显示。

这是我的 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;
                    }
                }
            }
        }
    }

【问题讨论】:

  • 所以您无法控制您可以允许用户做什么和不可以做什么?我认为必须有一些按钮或其他方式让用户可以重新打开登录屏幕。你为什么不直接删除那些?
  • 将您的代码从登录表单移动到 Program.cs 中的 Main() 方法
  • Hans Passant,我的 Program.cs 应该会启动登录窗口。而且我的代码已经在 Program.cs 中但无法正常工作。代码如下:

标签: c# mutex single-instance


【解决方案1】:

我做了一些小改动:


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;
                        }
                    }
                }
            }
        }
    }
}

按预期工作 - 即即使 Login 表单已关闭(并且主应用程序表单已启动),它也不会让用户再次运行应用程序。 我决定不在Login 中创建Main(我相信你的应用程序是这样工作的),而是将参数传递给Main。 我还对Login 做了一些小改动,使其具有UserName 属性(与Main 相同)。

【讨论】:

  • 我很好奇你为什么使用 for 循环来检查 else 语句中的进程,为什么不只显示信息消息?
【解决方案2】:

如果你对 Microsoft.VisualBasic 的引用没问题,你可以使用它的 SingleInstance 处理。

    [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());
    }
}

【讨论】:

  • 这还会让登录表单先显示吗?
  • 这是你的主要方法,所以它会阻止你正在使用的任何启动对象被加载到第二个实例上。
  • 这只适用于VB吗?我正在使用 c# WinForms
  • 我在我的 C# 程序中使用了这种技术。您需要添加对 Microsoft.VisualBasic 程序集的引用。
【解决方案3】:

如果您只想将Form 限制为一个实例,您可以执行以下操作:

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


    public static bool ShowLoginForm(){

        if(_loginForm.Visible)
             return false;

        _loginForm.Show();
        return true;
    }
}

所以如果有多个客户端会调用这个方法,这是唯一可能的显示登录表单的方法,如果它已经可见,它将不会被执行。

【讨论】:

  • 感谢 Tigran 的快速响应。登录表单(第一次)工作正常。问题是在主窗体已经运行后限制登录不打开。我该怎么做?
  • @user758961:如果您使用答案中提供的某种包装器,您实际上可以实现这一点。适当时致电ShowLoginForm(..)
  • @user758961:您可以将其扩展到CloseLoginForm(..) 或使用此技巧inside 登录表单本身。
【解决方案4】:
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;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-01
    • 2011-05-10
    • 2013-10-14
    • 1970-01-01
    • 2023-03-05
    • 2014-05-11
    • 2013-05-09
    • 1970-01-01
    相关资源
    最近更新 更多