分享
 
 
 

基于.Net平台应用程序唯一运行实例C#代码实现

王朝c#·作者佚名  2006-12-27
窄屏简体版  字體: |||超大  

基于.Net平台应用程序唯一运行实例C#代码实现

作者:郑佐

时间:2006-7-2

概述

本文是针对《基于.Net平台应用程序唯一运行实例实现》的补充,文章给出功能实现代码,其中SingleInstance类实现只允许一个实例运行,Program为测试主程序入口。在代码中标识说明文字。完整代码下载

主要代码

SingleInstance.cs文件,

using System;

using System.IO;

using System.Diagnostics;

using System.Threading;

using System.Reflection;

using System.Runtime.InteropServices;

/*------------------------------------------------

郑佐 2006-07-01 http://blog.csdn.net/zhzuo

--------------------------------------------------*/

namespace Zhengzuo.CSharpCode

{

/// <summary>

/// 只启动一个应用程序实例控制类

/// </summary>

public static class SingleInstance

{

private const int WS_SHOWNORMAL = 1;

[DllImport("User32.dll")]

private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

[DllImport("User32.dll")]

private static extern bool SetForegroundWindow(IntPtr hWnd);

//标志文件名称

private static string runFlagFullname = null;

//声明同步基元

private static Mutex mutex = null;

/// <summary>

/// static Constructor

/// </summary>

static SingleInstance()

{

}

#region api实现

/// <summary>

/// 获取应用程序进程实例,如果没有匹配进程,返回Null

/// </summary>

/// <returns>返回当前Process实例</returns>

public static Process GetRunningInstance()

{

Process currentProcess = Process.GetCurrentProcess();//获取当前进程

//获取当前运行程序完全限定名

string currentFileName = currentProcess.MainModule.FileName;

//获取进程名为ProcessName的Process数组。

Process[] processes = Process.GetProcessesByName(currentProcess.ProcessName);

//遍历有相同进程名称正在运行的进程

foreach (Process process in processes)

{

if (process.MainModule.FileName == currentFileName)

{

if (process.Id != currentProcess.Id)//根据进程ID排除当前进程

return process;//返回已运行的进程实例

}

}

return null;

}

/// <summary>

/// 获取应用程序句柄,设置应用程序前台运行,并返回bool值

/// </summary>

public static bool HandleRunningInstance(Process instance)

{

//确保窗口没有被最小化或最大化

ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);

//设置真实例程为foreground window

return SetForegroundWindow(instance.MainWindowHandle);

}

/// <summary>

/// 获取窗口句柄,设置应用程序前台运行,并返回bool值,重载方法

/// </summary>

/// <returns></returns>

public static bool HandleRunningInstance()

{

Process p = GetRunningInstance();

if (p != null)

{

HandleRunningInstance(p);

return true;

}

return false;

}

#endregion

#region Mutex实现

/// <summary>

/// 创建应用程序进程Mutex

/// </summary>

/// <returns>返回创建结果,true表示创建成功,false创建失败。</returns>

public static bool CreateMutex()

{

return CreateMutex(Assembly.GetEntryAssembly().FullName);

}

/// <summary>

/// 创建应用程序进程Mutex

/// </summary>

/// <param name="name">Mutex名称</param>

/// <returns>返回创建结果,true表示创建成功,false创建失败。</returns>

public static bool CreateMutex(string name)

{

bool result = false;

mutex = new Mutex(true, name, out result);

return result;

}

/// <summary>

/// 释放Mutex

/// </summary>

public static void ReleaseMutex()

{

if (mutex != null)

{

mutex.Close();

}

}

#endregion

#region 设置标志实现

/// <summary>

/// 初始化程序运行标志,如果设置成功,返回true,已经设置返回false,设置失败将抛出异常

/// </summary>

/// <returns>返回设置结果</returns>

public static bool InitRunFlag()

{

if (File.Exists(RunFlag))

{

return false;

}

using (FileStream fs = new FileStream(RunFlag, FileMode.Create))

{

}

return true;

}

/// <summary>

/// 释放初始化程序运行标志,如果释放失败将抛出异常

/// </summary>

public static void DisposeRunFlag()

{

if (File.Exists(RunFlag))

{

File.Delete(RunFlag);

}

}

/// <summary>

/// 获取或设置程序运行标志,必须符合Windows文件命名规范

/// 这里实现生成临时文件为依据,如果修改成设置注册表,那就不需要符合文件命名规范。

/// </summary>

public static string RunFlag

{

get

{

if(runFlagFullname == null)

{

string assemblyFullName = Assembly.GetEntryAssembly().FullName;

//CommonApplicationData://"C:\\Documents and Settings\\All Users\\Application Data"

string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

//"C:\\Program Files\\Common Files"

//string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);

runFlagFullname = Path.Combine(path, assemblyFullName);

}

return runFlagFullname;

}

set

{

runFlagFullname = value;

}

}

#endregion

}

}

Program.cs文件,

using System;

using System.Windows.Forms;

using System.Diagnostics;

using Zhengzuo.CSharpCode;

/*------------------------------------------------

郑佐 2006-07-01 http://blog.csdn.net/zhzuo

--------------------------------------------------*/

namespace Zhengzuo.Test.WinGui

{

static class Program

{

[STAThread]

static void Main(string[] args)

{

if (args.Length == 0) //没有传送参数

{

Process p = SingleInstance.GetRunningInstance();

if (p != null) //已经有应用程序副本执行

{

SingleInstance.HandleRunningInstance(p);

}

else //启动第一个应用程序

{

RunApplication();

}

}

else //有多个参数

{

switch (args[0].ToLower())

{

case "-api":

if (SingleInstance.HandleRunningInstance() == false)

{

RunApplication();

}

break;

case "-mutex":

if (args.Length >= 2) //参数中传入互斥体名称

{

if ( SingleInstance.CreateMutex(args[1]) )

{

RunApplication();

SingleInstance.ReleaseMutex();

}

else

{

//调用SingleInstance.HandleRunningInstance()方法显示到前台。

MessageBox.Show("程序已经运行!");

}

}

else

{

if (SingleInstance.CreateMutex())

{

RunApplication();

SingleInstance.ReleaseMutex();

}

else

{

//调用SingleInstance.HandleRunningInstance()方法显示到前台。

MessageBox.Show("程序已经运行!");

}

}

break;

case "-flag"://使用该方式需要在程序退出时调用

if (args.Length >= 2) //参数中传入运行标志文件名称

{

SingleInstance.RunFlag = args[1];

}

try

{

if (SingleInstance.InitRunFlag())

{

RunApplication();

SingleInstance.DisposeRunFlag();

}

else

{

//调用SingleInstance.HandleRunningInstance()方法显示到前台。

MessageBox.Show("程序已经运行!");

}

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

break;

default:

MessageBox.Show("应用程序参数设置失败。");

break;

}

}

}

//启动应用程序

static void RunApplication()

{

Application.EnableVisualStyles();

Application.Run(new MainForm());

}

}

}

功能测试

功能测试类别包括下面五类,

1.本地系统同一应用程序目录;

2.本地系统同一应用程序修改运行文件名称使两次运行名称不同;

3.本地系统两次运行程序目录不同,不修改文件名称;

4.本地系统不同会话用户登录启动应用程序;

5.远程计算机程序访问启动应用程序(一个程序在远程另一个在本地)。

运行CMD命令行,

第一种调用方式:

WindowsApplication1.exe

或 WindowsApplication1.exe –api

第二种调用方式:

WindowsApplication1.exe –mutex

或WindowsApplication1.exe –mutex {F140AE26-626C-42f8-BD49-45025742205E}

第三种调用方式:

WindowsApplication1.exe –flag

或WindowsApplication1.exe –flag c:\blog.csdn.net.zhzuo

测试结果,

匹配/互斥/标志

1同一目录

2修改名称

3不同目录

4不同用户

5远程访问

1同一目录

O/O/O

2修改名称

X/O/O

3不同目录

X/O/O

4不同用户

#/X/O

5远程访问

X/O/O

备注:O - 表示成功,X – 表示失败,# - 程序第二个运行没有反应

针对远程访问的测试,需要在系统管理工具的.NET Framework 2.0 Configuration中进行设置授权该局域网路径允许访问,否则会抛出System.Security.SecurityException异常。

根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。

更多资源

关于.NET平台应用的开发,更多的技术文章可以访问http://blog.csdn.net/zhzuo,对于本文的建议或意见可在网站上留言。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有