.NET'te, bir uygulamanın birden çok örneğinin aynı anda çalışmasını önlemenin en iyi yolu nedir? Ve "en iyi" teknik yoksa, her çözümde dikkate alınması gereken bazı uyarılar nelerdir?
.NET'te, bir uygulamanın birden çok örneğinin aynı anda çalışmasını önlemenin en iyi yolu nedir? Ve "en iyi" teknik yoksa, her çözümde dikkate alınması gereken bazı uyarılar nelerdir?
Yanıtlar:
Mutex'i kullanın. GetProcessByName kullanan yukarıdaki örneklerden birinde birçok uyarı var. İşte konuyla ilgili güzel bir makale:
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;yürütülen derleme guid olduğunu alması için gerekli
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;
}
İşte sadece bir örneğin çalıştığından emin olmak için ihtiyacınız olan kod. Bu, adlandırılmış bir muteks kullanma yöntemidir.
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, bunu yapmak için Microsoft.VisualBasic derlemesinden WinFormsApplicationBase sınıfını kullanma üzerine bir gönderiye sahip .
Şimdiye kadar önerilen 3 temel teknik var gibi görünüyor.
Kaçırdığım herhangi bir uyarı var mı?
1 - program.cs'de bir referans oluşturun ->
using System.Diagnostics;
2 - void Main()Kodun ilk satırı olarak girin ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
Bu kadar.
Mutex? Bir yakalama var mı?
Bir yürütülebilir dosya için bir proje oluşturduğunuzda Visual Studio 2005 veya 2008 kullanıldığında, "Uygulama" panelinin içindeki özellikler pencerelerinde, uygulamayı tek bir örnek uygulamaya dönüştürmek için etkinleştirebileceğiniz "Tek örnekli uygulama yap" adlı bir onay kutusu vardır. .
İşte bahsettiğim pencerenin bir görüntüsü:
Bu bir Visual Studio 2008 windows uygulama projesidir.
Buradaki tüm çözümleri denedim ve C # .net 4.0 projemde hiçbir şey işe yaramadı. Benim için işe yarayan çözümü burada birine yardım etmeyi umuyorum:
Ana sınıf değişkenleri olarak:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
Uygulamanın zaten çalışıp çalışmadığını kontrol etmeniz gerektiğinde:
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
}
Diğer durumları sadece bazı koşullarla kapatmam gerekiyordu, bu amacım için iyi çalıştı
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 —Single-Instance_Detection_and_Management
Birden fazla çözümü denedikten sonra soru. WPF örneğini burada kullandım: 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'de:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
Bu makale, örnek sayısı üzerinde kontrole sahip bir Windows uygulamasını nasıl oluşturabileceğinizi veya yalnızca tek bir örneği nasıl çalıştırabileceğinizi açıklamaktadır. Bu, bir iş uygulamasının çok tipik bir ihtiyacıdır. Bunu kontrol etmek için zaten pek çok olası çözüm var.
http://www.openwinforms.com/single_instance_application.html
Bu, VB.Net'in kodudur
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
Bu C # kodudur
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'i kullanmanız gerekir.
Göz atın: http://www.devx.com/tips/Tip/20044
(Not: Bu eğlenceli bir çözümdür! Çalışır ancak bunu başarmak için kötü GDI + tasarımı kullanır.)
Uygulamanıza bir resim yerleştirin ve başlangıçta yükleyin. Uygulama çıkana kadar basılı tutun. Kullanıcı 2. bir örnek başlatamaz. (Elbette muteks çözümü çok daha temizdir)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Main(), WPF'nin nasıl çalışması gerektiğine aykırı bir yöntem gerektirir .
[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!
}
Kimden: Tek bir .NET Uygulaması örneğinin sağlanması
ve: Tek Örnek Uygulama Mutex'i
@Smink ve @Imjustpondering ile aynı yanıt:
GC.KeepAlive'ın neden önemli olduğunu öğrenmek için Jon Skeet'in C # ile ilgili SSS'si
Basitçe a kullanarak StreamWriter, buna ne dersiniz?
System.IO.File.StreamWriter OpenFlag = null; //globally
ve
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
Normalde adlandırılmış bir Mutex ile yapılır (yeni Mutex kullanın ("uygulamanızın adı", true) ve dönüş değerini kontrol edin), ancak Microsoft.VisualBasic.dll'de bunu sizin için yapabilecek bazı destek sınıfları da vardır .
Bu benim için saf C # ile çalıştı. try / catch, döngünüz sırasında muhtemelen listedeki bir işlemin çıktığı zamandır.
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());
}
Bir uygulamayı tek bir örnekle sınırlarken güvenliği göz önünde bulundurduğunuzdan emin olun:
Tam makale: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
Programın başka bir kopyasının çalışıp çalışmadığını tespit etmek için sabit isimli bir adlandırılmış muteks kullanıyoruz. Ancak bu aynı zamanda bir saldırganın önce muteksi oluşturabileceği ve böylece programımızın çalışmasını tamamen engelleyebileceği anlamına gelir! Bu tür hizmet reddi saldırılarını nasıl önleyebilirim?
...
Saldırgan, programınızın çalıştığı (veya çalışacağı) güvenlik bağlamında çalışıyorsa, yapabileceğiniz hiçbir şey yoktur. Programınızın başka bir kopyasının çalışıp çalışmadığını belirlemek için bulduğunuz "gizli el sıkışma" ne olursa olsun, saldırgan onu taklit edebilir. Doğru güvenlik bağlamında çalıştığı için, "gerçek" programın yapabildiği her şeyi yapabilir.
...
Açıktır ki kendinizi aynı güvenlik ayrıcalığıyla çalışan bir saldırgandan koruyamazsınız, ancak yine de kendinizi diğer güvenlik ayrıcalıklarıyla çalışan ayrıcalıksız saldırganlara karşı koruyabilirsiniz.
Mutex'inizde bir DACL ayarlamayı deneyin, işte .NET yolu: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
Bu yanıtların hiçbiri benim için işe yaramadı çünkü bunun monodevelop kullanarak Linux altında çalışmasına ihtiyacım vardı. Bu benim için harika çalışıyor:
Bu yöntemi benzersiz bir kimlik geçirerek çağırın
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);
}
}