【问题标题】:How to force C# .net app to run only one instance in Windows? [duplicate]如何强制 C# .net 应用程序在 Windows 中仅运行一个实例? [复制]
【发布时间】:2008-10-08 18:15:35
【问题描述】:

可能重复:
What is the correct way to create a single instance application?

如何强制 C# .net 应用在 Windows 中只运行一个实例?

【问题讨论】:

    标签: c# .net windows winforms


    【解决方案1】:

    我更喜欢类似于以下的互斥锁解决方案。这样,如果它已经加载,它会重新关注应用程序

    using System.Threading;
    
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SetForegroundWindow(IntPtr hWnd);
    
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
       bool createdNew = true;
       using (Mutex mutex = new Mutex(true, "MyApplicationName", out createdNew))
       {
          if (createdNew)
          {
             Application.EnableVisualStyles();
             Application.SetCompatibleTextRenderingDefault(false);
             Application.Run(new MainForm());
          }
          else
          {
             Process current = Process.GetCurrentProcess();
             foreach (Process process in Process.GetProcessesByName(current.ProcessName))
             {
                if (process.Id != current.Id)
                {
                   SetForegroundWindow(process.MainWindowHandle);
                   break;
                }
             }
          }
       }
    }
    

    【讨论】:

    • 关于以这种方式使用 MainWindowHandle 属性的一点仅供参考(正如我刚刚发现的那样):“如果关联的进程没有主窗口,MainWindowHandle 值为零。对于已隐藏的进程,即在任务栏中不可见的进程,该值也为零。对于在通知区域中显示为图标的进程可能是这种情况,在任务栏的最右侧。”
    • 好答案。我喜欢在接受答案上使用 SetForegroundWindow (如果您按照该链接加上下一个链接到的内容),它使用广播消息并强制窗口位于最顶层——这实际上不会聚焦窗口。这个答案应该是,因为在大多数情况下,新运行的进程有权将焦点传递给另一个进程。
    • SetForegroundWindow 不适合我。实际上,从来没有工作过。
    • @user1021726 "MyApplicationName" 应该是您独有的任何东西。我会建议一些有意义的东西,然后是 GUID。
    • 如果您的应用程序可以最小化,您可能还需要调用ShowWindow( process.MainWindowHandle, SW_RESTORE ) 来恢复它。 stackoverflow.com/questions/4566632/… 提供详细信息。 SW_RESTORE 为 9(来自msdn.microsoft.com/en-gb/library/windows/desktop/…)。
    【解决方案2】:

    要在 .net (C#) 中强制运行程序的一个实例,请在 program.cs 文件中使用以下代码:

    public static Process PriorProcess()
        // Returns a System.Diagnostics.Process pointing to
        // a pre-existing process with the same name as the
        // current one, if any; or null if the current process
        // is unique.
        {
            Process curr = Process.GetCurrentProcess();
            Process[] procs = Process.GetProcessesByName(curr.ProcessName);
            foreach (Process p in procs)
            {
                if ((p.Id != curr.Id) &&
                    (p.MainModule.FileName == curr.MainModule.FileName))
                    return p;
            }
            return null;
        }
    

    以及以下内容:

    [STAThread]
        static void Main()
        {
            if (PriorProcess() != null)
            {
    
                MessageBox.Show("Another instance of the app is already running.");
                return;
            }
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form());
        }
    

    【讨论】:

    • 这是不正确的方法。我可以在两个实例中运行你的程序——一个作为二进制启动,第二个从 VS 启动。
    • 好的,@greenoldman,但是从什么时候开始用户/客户“调试”您的应用程序,然后选择在其旁边运行第二个(二进制)。与我在这个网站上看到的许多基于 Mutex 的答案相比,这个答案相当不错。
    • 我知道这是几年后的事了,但万一有人像我一样发现这个:如果用户不是管理员(至少在 Win7 中)Process.GetProcessesByName 将抛出异常。
    【解决方案3】:

    这是我在我的应用程序中使用的:

    static void Main()
    {
      bool mutexCreated = false;
      System.Threading.Mutex mutex = new System.Threading.Mutex( true, @"Local\slimCODE.slimKEYS.exe", out mutexCreated );
    
      if( !mutexCreated )
      {
        if( MessageBox.Show(
          "slimKEYS is already running. Hotkeys cannot be shared between different instances. Are you sure you wish to run this second instance?",
          "slimKEYS already running",
          MessageBoxButtons.YesNo,
          MessageBoxIcon.Question ) != DialogResult.Yes )
        {
          mutex.Close();
          return;
        }
      }
    
      // The usual stuff with Application.Run()
    
      mutex.Close();
    }
    

    【讨论】:

      【解决方案4】:

      单实例应用程序的另一种方法是检查它们的哈希和。 在弄乱了互斥锁(没有按我想要的那样工作)之后,我得到了它的工作方式:

          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          static extern bool SetForegroundWindow(IntPtr hWnd);
      
          public Main()
          {
              InitializeComponent();
      
              Process current = Process.GetCurrentProcess();
              string currentmd5 = md5hash(current.MainModule.FileName);
              Process[] processlist = Process.GetProcesses();
              foreach (Process process in processlist)
              {
                  if (process.Id != current.Id)
                  {
                      try
                      {
                          if (currentmd5 == md5hash(process.MainModule.FileName))
                          {
                              SetForegroundWindow(process.MainWindowHandle);
                              Environment.Exit(0);
                          }
                      }
                      catch (/* your exception */) { /* your exception goes here */ }
                  }
              }
          }
      
          private string md5hash(string file)
          {
              string check;
              using (FileStream FileCheck = File.OpenRead(file))
              {
                  MD5 md5 = new MD5CryptoServiceProvider();
                  byte[] md5Hash = md5.ComputeHash(FileCheck);
                  check = BitConverter.ToString(md5Hash).Replace("-", "").ToLower();
              }
      
              return check;
          }
      

      它只检查进程 ID 的 md5 总和。

      如果找到此应用程序的实例,它会聚焦正在运行的应用程序并自行退出。

      你可以重命名它或对你的文件做你想做的事。如果 md5 哈希相同,则不会打开两次。

      有人对此有什么建议吗?我知道它已被回答,但也许有人正在寻找互斥锁替代品。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多