Autor Beitrag
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Fr 05.12.03 20:52 
Hallo,

villeicht habt ihr euch schon gefragt, wie Programme wie z.B. Winamp das schaffen, dass sie sich nur EINMAL starten lassen. Wenn man die Anwendung ein 2. mal starten will (wenn sie also schon läuft), verweigert sie den Start.

Das lässt sich auf verschiedene Weisen implementieren, aber wir werden dafür eine Semaphore verwenden. Eine Semaphore ist ein von Windows verwaltetes Objekt. Jede Semaphore wird über einen String identifiziert. Wenn man eine Semaphore erzeugen will, muss man einen String angeben, der dann der Semaphore zugeordnet ist. Versucht man, noch eine Semaphore mit dem gleichen String zu erzeugen, gibt es einen Fehler (OHNE Dialogbox, keine Angst).

Also erzeugt ihr einfach beim Programmstart eine Semaphore, mit einem möglichst einzigartigen String, also nicht so was wie "Mein Mutex", sondern lasst euch was einfallen (am besten eignet sich ein GUID), die Länge ist auf 260 Zeichen begrenzt. Existiert die Semaphore schon, wird die Instanz sofort beendet.

So, dann zum eingemachten. Da die Semaphore gleich zum Programstart aufgerufen werden soll schreiben wir ihn gleich in die DPR. Hier die modifizierte DPR:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
{ ... }

var
  Semaphore: THandle;

begin
  // Message registrieren bzw. ID holen
  ActivationMessage := RegisterWindowMessage(PChar(MyUnit.MyGUID));

  // Semaphore erzeugen
  Semaphore := CreateSemaphore(nil11, PChar(MyUnit.MyGUID));

  // Prüfen ob die Semaphore bereits existierte
  if (GetLastError = ERROR_ALREADY_EXISTS) then
    PostMessage(HWND_BROADCAST, MyUnit.ActivationMessage, 00)
  else
  begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end;

  CloseHandle(Semaphore);
end;

Jetzt im Hauptformular eine TApplicationEvents einfügen (Register "System"). Davon das Ereignis "OnMessage" implementieren. Dazu diesen Code verwenden:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
interface

{ ... }

const
  // Ein eigener GUID, dazu im Quelltexteditor [STRG+SHIFT+G] drücken
  MyGUID = '{C09CD12A-F97B-450F-A493-7DC11DC32FD6}';

var
  ActivationMessage: Cardinal;

implementation

{ ... }

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  if (Msg.message = ActivationMessage) then
  begin
    Application.Restore;
    SetForegroundWindow(Handle);
    SetActiveWindow(Handle);
    Handled := True;
  end;
end;

Wie ihr seht: die Semaphore wird noch VOR Apllication.Create aufgerufen - wenn bereits eine Instanz des Programms läuft, wird die neue Instanz beendet, noch bevor ein Fenster oder ein Taskbar-Icon zu sehen war. Wir beenden dann ganz einfahc mit "Halt";

Dann habe ich noch was in das Hauptformular eingetragen, damit die erste Instanz angezeigt wird, wenn das ÜProgramm ein 2. mal gestartet werden soll. Dazu habe ich eine Nachricht verschickt, die ich mir von RegisterWindowMessage() geholt habe - der Zurückgegebene Wert ist von Windows erzeugt und systemweit einzigartig.

"Form1" ist das Hauptformular, "MyUnit" die Unit in der es enthalten ist.

Das war's auch schon wieder - ein ganz einfacher Code, ist in einer Minute eingebaut.

Für Newbies: eine Instanz ist sozusagen der Prozess einer Anwendung - wenn man eine Anwendung (nehmen wir doch mal Delphi) zweimal startet, hat man 2 mal die selbe Anwendung (also Delphi), aber zwei verschiedene (unabhängige) Instanzen.

_________________
Life is a bad adventure, but the graphic is really good!


Zuletzt bearbeitet von Andreas Pfau am Fr 09.01.04 16:59, insgesamt 1-mal bearbeitet