C#[Win32&WinCE&WM]应用程序只能运行一个实例:MutexHelper

803 查看


图片来自网络/图文无关

前言

在开发应用程序时,通常只让程序运行一个实例。所以,就要判断程序是否已经运行。

下面是我自己在项目中使用到,封装好的帮助类。有 普通的 C# 应用程序 和 Windows CE 和 Windows Mobile 应用程序使用的方法。

主要是通过 System.Threading.Mutex 类 和 Win32 API 来实现,下面就是各自的代码,调用示例在最后面。

普通 C# 应用程序

主要是 Windows 窗体应用程序和控制台程序。

1. 使用 System.Threading.Mutex 类

参考:Mutex 类(System.Threading)

using System.Threading;

namespace XY.Util.Helper
{
    /// <summary>
    /// Mutex helper
    /// </summary>
    public class MutexHelper
    {
        /// <summary>
        /// 判断程序是否已经运行
        /// <param name="assembly">程序集实例</param>
        /// </summary>
        /// <returns>
        /// true: 程序已运行
        /// false: 程序未运行
        /// </returns>
        public static bool IsApplicationOnRun(System.Reflection.Assembly assembly)
        {
            string strAppName = assembly.GetName().Name;
            return IsApplicationOnRun(strAppName);
        }

        /// <summary>
        /// 判断程序是否已经运行
        /// <param name="assemblyName">程序名称</param>
        /// </summary>
        /// <returns>
        /// true: 程序已运行
        /// false: 程序未运行
        /// </returns>
        public static bool IsApplicationOnRun(string assemblyName)
        {
            bool ret = false;
            //第一个参数:true--给调用线程赋予互斥体的初始所属权  
            //第一个参数:互斥体的名称  
            //第三个参数:返回值,如果调用线程已被授予互斥体的初始所属权,则返回true
            Mutex mutex = new Mutex(true, assemblyName, out ret);
            return !ret;
        }
    }
}

2. 使用 Win32 API

using System;
using System.Runtime.InteropServices;

namespace XY.Util.Helper
{
    /// <summary>
    /// Mutex helper
    /// </summary>
    public class MutexHelper
    {
        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr OpenMutex(uint dwDesiredAccess, bool bInitialOwner, string lpName);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);

        /// <summary>
        /// 判断程序是否已经运行
        /// <param name="assembly">程序集实例</param>
        /// </summary>
        /// <returns>
        /// true: 程序已运行
        /// false: 程序未运行
        /// </returns>
        public static bool IsApplicationOnRun(System.Reflection.Assembly assembly)
        {
            string strAppName = assembly.GetName().Name;
            return IsApplicationOnRun(strAppName);
        }

        /// <summary>
        /// 判断程序是否已经运行
        /// <param name="assemblyName">程序名称</param>
        /// </summary>
        /// <returns>
        /// true: 程序已运行
        /// false: 程序未运行
        /// </returns>
        public static bool IsApplicationOnRun(string assemblyName)
        {
            bool ret = false;

            if (OpenMutex(0x1F0001, false, assemblyName) == IntPtr.Zero)
            {
                CreateMutex(IntPtr.Zero, false, assemblyName);
                ret = true;
            }

            return ret;
        }
    }
}

Windows CE | Windows Mobile 应用程序

在 Windows CE 和 Windows Mobile 中实现,是通过 Win32 API实现的,下面是封装的帮助类:

参考:

using System;
using System.Runtime.InteropServices;

namespace XY.Util.Helper
{
    /// <summary>
    /// Mutex helper
    /// </summary>
    public class MutexHelper
    {
        [DllImport("coredll.dll", EntryPoint = "CreateMutex", SetLastError = true)]
        public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);

        [DllImport("coredll.dll", EntryPoint = "ReleaseMutex", SetLastError = true)]
        public static extern bool ReleaseMutex(IntPtr hMutex);

        private const int ERROR_ALREADY_EXISTS = 0183;

        /// <summary>
        /// 判断程序是否已经运行
        /// <param name="assembly">程序集实例</param>
        /// </summary>
        /// <returns>
        /// true: 程序已运行
        /// false: 程序未运行
        /// </returns>
        public static bool IsApplicationOnRun(System.Reflection.Assembly assembly)
        {
            string strAppName = assembly.GetName().Name;
            return IsApplicationOnRun(strAppName);
        }

        /// <summary>
        /// 判断程序是否已经运行
        /// <param name="assemblyName">程序名称</param>
        /// </summary>
        /// <returns>
        /// true: 程序已运行
        /// false: 程序未运行
        /// </returns>
        public static bool IsApplicationOnRun(string assemblyName)
        {
            IntPtr hMutex = CreateMutex(IntPtr.Zero, true, assemblyName);
            if (hMutex == IntPtr.Zero)
            {
                throw new ApplicationException("Failure creating mutex: " + Marshal.GetLastWin32Error().ToString("X"));
            }
            if (Marshal.GetLastWin32Error() == ERROR_ALREADY_EXISTS)
            {
                ReleaseMutex(hMutex);
                return true;
            }
            return false;
        }
    }
}

示例代码

调用示例:

using System;
using System.Reflection;
using XY.Util.Helper;

namespace MutexTest
{
    static class Program
    {
        [MTAThread]
        static void Main(string[] args)
        {
            bool run;

            //方式一
            run = MutexHelper.IsApplicationOnRun("ApplicationName");

            //方式二
            run = MutexHelper.IsApplicationOnRun(Assembly.GetExecutingAssembly());

            if (run)
            {
                // application is running...
                // Exit.
            }
            else
            {
                // start application ...
                // startup...
            }
        }
    }
}