Hauptseite >Tips zu VB5/6 > Mehrfachstart einer Anwendung verhindern | |
Manchmal ist es wünschenwert, dass von der eigenen Anwendung nur eine Instanz gestartet werden kann.
Beispielsweise, wenn diese eine Access-Datenbank exklusiv öffnet; eine zweite Instanz würde dann am
Öffnen dieser Datenbank scheitern.
VB bietet mit der PrevInstance-Eigenschaft des App-Objekt eine komfortable Möglichkeit, um festzustellen, ob bereits eine Instanz läuft. Um die folgenden Beispiele auszuprobieren, erzeugen Sie ein neues Projekt mit einer Form und einem Standardmodul; legen Sie in letzterem eine Sub Main() an und legen Sie diese als Startobjekt fest.
Wenn Sie mit diesem Code nun eine ausführbare Datei erzeugen und versuchen, diese mehrmals hintereinander zu
starten, werden Sie sehen, dass keine weitere Instanz erzeugt wird, solange die erste noch existiert.
So weit, so gut. Die vorgestellte Lösung hat jedoch eine Reihe von Nachteilen. Der wohl gravierendste besteht darin, dass der Benutzer die ausführbare Datei nur in ein anderes Verzeichnis zu kopieren braucht, um die Sperre auszuhebeln. VB erkennt eine vorherige Instanz nicht mehr, wenn diese aus einem anderen Verzeichnis gestartet wurde. Es gibt eine Reihe von Möglichkeiten, dieses Manko zu umgehen. Meine bevorzugte Variante besteht darin, mittels FindWindowEx() nach Vorgänger-Instanzen zu suchen:
Im dritten Parameter des Aufrufs von FindWindowEx() übergeben Sie den Klassennamen aller von VB6
erzeugten Forms: "ThunderRT6FormDC". Wenn Sie mit VB5 arbeiten, ersetzen Sie diesen Wert durch "ThunderRT5Form".
Nebenbei: läuft das Programm in der IDE, lauten die Klassennamen anders ("ThunderForm" in VB5, "ThunderFormDC" in VB6).
In vierten Parameter des Aufrufs von FindWindowEx() übergeben Sie die Titelzeile Ihres Hauptformulars, in unserem Testbeispiel "Form1". Wenn Sie nun wieder das Programm kompilieren und die ausführbare Datei in zwei verschiedenen Verzeichnissen speichern, werden Sie sehen, dass sich das Programm jetzt nicht mehr doppelt starten lässt. Der Nachteil an dieser Variante ist, dass Sie die Titelzeile Ihres Hauptformulars im Programmablauf nicht änderen dürfen. Damit funktioniert diese Lösung z.B. nicht mehr für MDI-Forms, die in der Titelleiste auch den Titel eines maximierten, aktiven MDI-Childs anzeigt. Zudem könnte ein anderes, in der gleichen VB-Version geschriebenes Programm zufällig den gleichen Text in der Titelleiste stehen haben und damit fälschlich als Vorgänger-Instanz des eigenen Programms identifiziert werden. Es empfiehlt sich also, ein anderes Erkennungskriterium als den Titelleisten-Text zu verwenden. Auch hier gibt es wieder mehrere denkbare Varianten; so könnte man z.B. das Hauptformular subclassen und eine eigene Fensternachricht definieren, auf die hin sich das Programm mit einem festgelegten Rückgabewert ausweist - oder auch nicht (Rückgabewert 0), wenn es sich um ein "fremdes" Fenster handelt. Eine deutlich einfachere und vor allem IDE-stabile Möglichkeit bieten die API-Funktionen SetProp() und GetProp() an; mit SetProp() verpassen Sie Ihrem Formular eine ganzzahlige Eigenschaft (Long-Wert) mit einem bestimmten Namen; mit GetProp() können Sie ein beliebiges Fenster abfragen, ob es diese Eigenschaft besitzt; wenn nicht, liefert die Funktion 0& zurück:
Wählen Sie für MY_IDENTIFIER_NAME eine möglichst eindeutige Bezeichnung und für
MY_IDENTIFIER_VALUE einen beliebigen ganzzahligen Wert; damit wird es äusserst unwahrscheinlich,
dass eine andere Applikation die gleiche Kombination zur Selbst-Identifikation verwendet.
Bevor das Formular entladen wird, sollte man die Fenstereigenschaft zurücksetzen:
Es ist natürlich nicht damit getan, die zweite Instanz einfach nicht starten zu lassen; es sollte schon irgendetwas passieren, wenn der Benutzer eine solche zweite Instanz starten will. Naheliegend wäre, dass die zweite Instanz die erste noch sichtbar macht und aktiviert, bevor sie sich verabschiedet:
Bleibt noch ein Problem: Wenn die zweite Instanz mit einem Parameter, beispielsweise mit einem
Dateinamen, aufgerufen wird, sollte diese Information an die erste Instanz weitergegeben werden,
damit diese entsprechend reagieren kann. Auch hier gibt es wieder verschiedene Möglichkeiten wie
z.B. DDE. Für eine schlanke, einfache Möglichkeit
können wir ebenfalls das Gespann SetProp() und GetProp() einsetzen: Verpassen Sie Ihrem
Formular eine versteckte Textbox (Visible = False), in die die zweite Instanz ihren
Parameter-Wert schreiben kann; die erste Instanz hat nun die Aufgabe, im Change-Event die
Information zu verarbeiten. Damit die zweite Instanz erfahren kann, welches Window-Handle diese
Textbox hat, machen Sie es einfach über eine WindowProperty öffentlich.
Ein vollständiges Beispielprojekt können Sie hier herunterladen. Bitte passen Sie die globale Konstante VB_FORM_CLASS$ in Module1 entsprechend der verwendeten VB-Version an. In der IDE ist ein Test naturgemäss wenig anschaulich, schliesslich können Sie das gleiche Projekt nicht mehrmals in der IDE öffnen und starten. Kompilieren Sie das Programm und starten Sie es mehrfach hintereinander mit unterschiedlichen Aufrufparametern: Projekt1.exe AAA Projekt1.exe BBB Projekt1.exe CCC ... Minimieren Sie ruhig zwischendurch das Programmfenster; es wird bei erneutem Programmaufruf wiederhergestellt. Sollte sich das Programm wider Erwarten mehrfach starten lassen, überprüfen Sie bitte die globale Konstante VB_FORM_CLASS$ in Module1. |
|
Hauptseite > Tips zu VB5/6 > diese Seite | |
© 2001-2021 Wolfgang Enzinger |