前两天在博客园看到《如何防止程序屡次运行》,文章写的很好,最后还留下一个问题给咱们思考。关于Winform的防止屡次运行,曾经也想研究过,可是后来工做上没有须要,因而就放弃了研究,这两天找资料,将其封装了一下,最后实现的效果为:Winform程序运行后,再次点击exe,会将Winform显示出去,若该窗体被其余窗体遮挡,则将其前置,若该窗体被最小化至托盘,将其显示并前置。html
使用命名事件,进程在此启动时,前一个进程会收到通知,并作出回应。ide
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms; namespace Ulitiy { /// <summary> /// 任务栏简单封装 /// </summary> /// <remarks> /// 检查程序是否再次运行:在main方法里调用:TaskBarUtil.CheckCreated(); /// 主窗体在load事件或者构造方法初始化组件后调用:new TaskBarUtil(this, notifyIcon1); /// </remarks> public class TaskBarUtil { private Form mainForm; private NotifyIcon notifyIcon1; public static EventWaitHandle ProgramStarted; public TaskBarUtil(Form main, NotifyIcon notifyIcon1) { this.mainForm = main; this.notifyIcon1 = notifyIcon1; Load(); } [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); #region 右下角图标控制 private void Load() { //注册进程OnProgramStarted ThreadPool.RegisterWaitForSingleObject(ProgramStarted, (obj, timeout) => { ShowForm(); }, null, -1, false); #region 窗体事件 mainForm.SizeChanged += new EventHandler((sender, e) => { if (mainForm.WindowState == FormWindowState.Minimized) { HideForm(); } }); mainForm.FormClosing += new FormClosingEventHandler((sender, e) => { //注意判断关闭事件Reason来源于窗体按钮,不然用菜单退出时没法退出! if (e.CloseReason == CloseReason.UserClosing) { mainForm.WindowState = FormWindowState.Minimized; //使关闭时窗口向右下角缩小的效果 notifyIcon1.Visible = true; e.Cancel = true; } }); #endregion #region 任务栏图标上下文事件 ContextMenuStrip contextMenuStrip1 = new ContextMenuStrip(); //设置任务栏图标上下文事件 var tsmShow = new ToolStripMenuItem(); tsmShow.Name = "tsmShow"; tsmShow.Text = "显示"; tsmShow.Click += new System.EventHandler((sender, e) => { if (mainForm.Visible) return; ShowForm(); }); var tsmExit = new ToolStripMenuItem(); tsmExit.Text = "退出"; tsmExit.Name = "tsmShow"; tsmExit.Click += new System.EventHandler((sender, e) => { Application.Exit(); }); contextMenuStrip1.Items.Add(tsmShow); contextMenuStrip1.Items.Add(tsmExit); #endregion #region 任务栏图标事件 notifyIcon1.ContextMenuStrip = contextMenuStrip1; notifyIcon1.BalloonTipIcon = ToolTipIcon.Info; //notifyIcon1.Click += new EventHandler((sender, e) => //{ // //ShowForm(); //}); notifyIcon1.MouseClick += new MouseEventHandler((sender, e) => { if (e.Button != MouseButtons.Right) { ShowForm(); } }); #endregion } private void ShowForm() { mainForm.Visible = true; //显示窗体 if (mainForm.WindowState == FormWindowState.Minimized) mainForm.WindowState = FormWindowState.Normal; //恢复窗体默认大小 //该属性在设置后,再次双击exe,会致使窗体在弹出时假死,使用form的Actived事件替代 //mainForm.ShowInTaskbar = true; mainForm.Show(); //前置该窗体 SetForegroundWindow(mainForm.Handle); } private void HideForm() { mainForm.Visible = false; //隐藏窗体 //notifyIcon1.ShowBalloonTip(3000, "提示", "双击恢复窗口", ToolTipIcon.Info); //出显汽泡提示,能够不用 //mainForm.ShowInTaskbar = false; //从状态栏中隐藏 mainForm.Hide(); } #endregion #region 检查是否启动过,若是启动则通知前一个进程,并退出当前进程 /// <summary> /// 检查是否启动过,若是启动则通知前一个进程,并退出当前进程 /// </summary> public static void CheckCreated() { // 尝试建立一个命名事件 bool createNew; //ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, "MyStartEvent", out createNew); ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Application.ProductName, out createNew); // 若是该命名事件已经存在(存在有前一个运行实例),则发事件通知并退出 if (!createNew) { TaskBarUtil.ProgramStarted.Set(); Environment.Exit(1); } } #endregion } }
其中遇到的问题有在显示和隐藏对窗体的操做中,若是改变form的ShowInTaskbar会出问题。通过不严格的测试,这种发生在,在Winform运行后,屡次点击exe,在此过程当中单机窗体关闭,偶尔会出现没法找到句柄的错误。因此在显示和隐藏窗体的操做中,就没有对该属性进行操做。测试
封装类包含了以下功能:this
一、Winform 进程只能运行一个实例。spa
二、Winform 任务栏图标含上下文菜单,显示和退出,并包含相应的事件。code
3. Winform 任务栏图标含鼠标点击事件,点击即显示窗体。orm
使用过程当中注意: 拖入notifyicon控件,并指定图标。htm
若是不须要这其中的功能,能够将类任意修改,知足你的须要。blog
示例下载进程