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 原子操作,上面几种方法中, 综合考虑利用 ...
随机推荐
- asp.net 获得客户端 mac 地址
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- Redis 中文入库成功,读取数据写入文件乱码问题
近期须要用到redis ,可是在编码这个问题上,纠结了非常久. 需求 :每天一个进程将中文文件入库到redis中(不定时更新) ,另外几个进程读取redis中的信息 ,并处理数据结果.使 ...
- jQuery选取和操纵元素的特点
jQuery选取和操纵元素的特点 JavaScript选取元素 先来看看不用jQuery的时候我们是怎么处理元素选取的. JavaScript选取元素的时候,可以根据id获取元素,当id不存在的时候, ...
- Swift编程语言学习4.1——周期
Swift它提供了类似 C 流量控制结构语言,它包含运行多个任务的能力for和while周期.选择根据不同的编码分支机构的具体条件来运行if和switch声明,有控制流程跳转到其他代码break和co ...
- SQLServer 2005 数据库定阅复制实现双机热备(主要是sharepoint 内容数据库)
原文:SQLServer 2005 数据库定阅复制实现双机热备(主要是sharepoint 内容数据库) 场景 公司最近的sharepoint的数据库服务器老是出问题,并且在一旦出现问题,就导致无法正 ...
- Error with mysqld_safe
出处:http://bugs.mysql.com/bug.php?id=18403 Description: - I downloaded the binary file “Standard 5.0. ...
- 干净的架构The Clean Architecture
干净的架构The Clean Architecture 这是著名软件大师Bob大叔提出的一种架构,也是当前各种语言开发架构.干净架构提出了一种单向依赖关系,从而从逻辑上形成一种向上的抽象系统. 我们经 ...
- CentOS 5.8安装SugarCRM 6.5版本
环境:CentOS 5.8,安装了Asterisk 1.8 升级php到5.2SugarCRM 6.5: Minimum PHP version required is 5.2.0. You are ...
- .NET MVC4 实训记录之一(引入Unity3.0 Ioc框架)
一直在做维护项目,没有机会接触完整的架构,于是自学.NET MVC.自今日起,将自学的过程.遇到的问题以及解决方案记录下来. 在WebApp项目中右键,使用NuGet引入Unity3.0.
- Javascript中布尔运算符的高级应用
对象检测语句:var W3CDOM = document.getElementsByTagName && document.createElement 为了执行运算符&& ...