需求:1、点击“关闭”按钮时,程序最小化到托盘,并没有退出,这时再次运行程序,不会重复运行,而是显示已运行的程序;2、支持不同目录;3、支持修改名称。

代码(不支持修改名称,不支持不同目录):

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tool;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices; namespace 计算器
{
static class Program
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// 该函数设置由不同线程产生的窗口的显示状态。
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分。</param>
/// <returns>如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零。</returns>
[DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
/// <summary>
/// 该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
/// </summary>
/// <param name="hWnd">将被激活并被调入前台的窗口句柄。</param>
/// <returns>如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。</returns>
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int SW_SHOWNORMAL = ; /// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); Process processes = RunningInstance();
if (processes == null)
{
Application.Run(new Form1());
}
else
{
HandleRunningInstance(processes);
}
} /// <summary>
/// 获取正在运行的实例,没有运行的实例返回null;
/// </summary>
public static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process process in processes)
{
if (process.Id != current.Id)
{
if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
{
return process;
}
}
}
return null;
} /// <summary>
/// 显示已运行的程序。
/// </summary>
public static void HandleRunningInstance(Process instance)
{
try
{
IntPtr formHwnd = FindWindow(null, "计算器");
ShowWindow(formHwnd, SW_SHOWNORMAL); //显示
SetForegroundWindow(formHwnd); //放到前端
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}

代码(支持修改名称,支持不同目录):

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tool;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices; namespace 计算器
{
static class Program
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// 该函数设置由不同线程产生的窗口的显示状态。
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分。</param>
/// <returns>如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零。</returns>
[DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
/// <summary>
/// 该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
/// </summary>
/// <param name="hWnd">将被激活并被调入前台的窗口句柄。</param>
/// <returns>如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。</returns>
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int SW_SHOWNORMAL = ; /// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Common.AutoRegister(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); bool createNew;
using (System.Threading.Mutex m = new System.Threading.Mutex(true, Application.ProductName, out createNew))
{
if (createNew)
{
FileOperator.SetValue("ProcessId", Process.GetCurrentProcess().Id.ToString()); //进程ID写入文件
Application.Run(new Form1());
}
else
{
try
{
string strProcessId = FileOperator.GetValue("ProcessId"); //从文件中获取进程ID
int processId = Convert.ToInt32(strProcessId);
Process process = Process.GetProcessById(processId);
HandleRunningInstance(process);
}
catch
{
FileOperator.SetValue("ProcessId", Process.GetCurrentProcess().Id.ToString()); //进程ID写入文件
Application.Run(new Form1());
}
}
}
} /// <summary>
/// 显示已运行的程序。
/// </summary>
public static void HandleRunningInstance(Process instance)
{
try
{
IntPtr formHwnd = FindWindow(null, "计算器");
ShowWindow(formHwnd, SW_SHOWNORMAL); //显示
SetForegroundWindow(formHwnd); //放到前端
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}

其实,IntPtr formHwnd = FindWindow(null, "计算器"); 这段代码是有BUG的,比如你打开一个名为“计算器”的文件夹,那么FindWindow找到的其实是这个文件夹,而不是计算器程序。我们可以在主窗体第一次显示的时候,记下窗口句柄,代码如下:

private void Form1_Shown(object sender, EventArgs e)
{
FileOperator.SetValue("hwnd", Process.GetCurrentProcess().MainWindowHandle.ToString());
}

然后,显示已运行的程序时,从文件中读取之前记录的窗口句柄,代码如下:

/// <summary>
/// 显示已运行的程序
/// </summary>
public static void HandleRunningInstance(Process instance)
{
try
{
IntPtr hwnd = new IntPtr(Convert.ToInt32(FileOperator.GetValue("hwnd")));
ShowWindow(hwnd, SW_SHOWNORMAL); //显示
SetForegroundWindow(hwnd); //放到前端
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

综上,再整理一下,就能得到完美的解决方案。

Winform防止程序重复运行的更多相关文章

  1. C# Winform防止一个程序重复运行

    1: //在写一些服务型的软件的时候,你可能不希望一个操作系统里有两个副本在运行,这样也许会扰乱你的操作.这时,你就需要限制程序的副本.下面的这个方法,很简单的就可以实现上述功能. using Sys ...

  2. C# WINFORM判断程序是否运行,且只能运行一个实例(转)

    判断程序是否已经运行,使程序只能运行一个实例有很多方法,下面记录两种, 方法1:线程互斥 static class Program { private static System.Threading. ...

  3. winform判断程序是否运行,且只能运行一个实例

    前言 判断程序是否已经运行,使程序只能运行一个实例有很多方法,下面记录两种. 目前使用的是第一种方法. 方法1:线程互斥 static class Program { private static S ...

  4. C# .NET Winform等程序一运行就闪退 不同环境 换到其他电脑,例如XP之类的解决方法。

    我现在写标题就跟写tag一样,方便大家索引. 有时候经常会把.NET写的程序拿到其他客户机,发现直接闪退,啥也不报错..那就很蛋疼,又不可能去装IDE来检测是吧,网上还有很多说啥看系统日志的,什么图标 ...

  5. [转]使用互斥对象让程序只运行一次(delphi)

    使用互斥对象让程序只运行一次“怎么让我的程序在运行时不能重复打开?”经常在论坛上看到有朋友问这方面的问题.本文将比较详细的说明这一问题,并给出一个较为完善的解决方案. 尽管这已经不是一个新问题了,但这 ...

  6. C#检测应用程序重复启动----函数检测(可以在多用户登录情况下检测)

    上文是在网上找的检测程序重复运行的类,但是感觉不是很好用,而且还使用了API,似乎完全没有必要,于是晚上自己写了一个函数,经过测试,在多用户下仍然可以检测到程序的多次运行.当然,如果程序改了名字还是可 ...

  7. [WinForm]C# .net防止一个程序(WinForm)重复运行的方法。

    最近比较忙,邮件预警系统暂停了没时间去处理,临时处理:直接执行exe文件! 可是问题来了: 我点击了两次,原来几乎在同时执行这个进程,我在程序中有线程时间睡眠2秒一次等待队列,打开进程果然两个MAIL ...

  8. MONO 如何打包 .NET程序独立运行(winform篇)

    .NET程序独立运行是指运行.NET的电脑上,不需要安装.NET框架. .NET程序集“独立运行”并非真正的独立,它是运行在mono运行时基础之上的.由于这个运行时可以独立存在,所以,我们不需要在目标 ...

  9. winform .net2.0的程序如何运行于.net 4.x

    约束 最近有一个winform项目,要求: (1)程序能够运行在winxp, win7, win8, win10中 (2)安装尽可能简单,尽量不要安装.net framework.即使要安装也要尽可以 ...

随机推荐

  1. python的高性能web应用的开发与测试实验

    python的高性能web应用的开发与测试实验 tornado“同步和异步”网络IO模型实验 引言 python语言一直以开发效率高著称,被广泛地应用于自动化领域: 测试自动化 运维自动化 构建发布自 ...

  2. leveldb源码学习系列

    楼主从2014年7月份开始学习<>,由于书籍比较抽象,为了加深思考,同时开始了Google leveldb的源码学习,主要是想学习leveldb的设计思想和Google的C++编程规范.目 ...

  3. Oracle存在修改,不存在插入记录

    接触编程以来,在数据存储方面一直用的MS SQL.Oracle这名字对我来说是如此的熟悉,但是对其内容却很陌生,最近公司的一个项目用起了Oracle,所以也开始高调的用起了Oracle.在没有接触Or ...

  4. 如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)

    六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...

  5. iOS——Core Animation 知识摘抄(三)

    原文地址:http://www.cocoachina.com/ios/20150105/10827.html CAShapeLayer CAShapeLayer是一个通过矢量图形而不是bitmap来绘 ...

  6. js 倒计时实现

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. Senparc.Weixin.MP SDK 微信公众平台开发教程(三):微信公众平台开发验证

    要对接微信公众平台的"开发模式",即对接到自己的网站程序,必须在注册成功之后(见Senparc.Weixin.MP SDK 微信公众平台开发教程(一):微信公众平台注册),等待官方 ...

  8. MSP是什么?

    本人在项目管理圈儿也算是摸爬滚打了几载,近几年真是各种压力大,看同行们各种参加培训.认证......我也不能懈怠啊,赶紧上网搜搜相关的培训和认证信息,不搜不知道一搜吓一跳.原本只知道PMP和PRINC ...

  9. 关于 fir.im 你可能不知道的实用小工具

    大家可能都知道 fir.im 是做测试发包的,上传你的 IPA/APK, 测试用户可以通过一个短链接和二维码就可快速安装测试. 除了基本的发包功能即应用上传下载外,fir.im 还为提高发包体验提供了 ...

  10. asp.net mvc 使用ajax请求 控制器 (PartialViewResult)分部的action,得到一个分部视图(PartialView)的HTML,进行渲染

    在asp.net mvc 使用ajax请求获取数据的时候,我们一般是返回json或者xml,然后解析这些数据进行渲染,这样会比较麻烦,可以请求一个 分部action,返回一个分部视图 直接可以渲染,不 ...