Impedire più istanze di una determinata app in .NET?

In .NET, qual è il modo migliore per impedire l’esecuzione simultanea di più istanze di un’app? E se non esiste una tecnica “migliore”, quali sono alcune delle avvertenze da considerare con ciascuna soluzione?

Usa Mutex. Uno degli esempi sopra riportati con GetProcessByName presenta molti avvertimenti. Ecco un buon articolo sull’argomento:

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

Ecco il codice necessario per garantire che sia in esecuzione una sola istanza. Questo è il metodo per usare un mutex denominato.

 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 ha un post sull’utilizzo della class WinFormsApplicationBase dall’assembly Microsoft.VisualBasic per fare ciò.

Sembra che ci siano 3 tecniche fondamentali che sono state suggerite finora.

  1. Deriva dalla class Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase e imposta la proprietà IsSingleInstance su true. (Credo che un avvertimento qui sia che questo non funzionerà con le applicazioni WPF, vero?)
  2. Utilizzare un mutex denominato e verificare se è già stato creato.
  3. Ottieni un elenco di processi in esecuzione e confronta i nomi dei processi. (Questo ha l’avvertenza di richiedere che il nome del processo sia unico rispetto a qualsiasi altro processo in esecuzione sulla macchina di un dato utente.)

Eventuali avvertenze che ho perso?

Ho provato tutte le soluzioni qui e niente ha funzionato nel mio progetto C # .net 4.0. Sperando di aiutare qualcuno qui la soluzione che ha funzionato per me:

Come variabili principali della class:

 private static string appGuid = "WRITE AN UNIQUE GUID HERE"; private static Mutex mutex; 

Quando è necessario verificare se l’app è già in esecuzione:

 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 } 

Avevo bisogno di chiudere altre istanze solo con alcune condizioni, questo ha funzionato bene per il mio scopo

Utilizzando Visual Studio 2005 o 2008 quando si crea un progetto per un eseguibile, nelle windows delle proprietà all’interno del pannello “Applicazione” è presente una casella di controllo denominata “Crea applicazione di istanza singola” che è ansible triggersre per convertire l’applicazione in un’applicazione singola istanza .

Ecco una cattura della finestra di cui sto parlando: inserisci la descrizione dell'immagine qui Questo è un progetto di applicazione Windows di Visual Studio 2008.

Questo articolo spiega semplicemente come è ansible creare un’applicazione Windows con controllo sul numero delle sue istanze o eseguire solo una singola istanza. Questa è una necessità molto tipica di un’applicazione aziendale. Ci sono già molte altre possibili soluzioni per controllarlo.

http://www.openwinforms.com/single_instance_application.html

Usa VB.NET! No davvero 😉

utilizzando Microsoft.VisualBasic.ApplicationServices;

WindowsFormsApplicationBase di VB.Net fornisce una proprietà “SingleInstace”, che determina altre istanze e consente l’esecuzione di una sola istanza.

Devi usare System.Diagnostics.Process.

Controlla: http://www.devx.com/tips/Tip/20044

Questo è il codice per 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 

Questo è il codice per 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()); } } 

(Nota: questa è una soluzione divertente! Funziona ma usa un cattivo design GDI + per ottenere questo risultato.)

Inserisci un’immagine con la tua app e caricala all’avvio. Mantieni fino alla chiusura dell’app. L’utente non sarà in grado di avviare una seconda istanza. (Ovviamente la soluzione mutex è molto più pulita)

 private static Bitmap randomName = new Bitmap("my_image.jpg"); 

Dopo aver provato più soluzioni ho la domanda. Ho finito per utilizzare l’esempio per WPF qui: 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(); } } } 

In App.xaml:

 x:Class="*YourNameSpace*.App" StartupUri="MainWindow.xaml" Startup="App_Startup" 

1 – Creare un riferimento in program.cs ->

 using System.Diagnostics; 

2 – Metti in void Main() come prima riga di codice ->

  if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1) return; 

Questo è tutto.

Semplicemente usando StreamWriter , che ne dici di questo?

 System.IO.File.StreamWriter OpenFlag = null; //globally 

e

 try { OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning"); } catch (System.IO.IOException) //file in use { Environment.Exit(0); } 

Normalmente è fatto con un Mutex chiamato (usa il nuovo Mutex (“nome della tua app”, vero) e controlla il valore restituito), ma ci sono anche alcune classi di supporto in Microsoft.VisualBasic.dll che possono farlo per te .

Questo ha funzionato per me in puro C #. il try / catch è quando eventualmente un processo nella lista si chiude durante il ciclo.

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

Da: Garantire una singola istanza di .NET Application

e: Mutex applicazione singola istanza

La stessa risposta di @Smink e @Imjustpondering con una svolta:

Le domande frequenti di Jon Skeet su C # per scoprire perché GC.KeepAlive è importante

Assicurati di considerare la sicurezza quando si limita un’applicazione a una singola istanza:

Articolo completo: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813

Stiamo usando un mutex denominato con un nome fisso per rilevare se un’altra copia del programma è in esecuzione. Ma ciò significa anche che un utente malintenzionato può creare prima il mutex, impedendo così al nostro programma di funzionare affatto! Come posso prevenire questo tipo di attacco denial of service?

Se l’autore dell’attacco è in esecuzione nello stesso contesto di sicurezza in cui il programma è (o sarebbe) in esecuzione, non c’è nulla che tu possa fare. Qualunque sia la “stretta di mano segreta” che ti viene in mente per determinare se un’altra copia del tuo programma è in esecuzione, l’attaccante può imitarla. Poiché è in esecuzione nel contesto di sicurezza corretto, può fare tutto ciò che il programma “reale” può fare.

Chiaramente non puoi proteggerti da un utente malintenzionato con lo stesso privilegio di sicurezza, ma puoi comunque proteggerti da aggressori non privilegiati che eseguono altri privilegi di sicurezza.

Prova a impostare un DACL sul tuo mutex, ecco il modo .NET: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx