本文實例講述了WinForm防止程序重復運行的方法。分享給大家供大家參考,具體如下:
需求:
1、點擊“關閉”按鈕時,程序最小化到托盤,并沒有退出,這時再次運行程序,不會重復運行,而是顯示已運行的程序;
2、支持不同目錄;
3、支持修改名稱。
代碼(不支持修改名稱,不支持不同目錄):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
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); } } } } |
代碼(支持修改名稱,支持不同目錄):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
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找到的其實是這個文件夾,而不是計算器程序。我們可以在主窗體第一次顯示的時候,記下窗口句柄,代碼如下:
1
2
3
4
|
private void Form1_Shown( object sender, EventArgs e) { FileOperator.SetValue( "hwnd" , Process.GetCurrentProcess().MainWindowHandle.ToString()); } |
然后,顯示已運行的程序時,從文件中讀取之前記錄的窗口句柄,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/// <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#程序設計有所幫助。