|
|
|
|
Programmieren mit C++Borland C++32-Bit-ProgrammierungNur eine Instanz starten
|
Wie wird unter WIN32 mittels C++Builder erreicht, daß nur eine Instanz gestartet werden kann?
| Frage | |
Der C++Builder erzeugt automatisch eine formularlose Hauptdatei, deren Dateiname dem Projektnamen entspricht. In dieser Datei ist die Funktion WinMain() implementiert, die alle Formulare erzeugt und die Anwendung startet. Eine einfache Variante dieser Datei mit Defaultbezeichner wäre:
#include
#pragma hdrstop
USEFORM("Unit1.cpp", Form1);
USERES("Project1.res");
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
Hier wird zunächst die Anwendung initialisiert und das Formular erzeugt. Kommt es zu einem Fehler, wird automatisch in die Fehlerbehandlung gesprungen, die eine einfache Fehlermeldung ausgibt.
Soll eine Anwendung nur einmal gestartet werden, muß die entsprechende Abfrage in die Funktion WinMain() integriert werden. Dazu implementiert die Funktion GetPrevInstName zunächst eine komfortable Möglichkeit, den Fenstertitel der Anwendung zu ermitteln, wobei der String „PREVINST:“ vorangestellt wird.
| Lösung |
char* GetPrevInstName()
{
char *Buf, *temp;
Buf = (char *) malloc(MAX_PATH);
temp = (char *) malloc(MAX_PATH);
GetWindowText(Application->Handle,
Buf, MAX_PATH);
strcpy(temp, "PREVINST:");
strcat(temp, Buf);
free(Buf);
return temp;
}
Die Haupt-Programmschleife verwendet zur Feststellung, ob bereits eine Instanz der Anwendung installiert ist, ein Mutex-Objekt. Dazu wird zunächst der Anwendungstitel mit dem Default-Titel vorbelegt.
| Funktion GetPrevInstName |
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
THandle Mutex;
Application->Title = "Single_App";
Anschließend wird das Mutex-Objekt erzeugt.
| Funktion WinMain() |
Mutex = (int)CreateMutex(
NULL, true,
GetPrevInstName() );
Die Funktion CreateMutex returniert dann, wenn bereits eine Instanz gleichen Namens existiert, den Wert 0, also ein NULL-Handle, zurück. Zusätzlich ist auch noch der allgemeine Fehlerstatus des Aufrufs über GetLastError() zu prüfen. Liefern beide Tests Negativresultate, kann die Anwendung wie gewohnt gestartet werden.
if ((Mutex != NULL) && (GetLastError() == 0))
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
try
{
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
Abschließend ist der ggfs. erzeugte Mutex zu zerstören.
if (Mutex != 0)
CloseHandle(&Mutex);
}
War das Programm bereits gestartet, kann die vorhergehende Instanz ermittelt und aktiviert werden. Dazu wird ein Fenster mit dem entsprechenden Titel via FindWindow() gesucht. Da die Mutex-Abfrage zuvor eine Instanz gefunden hat, sollte dieser Aufruf nicht fehlschlagen.
| Mutex-Objekt erzeugen |
else
{
HWND PrevInst;
char s[30];
strcpy(s, (Application->Title).c_str());
Application->Title = "$%$%$";
PrevInst = FindWindow(NULL, s);
Wird das Fenster gefunden, kann die vorhergehende Instanz angezeigt werden. Dazu wird diese entweder restauriert, wenn sie als Symbol vorliegt, oder einfach nach vorn gebracht und aktiviert.
| Fenster ermitteln |
if (PrevInst != 0)
{
if (IsIconic(PrevInst))
ShowWindow(PrevInst, SW_RESTORE);
else
BringWindowToTop(PrevInst);
Die aktuelle Instanz der Anwendung wird nicht mehr benötigt und muß beendet werden.
| Fenster der vorherigen Instanz anzeigen |
Application->Terminate();
}
}
return 0;
}
| Anwendungsin-stanz terminieren
|
|
|