Winform 单实例运行
Winform 单实例运行
前言
前两天在博客园看到《如何防止程序多次运行》,文章写的很好,最后还留下一个问题给我们思考。关于Winform的防止多次运行,曾经也想研究过,但是后来工作上没有需要,于是就放弃了研究,这两天找资料,将其封装了一下,最后实现的效果为:Winform程序运行后,再次点击exe,会将Winform显示出去,若该窗体被其他窗体遮挡,则将其前置,若该窗体被最小化至托盘,将其显示并前置。
原理
使用命名事件,进程在此启动时,前一个进程会收到通知,并做出回应。

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,在此过程中单机窗体关闭,偶尔会出现无法找到句柄的错误。所以在显示和隐藏窗体的操作中,就没有对该属性进行操作。
封装类包含了如下功能:
1、Winform 进程只能运行一个实例。
2、Winform 任务栏图标含上下文菜单,显示和退出,并包含相应的事件。
3. Winform 任务栏图标含鼠标点击事件,点击即显示窗体。
使用过程中注意: 拖入notifyicon控件,并指定图标。
如果不需要这其中的功能,可以将类任意修改,满足你的需要。
参考文章
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。
感谢阅读,希望这篇文章能给你带来帮助!
Winform 单实例运行的更多相关文章
- WinForm 登录窗体 + 单实例运行
关于怎么在winform里增加登录窗体或者如何让winform程序单实例运行网上都很多例子. 然而两者结合起来呢? //Program.cs static class Program { public ...
- DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法
原文:DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA ...
- Qt实现应用程序单实例运行--LocalServer方式
使Qt应用程序能够单实例运行的典型实现方法是使用共享内存实现.该方法实现简单,代码简洁. 但有一个致命缺陷:共享内存(QSharedMemory)实现的单程序运行,当运行环境是UNIX时,并且程序不幸 ...
- wpf单实例运行
默认情况下我们可以打开一个应用程序多个实例,例如你双击一个exe多次.当然有些时候这么做会带来很多好处,但是有时我们又不希望这么做,要避免这个问题其实很简单,同WinForm中单实例运行一个应用是一样 ...
- C++实现程序单实例运行的两种方式
简介 在我们编写程序的时候,经常会注意到的一个问题就是如何能够让程序只运行一个实例,确保不会让同一个程序多次运行,从而产生诸多相同进程,给我们的带来不便呢?那么常用的有以下四种方法,第一种方法是通过扫 ...
- Windows进程单实例运行
场景 Windows进程单实例运行,如果有进程没有退出,继续等待,直到进程完全退出,才会进入下一个实例 HANDLE pHandle = NULL; do { pHandle = ...
- c#设计应用程序单实例运行
利用WindowsFormsApplicationBase的IsSingleInstance来控制应用程序只能单实例运行. [DllImport("user32.dll", Ent ...
- c# 单实例运行
/// <summary> /// 单实例运行程序 /// </summary> static void SingleInstanceRun() { bool isAppRun ...
- C#实现单实例运行
C#实现单实例运行的方法,也有多种,比如利用 Process 查找进程的方式,利用 API findwindow 查找窗体的方式,还有就是 利用 Mutex 原子操作,上面几种方法中, 综合考虑利用 ...
随机推荐
- MVC 验证码
验证码类 public class VerifyCode { public string checkCode = String.Empty; public byte[] BuildImg() { in ...
- 批处理命令篇--配置免安装mysql 5.6.22, 以及1067错误的一个解决方法
mysql 服务启动出现1067错误的一个解决方法: 当服务启动出现1067错误时,可查看“windows 事件查看器”,发现类似错误提示 Can't find messagefile 'F:\ ...
- EasyUI基础知识Draggable(拖累)
学习前easyui基于解析器,装载机.对他们来说,入门阶段,我们只需要在一个简单的理解.第一阶段,不宜过深后,.接着,根据easyui订购的文件正在研究安排官方网站Draggable插入. Dragg ...
- 省钱加油(Fuel Economy)题解
题目 农夫约翰决定去做一个环游国家旅行,为了不让他的奶牛们感到孤单,于是他决定租一辆货车带领他的奶牛们一起去旅行.这辆货车的油箱最多可以承载G 个单位的油,同时为了简化问题,规定每一个单位的油可以行使 ...
- hibernate的orphanRemoval
在@OneToMany与@OneToOne中使用orphanRemoval = true时候 改动保存时候setXXX org.springframework.orm.hibernate3.Hiber ...
- sql性能
---正在运行的 select a.username, a.sid,b.SQL_TEXT, b.SQL_FULLTEXT from v$session a, v$sqlarea b where a ...
- js 实现自动换行
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Spring IOC 之Bean定义的继承
一个Bean的定义可以包含大量的配置信息,包括构造器参数.属性值以及容器规范信息,比如初始化方法.静态工厂方法名字等等.一子bean的定义可以从父bean的定义中继承配置数据信息.子bean定义可以覆 ...
- Linux Kernel的Makefile与Kconfig文件的语法
https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt Introduction ------------ The c ...
- 开发者需要了解的WebKit
2013-3-22 22:37| 发布者: sxwgf| 查看: 575| 评论: 0|来自: infoq 摘要: Paul Irish是著名的前端开发工程师,同时他也是Chrome开发者关系团队成员 ...