【问题标题】:C# Application Exit with Mutex使用互斥锁的 C# 应用程序退出
【发布时间】:2017-11-29 19:46:09
【问题描述】:

希望您能提供帮助,我一直在阅读有关互斥锁的信息,并且我相信我理解它 - 它应该只限于一个应用程序进程。

有了这个社区的一些指导和一些谷歌搜索——我已经创建了这个简单的代码。

关于应用程序:C# 中的简单 Windows 窗体应用程序

声明的变量:

static Mutex mutex = new Mutex(true, "TestAppForm");

在 AppForm_Load() 上我有以下代码。

if (!mutex.WaitOne(2000))
        {

            System.Windows.Forms.Application.Exit();          
            return;
        }
        else
        {
            try
            {
              // My Code
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }

我相信我的代码可以正常工作,因为它仅限于一个应用程序。

但是,我注意到当它打开应用程序然后通过模式退出代码将其关闭时,我可以看到它闪烁。

我想要达到的目标::

我想运行应用程序并检查它是否已经在运行 - 如果没有,那就很好,然后继续其余的。 如果应用程序正在运行,我想结束进程然后我想在正在运行的应用程序上设置 FOCUS。

谢谢。

==

感谢您在谷歌搜索后找到这篇文章的所有帮助:

http://sanity-free.org/143/csharp_dotnet_single_instance_application.html

这帮助我让它发挥作用。

【问题讨论】:

    标签: c# mutex


    【解决方案1】:

    AppForm_Load 不是应用程序的第一个入口点。找到创建表单的代码并在那里执行。

    【讨论】:

    • 谢谢 Dylan,我可以假设你的意思是 AppForm() 它有 InitializeComponent();里面?
    • 除非您更改了 VS 为您生成的样板代码,否则入口点根本不在 AppForm 中。正如我所说,找到创建表单的代码。
    【解决方案2】:

    如果你想创建一个单例应用程序,你不能在AppForm_Load 中实现Mutex 逻辑,因为当你到达那个点(这不是你的程序集的入口点/主要方法)时,这意味着你的应用程序有已经开始了。通过您的实现,您充其量可以在您注意到之前创建的另一个实例已经在运行时关闭新实例......为什么不直接“阻止”新实例的创建?

    这是我的单例应用程序模板(Program 类是包含我的应用程序入口点 static void Main 的静态类):

    #region Using Directives
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Windows.Forms;
    #endregion
    
    namespace MyNamespace
    {
        public static class Program
        {
            #region Members: Static
            private static Int32 s_MutexMessage;
            private static Mutex s_Mutex;
            #endregion
    
            #region Properties: Static
            public static Int32 MutexMessage
            {
                get { return s_MutexMessage; }
            }
            #endregion
    
            #region Methods: Entry Point
            [STAThread]
            public static void Main()
            {
                Assembly assembly = Assembly.GetExecutingAssembly();
                String assemblyGuid = ((GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;
                String mutexName = String.Format(CultureInfo.InvariantCulture, "Local\\{{{0}}}", assemblyGuid);
    
                s_MutexMessage = NativeMethods.RegisterWindowMessage(assemblyGuid);
    
                Boolean mutexCreated;
                s_Mutex = new Mutex(true, mutexName, out mutexCreated);
    
                if (!mutexCreated)
                {
                    NativeMethods.PostMessage((new IntPtr(0xFFFF)), s_MutexMessage, IntPtr.Zero, IntPtr.Zero);
                    return;
                }
    
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new ApplicationForm());
    
                s_Mutex.ReleaseMutex();
            }
            #endregion
        }
    }
    

    然后,在表单类中(在我的示例中为 ApplicationForm):

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == Program.MutexMessage)
        {
            if (NativeMethods.IsIconic(Handle))
                NativeMethods.ShowWindow(Handle, 0x00000009);
    
            NativeMethods.SetForegroundWindow(Handle);
        }
    
        base.WndProc(ref m);
    }
    

    最后,为了完整起见,这里是我的代码使用的导入,位于NativeMethods 类中(记得将其标记为internal,这是一个不容忽视的好习惯):

    internal static class NativeMethods
    {
        #region Importations
        [DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern Boolean IsIconic([In] IntPtr windowHandle);
    
        [DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = false, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern Boolean PostMessage([In, Optional] IntPtr windowHandle, [In] Int32 message, [In] IntPtr wParameter, [In] IntPtr lParameter);
    
        [DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern Boolean SetForegroundWindow([In] IntPtr windowHandle);
    
        [DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern Boolean ShowWindow([In] IntPtr windowHandle, [In] Int32 command);
    
        [DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = false, SetLastError = true)]
        internal static extern Int32 RegisterWindowMessage([In] String message);
    }
    

    此实现比仅基于 Mutex 对象的传统实现要长一点,需要广泛使用本机互操作,并且必须在项目中的不同类之间拆分...但我使用它模板很长时间以来很久以前,我可以肯定它是防弹的。

    【讨论】:

    • 谢谢 Tommaso,我现在就看看 - 必须承认,这个 NativeMethods 在这一点上对我来说是高级的 [c# 新手]
    • 虽然进步了,但这里只是复制粘贴的问题。当然你会同时学到一些东西xD
    • 抱歉 :( - 我收到错误 ""string mutexname = ("Local\\{{{0}}}").FormatInvariant(assemblyGuid); 我不确定我在哪里粘贴受保护的覆盖 void WndProc(ref Message m) {} 我粘贴在 Form1() 中,但也报告了错误。我创建了新表单来测试它 - 谢谢。
    • 我以前使用的 Mutex 代码与我自己编写的非常相似。但是偶尔在我编写的带有 IPC 的多线程、多进程应用程序中,我们发现互斥体正在被创建,尽管它已经在使用中。我最终回到了旧的独占文件写入一个临时命名不完整的文件,其他应用程序都不应该使用它。你的结果可能会有所不同,我一直认为永远不应该发生。
    • @netniV 我认为这是因为 Mutex 必须使用“全局”或“本地”前缀创建,具体取决于它的用法和运行应用程序的环境。阅读此处了解更多信息msdn.microsoft.com/en-us/library/f55ddskf(v=vs.110).aspx
    【解决方案3】:

    不要在AppForm_Load 中检查互斥体,而是在Main 方法中检查它,如下所示:

    private static Mutex _mutex = new Mutex(true, "AppMutex");
    
    static void Main()
    {
        if(!_mutex.WaitOne(0, true))
        {
            return;
        }
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new AppForm());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-10
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多