Wie kann mit C # und WPF unter .NET (anstelle von Windows Forms oder Konsole) eine Anwendung erstellt werden, die nur als einzelne Instanz ausgeführt werden kann?
Ich weiß, dass es etwas mit einer mythischen Sache zu tun hat, die Mutex genannt wird. Selten kann ich jemanden finden, der sich die Mühe macht, anzuhalten und zu erklären, was eine davon ist.
Der Code muss auch die bereits ausgeführte Instanz darüber informieren, dass der Benutzer versucht hat, eine zweite zu starten, und möglicherweise auch Befehlszeilenargumente übergeben, falls vorhanden.
Antworten:
Hier ist ein sehr guter Artikel zur Mutex-Lösung. Der im Artikel beschriebene Ansatz ist aus zwei Gründen vorteilhaft.
Erstens ist keine Abhängigkeit von der Microsoft.VisualBasic-Assembly erforderlich. Wenn mein Projekt bereits von dieser Assembly abhängig wäre, würde ich wahrscheinlich empfehlen, den in einer anderen Antwort gezeigten Ansatz zu verwenden . Aber so wie es ist, verwende ich nicht die Microsoft.VisualBasic-Assembly und möchte meinem Projekt lieber keine unnötige Abhängigkeit hinzufügen.
Zweitens zeigt der Artikel, wie die vorhandene Instanz der Anwendung in den Vordergrund gerückt wird, wenn der Benutzer versucht, eine andere Instanz zu starten. Das ist eine sehr nette Geste, die die anderen hier beschriebenen Mutex-Lösungen nicht ansprechen.
AKTUALISIEREN
Zum 01.08.2014 ist der Artikel, auf den ich oben verlinkt habe, noch aktiv, aber der Blog wurde seit einiger Zeit nicht mehr aktualisiert. Das macht mir Sorgen, dass es irgendwann verschwinden könnte und damit die befürwortete Lösung. Ich reproduziere den Inhalt des Artikels hier für die Nachwelt. Die Wörter gehören ausschließlich dem Blog-Inhaber von Sanity Free Coding .
quelle
Mutex
Konstruktor benötigt lediglich eine Zeichenfolge, sodass Sie einen beliebigen Zeichenfolgennamen angeben können , z. B. "This Is My Mutex". Da ein 'Mutex' ein Systemobjekt ist, das anderen Prozessen zur Verfügung steht, möchten Sie normalerweise, dass der Name eindeutig ist, damit er nicht mit anderen 'Mutex'-Namen auf demselben System kollidiert. In dem Artikel ist die kryptisch aussehende Zeichenfolge eine 'Guid'. Sie können dies programmgesteuert durch Aufrufen generierenSystem.Guid.NewGuid()
. Im Fall des Artikels hat der Benutzer ihn wahrscheinlich über Visual Studio generiert, wie hier gezeigt: msdn.microsoft.com/en-us/library/ms241442(VS.80).aspxSie könnten die Mutex-Klasse verwenden, aber Sie werden bald feststellen, dass Sie den Code implementieren müssen, um die Argumente und dergleichen selbst zu übergeben. Nun, ich habe einen Trick beim Programmieren in WinForms gelernt, als ich Chris Sells Buch gelesen habe . Dieser Trick verwendet eine Logik, die uns bereits im Framework zur Verfügung steht. Ich weiß nichts über dich, aber wenn ich etwas über Dinge lerne, die ich im Framework wiederverwenden kann, ist das normalerweise der Weg, den ich gehe, anstatt das Rad neu zu erfinden. Es sei denn natürlich, es macht nicht alles, was ich will.
Als ich zu WPF kam, hatte ich eine Möglichkeit, denselben Code zu verwenden, jedoch in einer WPF-Anwendung. Diese Lösung sollte Ihren Anforderungen anhand Ihrer Frage entsprechen.
Zuerst müssen wir unsere Anwendungsklasse erstellen. In dieser Klasse überschreiben wir das OnStartup-Ereignis und erstellen eine Methode namens Activate, die später verwendet wird.
Zweitens müssen wir eine Klasse erstellen, die unsere Instanzen verwalten kann. Bevor wir das durchgehen, werden wir tatsächlich Code wiederverwenden, der sich in der Microsoft.VisualBasic-Assembly befindet. Da ich in diesem Beispiel C # verwende, musste ich auf die Assembly verweisen. Wenn Sie VB.NET verwenden, müssen Sie nichts tun. Die Klasse, die wir verwenden werden, ist WindowsFormsApplicationBase und erbt unseren Instanzmanager davon und nutzt dann Eigenschaften und Ereignisse, um die einzelne Instanzierung zu verarbeiten.
Grundsätzlich verwenden wir die VB-Bits, um einzelne Instanzen zu erkennen und entsprechend zu verarbeiten. OnStartup wird ausgelöst, wenn die erste Instanz geladen wird. OnStartupNextInstance wird ausgelöst, wenn die Anwendung erneut ausgeführt wird. Wie Sie sehen können, kann ich über die Ereignisargumente zu dem gelangen, was in der Befehlszeile übergeben wurde. Ich habe den Wert auf ein Instanzfeld gesetzt. Sie können die Befehlszeile hier analysieren oder sie über den Konstruktor und den Aufruf der Activate-Methode an Ihre Anwendung übergeben.
Drittens ist es Zeit, unseren EntryPoint zu erstellen. Anstatt die Anwendung wie gewohnt neu zu gestalten, werden wir unseren SingleInstanceManager nutzen.
Nun, ich hoffe, Sie können alles verfolgen und diese Implementierung verwenden und zu Ihrer eigenen machen.
quelle
Von hier aus .
Eine übliche Verwendung für einen prozessübergreifenden Mutex besteht darin, sicherzustellen, dass jeweils nur eine Instanz eines Programms ausgeführt werden kann. So geht's:
Eine gute Funktion von Mutex ist, dass die CLR den Mutex automatisch freigibt, wenn die Anwendung beendet wird, ohne dass ReleaseMutex zuerst aufgerufen wird.
quelle
MSDN hat tatsächlich eine Beispielanwendung für C # und VB, um genau dies zu tun: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx
'Another instance of the app is running. Bye'
er kein sehr zufriedener Benutzer wäre. Sie MÜSSEN einfach (in einer GUI-Anwendung) zu dieser Anwendung wechseln und die angegebenen Argumente übergeben - oder wenn Befehlszeilenparameter keine Bedeutung haben, müssen Sie die möglicherweise minimierte Anwendung öffnen.Das Framework hat bereits Unterstützung dafür - es ist nur so, dass ein Idiot die DLL genannt hat
Microsoft.VisualBasic
und es nicht in soMicrosoft.ApplicationUtils
etwas hineingesteckt wurde . Überwinde es - oder öffne Reflector.Tipp: Wenn Sie diesen Ansatz genau so verwenden, wie er ist, und Sie bereits eine App.xaml mit Ressourcen usw. haben, sollten Sie sich dies auch ansehen .
quelle
Dieser Code sollte zur Hauptmethode gehen. Schauen Sie sich hier für weitere Informationen über die wichtigste Methode in WPF.
Methode 2
Hinweis: Bei den oben genannten Methoden wird davon ausgegangen, dass Ihr Prozess / Ihre Anwendung einen eindeutigen Namen hat. Weil es den Prozessnamen verwendet, um festzustellen, ob vorhandene Prozessoren vorhanden sind. Wenn Ihre Anwendung einen sehr gebräuchlichen Namen hat (z. B. Editor), funktioniert der oben beschriebene Ansatz nicht.
quelle
ProcessName
Gibt den Namen der ausführbaren Datei abzüglich der zurückexe
. Wenn Sie eine Anwendung mit dem Namen "Notepad" erstellen und der Windows-Editor ausgeführt wird, wird er als Ihre Anwendung erkannt.Nun, ich habe eine Einwegklasse dafür, die für die meisten Anwendungsfälle problemlos funktioniert:
Verwenden Sie es so:
Hier ist es:
quelle
Eine neue Anwendung, die Mutex- und IPC-Inhalte verwendet und außerdem alle Befehlszeilenargumente an die ausgeführte Instanz übergibt, ist WPF Single Instance Application .
quelle
Die Code C # .NET-Einzelinstanzanwendung , die als Referenz für die markierte Antwort dient, ist ein guter Anfang.
Ich habe jedoch festgestellt, dass es nicht sehr gut mit den Fällen umgeht, in denen für die bereits vorhandene Instanz ein modales Dialogfeld geöffnet ist, unabhängig davon, ob es sich um ein verwaltetes (wie ein anderes Formular wie ein About-Feld) oder ein nicht verwaltetes (wie das) handelt OpenFileDialog auch bei Verwendung der Standard-.NET-Klasse). Mit dem ursprünglichen Code wird das Hauptformular aktiviert, das modale bleibt jedoch inaktiv, was seltsam aussieht. Außerdem muss der Benutzer darauf klicken, um die App weiterhin verwenden zu können.
Daher habe ich eine SingleInstance-Dienstprogrammklasse erstellt, um all dies für Winforms- und WPF-Anwendungen ganz automatisch zu erledigen.
Winforms :
1) Ändern Sie die Programmklasse wie folgt:
2) Ändern Sie die Hauptfensterklasse wie folgt:
WPF:
1) Ändern Sie die App-Seite wie folgt (und stellen Sie sicher, dass Sie die Erstellungsaktion auf Seite setzen, um die Hauptmethode neu definieren zu können):
2) Ändern Sie die Hauptfensterklasse wie folgt:
Und hier ist die Utility-Klasse:
quelle
Hier ist ein Beispiel, mit dem Sie eine einzelne Instanz einer Anwendung haben können. Wenn neue Instanzen geladen werden, übergeben sie ihre Argumente an die Hauptinstanz, die ausgeführt wird.
quelle
Nur ein paar Gedanken: Es gibt Fälle, in denen nur eine Instanz einer Anwendung nicht "lahm" sein muss, wie manche glauben machen würden. Datenbank-Apps usw. sind um eine Größenordnung schwieriger, wenn einem einzelnen Benutzer mehrere Instanzen der App für den Zugriff auf eine Datenbank zugelassen werden (Sie wissen, dass alle Datensätze aktualisiert werden, die in mehreren Instanzen der App für die Benutzer geöffnet sind Maschine usw.). Verwenden Sie für die Sache "Namenskollision" zunächst keinen von Menschen lesbaren Namen - verwenden Sie stattdessen eine GUID oder, noch besser, eine GUID + den von Menschen lesbaren Namen. Die Wahrscheinlichkeit einer Namenskollision ist einfach vom Radar gefallen, und der Mutex kümmert sich nicht darum Wie jemand betonte, würde ein DOS-Angriff scheiße sein, aber wenn die böswillige Person sich die Mühe gemacht hat, den Mutex-Namen zu erhalten und ihn in ihre App zu integrieren, Sie sind sowieso so ziemlich ein Ziel und müssen VIEL mehr tun, um sich zu schützen, als nur einen Mutex-Namen zu fummeln. Wenn man die Variante von: new Mutex (true, "einige GUID plus Name", aus AIsFirstInstance) verwendet, haben Sie bereits Ihren Indikator, ob der Mutex die erste Instanz ist oder nicht.
quelle
So viele Antworten auf eine so scheinbar einfache Frage. Nur um die Dinge hier ein wenig aufzurütteln, ist meine Lösung für dieses Problem.
Das Erstellen eines Mutex kann problematisch sein, da der JIT-er sieht, dass Sie ihn nur für einen kleinen Teil Ihres Codes verwenden, und ihn als bereit für die Speicherbereinigung markieren möchte. Es möchte Sie so ziemlich überraschen, dass Sie denken, dass Sie diesen Mutex nicht so lange verwenden werden. In Wirklichkeit möchten Sie an diesem Mutex festhalten, solange Ihre Anwendung ausgeführt wird. Der beste Weg, dem Müllsammler zu sagen, er solle Mutex in Ruhe lassen, besteht darin, ihm zu sagen, er solle ihn über die verschiedenen Generationen der Garagensammlung hinweg am Leben erhalten. Beispiel:
Ich habe die Idee von dieser Seite gestrichen: http://www.ai.uga.edu/~mc/SingleInstance.html
quelle
Es sieht so aus, als gäbe es einen wirklich guten Weg, damit umzugehen:
WPF-Einzelinstanzanwendung
Dies bietet eine Klasse, die Sie hinzufügen können und die alle Mutex- und Messaging-Probleme verwaltet, um die Implementierung so zu vereinfachen, dass sie einfach trivial ist.
quelle
Der folgende Code ist meine WCF-Lösung für Named Pipes zum Registrieren einer Einzelinstanzanwendung. Es ist schön, weil es auch ein Ereignis auslöst, wenn eine andere Instanz versucht zu starten, und die Befehlszeile der anderen Instanz empfängt.
Es ist auf WPF ausgerichtet, weil es die
System.Windows.StartupEventHandler
Klasse verwendet, aber dies könnte leicht geändert werden.Dieser Code erfordert einen Verweis auf
PresentationFramework
undSystem.ServiceModel
.Verwendungszweck:
Quellcode:
quelle
Sie sollten niemals einen benannten Mutex verwenden, um eine Einzelinstanzanwendung zu implementieren (oder zumindest nicht für Produktionscode). Bösartiger Code kann leicht DoS ( Denial of Service ) Ihren Arsch ...
quelle
Schauen Sie sich den folgenden Code an. Es ist eine großartige und einfache Lösung, um mehrere Instanzen einer WPF-Anwendung zu verhindern.
quelle
Hier ist was ich benutze. Es kombinierte die Prozessaufzählung, um Switching und Mutex durchzuführen, um sich vor "aktiven Klickern" zu schützen:
quelle
Ich fand die einfachere Lösung, ähnlich der von Dale Ragan, aber leicht modifiziert. Es macht praktisch alles, was Sie brauchen, und basiert auf der Standardklasse Microsoft WindowsFormsApplicationBase.
Zunächst erstellen Sie die SingleInstanceController-Klasse, die Sie in allen anderen Einzelinstanzanwendungen verwenden können, die Windows Forms verwenden:
Dann können Sie es in Ihrem Programm wie folgt verwenden:
Sowohl das Programm als auch die SingleInstanceController_NET-Lösung sollten auf Microsoft.VisualBasic verweisen. Wenn Sie die laufende Anwendung nur als normales Fenster reaktivieren möchten, wenn der Benutzer versucht, das laufende Programm neu zu starten, kann der zweite Parameter im SingleInstanceController null sein. Im angegebenen Beispiel wird das Fenster maximiert.
quelle
Update 2017-01-25. Nachdem ich einige Dinge ausprobiert hatte, entschied ich mich für VisualBasic.dll, es ist einfacher und funktioniert besser (zumindest für mich). Ich lasse meine vorherige Antwort nur als Referenz ...
Nur als Referenz habe ich dies getan, ohne Argumente zu übergeben (was ich nicht begründen kann ... Ich meine eine einzelne App mit Argumenten, die von einer Instanz an eine andere weitergegeben werden sollen). Wenn eine Dateizuordnung erforderlich ist, sollte für jedes Dokument eine App (gemäß den Standarderwartungen des Benutzers) eingerichtet werden. Wenn Sie Argumente an eine vorhandene App übergeben müssen, würde ich wahrscheinlich vb dll verwenden.
Da keine Argumente übergeben werden (nur Einzelinstanz-App), möchte ich keine neue Window-Nachricht registrieren und die in Matt Davis Solution definierte Nachrichtenschleife nicht überschreiben. Es ist zwar keine große Sache, eine VisualBasic-DLL hinzuzufügen, aber ich ziehe es vor, keine neue Referenz hinzuzufügen, nur um eine Einzelinstanz-App zu erstellen. Außerdem bevorzuge ich es, eine neue Klasse mit Main zu instanziieren, anstatt Shutdown über App.Startup-Override aufzurufen, um sicherzustellen, dass das Programm so schnell wie möglich beendet wird.
In der Hoffnung, dass es irgendjemandem gefällt ... oder ein bisschen inspiriert :-)
Die Projektstartklasse sollte als 'SingleInstanceApp' festgelegt werden.
WindowHelper:
quelle
Ohne Mutex, einfache Antwort:
Legen Sie es in die
Program.Main()
.Beispiel :
Sie können
MessageBox.Show
derif
Anweisung hinzufügen und "Anwendung läuft bereits" eingeben.Dies könnte für jemanden hilfreich sein.
quelle
Named-Mutex-basierte Ansätze sind nicht plattformübergreifend, da Named-Mutexe in Mono nicht global sind. Auf Prozessaufzählungen basierende Ansätze haben keine Synchronisation und können zu falschem Verhalten führen (z. B. können mehrere gleichzeitig gestartete Prozesse je nach Zeitpunkt alle selbst beendet werden). Fenstersystembasierte Ansätze sind in einer Konsolenanwendung nicht wünschenswert. Diese Lösung, die auf der Antwort von Divin aufbaut, behebt all diese Probleme:
quelle
Ich verwende Mutex in meiner Lösung, um mehrere Instanzen zu verhindern.
quelle
Verwenden Sie eine Mutex-Lösung:
quelle
Hier ist eine einfache Lösung, mit der die Anwendung ein bereits vorhandenes Fenster in den Vordergrund stellen kann, ohne auf benutzerdefinierte Fenstermeldungen zurückgreifen oder Prozessnamen blind suchen zu müssen.
Bearbeiten: Sie können Mutex und createNew auch statisch speichern und initialisieren, aber Sie müssen den Mutex explizit entsorgen / freigeben, sobald Sie damit fertig sind. Persönlich bevorzuge ich es, den Mutex lokal zu halten, da er automatisch entsorgt wird, selbst wenn die Anwendung geschlossen wird, ohne jemals das Ende von Main zu erreichen.
quelle
Sie können auch die CodeFluent Runtime verwenden , eine kostenlose Sammlung von Tools. Es bietet eine SingleInstance- Klasse zum Implementieren einer Einzelinstanzanwendung.
quelle
Ich habe der NativeMethods-Klasse eine sendMessage-Methode hinzugefügt.
Anscheinend funktioniert die Postmessage-Methode nicht, wenn die Anwendung nicht in der Taskleiste angezeigt wird. Die Verwendung der Sendmessage-Methode löst dies jedoch.
quelle
Hier ist das gleiche, was über Event implementiert wurde.
quelle
[Ich habe unten Beispielcode für Konsolen- und wpf-Anwendungen bereitgestellt.]
Sie müssen nur den Wert von überprüfen
createdNew
Variablen (Beispiel unten!), Nachdem Sie die benannte Mutex-Instanz erstellt haben.Der Boolesche Wert
createdNew
gibt false zurück:Der Boolesche Wert
createdNew
gibt true zurück:Konsolenanwendung - Beispiel:
WPF-Beispiel:
quelle
Eine zeitsparende Lösung für C # Winforms ...
Program.cs:
quelle
Bitte überprüfen Sie die vorgeschlagene Lösung von hier aus , dass Anwendungen einer Semaphore , um zu bestimmen , ob eine vorhandene Instanz bereits ausgeführt wird , arbeitet für eine Anwendung WPF und Argumente aus zweiter Instanz zur ersten bereits laufenden Instanz durch einen TcpListener verwenden und einen TcpClient passieren kann:
Es funktioniert auch für .NET Core, nicht nur für .NET Framework.
quelle
Ich kann hier keine kurze Lösung finden, also hoffe ich, dass dies jemandem gefällt:
AKTUALISIERT am 20.09.2018
Fügen Sie diesen Code in Ihr
Program.cs
:quelle