Gleichzeitig laufende XNA-Spiele verhindern
Autor: Astror Enales
Inhaltsverzeichnis
^ Einleitung
Spiele werden meistens einmal gestartet, gespielt und wieder geschlossen. Doch man hat so gut wie nie zwei oder mehr Instanzen des gleichen Spiels offen. Doch passiert es ab und zu, sei es durch Unachtsamkeit oder einen anderen Fehler, dass plötzlich das Spiel zweimal gestartet wurde. Das verlangsamt den Rechner meist enorm, oder es gibt Probleme weil das Spiel die Maus abfängt. Natürlich kann es auch anderweitig vom Entwickler gewollt sein, dass immer nur eine Instanz gleichzeitig offen sein kann.
Das klingt zuerst schwer, ist es aber ganz und gar nicht, denn C# liefert schon alles mit was wir benötigen. Mutex heißt das Zauberwort zu diesem Thema.
Nun aber ran an die Praxis
^ Implementierung
C# bietet im Namespace System.Threading die Klasse Mutex an. Diese beinhaltet alles was wir benötigen. Also rasch den Namespace in die Usings eingefügt und wir können loslegen. Halt, wohin damit? Am Besten implementiert man den Mutex dort, wo das Spiel startet. Also in der Main-Methode. Jedoch steht es einem komplett frei, an welcher Stelle man ihn implementiert.
In unserem Beispiel nutzen wir die Main-Methode.
Damit der Mutex weiß wie unser Spiel heißt und wonach er ausschau halten muss, definieren wir zuallererst einen String welcher unser Spiel identifizieren wird.
const string MutexId = "Spielname";
static void Main(string[] args)
{ ... }
static void Main(string[] args)
{ ... }
Als nächstes testen wir nun ob bereits eine Instanz läuft.
Dafür deklarieren wir in der Main-Methode eine Variable des Typs Mutex und füllen sie mit der statischen Mutex-Methode Mutex.OpenExisting(MutexId).
Das sieht dann folgendermaßen aus:
const string MutexId = "Spielname";
static void Main(string[] args)
{
Mutex mutexInstance = Mutex.OpenExisting(MutexId);
Game1 game = new Game1();
game.Run();
}
static void Main(string[] args)
{
Mutex mutexInstance = Mutex.OpenExisting(MutexId);
Game1 game = new Game1();
game.Run();
}
Um nun zu testen ob die Instanz läuft hat C# ein recht eigenartiges System hinter dieser Methode.
Wenn bereits eine Instanz läuft wird die Variable mutexInstance gefüllt. Wenn aber noch keine Instanz vorhanden ist, wird eine Exception geworfen. Damit unser Spiel nicht deswegen crasht bedienen wir uns eines try-catch-Blocks.
Wenn also eine Instanz vorhanden ist beenden wir das Spiel mit "Environment.Exit(0);".
Wenn keine Instanz läuft und wir die Exception abfangen, starten wir mit dem Konstruktor new Mutex(true, MutexId) die Blockierung für jede weitere Instanz.
const string MutexId = "Spielname";
static void Main(string[] args)
{
Mutex mutexInstance;
try
{
// Versuchen eine vorhandene Instanz zu finden
mutexInstance = Mutex.OpenExisting(MutexId);
// Wenn eine Instanz existiert dann beenden wir das Programm
Environment.Exit(0);
}
catch (Exception ex)
{
// Wir haben keine laufende Instanz gefunden
// Also blockieren wir jede weitere Instanz die gestartet wird.
mutexInstance = new Mutex(true, MutexId);
}
Game1 game = new Game1();
game.Run();
}
static void Main(string[] args)
{
Mutex mutexInstance;
try
{
// Versuchen eine vorhandene Instanz zu finden
mutexInstance = Mutex.OpenExisting(MutexId);
// Wenn eine Instanz existiert dann beenden wir das Programm
Environment.Exit(0);
}
catch (Exception ex)
{
// Wir haben keine laufende Instanz gefunden
// Also blockieren wir jede weitere Instanz die gestartet wird.
mutexInstance = new Mutex(true, MutexId);
}
Game1 game = new Game1();
game.Run();
}
Scheint fertig zu sein, doch ein wichtiger Teil fehlt noch! Schließlich muss der Mutex auch wissen wann er wieder erlauben soll, Instanzen zu starten
Wenn das Spiel geschlossen wird, wird jeglicher Code ausgeführt der nach dem game.Run() in der Main-Methode kommt. Deshalb müssen wir dort noch die Blockierung aufheben. Dies geschieht mit der folgenden Code-Zeile:
mutexInstance.ReleaseMutex();
Fertig sind wir und können nun testen. Wenn keine weitere Instanz sich öffnet hat alles wunderbar funktioniert
Abschließen noch einmal der komplette Code:
const string MutexId = "Spielname";
static void Main(string[] args)
{
Mutex mutexInstance;
try
{
// Versuchen eine vorhandene Instanz zu finden
mutexInstance = Mutex.OpenExisting(MutexId);
// Wenn eine Instanz existiert dann beenden wir das Programm
Environment.Exit(0);
}
catch (Exception ex)
{
// Wir haben keine laufende Instanz gefunden
// Also blockieren wir jede weitere Instanz die gestartet wird.
mutexInstance = new Mutex(true, MutexId);
}
Game1 game = new Game1();
game.Run();
mutexInstance.ReleaseMutex();
}
static void Main(string[] args)
{
Mutex mutexInstance;
try
{
// Versuchen eine vorhandene Instanz zu finden
mutexInstance = Mutex.OpenExisting(MutexId);
// Wenn eine Instanz existiert dann beenden wir das Programm
Environment.Exit(0);
}
catch (Exception ex)
{
// Wir haben keine laufende Instanz gefunden
// Also blockieren wir jede weitere Instanz die gestartet wird.
mutexInstance = new Mutex(true, MutexId);
}
Game1 game = new Game1();
game.Run();
mutexInstance.ReleaseMutex();
}
^ Abschluss
Das ist auch schon das Ende dieses kleinen Artikels.
Natürlich gibt es noch viele andere Möglichkeiten das selbe Ziel zu erreichen, wie zum Beispiel einem Invoke auf Funktionen der user32.dll um die aktuelle Prozessliste zu checken. Doch ist die Mutex-Lösung meiner Meinung nach die Einfachste. Andere Lösungen, Lob oder Kritik können gerne im entsprechenden Thread gepostet werden.

