c#WinForm 程序单实例运行并打开前一个实例(Mutex+API)

时间:2021-11-15 11:57:04

要实现程序单实例运行并打开前一个实例有许多方法,如大多数网上的Process 方法。但,如果程序从IDE(像vs)运行,然后再双击bin/debug里的程序,运行了2个实例了。本人用的是Mutex来控制程序单实例运行,API操作前实例的窗体句柄来实现的。.Net里有Form的Handle属性来获取窗体句柄。

 

本人在vs2008中写的,效果:可行;最大最小化时双击会变为普通状态。

如有更好的方法,请大家拿出来研究。代码如下:

 

创建程序设置:

 

名称:w    类型:Int64 范围:用户 值:0

 

在Program.cs里:

 

using System.Threading;

using System.Runtime.InteropServices;

using System.Diagnostics;

using System.Reflection;

using WindowsFormsApplication1.Properties;   //加入项目设置

 

 

 

static class Program

    {

        #region Win32 API 函数

 

        //该函数设置由不同线程产生的窗口的显示状态;

        //如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零。

        [DllImport("user32.dll")]

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

 

        //该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。

        //如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。

        [DllImport("user32.dll")]

        private static extern bool SetForegroundWindow(IntPtr hWnd);

 

        // IsIconicIsZoomed ------ 分别判断窗口是否已最小化、最大化

        [DllImport("user32.dll")]

        private static extern bool IsIconic(IntPtr hWnd);

        [DllImport("user32.dll")]

        private static extern bool IsZoomed(IntPtr hWnd);

 

        //获取当前系统中被激活的窗口

        [DllImport("user32.dll")]

        private static extern IntPtr GetForegroundWindow();

 

        //获取指定窗口的进程 ID 或线程 ID

        [DllImport("user32.dll")]

        private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        #endregion

 

        private const int SW_SHOWNORMAL = 1;

        private const int SW_RESTORE = 9;

    

        [STAThread]

        static void Main()

        {

            bool b;

            string a = "1";     //名字任意

            Mutex m = new Mutex(true, a, out b);

            if (b)

            {

                m.ReleaseMutex();

               

                Application.EnableVisualStyles();

                Application.SetCompatibleTextRenderingDefault(false);

                Application.Run(new Form1());

            }

            else

            {

                Settings s = new Settings();

                IntPtr i = (IntPtr)s.w;

                SetForegroundWindow(i);

                if (IsIconic(i))

                {

                    ShowWindowAsync(i, SW_RESTORE);

                }

                else

                {

                    ShowWindowAsync(i, SW_SHOWNORMAL);

                }

            }

        }

    }

 

在Form1.cs里:(加入Load事件)

 

using WindowsFormsApplication3.Properties;

 

private void Form1_Load(object sender, EventArgs e)

{

     Settings r = new Settings();

     r.w = (Int64)this.Handle;

     r.Save();

}

 

 

ok了.wpf也一样能行,方法一样,只不过是在Loaded事件中罢了.