class InstanceManager {
[DllImport("user32.dll")] //使用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;
public static Process RunningInstance() { //查找是否有同名的进程并比对信息
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach(Process process in processes){
if (current.Id != process.Id &&
current.MainModule.FileName == process.MainModule.FileName) {
return process;
}
}
return null;
}
public static void HandleRunningProcess(Process instance) {
//确保窗口没有被最小化和最大化
ShowWindowAsync(instance.MainWindowHandle,WS_SHOWNORMAL);
//将窗体显示在前面
SetForegroundWindow(instance.MainWindowHandle);
}
}
现在很多应用程序启动后都有多个进程在运行,所以在方法RunningInstance中我们通过MainModule来获得应用程序启动进程的可执行文件信息,而不是直接比较进程名。这样也避免了当前进程的进程名只是与其他应用程序包含的某个进程名相同而被阻止运行的情况,当然启动进程的进程名也有可能相同,这也是我觉得这种方法不足的地方之一,希望能够有所改进,或许可以比对更多的信息,或许还有其他的什么方法。
在方法HandleRunningProcess中是通过user32.dll中提供的两个函数实现显示和激活的,我搜了很多地方并没有发现C#中有支持显示和激活窗体的类或方法,不知道是不是还没找到,如果有人知道希望能告诉我一下。
在实现了上面的类后,就可以在Main函数中的显示和实例化窗体之前加入相应的判断,代码如下:
static void Main()
{
Process instance = InstanceManager.RunningInstance();
if (instance == null)
{ //下面的三行代码是之前Main函数中的
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else {
InstanceManager.HandleRunningProcess(instance);
}
}
========================================================================
/*
//防止客户端大厅启动多个进程
//大厅启动的进程数
//声明互斥体
mutex = new Mutex(false, "ThisShouldOnlyRunOnce_ICST_CLientHome ");
//判断互斥体是否使用中。
bool Running = !mutex.WaitOne(0, false);
if (!Running)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//frmMainHome frm= new frmMainHome();
FrmLogin frm = new FrmLogin();
Application.Run(frm);
}
else
{
//Common.Common.MessageBoxShow("应用程序已经启动!","提示信息",MessageBoxButtons.OK,MessageBoxIcon.Information);
}*/