Dans .NET, quel est le meilleur moyen d'empêcher plusieurs instances d'une application de s'exécuter en même temps? Et s'il n'y a pas de «meilleure» technique, quelles sont certaines des mises en garde à prendre en compte avec chaque solution?
Dans .NET, quel est le meilleur moyen d'empêcher plusieurs instances d'une application de s'exécuter en même temps? Et s'il n'y a pas de «meilleure» technique, quelles sont certaines des mises en garde à prendre en compte avec chaque solution?
Réponses:
Utilisez Mutex. L'un des exemples ci-dessus utilisant GetProcessByName comporte de nombreuses mises en garde. Voici un bon article sur le sujet:
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;qui obtiendra le guide de l'assembly en cours d'exécution
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;
}
Voici le code dont vous avez besoin pour vous assurer qu'une seule instance est en cours d'exécution. C'est la méthode d'utilisation d'un mutex nommé.
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 a publié un article sur l'utilisation de la classe WinFormsApplicationBase de l'assembly Microsoft.VisualBasic pour ce faire.
Il semble que 3 techniques fondamentales ont été suggérées jusqu'à présent.
Des mises en garde que j'ai manquées?
1 - Créer une référence dans program.cs ->
using System.Diagnostics;
2 - Mettre en void Main()première ligne de code ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
C'est tout.
Mutex? Y a-t-il un hic?
À l'aide de Visual Studio 2005 ou 2008, lorsque vous créez un projet pour un exécutable, dans les fenêtres de propriétés du panneau "Application", il y a une case à cocher intitulée "Créer une application d'instance unique" que vous pouvez activer pour convertir l'application sur une application à instance unique .
Voici une capture de la fenêtre dont je parle:
Il s'agit d'un projet d'application Windows Visual Studio 2008.
J'ai essayé toutes les solutions ici et rien n'a fonctionné dans mon projet C # .net 4.0. En espérant aider quelqu'un ici la solution qui a fonctionné pour moi:
En tant que variables de classe principales:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
Lorsque vous devez vérifier si l'application est déjà en cours d'exécution:
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
}
J'avais besoin de fermer d'autres istances uniquement avec certaines conditions, cela a bien fonctionné pour mon objectif
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 —Single-Instance_Detection_and_Management
Après avoir essayé plusieurs solutions, je pose la question. J'ai fini par utiliser l'exemple pour WPF ici: 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();
}
}
}
Dans App.xaml:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
Cet article explique simplement comment vous pouvez créer une application Windows avec un contrôle sur le nombre de ses instances ou exécuter une seule instance. Il s'agit d'un besoin très typique d'une application métier. Il existe déjà de nombreuses autres solutions possibles pour contrôler cela.
http://www.openwinforms.com/single_instance_application.html
Ceci est le code pour 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
Ceci est le code pour 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());
}
}
Vous devez utiliser System.Diagnostics.Process.
Consultez: http://www.devx.com/tips/Tip/20044
(Remarque: c'est une solution amusante! Cela fonctionne mais utilise une mauvaise conception GDI + pour y parvenir.)
Mettez une image avec votre application et chargez-la au démarrage. Maintenez-le enfoncé jusqu'à ce que l'application se ferme. L'utilisateur ne pourra pas démarrer une deuxième instance. (Bien sûr, la solution mutex est beaucoup plus propre)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Main()méthode qui va à l'encontre de la façon dont WPF est censé fonctionner.
[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!
}
De: Assurer une seule instance de l'application .NET
et: Mutex d'application à instance unique
Même réponse que @Smink et @Imjustpondering avec une torsion:
FAQ de Jon Skeet sur C # pour découvrir pourquoi GC.KeepAlive est important
En utilisant simplement un StreamWriter, que diriez-vous de cela?
System.IO.File.StreamWriter OpenFlag = null; //globally
et
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
Normalement, cela est fait avec un Mutex nommé (utilisez le nouveau Mutex ("votre nom d'application", true) et vérifiez la valeur de retour), mais il existe également des classes de support dans Microsoft.VisualBasic.dll qui peuvent le faire pour vous .
Cela a fonctionné pour moi en pur C #. le try / catch se produit lorsqu'un processus de la liste se termine pendant votre boucle.
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());
}
Veillez à prendre en compte la sécurité lors de la restriction d'une application à une seule instance:
Article complet: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
Nous utilisons un mutex nommé avec un nom fixe afin de détecter si une autre copie du programme est en cours d'exécution. Mais cela signifie également qu'un attaquant peut créer le mutex en premier, empêchant ainsi notre programme de s'exécuter du tout! Comment puis-je empêcher ce type d'attaque par déni de service?
...
Si l'attaquant s'exécute dans le même contexte de sécurité que votre programme est (ou serait) en cours d'exécution, alors vous ne pouvez rien faire. Quelle que soit la "poignée de main secrète" que vous proposez pour déterminer si une autre copie de votre programme est en cours d'exécution, l'attaquant peut l'imiter. Puisqu'il s'exécute dans le bon contexte de sécurité, il peut faire tout ce que le «vrai» programme peut faire.
...
Il est clair que vous ne pouvez pas vous protéger contre un attaquant exécutant le même privilège de sécurité, mais vous pouvez toujours vous protéger contre des attaquants non privilégiés exécutant d'autres privilèges de sécurité.
Essayez de définir un DACL sur votre mutex, voici la méthode .NET: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
Aucune de ces réponses n'a fonctionné pour moi car j'avais besoin de cela pour fonctionner sous Linux en utilisant monodevelop. Cela fonctionne très bien pour moi:
Appelez cette méthode en lui passant un identifiant unique
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);
}
}