1) 根据“程序集的签名”获取已运行的实例
/// <summary> /// 根据“程序集的签名”获取已运行的实例 /// .EXE 文件改名或路径改变,此方法可正常工作 /// </summary> /// <param name="runningProcess">前一个实例的 Process</param> /// <returns>是否有相同的实例在运行 ture/false</returns> /// <remarks>需要对程序集进行签名。存在问题:速度稍慢。</remarks> private static bool GetRunningProcessByAssemblyName(out Process runningProcess) { bool returnValue = false; runningProcess = null; AssemblyName currentAssemblyName = AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location); AssemblyName processAssemblyName = new AssemblyName(); Process current = Process.GetCurrentProcess(); Process[] processes = Process.GetProcesses(); foreach (Process process in processes) { // 排除一些其他进程,可以加快点速度。 if (process.Id != current.Id && process.ProcessName != "System" && process.ProcessName != "csrss" && process.ProcessName != "svchost" && process.ProcessName != "services" && process.ProcessName != "smss" && process.ProcessName != "winlogon" && process.ProcessName != "explorer" && process.ProcessName != "pds" && process.ProcessName != "alg" && process.ProcessName != "msdtc" && process.ProcessName != "spoolsv" && process.ProcessName != "lsass" && process.ProcessName != "Idle" && process.ProcessName != "iexplore" && process.ProcessName != "sqlserver" && process.ProcessName != "notepad" && process.ProcessName != "360tray" && process.ProcessName != "XDict" ) { try { // 获取文件的程序集 processAssemblyName = AssemblyName.GetAssemblyName(process.MainModule.FileName); } catch (Exception) { processAssemblyName = null; } // 通过 GetPublicKey() 来获取程序集的公钥;需要对程序集签名,否则 GetPublicKey() 返回的是 Null。 if (processAssemblyName != null && CompareBytes(currentAssemblyName.GetPublicKey(), processAssemblyName.GetPublicKey())) { runningProcess = process; returnValue = true; break; } } } return returnValue; }
2) 根据“进程名称”获取已运行的实例
/// <summary> /// 根据“进程名称”获取已运行的实例 /// </summary> /// <param name="runningProcess">前一个实例的 Process</param> /// <returns>是否有相同的实例在运行 ture/false</returns> /// <remarks>存在问题:1)有可能有相同的进程名; 2)修改了文件名,此方法失效。</remarks> private static bool GetRunningProcessByProcessName(out Process runningProcess) { bool returnValue = false; runningProcess = null; Process current = Process.GetCurrentProcess(); Process[] processes = Process.GetProcessesByName(current.ProcessName); foreach (Process process in processes) { if (process.Id != current.Id) { if (process.ProcessName == current.ProcessName) { runningProcess = process; returnValue = true; break; } } } return returnValue; }
3) 根据“进程名称和路径”获取已运行的实例
/// <summary> /// 根据“进程名称和路径”获取已运行的实例 /// </summary> /// <param name="runningProcess">前一个实例的 Process</param> /// <returns>是否有相同的实例在运行 ture/false</returns> /// <remarks>存在问题:修改了文件名或改变了文件路径,此方法失效。</remarks> private static bool GetRunningProcessByProcessFullName(out Process runningProcess) { bool returnValue = false; runningProcess = null; Process current = Process.GetCurrentProcess(); Process[] processes = Process.GetProcessesByName(current.ProcessName); foreach (Process process in processes) { if (process.Id != current.Id) { if (process.MainModule.FileName == Assembly.GetExecutingAssembly().Location) { runningProcess = process; returnValue = true; break; } } } return returnValue; }
4) 根据“Mutex”判断是否有相同的实例在运行
/// <summary> /// 根据“Mutex”判断是否有相同的实例在运行 /// </summary> /// <param name="runningProcess">总是 null</param> /// <returns>是否有相同的实例在运行 ture/false</returns> /// <remarks>存在问题:不能返回前一个实例的 Process</remarks> private static bool GetRunningProcessByMutex(out Process runningProcess) { bool returnValue = false; runningProcess = null; bool isCreated; Mutex m = new Mutex(false, "OneInstance", out isCreated); if (!(isCreated)) { MessageBox.Show("已经有相同的实例在运行。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } returnValue = !isCreated; return returnValue; } #region 私有方法 /// <summary> /// 设置指定进程的窗口为活动 /// </summary> private static void SetForegroundProcess(Process process) { bool isIcon = IsIconic(process.MainWindowHandle); // 窗口是否已最小化 if (isIcon) { // 还原窗口 ShowWindowAsync(process.MainWindowHandle, SW_RESTORE); } else { // 将窗口设为前台窗口 SetForegroundWindow(process.MainWindowHandle); } } /// <summary> /// 比较两个字节数组是否相等 /// </summary> private static bool CompareBytes(byte[] bytes1, byte[] bytes2) { if (bytes1 == null || bytes2 == null) return false; if (bytes1.Length != bytes2.Length) return false; for (int i = 0; i < bytes1.Length; i++) { if (bytes1[i] != bytes2[i]) return false; } return true; } #endregion #region Windows API 声明 /// <summary> /// 恢复一个最小化的程序,并将其激活 /// </summary> /// <param name="hWnd">窗口句柄</param> /// <returns>非零表示成功,零表示失败</returns> [System.Runtime.InteropServices.DllImport("User32.dll")] private static extern bool OpenIcon(IntPtr hWnd); /// <summary> /// 窗口是否已最小化 /// </summary> /// <param name="hWnd">窗口句柄</param> /// <returns>非零表示成功,零表示失败</returns> [System.Runtime.InteropServices.DllImport("User32.dll")] private static extern bool IsIconic(IntPtr hWnd); /// <summary> /// 将窗口设为系统的前台窗口 /// </summary> /// <param name="hWnd">窗口句柄</param> /// <returns>非零表示成功,零表示失败</returns> [System.Runtime.InteropServices.DllImport("User32.dll")] private static extern int SetForegroundWindow(IntPtr hWnd); /// <summary> /// 与ShowWindow相似,只是这时的ShowWindow命令会投递到指定的窗口,然后进行异步处理。 /// 这样一来,就可控制从属于另一个进程的窗口的可视情况。 /// 同时无须担心另一个进程挂起的时候,自己的应用程序也会牵连其中返回值 /// </summary> /// <param name="hWnd">窗口句柄</param> /// <param name="cmdShow">为窗口指定可视性方面的一个命令</param> /// <returns>如窗口之前是可见的,则返回TRUE(非零),否则返回FALSE(零)</returns> [System.Runtime.InteropServices.DllImport("User32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow); private const int SW_HIDE = 0; //隐藏窗口,活动状态给令一个窗口 private const int SW_SHOWNORMAL = 1; //用原来的大小和位置显示一个窗口,同时令其进入活动状态 private const int SW_SHOWMINIMIZED = 2; //最小化窗口,并将其激活 private const int SW_SHOWMAXIMIZED = 3; //最大化窗口,并将其激活 private const int SW_SHOWNOACTIVATE = 4; //用最近的大小和位置显示一个窗口,同时不改变活动窗口 private const int SW_RESTORE = 9; //用原来的大小和位置显示一个窗口,同时令其进入活动状态 private const int SW_SHOWDEFAULT = 10; //根据默认 创建窗口时的样式 来显示 #endregion