WinForm防止程序重復(fù)運(yùn)行的方法分析
本文實(shí)例講述了WinForm防止程序重復(fù)運(yùn)行的方法。分享給大家供大家參考,具體如下:
需求:
1、點(diǎn)擊“關(guān)閉”按鈕時(shí),程序最小化到托盤,并沒(méi)有退出,這時(shí)再次運(yùn)行程序,不會(huì)重復(fù)運(yùn)行,而是顯示已運(yùn)行的程序;
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 計(jì)算器
{
static class Program
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// 該函數(shù)設(shè)置由不同線程產(chǎn)生的窗口的顯示狀態(tài)。
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="cmdShow">指定窗口如何顯示。查看允許值列表,請(qǐng)查閱ShowWlndow函數(shù)的說(shuō)明部分。</param>
/// <returns>如果函數(shù)原來(lái)可見(jiàn),返回值為非零;如果函數(shù)原來(lái)被隱藏,返回值為零。</returns>
[DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
/// <summary>
/// 該函數(shù)將創(chuàng)建指定窗口的線程設(shè)置到前臺(tái),并且激活該窗口。鍵盤輸入轉(zhuǎn)向該窗口,并為用戶改各種可視的記號(hào)。系統(tǒng)給創(chuàng)建前臺(tái)窗口的線程分配的權(quán)限稍高于其他線程。
/// </summary>
/// <param name="hWnd">將被激活并被調(diào)入前臺(tái)的窗口句柄。</param>
/// <returns>如果窗口設(shè)入了前臺(tái),返回值為非零;如果窗口未被設(shè)入前臺(tái),返回值為零。</returns>
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int SW_SHOWNORMAL = 1;
/// <summary>
/// 應(yīng)用程序的主入口點(diǎn)。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Process processes = RunningInstance();
if (processes == null)
{
Application.Run(new Form1());
}
else
{
HandleRunningInstance(processes);
}
}
/// <summary>
/// 獲取正在運(yùn)行的實(shí)例,沒(méi)有運(yùn)行的實(shí)例返回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>
/// 顯示已運(yùn)行的程序。
/// </summary>
public static void HandleRunningInstance(Process instance)
{
try
{
IntPtr formHwnd = FindWindow(null, "計(jì)算器");
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 計(jì)算器
{
static class Program
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// 該函數(shù)設(shè)置由不同線程產(chǎn)生的窗口的顯示狀態(tài)。
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="cmdShow">指定窗口如何顯示。查看允許值列表,請(qǐng)查閱ShowWlndow函數(shù)的說(shuō)明部分。</param>
/// <returns>如果函數(shù)原來(lái)可見(jiàn),返回值為非零;如果函數(shù)原來(lái)被隱藏,返回值為零。</returns>
[DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
/// <summary>
/// 該函數(shù)將創(chuàng)建指定窗口的線程設(shè)置到前臺(tái),并且激活該窗口。鍵盤輸入轉(zhuǎn)向該窗口,并為用戶改各種可視的記號(hào)。系統(tǒng)給創(chuàng)建前臺(tái)窗口的線程分配的權(quán)限稍高于其他線程。
/// </summary>
/// <param name="hWnd">將被激活并被調(diào)入前臺(tái)的窗口句柄。</param>
/// <returns>如果窗口設(shè)入了前臺(tái),返回值為非零;如果窗口未被設(shè)入前臺(tái),返回值為零。</returns>
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int SW_SHOWNORMAL = 1;
/// <summary>
/// 應(yīng)用程序的主入口點(diǎn)。
/// </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()); //進(jìn)程ID寫(xiě)入文件
Application.Run(new Form1());
}
else
{
try
{
string strProcessId = FileOperator.GetValue("ProcessId"); //從文件中獲取進(jìn)程ID
int processId = Convert.ToInt32(strProcessId);
Process process = Process.GetProcessById(processId);
HandleRunningInstance(process);
}
catch
{
FileOperator.SetValue("ProcessId", Process.GetCurrentProcess().Id.ToString()); //進(jìn)程ID寫(xiě)入文件
Application.Run(new Form1());
}
}
}
}
/// <summary>
/// 顯示已運(yùn)行的程序。
/// </summary>
public static void HandleRunningInstance(Process instance)
{
try
{
IntPtr formHwnd = FindWindow(null, "計(jì)算器");
ShowWindow(formHwnd, SW_SHOWNORMAL); //顯示
SetForegroundWindow(formHwnd); //放到前端
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
其實(shí),IntPtr formHwnd = FindWindow(null, "計(jì)算器"); 這段代碼是有BUG的,比如你打開(kāi)一個(gè)名為“計(jì)算器”的文件夾,那么FindWindow找到的其實(shí)是這個(gè)文件夾,而不是計(jì)算器程序。我們可以在主窗體第一次顯示的時(shí)候,記下窗口句柄,代碼如下:
private void Form1_Shown(object sender, EventArgs e)
{
FileOperator.SetValue("hwnd", Process.GetCurrentProcess().MainWindowHandle.ToString());
}
然后,顯示已運(yùn)行的程序時(shí),從文件中讀取之前記錄的窗口句柄,代碼如下:
/// <summary>
/// 顯示已運(yùn)行的程序
/// </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);
}
}
綜上,再整理一下,就能得到完美的解決方案。
更多關(guān)于C#相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《WinForm控件用法總結(jié)》、《C#窗體操作技巧匯總》、《C#數(shù)據(jù)結(jié)構(gòu)與算法教程》、《C#常見(jiàn)控件用法教程》、《C#面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》及《C#程序設(shè)計(jì)之線程使用技巧總結(jié)》
希望本文所述對(duì)大家C#程序設(shè)計(jì)有所幫助。
- C# WinForm 判斷程序是否已經(jīng)在運(yùn)行,且只允許運(yùn)行一個(gè)實(shí)例,附源碼
- WinForm實(shí)現(xiàn)程序一段時(shí)間不運(yùn)行自動(dòng)關(guān)閉的方法
- .Net WInform開(kāi)發(fā)筆記(二)Winform程序運(yùn)行結(jié)構(gòu)圖及TCP協(xié)議在Winform中的應(yīng)用
- ASP.NET也像WinForm程序一樣運(yùn)行的實(shí)現(xiàn)方法
- c# Winform 程序自動(dòng)更新實(shí)現(xiàn)方法
- C#中WinForm程序退出方法技巧總結(jié)
- C# WinForm應(yīng)用程序降低系統(tǒng)內(nèi)存占用方法總結(jié)
- C# WinForm程序完全退出的問(wèn)題解決
- 解讀在C#中winform程序響應(yīng)鍵盤事件的詳解
- .Net中導(dǎo)出數(shù)據(jù)到Excel(asp.net和winform程序中)
相關(guān)文章
c# 使用模式匹配以及 is 和 as 運(yùn)算符安全地進(jìn)行強(qiáng)制轉(zhuǎn)換
這篇文章主要介紹了c# 使用模式匹配以及 is 和 as 運(yùn)算符安全地進(jìn)行強(qiáng)制轉(zhuǎn)換,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2020-10-10
.net 通過(guò) WebAPI 調(diào)用nsfwjs 進(jìn)行視頻鑒別功能
這篇文章主要介紹了.net 通過(guò) WebAPI 調(diào)用 nsfwjs 進(jìn)行視頻鑒別,文末給大家提到了FFMPEG獲取視頻關(guān)鍵幀并保存成jpg圖像的相關(guān)知識(shí),需要的朋友可以參考下2021-09-09
C#預(yù)定義數(shù)據(jù)類型之值類型和引用類型介紹
這篇文章主要介紹了C#預(yù)定義數(shù)據(jù)類型之值類型和引用類型介紹,本文著重講解了引用類型中的object(對(duì)象)類型和string(字符串)類型,需要的朋友可以參考下2015-03-03
C#批量插入數(shù)據(jù)到sqlserver的方法詳解
這篇文章主要為大家詳細(xì)介紹了C#中四種可以批量插入數(shù)據(jù)到sqlserver的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2025-02-02
WPF+SkiaSharp實(shí)現(xiàn)自繪拖曳小球
WPF的拖曳效果,基本配置一下,就可以了,但是自繪的話,就得自己控制。本文將利用WPF+SkiaSharp實(shí)現(xiàn)自繪拖曳小球,感興趣的可以動(dòng)手嘗試一下2022-07-07

