大家好:
我在的公司是家鸟不拉屎的公司,SB测试没事找事做,那天用屁股告诉我,我的.NET单机应用程序,他让我判断如何在一台机器上只运行一个程序,小弟实在愚拙不知该怎么做,请各位同行们帮帮我吧,难兄难弟呀
我在的公司是家鸟不拉屎的公司,SB测试没事找事做,那天用屁股告诉我,我的.NET单机应用程序,他让我判断如何在一台机器上只运行一个程序,小弟实在愚拙不知该怎么做,请各位同行们帮帮我吧,难兄难弟呀
解决方案 »
- datagridview更新,删除问题,求代码
- datagridview批量修改单元格值呢???就是我选定的单元格,我输入一个值,我所选的所有单元格都等于这个值
- c# 用mcisendstring 播放mp3等文件的类
- 请问在c#与vb.net中,与excel文件的连接字符串怎样写?
- TableAdapter.Fill()的过程长,影响界面。怎样解决?
- else为什么不执行
- 在ADO.NET中如何控制每次只传送部分数据?
- 有做过上网记费系统的高手吗?
- 求助:大虾请帮忙
- ConnetcionString
- 请问如何把webrequest得到的网页源码中制定的代码取出来并进行分析?
- 如果我要计算日期,但日期是1899 年 12 月 30 日之前的,我该怎么办?
using System;
using System.Diagnostics;
using System.ComponentModel;namespace MyProcessSample
{
/// <summary>
/// Shell for the sample.
/// </summary>
public class MyProcess
{
public void BindToRunningProcesses()
{
// Get the current process.
Process currentProcess = Process.GetCurrentProcess();
// Get all instances of Notepad running on the local
// computer.
Process [] localByName = Process.GetProcessesByName("notepad");
// Get all instances of Notepad running on the specifiec
// computer.
// 1. Using the computer alias (do not precede with "\\").
Process [] remoteByName = Process.GetProcessesByName("notepad", "myComputer");
// 2. Using an IP address to specify the machineName parameter.
Process [] ipByName = Process.GetProcessesByName("notepad", "169.0.0.0");
// Get all processes running on the local computer.
Process [] localAll = Process.GetProcesses();
// Get all processes running on the remote computer.
Process [] remoteAll = Process.GetProcesses("myComputer");
// Get a process on the local computer, using the process id.
Process localById = Process.GetProcessById(1234);
// Get a process on a remote computer, using the process id.
Process remoteById = Process.GetProcessById(2345, "myComputer");
}
public static void Main()
{
MyProcess myProcess = new MyProcess();
myProcess.BindToRunningProcesses(); }
}
}
http://msdn2.microsoft.com/zh-CN/library/system.threading.mutex.aspx
顺便给你提两个建议:
1,尊重你所在的公司,培养好良好的职业道德,毕竟所有的公司都是从小的开始发展起来的,而且一个程序员只有慢慢培养自己的能力才能在更好的舞台上面有更好的表现,而且再小的一个公司也是有很好的程序员的,多多向他们学习。
2,尊重测试人员,他们是你和客户健最后一道防线,也是最后可以信赖的人,他们可以将你的错误屏蔽在公司内开发时,可以让你不会以后直接面对客户的刁难。
希望你有个良好的职业发展。
using System.Runtime.InteropServices;
把实现唯一运行实例功能的类名取为SingleInstance,在类前面加static关键字为C# 2.0新增的语言特征。
public static class SingleInstance {}
使用GetRunningInstance静态方法获取应用程序进程实例,如果没有匹配进程,返回Null值,
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;
} 接下来调用两个WinAPI,其功能将在包装方法中描述,
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd); 定义类成员辅助变量,
private const int WS_SHOWNORMAL = 1; 以上的方法声明为私有,对其进一步包装,HandleRunningInstance静态方法为获取应用程序句柄,设置应用程序为前台运行,并返回bool值。
public static bool HandleRunningInstance(Process instance)
{
//确保窗口没有被最小化或最大化
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
//设置为foreground window
return SetForegroundWindow(instance.MainWindowHandle);
} 对上面的方法创建一个重载版本,使调用代码更加简洁,
public static bool HandleRunningInstance()
{
Process p = GetRunningInstance();
if (p != null)
{
HandleRunningInstance(p);
return true;
}
return false;
} 上面的方法实现获取已经运行的进程实例的句柄,并获取其焦点显示到前台,这个很有用,在其他实现方式中也可以用到。在Main函数中调用下面代码实现单一应用程序实例,
Process p = SingleInstance.GetRunningInstance();
if (p != null) //已经有应用程序副本执行
{
SingleInstance.HandleRunningInstance(p);
}
else //启动第一个应用程序
{
Application.Run(new MainForm());
} 简洁的调用为,
if (SingleInstance.HandleRunningInstance()== false)
{
Application.Run(new MainForm());
} 可见,在上面的实现过程中,由于关键信息采用应用程序的完整文件名,因此在文件名称或路径名称修改后,以上实现就会失效。 进程互斥
在这个实现方式中需要定义一个进程同步基元,可以理解为临界资源,该资源只允许一个进程使用。根据这一点实现应用程序唯一运行实例就比较简单了。
实现步骤如下,
1.应用程序初始化访问该同步基元;
2.可以访问,说明该同步基元未被使用,也就是说没有应用程序实例运行,使用同步基元,可以继续初始化成为第一个运行实例。
3.不可以访问,说明该同步基元已被使用,也就是说已有应用程序实例运行,停止当前程序初始化,提示已有应用程序运行。
4.应用程序实例退出释放同步基元占用。 在代码中笔者使用System.Threading.Mutex类实现同步基元,实现应用程序实例之间互斥功能。Mutex默认名字取Assembly.GetEntryAssembly().FullName。
在类成员中声明同步基元,
private static Mutex mutex = null; CreateMutex静态方法创建应用程序进程Mutex,返回创建结果为true表示创建成功,false失败。
public static bool CreateMutex()
{
return CreateMutex(Assembly.GetEntryAssembly().FullName);
} 实现其重载方法,让用户可以自定义Mutex名字,
public static bool CreateMutex(string name)
{
bool result = false;
mutex = new Mutex(true, name, out result);
return result;
} 对应的释放Mutex资源方法为,
public static void ReleaseMutex()
{
if (mutex != null)
{
mutex.Close();
}
} 在Main函数中调用下面代码实现单一应用程序实例,
if (SingleInstance.CreateMutex())
{
Application.Run(new MainForm());
SingleInstance.ReleaseMutex();
}
else
{
MessageBox.Show("程序已经运行!");
} 可见,在上面的实现过程中,Mutex名字是同步基元的唯一标识,如果刚好有不同的应用程序使用了相同名称的Mutex,那不同的应用程序实例也会出现互斥现象。 运行标志
使用应用程序运行标志简单来讲就是在程序初始化的时候设置一个标志表示程序已运行,在程序运行结束的时候删除该标志。
基本步骤如下,
1.应用程序初始化检查运行标志是否已经设置;
2.发现已经设置,说明已有应用程序实例运行,停止当前程序初始化,提示已有应用程序运行。 3.发现没有设置,说明没有应用程序实例运行,继续当前程序初始化。
4.退出应用程序时删除该运行标志。 对于标志存储载体可以使用注册表、数据库或外部文件等,这里的代码使用外部文件实现。对存放标志的文件目录选择C:\Documents and Settings\All Users\Application Data,也可以是C:\Program Files\Common Files。
声明类成员标志文件名称变量,
private static string runFlagFullname = null; 初始化程序运行标志,如果设置成功,返回true,已经设置返回false,设置失败将抛出异常,
public static bool InitRunFlag()
{
if (File.Exists(RunFlag))
{
return false;
}
using (FileStream fs = new FileStream(RunFlag, FileMode.Create))
{
}
return true;
} 释放初始化程序运行标志,如果释放失败将抛出异常,
public static void DisposeRunFlag()
{
if (File.Exists(RunFlag))
{
File.Delete(RunFlag);
}
} 获取或设置程序运行标志,必须符合Windows文件命名规范,
public static string RunFlag
{
get
{
if(runFlagFullname == null)
{
string assemblyFullName = Assembly.GetEntryAssembly().FullName;
string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
runFlagFullname = Path.Combine(path, assemblyFullName);
}
return runFlagFullname;
}
set
{
runFlagFullname = value;
}
} 在Main函数中调用下面代码实现单一应用程序实例,
if (SingleInstance.InitRunFlag())
{
Application.Run(new MainForm());
SingleInstance.DisposeRunFlag();
}
else
{
MessageBox.Show("程序已经运行!");
} 可见,在上面的实现过程中,需要访问文件IO,因此有可能会出现异常,对异常需要进行具体处理。如果不同应用程序使用了相同的运行标志,也会出现进程互斥实现中存在的问题。由于运行标志存在外部载体中,如果笔者把启动的应用程序进程实例直接在Windows管理器进程列表中结束或使其产生异常,那设置的运行标志就不会销毁,应用程序就没法再次运行。