wiki:csharp:winform-fz-cx-dkdc
防止窗体打开多次
/// <summary> /// 当前已经打开的窗口对象名称列表 /// </summary> public static ArrayList FormList = new ArrayList(); /// <summary> /// 查看已打开的窗口是否包括该名称的对象 /// </summary> /// <param name="formName"></param> /// <returns></returns> public static bool IsFormExist(ref Form form, string formName) { bool opened = false; foreach (Form frm in FormList) { if (frm.Name == formName) { opened = true; form = frm; break; } } return opened; } private void frmProjectManager_FormClosed(object sender, FormClosedEventArgs e) { Functions.FormList.Remove(this); } /// <summary> /// 新建项目 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ctBtb_NewProject_Click(object sender, EventArgs e) { frmProjectManager frmProjectManager1 = null; Form frm = null; if (Functions.IsFormExist(ref frm, "frmProjectManager1")) { frmProjectManager1 = frm as frmProjectManager; } else { frmProjectManager1 = new frmProjectManager(); Functions.FormList.Add(frmProjectManager1); } frmProjectManager1.Name = "frmProjectManager1"; frmProjectManager1.Location = new Point(Functions.FrmBounds.Left, Functions.FrmBounds.Top); if(!frmProjectManager1.Visible) frmProjectManager1.Show(this); }
防止程序打开、运行、启动多次(a,GUID)
实现思路:
在Main()方法开始时遍历所有进程,获取每个进程的程序集GUID和PID,若发现有跟自己GUID相同且PID不同的进程,就勒令自身退出。 注:
- 采用GUID是为了尽可能保证判定的可靠性,采用进程名太不靠谱。而且程序集GUID是建立项目时就生成的,不随版本、内容的变化而变化,所以除非人为改动,否则同一项目编译若干次都还是那个GUID,用来判断程序集身份再适合不过。题外,网上盛传的互斥体方法,互斥名也建议用GUID;
- 之所以要加上进程ID的判断,是因为遍历的进程中已经包含自身进程,所以必须排除自身;
- 访问某些进程的MainModule属性会引发异常,所以采用try-catch跳过这些进程;
- 经尝试只有C#写的程序才能获取到GUID(有点废话~),但这样已经足够;
- 退出自身这里采用的是Environment.Exit()方法,Application.Exit()方法不管用,程序仍然会运行,我猜原因是Application都还没Run过,所以Exit不了~(小弟入门水平,很多东西只能靠坑蒙拐骗~哦不,是连蒙带猜)
- testallapirefreshpolicy.cs
using System; using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; namespace TestCallAPIRefreshPolicy { static class Program { [STAThread] static void Main() { Guid ownGUID = new Guid(((GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(GuidAttribute))).Value); Guid proGUID; int ownPID = Process.GetCurrentProcess().Id; int proPID; foreach (Process p in Process.GetProcesses()) { try { proGUID = new Guid(((GuidAttribute)Attribute.GetCustomAttribute(Assembly.LoadFile(p.MainModule.FileName), typeof(GuidAttribute))).Value); proPID = p.Id; if (proGUID.Equals(ownGUID) && proPID != ownPID) { MessageBox.Show("程序已运行"); Environment.Exit(Environment.ExitCode); } } catch { continue;//遇上进程访问异常就跳过该进程 } } //若未被Exit,正常启动 Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FmMain()); } } }
防止程序启动多次
经常我们会有这样的需求,只让应用程序运行一个实体。通常我们的情况是,双击一个exe文件,就运行一个程序的实体,再双击一次这个exe文件,又运行这个应用程序的另一个实体。就拿QQ游戏来说吧,一台电脑上一般只能运行一个QQ游戏大厅(不过以前听说过有双开的)。 那我们的程序也能像QQ游戏那里禁止多次启动吗,答案是可以的,下面介绍下一个简单的实现方法,那就是Mutex(互斥)。
Mutex(mutual exclusion,互斥)是.Net Framework中提供跨多个线程同步访问的一个类。它非常类似了Monitor类,因为他们都只有一个线程能拥有锁定。而操作系统能够识别有名称的互斥,我们可以给互斥一个唯一的名称,在程序启动之前加一个这样的互斥。这样每次程序启动之前,都会检查这个命名的互斥是否存在。如果存在,应用程序就退出。
- main.cs
static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { bool createdNew; //系统能够识别有名称的互斥,因此可以使用它禁止应用程序启动两次 //第二个参数可以设置为产品的名称:Application.ProductName //每次启动应用程序,都会验证名称为SingletonWinAppMutex的互斥是否存在 Mutex mutex = new Mutex(false, "SingletonWinAppMutex", out createdNew); //如果已运行,则在前端显示 //createdNew == false,说明程序已运行 if (!createdNew) { Process instance = GetExistProcess(); if (instance != null) { SetForegroud(instance); Application.Exit(); return; } } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } /// <summary> /// 查看程序是否已经运行 /// </summary> /// <returns></returns> private static Process GetExistProcess() { Process currentProcess = Process.GetCurrentProcess(); foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName)) { if ((process.Id != currentProcess.Id) && (Assembly.GetExecutingAssembly().Location == currentProcess.MainModule.FileName)) { return process; } } return null; } /// <summary> /// 使程序前端显示 /// </summary> /// <param name="instance"></param> private static void SetForegroud(Process instance) { IntPtr mainFormHandle = instance.MainWindowHandle; if (mainFormHandle != IntPtr.Zero) { ShowWindowAsync(mainFormHandle, 1); SetForegroundWindow(mainFormHandle); } } [DllImport("User32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("User32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow); }
wiki/csharp/winform-fz-cx-dkdc.txt · 最后更改: 2023/01/03 15:25 由 127.0.0.1
评论