如何强制 C# .net 应用程序在 Windows 中仅运行一个实例? [复制]

Posted

技术标签:

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

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

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

【问题讨论】:

【参考方案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 ) 来恢复它。 ***.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 哈希相同,则不会打开两次。

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

【讨论】:

以上是关于如何强制 C# .net 应用程序在 Windows 中仅运行一个实例? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

当任何数学运算在 .net 4 中产生“NaN”时,如何强制 C# 编译器抛出异常?

C# .Net 4.0 应用程序中托管的 C++ ActiveX 控件中的 Xml.Serializer 非法强制转换异常

如何强制更新/防止在 Linux 上运行并由 nginx 反向代理服务器托管的 .NET Core Web 应用程序的 HTML 缓存

处理器关联组 C#

C#WPF如何强制执行单个windows实例

如何在启动程序且 UAC 被禁用时强制提示输入凭据?