好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

WinForm防止程序重复运行的方法分析

本文实例讲述了WinForm防止程序重复运行的方法。分享给大家供大家参考,具体如下:

需求:

1、点击[关闭]按钮时,程序最小化到托盘,并没有退出,这时再次运行程序,不会重复运行,而是显示已运行的程序;
2、支持不同目录;
3、支持修改名称。

代码 (不支持修改名称,不支持不同目录):

?

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using Tool;

using System.Diagnostics;

using System.Reflection;

using System.Runtime.InteropServices;

namespace 计算器

{

   static class Program

   {

     [DllImport( "user32.dll" )]

     public static extern IntPtr FindWindow( string lpClassName, string lpWindowName);

     /// <summary>

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

     /// </summary>

     /// <param name="hWnd">窗口句柄</param>

     /// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分。</param>

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

     [DllImport( "User32.dll" )]

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

     /// <summary>

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

     /// </summary>

     /// <param name="hWnd">将被激活并被调入前台的窗口句柄。</param>

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

     [DllImport( "User32.dll" )]

     private static extern bool SetForegroundWindow(IntPtr hWnd);

     private const int SW_SHOWNORMAL = 1;

     /// <summary>

     /// 应用程序的主入口点。

     /// </summary>

     [STAThread]

     static void Main()

     {

       Application.EnableVisualStyles();

       Application.SetCompatibleTextRenderingDefault( false );

       Process processes = RunningInstance();

       if (processes == null )

       {

         Application.Run( new Form1());

       }

       else

       {

         HandleRunningInstance(processes);

       }

     }

     /// <summary>

     /// 获取正在运行的实例,没有运行的实例返回null;

     /// </summary>

     public 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 ;

     }

     /// <summary>

     /// 显示已运行的程序。

     /// </summary>

     public static void HandleRunningInstance(Process instance)

     {

       try

       {

         IntPtr formHwnd = FindWindow( null , "计算器" );

         ShowWindow(formHwnd, SW_SHOWNORMAL);  //显示

         SetForegroundWindow(formHwnd);     //放到前端

       }

       catch (Exception ex)

       {

         MessageBox.Show(ex.Message);

       }

     }

   }

}

代码 (支持修改名称,支持不同目录):

?

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using Tool;

using System.Diagnostics;

using System.Reflection;

using System.Runtime.InteropServices;

namespace 计算器

{

   static class Program

   {

     [DllImport( "user32.dll" )]

     public static extern IntPtr FindWindow( string lpClassName, string lpWindowName);

     /// <summary>

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

     /// </summary>

     /// <param name="hWnd">窗口句柄</param>

     /// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分。</param>

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

     [DllImport( "User32.dll" )]

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

     /// <summary>

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

     /// </summary>

     /// <param name="hWnd">将被激活并被调入前台的窗口句柄。</param>

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

     [DllImport( "User32.dll" )]

     private static extern bool SetForegroundWindow(IntPtr hWnd);

     private const int SW_SHOWNORMAL = 1;

     /// <summary>

     /// 应用程序的主入口点。

     /// </summary>

     [STAThread]

     static void Main()

     {

       Common.AutoRegister();

       Application.EnableVisualStyles();

       Application.SetCompatibleTextRenderingDefault( false );

       bool createNew;

       using (System.Threading.Mutex m = new System.Threading.Mutex( true , Application.ProductName, out createNew))

       {

         if (createNew)

         {

           FileOperator.SetValue( "ProcessId" , Process.GetCurrentProcess().Id.ToString()); //进程ID写入文件

           Application.Run( new Form1());

         }

         else

         {

           try

           {

             string strProcessId = FileOperator.GetValue( "ProcessId" ); //从文件中获取进程ID

             int processId = Convert.ToInt32(strProcessId);

             Process process = Process.GetProcessById(processId);

             HandleRunningInstance(process);

           }

           catch

           {

             FileOperator.SetValue( "ProcessId" , Process.GetCurrentProcess().Id.ToString()); //进程ID写入文件

             Application.Run( new Form1());

           }

         }

       }

     }

     /// <summary>

     /// 显示已运行的程序。

     /// </summary>

     public static void HandleRunningInstance(Process instance)

     {

       try

       {

         IntPtr formHwnd = FindWindow( null , "计算器" );

         ShowWindow(formHwnd, SW_SHOWNORMAL);  //显示

         SetForegroundWindow(formHwnd);     //放到前端

       }

       catch (Exception ex)

       {

         MessageBox.Show(ex.Message);

       }

     }

   }

}

其实,IntPtr formHwnd = FindWindow(null, "计算器"); 这段代码是有BUG的,比如你打开一个名为[计算器]的文件夹,那么FindWindow找到的其实是这个文件夹,而不是计算器程序。我们可以在主窗体第一次显示的时候,记下窗口句柄,代码如下:

?

private void Form1_Shown( object sender, EventArgs e)

{

   FileOperator.SetValue( "hwnd" , Process.GetCurrentProcess().MainWindowHandle.ToString());

}

然后,显示已运行的程序时,从文件中读取之前记录的窗口句柄,代码如下:

?

/// <summary>

/// 显示已运行的程序

/// </summary>

public static void HandleRunningInstance(Process instance)

{

   try

   {

     IntPtr hwnd = new IntPtr(Convert.ToInt32(FileOperator.GetValue( "hwnd" )));

     ShowWindow(hwnd, SW_SHOWNORMAL); //显示

     SetForegroundWindow(hwnd); //放到前端

   }

   catch (Exception ex)

   {

     MessageBox.Show(ex.Message);

   }

}

综上,再整理一下,就能得到完美的解决方案。

希望本文所述对大家C#程序设计有所帮助。

dy("nrwz");

查看更多关于WinForm防止程序重复运行的方法分析的详细内容...

  阅读:53次