Wie kann in .NET am besten verhindert werden, dass mehrere Instanzen einer App gleichzeitig ausgeführt werden? Und wenn es keine "beste" Technik gibt, welche Einschränkungen sind bei jeder Lösung zu beachten?
Wie kann in .NET am besten verhindert werden, dass mehrere Instanzen einer App gleichzeitig ausgeführt werden? Und wenn es keine "beste" Technik gibt, welche Einschränkungen sind bei jeder Lösung zu beachten?
Antworten:
Verwenden Sie Mutex. Eines der obigen Beispiele für die Verwendung von GetProcessByName weist viele Einschränkungen auf. Hier ist ein guter Artikel zu diesem Thema:
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;die die ausführende Assembly ist guid zu bekommen
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;
}
Hier ist der Code, den Sie benötigen, um sicherzustellen, dass nur eine Instanz ausgeführt wird. Dies ist die Methode zur Verwendung eines benannten 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 hat einen Beitrag zur Verwendung der WinFormsApplicationBase-Klasse aus der Microsoft.VisualBasic-Assembly, um dies zu tun.
Es hört sich so an, als ob bisher drei grundlegende Techniken vorgeschlagen wurden.
Irgendwelche Vorbehalte, die ich verpasst habe?
1 - Erstellen Sie eine Referenz in program.cs ->
using System.Diagnostics;
2 - void Main()Als erste Codezeile eingeben ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
Das ist es.
Mutex? Gibt es einen Haken?
Wenn Sie Visual Studio 2005 oder 2008 verwenden, um ein Projekt für eine ausführbare Datei zu erstellen, befindet sich in den Eigenschaftenfenstern im Bereich "Anwendung" ein Kontrollkästchen mit dem Namen "Einzelinstanzanwendung erstellen", das Sie aktivieren können, um die Anwendung in eine Einzelinstanzanwendung zu konvertieren .
Hier ist eine Aufnahme des Fensters, von dem ich spreche:
Dies ist ein Windows Studio-Anwendungsprojekt von Visual Studio 2008.
Ich habe alle Lösungen hier ausprobiert und in meinem C # .net 4.0-Projekt hat nichts funktioniert. In der Hoffnung, hier jemandem die Lösung zu helfen, die für mich funktioniert hat:
Als Hauptklassenvariablen:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
Wenn Sie überprüfen müssen, ob die App bereits ausgeführt wird:
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
}
Ich musste andere Stellen nur unter bestimmten Bedingungen schließen, dies funktionierte gut für meinen Zweck
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 - Single-Instance_Detection_and_Management
Nach dem Ausprobieren mehrerer Lösungen stelle ich die Frage. Am Ende habe ich das Beispiel für WPF hier verwendet: 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"
In diesem Artikel wird lediglich erläutert, wie Sie eine Windows-Anwendung mit Kontrolle über die Anzahl ihrer Instanzen erstellen oder nur eine einzelne Instanz ausführen können. Dies ist ein sehr typischer Bedarf einer Geschäftsanwendung. Es gibt bereits viele andere mögliche Lösungen, um dies zu kontrollieren.
http://www.openwinforms.com/single_instance_application.html
Dies ist der Code für 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
Dies ist der Code für 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());
}
}
Sie müssen System.Diagnostics.Process verwenden.
Überprüfen Sie heraus: http://www.devx.com/tips/Tip/20044
(Hinweis: Dies ist eine unterhaltsame Lösung! Sie funktioniert, verwendet jedoch schlechtes GDI + -Design, um dies zu erreichen.)
Fügen Sie ein Bild in Ihre App ein und laden Sie es beim Start. Halten Sie die Taste gedrückt, bis die App beendet wird. Der Benutzer kann keine zweite Instanz starten. (Natürlich ist die Mutex-Lösung viel sauberer)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Main()Methode, die gegen die Funktionsweise von WPF verstößt.
[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!
}
Von: Sicherstellen einer einzelnen Instanz von .NET Application
und: Single Instance Application Mutex
Gleiche Antwort wie @Smink und @Imjustpondering mit einem Twist:
Jon Skeets FAQ zu C # , um herauszufinden, warum GC.KeepAlive wichtig ist
Einfach mit a StreamWriter, wie wäre es damit?
System.IO.File.StreamWriter OpenFlag = null; //globally
und
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
Normalerweise wird dies mit einem benannten Mutex durchgeführt (verwenden Sie einen neuen Mutex ("Ihr App-Name", true) und überprüfen Sie den Rückgabewert), aber es gibt auch einige Support-Klassen in Microsoft.VisualBasic.dll, die dies für Sie tun können .
Das hat bei mir in reinem C # funktioniert. Der Versuch / Fang ist, wenn möglicherweise ein Prozess in der Liste während Ihrer Schleife beendet wird.
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());
}
Berücksichtigen Sie unbedingt die Sicherheit, wenn Sie eine Anwendung auf eine einzelne Instanz beschränken:
Vollständiger Artikel: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
Wir verwenden einen benannten Mutex mit einem festen Namen, um festzustellen, ob eine andere Kopie des Programms ausgeführt wird. Das bedeutet aber auch, dass ein Angreifer zuerst den Mutex erstellen kann, wodurch verhindert wird, dass unser Programm überhaupt ausgeführt wird! Wie kann ich diese Art von Denial-of-Service-Angriff verhindern?
...
Wenn der Angreifer im selben Sicherheitskontext ausgeführt wird, in dem Ihr Programm ausgeführt wird (oder werden würde), können Sie nichts tun. Unabhängig davon, welchen "geheimen Handschlag" Sie erstellen, um festzustellen, ob eine andere Kopie Ihres Programms ausgeführt wird, kann der Angreifer dies nachahmen. Da es im richtigen Sicherheitskontext ausgeführt wird, kann es alles tun, was das "echte" Programm kann.
...
Natürlich können Sie sich nicht vor einem Angreifer schützen, der mit demselben Sicherheitsrecht ausgeführt wird, aber Sie können sich trotzdem vor nicht privilegierten Angreifern schützen, die mit anderen Sicherheitsberechtigungen ausgeführt werden.
Versuchen Sie, eine DACL für Ihren Mutex festzulegen. Gehen Sie dazu wie folgt vor: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
Keine dieser Antworten funktionierte für mich, da ich diese brauchte, um unter Linux mit Monodevelop zu arbeiten. Das funktioniert gut für mich:
Nennen Sie diese Methode eine eindeutige ID
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);
}
}