.NET'te belirli bir uygulamanın birden fazla örneği engelleniyor mu?


123

.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:


151

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";

1
Bir muteks kullanmak .net olmayan kodlar için de işe
yarar

9
İşte bazı iyi yorumlarla birlikte biraz daha doldurulmuş bir sürüm: stackoverflow.com/questions/229565/…
Richard Watson

2
@ClarkKent: Mutex isminin başka bir uygulamadaki isimle çakışmaması için sadece rastgele bir dizge.
jgauffin

Bu da belirli sayıda örnekle sınırlı olabilir mi?
Alejandro del Río

4
Daha iyi bir kontrole sahip olmak amacıyla sürüm veya uygulama guıd değiştirilirken, şunları kullanabilirsiniz: string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;yürütülen derleme guid olduğunu alması için gerekli
ciosoriog

22
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;
}

1
Bunu görmesi gerektiğini düşünüyorum: odetocode.com/blogs/scott/archive/2004/08/20/…
SubmarineX

@SubmarineX Bu makalenin doğru olduğundan nasıl eminsiniz? hala mutex ve codeproject.com/Articles/4975/…
John Nguyen

Zaman ve çabaları için şaşırtıcı Sadece mükemmel teşekkürler
Ahmed Mahmoud

2
-1 Bu hızlı çözüm olsa da, a.exe'yi atlatmak da çok kolaydır, b.exe olarak yeniden adlandırılabilir ve her ikisi de çalışır. + bunun amaçlandığı gibi çalışmayacağı diğer durumlar. Dikkatle kullanın!
Lars Nielsen

Bu, mono-geliştirmeyle çalışmaz. Windows ortamları altında yine de harika çalışıyor.
Tono Nam

20

İş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();
        }
    }
}

2
Bir WPF uygulaması için Application.Current.Shutdown (); Bu yöntem bir cazibe gibi çalışır. Teşekkürler Terrapin.
Jeff

Burada asıl önemli olan mutex'i statik yapmanızdır. Diğer durumda olduğu gibi GC bunu toplayacaktır.
Oleksii

Mutex adlı eserin sadeliğinden ve netliğinden keyif aldım. Bu kod özlü ve etkilidir.
Çad

7

Hanselman, bunu yapmak için Microsoft.VisualBasic derlemesinden WinFormsApplicationBase sınıfını kullanma üzerine bir gönderiye sahip .


Bunu birkaç yıldır kullanıyorum, ancak şimdi Mutex tabanlı bir çözüme geçmek istiyorum. Bununla ilgili sorunları bildiren müşterilerim var ve bunun için Remoting'i kullandığından şüpheleniyorum.
Richard Watson

5

Şimdiye kadar önerilen 3 temel teknik var gibi görünüyor.

  1. Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase sınıfından türetin ve IsSingleInstance özelliğini true olarak ayarlayın. (Burada bir uyarı, bunun WPF uygulamalarıyla çalışmayacağına inanıyorum, değil mi?)
  2. Adlandırılmış bir muteks kullanın ve önceden oluşturulmuş olup olmadığını kontrol edin.
  3. Çalışan işlemlerin bir listesini alın ve işlemlerin adlarını karşılaştırın. (Bu, işlem adınızın belirli bir kullanıcının makinesinde çalışan diğer işlemlere göre benzersiz olmasını zorunlu kılma uyarısına sahiptir.)

Kaçırdığım herhangi bir uyarı var mı?


3
3'ün çok verimli olduğunu düşünmüyorum. Mutex'e oy verirdim, birçok kez sorunsuz kullandım. 1. maddeyi hiç kullanmadım, c # içindeyken nasıl uçtuğundan emin değilim.
typemismatch

2
Seçenek 1 hala WPF ile çalışıyor, sadece biraz daha karmaşık. msdn.microsoft.com/en-us/library/ms771662.aspx
Graeme Bradbury

5

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.


Bunun farkı nedir Mutex? Bir yakalama var mı?
Harambe Saldırı Helikopteri

İşlemin adını kullanıyor. İsim tekrarlanırsa yanlış bir bayrak oluşturur. Başka bir durumda,
muteksten

4

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ü: görüntü açıklamasını buraya girin Bu bir Visual Studio 2008 windows uygulama projesidir.


3
Bahsettiğiniz bu onay kutusunu C # / WPF uygulamam için aradım ve yok.
HappyNomad

3
Bunu VS 2008 C # / WinForms uygulamamın özelliklerinde de görmüyorum.
Jesse McGrew

VS2005'te de değil. Eski VB stüdyosundan bahsediyor olmalı.
nawfal

Evet seçenek var, bu seçeneği bulabileceğiniz pencerenin bir görüntüsünü eklemek için yazıyı değiştirdim.
Doliveras

6
Seçenek, C # için değil, sadece VB.NET uygulaması için mevcuttur. Görünüşe göre seçeneğin kendisi Microsoft.VisualBasic derlemesinden WinFormsApplicationBase sınıfını kullanıyor.
amolbk

4

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ı


Muteksi gerçekten edinmenize ve serbest bırakmanıza gerek yok. Bilmeniz gereken tek şey, nesneyi zaten başka bir uygulamanın oluşturup oluşturmadığıdır (yani, çekirdek referans sayısı> = 1).
Michael Goldshteyn


3

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"


2

VB.NET kullanın! Hayır: gerçekten;)

Microsoft.VisualBasic.ApplicationServices kullanarak;

VB.Net'ten WindowsFormsApplicationBase, size diğer Örnekleri belirleyen ve yalnızca bir Örneğin çalışmasına izin veren bir "SingleInstace" Özelliği sağlar.


2

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());
    }
}



1

(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");

Bu aslında basitliği açısından harika ve sadece görüntülerle değil hemen hemen her tür dosyayla çalışıyor. Mutex çözümünün "temiz" olmaktan uzak olduğunu hissediyorum. Son derece karmaşık ve görünüşe göre "doğru" yapmadığı için başarısız olmasının birçok yolu var. Ayrıca Main(), WPF'nin nasıl çalışması gerektiğine aykırı bir yöntem gerektirir .
Kyle Delaney

Bu bir tür böcek kullanımı gibidir. Çalışır ama bu amaç için yapılmamıştır. Bunu bir profesyonel olarak kullanmazdım.
Bitterblue

Evet, istisnalara güvenmeden bu kadar etkili ve basit bir çözümümüzün olmaması talihsiz bir durum.
Kyle Delaney

Tam olarak bir hata olmasa da. Hala .NET'in amaçlandığı gibi davranıyor.
Kyle Delaney

1
[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


-1, çünkü muteks ile bir using bloğu kullanmazsanız, bu KeepAlive'i gereksiz kılar. Ve evet, sanırım John Skeet bunu yanlış anladı. Bu durumda muteksi elden çıkarmanın neden yanlış olacağını açıklamıyor.

1

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);
}

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 .


0

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());
}

0

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


0

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); 
        }
    }         
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.