ใน. NET วิธีใดดีที่สุดในการป้องกันไม่ให้แอปหลายอินสแตนซ์ทำงานพร้อมกัน และหากไม่มีเทคนิคที่ "ดีที่สุด" ข้อควรระวังในการพิจารณาแต่ละวิธีมีอะไรบ้าง?
ใน. NET วิธีใดดีที่สุดในการป้องกันไม่ให้แอปหลายอินสแตนซ์ทำงานพร้อมกัน และหากไม่มีเทคนิคที่ "ดีที่สุด" ข้อควรระวังในการพิจารณาแต่ละวิธีมีอะไรบ้าง?
คำตอบ:
ใช้ Mutex หนึ่งในตัวอย่างข้างต้นโดยใช้ GetProcessByName มีข้อแม้มากมาย นี่คือบทความที่ดีในหัวข้อนี้:
http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx
[STAThread]
static void Main()
{
using(Mutex mutex = new Mutex(false, "Global\\" + appGuid))
{
if(!mutex.WaitOne(0, false))
{
MessageBox.Show("Instance already running");
return;
}
Application.Run(new Form1());
}
}
private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9";
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;คู่มือแอปของคุณคุณสามารถใช้: ซึ่งจะได้รับคำแนะนำของแอสเซมบลีการดำเนินการ
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn);
return;
}
นี่คือรหัสที่คุณต้องใช้เพื่อให้แน่ใจว่ามีเพียงอินสแตนซ์เดียวที่กำลังทำงานอยู่ นี่คือวิธีการใช้ชื่อ mutex
public class Program
{
static System.Threading.Mutex singleton = new Mutex(true, "My App Name");
static void Main(string[] args)
{
if (!singleton.WaitOne(TimeSpan.Zero, true))
{
//there is already another instance running!
Application.Exit();
}
}
}
Hanselman มีโพสต์เกี่ยวกับการใช้คลาส WinFormsApplicationBase จากแอสเซมบลี Microsoft.VisualBasic เพื่อทำสิ่งนี้
ดูเหมือนว่าจะมีเทคนิคพื้นฐาน 3 อย่างที่แนะนำไปแล้ว
ข้อควรระวังที่ฉันพลาด?
1 - สร้างข้อมูลอ้างอิงใน program.cs ->
using System.Diagnostics;
2 - ใส่void Main()เป็นบรรทัดแรกของรหัส ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
แค่นั้นแหละ.
Mutex? มีการจับหรือไม่?
การใช้ Visual Studio 2005 หรือ 2008 เมื่อคุณสร้างโครงการสำหรับปฏิบัติการบนหน้าต่างคุณสมบัติภายในแผง "แอปพลิเคชัน" จะมีกล่องกาเครื่องหมายชื่อ "สร้างแอปพลิเคชันอินสแตนซ์เดียว" ที่คุณสามารถเปิดใช้งานเพื่อแปลงแอปพลิเคชันบนแอปพลิเคชันอินสแตนซ์เดียว .
นี่คือการจับภาพหน้าต่างที่ฉันกำลังพูดถึง:
นี่คือโครงการแอปพลิเคชัน Windows ของ Visual Studio 2008
ฉันลองใช้วิธีแก้ปัญหาทั้งหมดที่นี่และไม่มีอะไรได้ผลในโครงการ C # .net 4.0 ของฉัน หวังว่าจะช่วยใครบางคนที่นี่วิธีแก้ปัญหาที่เหมาะกับฉัน:
เป็นตัวแปรคลาสหลัก:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
เมื่อคุณต้องการตรวจสอบว่าแอปกำลังทำงานอยู่หรือไม่:
bool mutexCreated;
mutex = new Mutex(true, "Global\\" + appGuid, out mutexCreated);
if (mutexCreated)
mutex.ReleaseMutex();
if (!mutexCreated)
{
//App is already running, close this!
Environment.Exit(0); //i used this because its a console app
}
ฉันต้องการปิด istances อื่น ๆ ด้วยเงื่อนไขบางอย่างเท่านั้นซึ่งใช้ได้ดีสำหรับจุดประสงค์ของฉัน
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 - Single-Instance_Detection_and_Management
หลังจากลองใช้วิธีแก้ปัญหาหลาย ๆ คำถามแล้ว ฉันลงเอยด้วยการใช้ตัวอย่างสำหรับWPFที่นี่: http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/
public partial class App : Application
{
private static Mutex _mutex = null;
protected override void OnStartup(StartupEventArgs e)
{
const string appName = "MyAppName";
bool createdNew;
_mutex = new Mutex(true, appName, out createdNew);
if (!createdNew)
{
//app is already running! Exiting the application
Application.Current.Shutdown();
}
}
}
ใน App.xaml:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
บทความนี้อธิบายวิธีสร้างแอปพลิเคชัน windows โดยควบคุมจำนวนอินสแตนซ์หรือเรียกใช้อินสแตนซ์เดียวเท่านั้น นี่เป็นความต้องการทั่วไปของแอปพลิเคชันทางธุรกิจ มีโซลูชันที่เป็นไปได้อื่น ๆ มากมายในการควบคุมสิ่งนี้
http://www.openwinforms.com/single_instance_application.html
ใช้ VB.NET! ไม่มีจริงๆ ;)
ใช้ Microsoft.VisualBasic.ApplicationServices;
WindowsFormsApplicationBase จาก VB.Net มีคุณสมบัติ "SingleInstace" ซึ่งกำหนดอินสแตนซ์อื่น ๆ และปล่อยให้อินสแตนซ์เดียวทำงาน
นี่คือรหัสสำหรับ VB.Net
Private Shared Sub Main()
Using mutex As New Mutex(False, appGuid)
If Not mutex.WaitOne(0, False) Then
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
Application.Run(New Form1())
End Using
End Sub
นี่คือรหัสสำหรับ C #
private static void Main()
{
using (Mutex mutex = new Mutex(false, appGuid)) {
if (!mutex.WaitOne(0, false)) {
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Application.Run(new Form1());
}
}
คุณต้องใช้ System.Diagnostics.Process
ตรวจสอบ: http://www.devx.com/tips/Tip/20044
(หมายเหตุ: นี่เป็นวิธีแก้ปัญหาที่สนุก! มันใช้ได้ แต่ใช้การออกแบบ GDI + ที่ไม่ดีเพื่อให้บรรลุเป้าหมายนี้)
ใส่รูปภาพลงในแอพของคุณและโหลดเมื่อเริ่มต้น กดค้างไว้จนกว่าแอปจะออก ผู้ใช้จะไม่สามารถเริ่มอินสแตนซ์ที่ 2 ได้ (แน่นอนว่าน้ำยา mutex สะอาดกว่ามาก)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Main()วิธีการที่ขัดกับวิธีการทำงานของ WPF
[STAThread]
static void Main() // args are OK here, of course
{
bool ok;
m = new System.Threading.Mutex(true, "YourNameHere", out ok);
if (! ok)
{
MessageBox.Show("Another instance is already running.");
return;
}
Application.Run(new Form1()); // or whatever was there
GC.KeepAlive(m); // important!
}
จาก: การตรวจสอบอินสแตนซ์เดียวของ. NET Application
และ: Single Instance Application Mutex
คำตอบเดียวกับ @Smink และ @Imjustpondering with a twist:
คำถามที่พบบ่อยของ Jon Skeet เกี่ยวกับ C #เพื่อค้นหาว่าทำไมGC. KeepAliveจึงมีความสำคัญ
เพียงแค่ใช้ a StreamWriter, แล้วล่ะ?
System.IO.File.StreamWriter OpenFlag = null; //globally
และ
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
โดยปกติจะใช้ชื่อ Mutex (ใช้ Mutex ใหม่ ("ชื่อแอปของคุณ" จริง) และตรวจสอบค่าส่งคืน) แต่ยังมีคลาสการสนับสนุนบางอย่างใน Microsoft.VisualBasic.dll ที่สามารถทำเพื่อคุณได้
สิ่งนี้ใช้ได้ผลสำหรับฉันใน C # ที่บริสุทธิ์ try / catch คือเมื่อกระบวนการในรายการออกจากการวนซ้ำของคุณ
using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
int procCount = 0;
foreach (Process pp in Process.GetProcesses())
{
try
{
if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
{
procCount++;
if(procCount > 1) {
Application.Exit();
return;
}
}
}
catch { }
}
Application.Run(new Form1());
}
อย่าลืมคำนึงถึงความปลอดภัยเมื่อ จำกัด แอปพลิเคชันไว้ที่อินสแตนซ์เดียว:
บทความแบบเต็ม: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
เราใช้ชื่อ mutex ที่มีชื่อตายตัวเพื่อตรวจสอบว่ามีการเรียกใช้โปรแกรมอื่นอยู่หรือไม่ แต่นั่นก็หมายความว่าผู้โจมตีสามารถสร้าง mutex ขึ้นมาได้ก่อนดังนั้นจึงป้องกันไม่ให้โปรแกรมของเราทำงานได้เลย! ฉันจะป้องกันการโจมตีปฏิเสธการให้บริการประเภทนี้ได้อย่างไร
...
หากผู้โจมตีกำลังทำงานในบริบทความปลอดภัยเดียวกับโปรแกรมของคุณ (หรือจะ) กำลังทำงานอยู่คุณก็ไม่สามารถทำอะไรได้ ไม่ว่าคุณจะ "จับมือเป็นความลับ" เพื่อตรวจสอบว่าโปรแกรมอื่นของคุณกำลังทำงานอยู่หรือไม่ผู้โจมตีสามารถเลียนแบบได้ เนื่องจากมันทำงานในบริบทความปลอดภัยที่ถูกต้องจึงสามารถทำอะไรก็ได้ที่โปรแกรม "จริง" สามารถทำได้
...
เห็นได้ชัดว่าคุณไม่สามารถป้องกันตัวเองจากผู้โจมตีที่ใช้สิทธิ์การรักษาความปลอดภัยเดียวกันได้ แต่คุณยังสามารถป้องกันตัวเองจากผู้โจมตีที่ไม่มีสิทธิได้รับสิทธิพิเศษด้านความปลอดภัยอื่น ๆ
ลองตั้งค่า DACL บน mutex ของคุณนี่คือวิธี. NET: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
คำตอบนี้ไม่ได้ผลสำหรับฉันเพราะฉันต้องการสิ่งนี้เพื่อทำงานภายใต้ Linux โดยใช้ monodevelop สิ่งนี้ใช้ได้ดีสำหรับฉัน:
เรียกวิธีนี้ว่ารหัสเฉพาะ
public static void PreventMultipleInstance(string applicationId)
{
// Under Windows this is:
// C:\Users\SomeUser\AppData\Local\Temp\
// Linux this is:
// /tmp/
var temporaryDirectory = Path.GetTempPath();
// Application ID (Make sure this guid is different accross your different applications!
var applicationGuid = applicationId + ".process-lock";
// file that will serve as our lock
var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);
try
{
// Prevents other processes from reading from or writing to this file
var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_InstanceLock.Lock(0, 0);
MonoApp.Logger.LogToDisk(LogType.Notification, "04ZH-EQP0", "Aquired Lock", fileFulePath);
// todo investigate why we need a reference to file stream. Without this GC releases the lock!
System.Timers.Timer t = new System.Timers.Timer()
{
Interval = 500000,
Enabled = true,
};
t.Elapsed += (a, b) =>
{
try
{
_InstanceLock.Lock(0, 0);
}
catch
{
MonoApp.Logger.Log(LogType.Error, "AOI7-QMCT", "Unable to lock file");
}
};
t.Start();
}
catch
{
// Terminate application because another instance with this ID is running
Environment.Exit(102534);
}
}