Cách Tạo Một Ứng Dụng SingleInstance (Application)

Để dễ hiểu, các bạn hãy hình dung rằng: cùng một tập tin thực thi *.EXE nhưng bạn DoubleClick 10 lần cách quãng vào nó thì chuyện gì sẽ sảy ra =>  bạn sẽ có 10 chương trình giống nhau trên DesckTop, trong một số trường hợp điều này là không được phép, vậy làm thế nào để thông báo cho người dùng rằng ứng dụng họ muốn thực thi đã được khởi động và đang làm việc trên hệ thống. Cùng tìm cách...


I> Cách I


Có rất nhiều cách trong đó có việc lấy danh sách các ứng dụng đang chạy trên hệ thống và kiểm tra ID ứng dụng người dùng muốn khởi động đã có hay chưa. Xem ví dụ sau.

Tạo một lớp mới với nội dung sau đây:

[code language="csharp"]
static class ProcessChecker
{
static string _requiredString;

internal static class NativeMethods
{
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern bool EnumWindows(EnumWindowsProcDel lpEnumFunc,
Int32 lParam);

[DllImport("user32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd,
ref Int32 lpdwProcessId);

[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString,
Int32 nMaxCount);

public const int SW_SHOWNORMAL = 1;
}

public delegate bool EnumWindowsProcDel(IntPtr hWnd, Int32 lParam);

static private bool EnumWindowsProc(IntPtr hWnd, Int32 lParam)
{
int processId = 0;
NativeMethods.GetWindowThreadProcessId(hWnd, ref processId);

StringBuilder caption = new StringBuilder(1024);
NativeMethods.GetWindowText(hWnd, caption, 1024);

// Use IndexOf to make sure our required string is in the title.
if (processId == lParam && (caption.ToString().IndexOf(_requiredString,
StringComparison.OrdinalIgnoreCase) != -1))
{
// Restore the window.
NativeMethods.ShowWindowAsync(hWnd, NativeMethods.SW_SHOWNORMAL);
NativeMethods.SetForegroundWindow(hWnd);
}
return true; // Keep this.
}

static public bool IsOnlyProcess(string forceTitle)
{
_requiredString = forceTitle;
foreach (Process proc in Process.GetProcessesByName(Application.ProductName))
{
if (proc.Id != Process.GetCurrentProcess().Id)
{
NativeMethods.EnumWindows(new EnumWindowsProcDel(EnumWindowsProc),
proc.Id);
return false;
}
}
return true;
}
}
[/code]

Sửa dụng như sau,

[code language="csharp"]
static void Main()
{
if (ProcessChecker.IsOnlyProcess("Windows Text")) //Nội dung này không quá quan trọng
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#region new instance
/////////////////////////
Application.Run(new Form1());
////////////////////////
#endregion
}
else
{
MessageBox.Show("this App is runing");
Application.Exit();
}
}
[/code]

II> Cách II


Cùng ý tưởng cách 1 nhưng ngắn gọn hơn nhiều

[code language="csharp"]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

Process currentProcess = Process.GetCurrentProcess();
Process[] processItems = Process.GetProcessesByName(currentProcess.ProcessName);
foreach (Process item in processItems)
{
if (item.Id != currentProcess.Id)
{
MessageBox.Show("Another instance running");
Application.Exit();
}
}
#region new instance
/////////////////////////
Application.Run(new Form1());
////////////////////////
#endregion
}
[/code]

III> Cách III


Cách này cao cấp hơn vì thế ngắn gọn hơn nhiều

[code language="csharp"]
static void Main()
{
bool firstInstance;
using (Mutex mutex = new Mutex(true, "Chuỗi Định Danh - Duy nhất", out firstInstance))
{
if (firstInstance)
{
#region new instance
/////////////////////////
Application.Run(new Form1());
////////////////////////
#endregion
}
else
{
MessageBox.Show("Another instance running", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
Application.Exit();
}
}
}
[/code]

SourceCode tham khảo tại đây
Chúc các bạn thành công!
Phạm Tuân


Chúc các bạn thành công!
PHẠM TUÂN

1 nhận xét:

Write nhận xét
Lâm Liều
AUTHOR
January 17, 2015 at 7:22 AM delete

Bác Tuân dạo này bá đạo quá ^_^

Reply
avatar