Entwickler-Ecke

Algorithmen, Optimierung und Assembler - only_one.pas - nur 1 Instanz, Fenster in den Vordergrund


galagher - Fr 16.06.06 13:01
Titel: only_one.pas - nur 1 Instanz, Fenster in den Vordergrund
Hallo zusammen!
only_one.pas verhindert, dass eine zweite Instanz eines Programms gestartet wird. Das funktioniert auch. Es soll aber das Fenster der laufenden Instanz in den Vordergrund bringen, und das funktioniert nicht. Kann das jemand zum Laufen bringen? Hier der Code:

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:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
{
 Diese Unit erlaubt es, ein Programm nur 1x zu starten.
 Wichtig: Application.Title muss ein String zugewiesen sein!
}



unit only_one;

interface

implementation

uses
  forms, windows;

var
  mutex : THandle;
  h     : HWnd;

initialization
  mutex := CreateMutex(nil,true,PChar(Application.Title));
  if getLastError = ERROR_ALREADY_EXISTS then begin
  h := 0;
  repeat
  h := FindWindowEx(0,h,'TApplication',PChar(Application.Title))
  until h <> application.handle;
  if h <> 0 then
  begin
    Windows.ShowWindow(h, SW_ShowNormal);
    windows.SetForegroundWindow(h);  //Klappt nicht - warum?
  end;
  halt;
end;

finalization
  ReleaseMutex(mutex);
end.


Narses - Fr 16.06.06 13:17

Moin!

Guckst du [http://www.delphi-forum.de/viewtopic.php?p=199576#199576]

cu
Narses


galagher - Fr 16.06.06 14:10

user profile iconNarses hat folgendes geschrieben:
Guckst du [http://www.delphi-forum.de/viewtopic.php?p=199576#199576]

Ja, das verhindert den Programmstart schon bei der 1. Instanz!


Narses - Fr 16.06.06 14:34

Moin!

Der Code funktioniert, ich verwende ihn genau so (natürlich mit angepasstem Formular-/Klassen-Namen).

cu
Narses


galagher - Fr 16.06.06 14:51

Vielleicht bin ich zu dämlich! Ich mache das so, und es ist wie vorher (der Sinn ist es ja, eine eigene Unit dafür zu haben, wie ich einen solchen Mutex in die *.dpr einbinde, weiss ich):

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:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
{
 Diese Unit erlaubt es, ein Programm nur 1x zu starten.
 Wichtig: Application.Title muss ein String zugewiesen sein!
}



unit only_one;

interface

implementation

uses
  forms, windows;

var
  mutex     : THandle;
  hWndFirst, hWndApp : HWnd;

initialization
(*  mutex := CreateMutex(nil,true,PChar(Application.Title));
  if getLastError = ERROR_ALREADY_EXISTS then begin
  h := 0;
  repeat
  h := FindWindowEx(0,h,'TApplication',PChar(Application.Title))
  until h <> application.handle;
  if h <> 0 then
  begin
    Windows.ShowWindow(h, SW_ShowNormal);
    windows.SetForegroundWindow(h);
  end;
  halt;
*)


Mutex := CreateMutex(NIL, TRUE, PChar(Application.Title));
if (GetLastError() = ERROR_ALREADY_EXISTS) then
begin
  hWndFirst := FindWindow(PChar(Application.Title), NIL);
  if (hWndFirst <> 0then
  begin
    hWndApp := GetWindow(hWndFirst, GW_OWNER); // Owner-Handle holen (Handle des TApplication-Fensters)
    if IsIconic(hWndApp) then
      ShowWindow(hWndApp, SW_RESTORE); // restoren wenn minimiert
    // Hauptfenster in den Vordergrund holen
    SetForegroundWindow(hWndFirst);
    BringWindowToTop(hWndFirst);
  end;
  CloseHandle(Mutex);
  Exit; // 2. Instanz kann gestartet werden
        //Halt oder Application.Terminate: 1. Instanz kommt nicht in den Vordergrund
end;

finalization
//  ReleaseMutex(mutex);
  CloseHandle(mutex);  //Ändert auch nichts
end.


Narses - Fr 16.06.06 18:21

Moin!

Da ist dein Problem:

Delphi-Quelltext
1:
2:
3:
4:
if (GetLastError() = ERROR_ALREADY_EXISTS) then
begin
  hWndFirst := FindWindow(PChar(Application.Title)NIL);
  if (hWndFirst <> 0then

Da muss der Klassenname deines Hauptformulars rein, also z.B. "TForm1". ;) Was für einen Titel deine Applikation hat, ist mal eher Wurst... :D

cu
Narses


galagher - Fr 16.06.06 20:43

Ok, so geht es:

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:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
{
 Diese Unit erlaubt es, ein Programm nur 1x zu starten.
 Wichtig: Application.Title muss ein String zugewiesen sein!
}



unit only_one;

interface

implementation

uses
  forms, windows;

var
  mutex: THandle;
  hWndFirst, hWndApp: HWnd;

initialization

Mutex := CreateMutex(NIL, TRUE, PChar(Application.Title));

if (GetLastError() = ERROR_ALREADY_EXISTS) then
begin
  hWndFirst := FindWindow('TForm1'NIL);
  if (hWndFirst <> 0then
  begin
    hWndApp := GetWindow(hWndFirst, GW_OWNER); // Owner-Handle holen (Handle des TApplication-Fensters)
    if IsIconic(hWndApp) then
      ShowWindow(hWndApp, SW_RESTORE); // restoren wenn minimiert
    // Hauptfenster in den Vordergrund holen
    SetForegroundWindow(hWndFirst);
    BringWindowToTop(hWndFirst);
  end;
  CloseHandle(Mutex);
  Halt;
end;

finalization
//  ReleaseMutex(mutex);
  CloseHandle(mutex);
end.


Danke! Bleibt aber die Frage: Was ist der Unterschied zwischen ReleaseMutex(mutex) und CloseHandle(mutex)? Oder ist das egal? Und gibt es etwas eleganteres als Halt oder Application.Terminate? Und wie ersetzt man 'Form1' durch den jeweiligen Klassennamen?