分享

点击程序只运行一个实例

 昵称10504424 2013-02-28

最近写C#窗体程序,希望运行程序时,第二次点击该程序(使其运行)只激活第一次运行的窗体,而不是重新创建新的窗体实例。一下子想到了在Program.Cs类中使用单实例的设计模式,然后得到警告“在设置窗体可视之前不允许创建窗体实例”,放弃掉这种想法,进行另一种尝试(使用Mutex或者Semaphore)来进行控制。

 

尝试一:参考资料为VB的代码,基本上是直接转译下语言

 

创建一个信号灯就可以了
Private Declare Function ReleaseSemaphore Lib "kernel32" (ByVal hSemaphore As Long, ByVal lReleaseCount As Long, lpPreviousCount As Long) As Long
Private Declare Function CreateSemaphore Lib "kernel32" Alias "CreateSemaphoreA" (lpSemaphoreAttributes As SECURITY_ATTRIBUTES, ByVal lInitialCount As Long, ByVal lMaximumCount As Long, ByVal lpName As String) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Type SECURITY_ATTRIBUTES nLength As Long
                                 lpSecurityDescriptor As Long
                                 bInheritHandle As Long
End Type
Dim Semaphore As String, Sema As Long, Security As SECURITY_ATTRIBUTES
Dim PrevSemaphore As Long, Turn As Long

Private Sub Form_Load()
Security.bInheritHandle = True '默认的安全值
Security.lpSecurityDescriptor = 0
Security.nLength = Len(Security)
Semaphore = "这里自己随便起个名" '创建或打开一个Semaphore记数信号,设资源空闲使用量为1
Sema = CreateSemaphore(Security, 1, 1, Semaphore) '申请一个权限,并立即返回
Turn = WaitForSingleObject(Sema, 0) '如果不是正常返回,则表示没有申请到资源的使用权限
If Turn <> 0 Then MsgBox "管理系统已经运行!", vbOKOnly + vbCritical, "提示"
End
End If
End Sub

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public class SECURITY_ATTRIBUTES
{
   public int nLength, lpSecurityDescriptor, bInheritHandle;
   //public string lpSecurityDescriptor;
   //public bool bInheritHandle;
 }
public partial class Form1 : Form
    {
        [DllImport("kernel32.dll")] //CharSet=CharSet.Auto|Ansi
        private static extern bool ReleaseSemaphore(int hSemaphore, int lReleaseCount, int lpPreviousCount);
        [DllImport("kernel32.dll")]
        private static extern IntPtr CreateSemaphore(SECURITY_ATTRIBUTES lpSemaphoreAttributes, int lInitialCount,int lMaximumCount,string lpName);
        [DllImport("kernel32.dll")]
        private static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);
        [DllImport("kernel32.dll")]
        private static extern IntPtr OpenSemaphore(int dwDesiredAccess,bool bInheritHandle,string lpName);
        private string Semaphore ;
        private int PrevSemaphore, Turn;
        private SECURITY_ATTRIBUTES Security;
        private IntPtr Sema;
        public Form1()
        {
            InitializeComponent();
            Security = new SECURITY_ATTRIBUTES();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Security.bInheritHandle = 1;               //等价于Security.bInheritHandle =True;
            Security.lpSecurityDescriptor = 0 ;
            Security.nLength = 12;                     //值为3*32/8
            Semaphore = "这里自己随便起个名";                   //创建或打开一个Semaphore记数信号,设资源空闲使用量为1
            Sema = CreateSemaphore(Security, 1, 1, Semaphore);  //申请一个权限,并立即返回
            Turn = WaitForSingleObject(Sema, 0);                //如果不是正常返回,则表示没有申请到资源的使用权限
            if(Turn!=0)
            {
                   MessageBox.Show("管理系统已经运行!","提示",MessageBoxButtons.OK);
                   //OpenSemaphore(SEMAPHORE_ALL_ACCESS
                   this.Close();
                  
            }
        }
    }
很不幸的是,对于EMAPHORE_ALL_ACCESS的value在C#中无法找到对应值,正要进行第二种尝试(使用Mutex),然后同事就找到另一种解决办法,其内容为转贴内容(如下):
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;

namespace WinFormStudy
{
    
static class Program
    {

        
/// <summary>
        
/// 应用程序的主入口点。
        
/// </summary>
        [STAThread]
        
static void Main()
        {
            Process instance 
= RunningInstance();
            
if (instance == null)
            {
                
//没有实例在运行
                Application.Run(new Form1());
            }
            
else
            {
                
//已经有一个实例在运行
                HandleRunningInstance(instance);
            }
        }
        
#region  确保程序只运行一个实例
        
private 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;
        }

        
private static void HandleRunningInstance(Process instance)
        {
            MessageBox.Show(
"已经在运行!""提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            ShowWindowAsync(instance.MainWindowHandle, 
1);  //调用api函数,正常显示窗口
            SetForegroundWindow(instance.MainWindowHandle); //将窗口放置最前端
        }
        [DllImport(
"User32.dll")]
        
private static extern bool ShowWindowAsync(System.IntPtr hWnd, int cmdShow);
        [DllImport(
"User32.dll")]
        
private static extern bool SetForegroundWindow(System.IntPtr hWnd);
        
#endregion
    }
}
其大意是找到程序集起始执行的文件地址,对正在运行的程序一一比较,如果存在相同情况的程序集,就将原来打开的程序集激活。【注意:窗体程序需要在任务栏上显示窗体图标,即showInTaskBar属性设置为true,最小化时不被隐藏,这样才能达到激活原实例的要求】

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多