有時候有這個需求 就是該應用程式在同一台電腦上只能執行一次
不管有多少個使用者都必須限制, 為什麼會突然實作這個功能呢?
在工作時必須撰寫一隻App, 此App必須當Server/Client 兩種角色
問題就出在於當Server端時, 會綁一組IP與Port, 當Listen此IP與Port時
如又再度重新開啟此App時, 將會產生錯誤, 因為此IP與Port的資源被占據了
所以產生錯誤……
這種錯誤有許多方法可以解決~~~我比較直覺~那就限制該App只能開一次
一樣透過Google查詢後, 發現網路上已經有許多方法[1-15], 但都不是最完美的~
所謂的完美就是 1) 同一台電腦上,不管有多少使用者都要限制, 只能開一次
、2) 當重複開啟時必須要阻止開起並且將原本正在執行的App帶到前景、
3) 如果此App正為常駐時, 必須喚起於前景、4) 該App被改檔名時要與原App視為
同一隻 ,且限制功能不能失效。 而此紀錄利用Winapi以達到以上需求
以下為Code……
using System.Diagnostics;
using System.Runtime.InteropServices;
// MianUI.cs
static readonly int SW_SHOWNORMAL = 9;
//==========================================================
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
//==========================================================
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
//==========================================================
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
//==========================================================
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
//==========================================================
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
//==========================================================
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindow(IntPtr hWnd);
//==========================================================
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
// For Windows Mobile, replace user32.dll with coredll.dll
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
//==========================================================
static private Mutex mutex;
static StringBuilder CurrentClassName = new StringBuilder(255);
static String MainWindwsText = "";
//
//
//
[STAThread]
static void Main(string[] arg)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//====================
MainUI GetMainInformation = new MainUI();
GetClassName(GetMainInformation.GetMainHandle(), CurrentClassName, 255);
MainWindwsText = GetMainInformation.GetWindowText();
//====================
Boolean IsExecution = false;
mutex = new Mutex(true, "Global\\" + MainWindwsText + CurrentClassName.ToString(), out IsExecution);
if (IsExecution == true)
{
Application.Run(GetMainInformation);
}
else
{
EnumWindowsProc CallOriginalFunction = new EnumWindowsProc(EnumProc);
EnumWindows(CallOriginalFunction, IntPtr.Zero);
}
}
//
public static bool EnumProc(IntPtr hWnd, IntPtr lParam)
{
StringBuilder WindowsText = new StringBuilder(255);
StringBuilder ClassName = new StringBuilder(255);
if (GetParent(hWnd) == IntPtr.Zero)
{
if (IsWindow(hWnd))
{
GetWindowText(hWnd, WindowsText, 255);
if (WindowsText.Length != 0)
{
if (WindowsText.ToString().Contains(MainWindowsText))
{
GetClassName(hWnd, ClassName, 255);
if (ClassName.ToString() == CurrentClassName.ToString())
{
ShowWindow(hWnd, SW_SHOWNORMAL);
SetForegroundWindow(hWnd);
}
}
}
}
}
return true;
}
[Refenerce] 無法避免重新命名之參考方法: [1] [C#]EXE執行檔單獨運行小技巧 [2] 如何維持.net程式單一執行個體應用程式 [3] 如何避免相同的 ConsoleApp 或 WinForm 同時間重複執行 [4] [C#] 避免重複開啟應用程式 [5] 防止程式重複執行 [6] 讓.net應用程式只執行一次 避免重複執行 能避免重新命名但無法喚起原有程式之參考方法 [7] 使用C#建立單一執行個體的應用程式。 其他參考之方法 [8] Finding which applications and services are listed in the System Tray? [9] Shell Tray Info - Arrange your system tray icons [10] 如何得到系統常駐中圖示所屬的應用程式的窗口hWnd [11] Writing a Win32 method to find if an application is already running [12] C# mobile 呼叫 win32 API [13] http://www.pinvoke.net/index.aspx 可以方便的將Winapi轉態於C#形式 [14] PInvoke.net add-in support for Visual Studio 2008 [15] 通过枚举窗口,实现最小化到托盘中程序的窗口显示 <==能將抓取常駐程式必且帶到前景
By Jiunway
沒有留言:
張貼留言