使用 Mutex 退出 C# 应用程序

C# Application Exit with Mutex

希望你能帮上忙,我一直在阅读有关互斥锁的内容,我相信我理解它——它应该只限于一个应用程序进程。

在这个社区的一些指导和一些谷歌搜索的帮助下,我创建了这个简单的代码。

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

声明的变量:

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

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

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

我想要达到的目标::

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

谢谢。

==

经过谷歌搜索,我找到了这个 post:

,感谢大家的帮助

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

这帮助我让它正常工作。

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

不要检查 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());
}

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

这是我的单例应用程序模板(Program class 静态 class 包含我的应用程序入口点 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
    }
}

然后,在 class 形式(在我的例子中是 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 class(记得标记为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 对象的传统实现稍微长一点,需要广泛使用本机互操作,并且必须在项目中的不同 class 之间拆分。 ..但我很久以前就使用它的模板,我可以肯定它是防弹的。

在此方法中,一个对象被定义为数据,我们可以在 class 中的 CSharp 编程中更新具有常量数据类型的单个数组中的多个变量,如在 mutux [=12] 中分配给此应用程序=] 这是怎么来的,但可靠且可预测