【问题标题】:Checking if my Windows application is running检查我的 Windows 应用程序是否正在运行
【发布时间】:2011-06-10 23:13:38
【问题描述】:

如何检查我的 C# Windows 应用程序是否正在运行?

我知道我可以检查进程名称,但如果exe更改,名称可以更改。

有什么方法可以让我的应用程序具有哈希键或其他东西吗?

【问题讨论】:

  • 如果您只想要一个实例,请查看 Mutex:stackoverflow.com/questions/819773/…
  • 以这种方式使用 Mutex 存在问题,而且有时我需要使用 Application.Restart 重新启动我的应用程序,这会与互斥体模式冲突。
  • 所以基本上,您的问题是:“如何在不实际创建互斥锁的情况下获得所有互斥锁功能”?为什么不问如何解决您在使用互斥锁时遇到的任何问题?
  • @Cody:我猜你是对的,我应该尝试解决与互斥锁的冲突。谢谢

标签: c# winforms


【解决方案1】:
public partial class App : System.Windows.Application
{
    public bool IsProcessOpen(string name)
    {
        foreach (Process clsProcess in Process.GetProcesses()) 
        {
            if (clsProcess.ProcessName.Contains(name))
            {
                return true;
            }
        }

        return false;
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        // Get Reference to the current Process
        Process thisProc = Process.GetCurrentProcess();

        if (IsProcessOpen("name of application.exe") == false)
        {
            //System.Windows.MessageBox.Show("Application not open!");
            //System.Windows.Application.Current.Shutdown();
        }
        else
        {
            // Check how many total processes have the same name as the current one
            if (Process.GetProcessesByName(thisProc.ProcessName).Length > 1)
            {
                // If ther is more than one, than it is already running.
                System.Windows.MessageBox.Show("Application is already running.");
                System.Windows.Application.Current.Shutdown();
                return;
            }

            base.OnStartup(e);
        }
    }

【讨论】:

  • 这很脆弱:IsProcessOpen("name of application.exe")。可执行文件可能在编写源代码和在用户机器上运行之间更改了名称。 Mutex 没有这个问题,也不假设应用程序是如何运行的。
  • 如果另一个应用程序实例正在运行,是否有任何方法可以“切换到”或“将进程置于前面”?
  • 枚举进程的窗口,找到前台的一个:EnumWindows。然后把这个窗口放在前面。
  • @abramlimpin App 无法派生密封类型应用程序
【解决方案2】:

推荐的方法是使用互斥锁。您可以在此处查看示例: http://www.codeproject.com/KB/cs/singleinstance.aspx

具体代码:


        /// 
        /// check if given exe alread running or not
        /// 
        /// returns true if already running
        private static bool IsAlreadyRunning()
        {
            string strLoc = Assembly.GetExecutingAssembly().Location;
            FileSystemInfo fileInfo = new FileInfo(strLoc);
            string sExeName = fileInfo.Name;
            bool bCreatedNew;

            Mutex mutex = new Mutex(true, "Global\\"+sExeName, out bCreatedNew);
            if (bCreatedNew)
                mutex.ReleaseMutex();

            return !bCreatedNew;
        }

【讨论】:

  • 如果检查应用程序与正在运行的应用程序相同,这将起作用。
  • 如果您使用 GUID 而不是 sExeName,它将适用于任何应用程序。
  • 这应该放在我的 C# 应用程序的哪个函数中?
【解决方案3】:

对于我的 WPF 应用程序,我定义了全局应用程序 ID 并使用信号量来处理它。

public partial class App : Application
{      
    private const string AppId = "c1d3cdb1-51ad-4c3a-bdb2-686f7dd10155";

    //Passing name associates this sempahore system wide with this name
    private readonly Semaphore instancesAllowed = new Semaphore(1, 1, AppId);

    private bool WasRunning { set; get; }

    private void OnExit(object sender, ExitEventArgs e)
    {
        //Decrement the count if app was running
        if (this.WasRunning)
        {
            this.instancesAllowed.Release();
        }
    }

    private void OnStartup(object sender, StartupEventArgs e)
    {
        //See if application is already running on the system
        if (this.instancesAllowed.WaitOne(1000))
        {
            new MainWindow().Show();
            this.WasRunning = true;
            return;
        }

        //Display
        MessageBox.Show("An instance is already running");

        //Exit out otherwise
        this.Shutdown();
    }
}

【讨论】:

    【解决方案4】:

    结帐:What is a good pattern for using a Global Mutex in C#?

    // unique id for global mutex - Global prefix means it is global to the machine
    const string mutex_id = "Global\\{B1E7934A-F688-417f-8FCB-65C3985E9E27}";
    
    static void Main(string[] args)
    {
        using (var mutex = new Mutex(false, mutex_id))
        {
            // edited by Jeremy Wiebe to add example of setting up security for multi-user usage
            // edited by 'Marc' to work also on localized systems (don't use just "Everyone") 
            var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            mutex.SetAccessControl(securitySettings);
    
            //edited by acidzombie24
            var hasHandle = false;
            try
            {
                try
                {
                    // note, you may want to time out here instead of waiting forever
                    //edited by acidzombie24
                    //mutex.WaitOne(Timeout.Infinite, false);
                    hasHandle = mutex.WaitOne(5000, false);
                    if (hasHandle == false) return;//another instance exist
                }
                catch (AbandonedMutexException)
                {
                    // Log the fact the mutex was abandoned in another process, it will still get aquired
                }
    
                // Perform your work here.
            }
            finally
            {
                //edit by acidzombie24, added if statemnet
                if (hasHandle)
                    mutex.ReleaseMutex();
            }
        }
    }
    

    【讨论】:

    • -1:正如OP所说,他知道他可以检查进程名称,他想知道如果更改应用程序名称该怎么办
    • @djeeg:我们读过同样的问题吗?你能指出 op 说的地方,他想知道如果应用程序名称更改了该怎么办
    • 第 2 行:“我知道我可以检查进程名称,但如果 exe 更改,名称可以更改。”
    【解决方案5】:

    你需要一种方式从应用程序中说“我正在跑步”,

    1) 打开 WCF ping 服务 2)在启动时写入注册表/文件并在关机时删除 3)创建一个互斥体

    ...我更喜欢 WCF 部分,因为您可能无法正确清理文件/注册表,而且 Mutex 似乎有其自身的问题

    【讨论】:

      【解决方案6】:

      Mutex 和 Semaphore 在我的情况下不起作用(我按照建议尝试了它们,但在我开发的应用程序中它没有起到作用)。在我稍作修改后,abramlimpin 提供的答案对我有用。

      这就是我最终得到它的方式。 首先,我创建了一些辅助函数:

      public static class Ext
      {
         private static string AssemblyFileName(this Assembly myAssembly)
          {
              string strLoc = myAssembly.Location;
              FileSystemInfo fileInfo = new FileInfo(strLoc);
              string sExeName = fileInfo.Name;
              return sExeName;
          }
      
          private static int HowManyTimesIsProcessRunning(string name)
          {
              int count = 0;
              name = name.ToLowerInvariant().Trim().Replace(".exe", "");
              foreach (Process clsProcess in Process.GetProcesses())
              {
                  var processName = clsProcess.ProcessName.ToLowerInvariant().Trim();
                  // System.Diagnostics.Debug.WriteLine(processName);
                  if (processName.Contains(name))
                  {
                      count++;
                  };
              };
              return count;
          }
      
          public static int HowManyTimesIsAssemblyRunning(this Assembly myAssembly)
          {
              var fileName = AssemblyFileName(myAssembly);
              return HowManyTimesIsProcessRunning(fileName);
          }
      }
      

      然后,我在 ma​​in 方法中添加了以下内容:

      [STAThread]
      static void Main()
      {
          const string appName = "Name of your app";
      
          // Check number of instances running:
          // If more than 1 instance, cancel this one.
          // Additionally, if it is the 2nd invocation, show a message and exit.
          var numberOfAppInstances = Assembly.GetExecutingAssembly().HowManyTimesIsAssemblyRunning();
          if (numberOfAppInstances == 2)
          {
             MessageBox.Show("The application is already running!
              +"\nClick OK to close this dialog, then switch to the application by using WIN + TAB keys.",
              appName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
          };
          if (numberOfAppInstances >= 2)
          {
              return;
          };
      }
      

      如果您第 3 次、第 4 次调用应用程序,它不会再显示警告,而是立即退出。

      【讨论】:

        【解决方案7】:

        我想我真的很简单,对于每个正在运行的 exe,您可以在磁盘上的已知位置 (c:\temp) 中创建/打开一个具有特殊名称“yourapp.lock”的文件,然后只需数一数有多少。

        更难的方法是打开一些进程间通信或套接字,因此您可以使用进程列表询问每个进程以查看它是否是您的应用程序。

        【讨论】:

        • 不可接受,因为我认为我不应该请求访问以直接写入磁盘,这会带来很多麻烦,但是谢谢
        【解决方案8】:

        在您的程序集数据中输入一个 guid。 将此指南添加到注册表。 在应用程序读取它自己的名称的地方输入一个 reg 键,并将名称作为值添加到那里。

        另一个任务观察者读取 reg 键并知道应用名称。

        【讨论】:

        • 应用程序崩溃重启后不会让您从“重复实例”消息中解救出来。不要使用注册表,当你忘记删除这个值时要小心不干净的退出
        • 使用注册表是一种选择,当您在文件系统的某处写入 .pid 文件时也是如此。如果应用程序崩溃,您需要清理这个烂摊子。与注册表相同,代码需要处理。
        【解决方案9】:

        您可以简单地使用变量和一个文件来检查您的程序是否正在运行。 当打开文件时包含一个值,当程序关闭时将此值更改为另一个值。

        【讨论】:

          猜你喜欢
          • 2016-07-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-28
          • 1970-01-01
          • 2019-02-16
          • 1970-01-01
          • 2014-09-26
          相关资源
          最近更新 更多