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单实例运行

  [C# 开发技巧]如何防止程序多次运行

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。

感谢阅读,希望这篇文章能给你带来帮助!

Winform 单实例运行的更多相关文章

  1. WinForm 登录窗体 + 单实例运行

    关于怎么在winform里增加登录窗体或者如何让winform程序单实例运行网上都很多例子. 然而两者结合起来呢? //Program.cs static class Program { public ...

  2. DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法

    原文:DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA ...

  3. Qt实现应用程序单实例运行--LocalServer方式

    使Qt应用程序能够单实例运行的典型实现方法是使用共享内存实现.该方法实现简单,代码简洁. 但有一个致命缺陷:共享内存(QSharedMemory)实现的单程序运行,当运行环境是UNIX时,并且程序不幸 ...

  4. wpf单实例运行

    默认情况下我们可以打开一个应用程序多个实例,例如你双击一个exe多次.当然有些时候这么做会带来很多好处,但是有时我们又不希望这么做,要避免这个问题其实很简单,同WinForm中单实例运行一个应用是一样 ...

  5. C++实现程序单实例运行的两种方式

    简介 在我们编写程序的时候,经常会注意到的一个问题就是如何能够让程序只运行一个实例,确保不会让同一个程序多次运行,从而产生诸多相同进程,给我们的带来不便呢?那么常用的有以下四种方法,第一种方法是通过扫 ...

  6. Windows进程单实例运行

    场景         Windows进程单实例运行,如果有进程没有退出,继续等待,直到进程完全退出,才会进入下一个实例 HANDLE pHandle = NULL; do  {  pHandle = ...

  7. c#设计应用程序单实例运行

    利用WindowsFormsApplicationBase的IsSingleInstance来控制应用程序只能单实例运行. [DllImport("user32.dll", Ent ...

  8. c# 单实例运行

    /// <summary> /// 单实例运行程序 /// </summary> static void SingleInstanceRun() { bool isAppRun ...

  9. C#实现单实例运行

    C#实现单实例运行的方法,也有多种,比如利用 Process 查找进程的方式,利用 API findwindow 查找窗体的方式,还有就是 利用 Mutex 原子操作,上面几种方法中, 综合考虑利用 ...

随机推荐

  1. hdu1047 Integer Inquiry 多次大数相加

    转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1047 Problem ...

  2. C# - Recommendations for Abstract Classes vs. Interfaces

     The choice of whether to design your functionality as an interface or an abstract class can somet ...

  3. Redis 优化查询性能

    一次使用 Redis 优化查询性能的实践   应用背景 有一个应用需要上传一组ID到服务器来查询这些ID所对应的数据,数据库中存储的数据量是7千万,每次上传的ID数量一般都是几百至上千数量级别. 以前 ...

  4. inux平台的C与C++

    课堂里学不到的C与C++那些事(一) 首先,声明一下这是一个系列的文章.至于整个系列有多少篇,笔者也不知道,不知道有多少篇,也不知道多久会更新一篇.反正只有一个原则,写出来的文 章能见得人才会公布出来 ...

  5. HTML5实现涂鸦板

    原文:HTML5实现涂鸦板 最近闲的,看了看html5,强大的绘图功能让我惊奇,于是,写了个小玩意---涂鸦板,能实现功能有:画画,改色,调整画笔大小 html5的绘图可以分为点,线,面,圆,图片等, ...

  6. 通过Web Api 和 Angular.js 构建单页面的web 程序

    通过Web Api 和 Angular.js 构建单页面的web 程序 在传统的web 应用程序中,浏览器端通过向服务器端发送请求,然后服务器端根据这个请求发送HTML到浏览器,这个响应将会影响整个的 ...

  7. ASP.NET如何显示农历时间

    ASP.NET如何显示农历时间 CS部分代码如下: 代码如下: public string ChineseTimeNow = "";  public string ForignTi ...

  8. 大约xib连接错误bug正确

    今天code什么时候,发现xib除了加载问题,研究发现的一个问题 在连接的时候, object一定要选择,您连接view,代替 File's Owner 版权声明:本文博客原创文章,博客,未经同意,不 ...

  9. Yii2中如何使用CodeCeption

    Yii2和CodeCeption CodeCeption是一个全栈的PHP测试框架,关于CodeCeption的介绍见:CodeCeption官方文档. Yii2官方增加了对CodeCeption的支 ...

  10. js 实现复制粘贴文本过滤(保留文字和图片)

    实现复制粘贴文本过滤(保留文字和图片) demo如下: <head> <meta http-equiv="Content-Type" content=" ...