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 原子操作,上面几种方法中, 综合考虑利用 ...
随机推荐
- fast-json.jar的用法
fast-json.jar 解析json数据:一种json数据解析方式是这种,点击这里下载jsonfast.jar+fastjsonAPI文档 [ { "id": 6378, &q ...
- WinForm播放视频
原文:WinForm播放视频 1背景 这几天一老友要求我做个小软件,在WinForm播放视频.印象中微软有个WM控件直接可以使用,晚上研究下 2实现方式 2.1微软草根 最简单的方式,是直接使用微软的 ...
- Java获取.properties配置文件某一项value根据key值
public static String getProperty(String key){ InputStream in = PropertiesUtils.class.getResourceAsSt ...
- Spring Resource之ResourceLoader
ResourceLoader接口意味着任何实现的对象都能够返回Resource实例. public interface ResourceLoader { Resource getResource(St ...
- [译]Java 垃圾回收介绍
说明:这篇文章来翻译来自于Javapapers 的Java Garbage Collection Introduction 在Java中,对象内存空间的分配与回收是由JVM中的垃圾回收进程自动完成的. ...
- js 模拟QQ聊天窗口图片播放效果(带滚轮缩放)
页面效果如下: 完整代码如下: <!DOCTYPE html> <html> <head> <title>Test</title> < ...
- 创业路(VC Pipeline),创业需要融资的阅读
企业家们经常问我,您的投资渠道(投资流程)到底是怎么样的? 看看有多少项目,有多少人遇到,频度,终于选择哪些公司进行了投资. 这让我认为有必要提高VC投资通道的可见度.同一时候也有助于介绍到底哪些方面 ...
- .NET的微型Web框架 Nancy
.NET的微型Web框架 Nancy .NET的微型Web框架 Nancy 大部分微软平台的开发人员如果选择开发框架只能是在ASP.NET WEBFORM和ASP.NET MVC两个之间选择. 而 ...
- 2014年3I工作室成员的正式名单
后3I认真审议和审查工作室的老师及相关人员,今天,新成员首次正式发布,如以下:博才文(11软件).黄彩云(11软件).朱小丹(11软件).海(11软件).欧剑灵(11此计).黄思源(12软件).黄龙营 ...
- wcf跨机器访问的问题
wcf跨机器访问的问题 在wcf跨机器的访问中遇到了各种无法访问的问题,本人也是在通过个人解决问题的基础上发表一下自己的经验,如果还有其他方面可能影响wcf跨机器的问题,还希望大家多多发言! 好了废话 ...