Update 2017-01-25. Nachdem ich einige Dinge ausprobiert hatte, entschied ich mich für die VisualBasic.dll, da sie einfacher ist und besser funktioniert (zumindest für mich). Ich lasse meine vorherige Antwort nur als Referenz...
Nur als Referenz, dies ist, wie ich ohne die Übergabe von Argumenten (die ich keinen Grund, so zu tun finden kann... Ich meine eine einzelne App mit Argumenten, die von einer Instanz zu einer anderen weitergegeben werden müssen). Wenn Dateizuordnung erforderlich ist, dann sollte eine App (pro Benutzer Standard-Erwartung) für jedes Dokument instanziiert werden. Wenn Sie Argumente an eine bestehende Anwendung weitergeben müssen, würde ich wohl eine vb dll verwenden.
Ich bevorzuge es, keine Args zu übergeben (nur eine einzelne Instanz der Anwendung), keine neue Fenstermeldung zu registrieren und die Nachrichtenschleife nicht zu überschreiben, wie in Matt Davis' Lösung definiert. Obwohl es keine große Sache ist, eine VisualBasic dll hinzuzufügen, ziehe ich es vor, keinen neuen Verweis hinzuzufügen, nur um eine Einzelinstanzanwendung zu erstellen. Außerdem ziehe ich es vor, eine neue Klasse mit Main zu instanziieren, anstatt Shutdown von App.Startup override aufzurufen, um sicherzustellen, dass die App so bald wie möglich beendet wird.
In der Hoffnung, dass es jemandem gefällt... oder ein bisschen inspiriert :-)
Die Startklasse des Projekts sollte als 'SingleInstanceApp' festgelegt werden.
public class SingleInstanceApp
{
[STAThread]
public static void Main(string[] args)
{
Mutex _mutexSingleInstance = new Mutex(true, "MonitorMeSingleInstance");
if (_mutexSingleInstance.WaitOne(TimeSpan.Zero, true))
{
try
{
var app = new App();
app.InitializeComponent();
app.Run();
}
finally
{
_mutexSingleInstance.ReleaseMutex();
_mutexSingleInstance.Close();
}
}
else
{
MessageBox.Show("One instance is already running.");
var processes = Process.GetProcessesByName(Assembly.GetEntryAssembly().GetName().Name);
{
if (processes.Length > 1)
{
foreach (var process in processes)
{
if (process.Id != Process.GetCurrentProcess().Id)
{
WindowHelper.SetForegroundWindow(process.MainWindowHandle);
}
}
}
}
}
}
}
WindowHelper:
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;
namespace HQ.Util.Unmanaged
{
public class WindowHelper
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
17 Stimmen
Gibt die CLR nicht automatisch alle nicht freigegebenen Mutexe frei, wenn die Anwendung ohnehin beendet wird?
2 Stimmen
@Cocowalla: Der Finalisierer sollte die nicht verwalteten Mutexe entsorgen, es sei denn, er kann nicht wissen, ob die Mutex von der verwalteten Anwendung erstellt oder an eine bestehende angehängt wurde.
1 Stimmen
Es ist sinnvoll, nur eine Instanz Ihrer Anwendung zu haben. Aber die Übergabe von Argumenten an eine bereits existierende Anwendung erscheint mir ein wenig albern. Ich kann keinen Grund dafür sehen, dies zu tun. Wenn Sie eine Anwendung mit einer Dateierweiterung verknüpfen, sollten Sie so viele Anwendungen öffnen, wie Benutzer Dokumente öffnen wollen. Das ist das Standardverhalten, das jeder Benutzer erwarten würde.
1 Stimmen
Ich möchte nur eine Korrektur meiner vorherigen Aussage vornehmen. Die Übergabe von Argumenten an eine bestehende Anwendung bedeutet, dass Sie eine MDI (Multi-Document-Interface) durchführen wollen. Ich dachte, dass MDI war eine Art, die Microsoft war drängen aus (Word und Excel sind jetzt SDI). Aber ich habe festgestellt, dass Chrome und IE beide MDI sind. Vielleicht sind wir in Jahren, in denen MDI zurück ist? (Aber ich bevorzuge immer noch SDI gegenüber MDI)
13 Stimmen
@Cocowalla Die CLR verwaltet keine nativen Ressourcen. Wenn ein Prozess jedoch beendet wird, werden alle Handles vom System (dem Betriebssystem, nicht der CLR) freigegeben.
2 Stimmen
Ich bevorzuge die Antwort von @huseyint. Sie verwendet die Microsoft-eigene Klasse 'SingleInstance.cs', so dass man sich keine Gedanken über Mutexe und IntPtrs machen muss. Außerdem besteht keine Abhängigkeit von VisualBasic (igitt). Siehe codereview.stackexchange.com/questions/20871/ für mehr...
1 Stimmen
Ich verwende SingleInstanceApp nuget. nuget.org/packages/SingleInstanceApp Funktioniert perfekt. Benötigt keine Microsoft.VisualBasic-Referenz. Hängt nicht von der App-Version ab (in Microsoft.VisualBasic schon). Die App wird nur durch eine eindeutige Zeichenfolge identifiziert.
0 Stimmen
Es sieht so aus, als ob diese Frage und die Antworten eine Fülle von Informationen enthalten - eine wahre Goldgrube!