Autor Beitrag
Terra23
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: So 20.04.03 13:35 
Hallo ihr.

Ich habe nun mit MathiasSimmack schon Kontakt aufgenommen und zwar geht es um folgendes:

Mein Programm darf nur einmal gestartet werden. Das klappt auch soweit, nur soll es dann in den Vordergrund geholt werden und da tauchen Schwierigkeiten auf.

Ich poste euch mal hier meine Unit, ich habe sie wie im Beispiel auch "Single" genannt und sie in mein Projekt eingebunden:

ausblenden 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:
unit Single;

interface

implementation

uses Windows, SysUtils;
var
    Aufruf: THandle;
    aWnd: HWND;
initialization
Aufruf:=CreateMutex(nil, True, 'MaskWallpaper - 504D4DE0-7207-11D7-BC27-000777640932');
If GetLastError=ERROR_ALREADY_EXISTS
Then Begin
     aWnd:=FindWindow('TForm1', 'MaskWallpaper - 504D4DE0-7207-11D7-DC27-000777640932');
     If (Not IsWindowVisible(aWnd)) Then SendMessage(aWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
     SetForegroundWindow(aWnd);
     Halt;
     End;
     
finalization
If Aufruf<>0 Then CloseHandle(Aufruf);

end.


Zunächst bekam ich die Meldung, daß das Programm nicht weiß, was aWnd ist. Das habe ich dann definiert und bekomme nun die Meldung "[Error] Single.pas(15): Undeclared identifier: 'WM_SYSCOMMAND'"..

In meiner Form-Unit steht folgendes:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
  private
    { Private declarations }

    procedure WMSysCommand(Var Message: TMessage); message WM_SYSCOMMAND;

  public
    { Public declarations }
  end;

...


procedure TForm1.WMSysCommand(Var Message: TMessage);
begin
If (Message.Msg=WM_SYSCOMMAND) And (Message.WParam=SC_RESTORE)
Then Application.Restore;
Inherited;
end


Kann mir vielleicht jemand sagen, was daran verkehrt ist? Was solche Art Programmierung angeht, bin ich echt nicht sonderlich bewandert. Ich muß mir alles selbst irgendwie beibringen.

Grüße, Alex..

_________________
Hasta La Victoria Siempre
GruppeCN
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 322



BeitragVerfasst: So 20.04.03 15:17 
OK,
so geht das in den Vordergrund Holen:
ausblenden Quelltext
1:
2:
Windows.ShowWindow(h, SW_ShowNormal);
        windows.SetForegroundWindow(h);


Und hier mal das ganze Unit(muss nur eingebunden werden):
ausblenden 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:
unit only_one;

interface

implementation
uses forms, windows;
var mutex : THandle;
    h     : HWnd;


initialization
  mutex := CreateMutex(nil,true,'Anwendungs Name');
  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;
  end;
finalization
  ReleaseMutex(mutex);
end.

_________________
Warum sind die Sachen, die du suchst, immer da, wo du zuletzt nachsiehst?
Weil du aufhörst zu suchen, wenn du sie gefunden hast.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 20.04.03 16:54 
Terra23 hat folgendes geschrieben:
Zunächst bekam ich die Meldung, daß das Programm nicht weiß, was aWnd ist. Das habe ich dann definiert und bekomme nun die Meldung "[Error] Single.pas(15): Undeclared identifier: 'WM_SYSCOMMAND'"..
ausblenden Quelltext
1:
uses Windows, SysUtils;					

Ach so, ja. Da fehlt dann noch die Unit Messages. Aber, wie gesagt, ich schreibe die paar Zeilen direkt in meinen DPR-Quelltext. das sieht dann bspw. so aus:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
const
  szClassname = 'TUninstallMainForm';
  szMutexname = 'Uninstaller10';
var
  { ... }
  HMHandle : THandle;
begin
  HMHandle := CreateMutex(nil,false,szMutexname);
  if(GetLastError = ERROR_ALREADY_EXISTS) then begin
    SendMessage(findwindow(szClassname,nil),WM_SYSCOMMAND,SC_RESTORE,0);
    SetForegroundWindow(findwindow(szClassname,nil));
    exit;
  end;

  { ... }

  // release mutex
  CloseHandle(HMHandle);
end.

In dem Fall habe ich keine HWND-Variable benutzt sondern direkt mit findwindow gearbeitet.

So, und dann käme (aber nur bei einem VCL-Programm!) der Form-Teil mit WM_SYSCOMMAND, um Probleme beim Minimieren abzufangen. Aber das hast du ja offensichtlich, und da gibt´s wohl keine Fehler?

Gruß.
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: So 20.04.03 17:19 
Direkt in den Quelltext heißt, nicht als Unit, oder?

Ich bekomme jetzt folgende Meldung:

ausblenden Quelltext
1:
[Error] Single.pas(13): Undeclared identifier: 'szClassname'					


Liegt das daran, daß ich das nun als Unit habe?

_________________
Hasta La Victoria Siempre
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 20.04.03 17:36 
Nee, du hast meine Konstanze ... äh, Konstante übersehen:
ausblenden Quelltext
1:
szClassname = 'TUninstallMainForm';					

:wink:

Schreib stattdessen einfach den Namen deiner Form rein, also "TForm1" oder wie dein Hauptformular heißt ...
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: So 20.04.03 18:00 
Ja, danke. Das funktioniert bisher soweit, nur wird jetzt ein Fehler erzeugt, der glaube ich, nicht Sinn ist:

Wenn ich versuche, mein Tool ein zweites Mal zu öffnen, wird in der Tray für jeden Programmstart ein weiteres TTrayIcon aufgerufen..

_________________
Hasta La Victoria Siempre
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 20.04.03 18:04 
Wie hast du den o.g. Code nun eingesetzt? Mit einer extra Unit oder direkt im DPR-Quelltext? Falls Unit, dann setze die mal an die erste Stelle im Projekt:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
program Project1;

uses
  Single, // <---
  Forms,
  Form1 in 'Unit1.pas', {Form1}
  { ... }

Es kann sein, dass tatsächlich erst noch das TNA-Icon erzeugt wird, bevor die Unit wirksam wird und das Programm beendet. Wenn du die Single-Unit an die erste Stelle setzt, dürfte das nicht mehr passieren.

Einer der Gründe, warum ich den Code direkt in den DPR-Text schreibe. :)
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: So 20.04.03 18:11 
Wenn ich das in die DPR schreibe, dann sagt er mir, er kennt Single nicht. So sieht meine DPR im Moment aus:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
program MaskWallpaper;

uses
  Single,
  Forms,
  MaskWallpaper_Unit in 'MaskWallpaper_Unit.pas' {Form1},
  MaskWallpaper_Unit2 in 'MaskWallpaper_Unit2.pas' {Form2},
  Single in 'Single.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.Title := 'MaskWallpaper';
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.


Was mache ich falsch bzw. wenn ich mich jetzt entschließe, deinen Code direkt in die DPR zu schreiben, was muß ich löschen und an welche Stelle in der DPR muß der Code stehen? Ich weiß, sind viele Fragen, aber vielleicht hilfst du mir ja dabei.

Meldung:

ausblenden Quelltext
1:
[Error] MaskWallpaper.dpr(8): string constant expected but identifier 'Single' found					

Grüße, Alex..[/code]

_________________
Hasta La Victoria Siempre
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 20.04.03 19:44 
Warum er sich an dem Begriff stört, weiß ich im Augenblick nicht. Am besten, du nimmst die erste Zeile raus und setzt stattdessen die letzte an den Anfang:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
uses
  Single, // <-- weg damit!

  Forms,
  MaskWallpaper_Unit in 'MaskWallpaper_Unit.pas' {Form1},
  MaskWallpaper_Unit2 in 'MaskWallpaper_Unit2.pas' {Form2},

  Single in 'Single.pas'; // <-- an den Anfang

Wenn du den Code direkt ohne extra Unit einbinden willst, dann geht das so: (Ich nehme mal meinen zuvor geposteten Code als Beispiel)
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
begin
  HMHandle := CreateMutex(nil,false,szMutexname);
  if(GetLastError = ERROR_ALREADY_EXISTS) then begin
    SendMessage(findwindow(szClassname,nil),WM_SYSCOMMAND,SC_RESTORE,0);
    SetForegroundWindow(findwindow(szClassname,nil));
    exit;
  end;

  Application.Initialize;
  Application.Title := 'MaskWallpaper';
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;

  // release mutex
  CloseHandle(HMHandle);
end.

In dem Fall nimmst du natürlich oben die Unit "Single" aus der Uses-Anweisung komplett raus.
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: So 20.04.03 23:50 
Hi Mathias.

Ich habe nun folgendes gemacht:

1) Die Unit Single komplett entfernt.
2) Den Kram aus der Form1-Unit (den, von dem du geschrieben hast, er würde Probleme beim minimieren etc. vermeiden) geschmissen.
3) Deinen Code in angepasster Form in meine DPR geschrieben.

Hier meine DPR:

ausblenden volle Höhe 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:
program MaskWallpaper;

uses
  Windows, SysUtils, Messages,
  Forms,
  MaskWallpaper_Unit in 'MaskWallpaper_Unit.pas' {Form1},
  MaskWallpaper_Unit2 in 'MaskWallpaper_Unit2.pas' {Form2};

{$R *.res}
var
  HMHandle: THandle;


begin

  HMHandle:=CreateMutex(Nil, False, 'MaskWallpaper');
  If (GetLastError=ERROR_ALREADY_EXISTS)
  Then Begin
       SendMessage(FindWindow('MaskWallpaper', nil), WM_SYSCOMMAND, SC_RESTORE, 0);
       SetForegroundWindow(FindWindow('MaskWallpaper', nil));
       Exit;
       End;

  Application.Initialize;
  Application.Title := 'MaskWallpaper';
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;

  CloseHandle(HMHandle);
end.


Es funktioniert auch alles soweit, d.h. mein Programm startet ohne Fehlermeldung. Es gibt jetzt nur noch ein Problem:

Es kommt nicht in den Vordergrund. Liegt das vielleicht an der TTrayIcon Komponente oder habe ich wieder einen Fehler reingehauen?

Grüße, Alex..

PS: Je öfter ich diese Sachen schreibe, lösche und ändere, desto besser verstehe ich einzelne Befehle und Aktionen. Cool, hä? 8)

Wäre aber nie ohne deine Hilfe zustande gekommen.. :oops:

CU

_________________
Hasta La Victoria Siempre
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 21.04.03 04:06 
Windows XP? :wink:
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 21.04.03 09:06 
Der Punkt 2
Terra23 hat folgendes geschrieben:
Den Kram aus der Form1-Unit (den, von dem du geschrieben hast, er würde Probleme beim minimieren etc. vermeiden) geschmissen.

war ein Fehler. Ich schrieb, der Code vermeidet Probleme! Er verursacht sie nicht. Du solltest das also wieder ergänzen.

Zitat:
... oder habe ich wieder einen Fehler reingehauen?

Ja.

Zitat:
ausblenden Quelltext
1:
2:
SendMessage(FindWindow('MaskWallpaper', nil), WM_SYSCOMMAND, SC_RESTORE, 0);
SetForegroundWindow(FindWindow('MaskWallpaper', nil));

Das Problem ist folgendes: findwindow erwartet als erste Angabe den Klassennamen eines Fensters. Dies kann bei einem NonVCL-Programm ein beliebiger Name sein. Bei einem VCL-Programm mit Forms entspricht der Klassenname allerdings dem Formnamen.

In deinem Fall wäre also
ausblenden Quelltext
1:
2:
SendMessage(FindWindow('TForm1', nil), WM_SYSCOMMAND, SC_RESTORE, 0);
SetForegroundWindow(FindWindow('TForm1', nil));

richtig. Wenn du dir mal anschaust, was passiert:

1. Für den Fall, dass das Fenster nicht sichtbar oder minimiert ist, wird mit
ausblenden Quelltext
1:
SendMessage(findwindow('TForm1',nil),WM_SYSCOMMAND,SC_RESTORE,0);					

angewiesen, es wieder (salopp gesagt) sichtbar zu machen. Das stimmt natürlich nicht ganz, denn SC_RESTORE bedeutet eigentlich
PSDK hat folgendes geschrieben:
Restores the window to its normal position and size.


2. Dann wird es mit
ausblenden Quelltext
1:
SetForegroundWindow(findwindow('TForm1',nil));					

zum aktiven Vordergrundfenster gemacht.

Aber dazu muss natürlich der Klassenname stimmen.
Du kannst und solltest vielleicht deinem Programm einen anderen Namen als TForm1 für dein Formular geben. Klick einfach im Objektinspektor auf Name und gib dort z.B. den von dir schon vorher benutzten Begriff "MaskWallpaper" ein.
In dem Fall wäre der Klassenname dann "TMaskWallpaper" (mit dem T am Anfang wirst du leben müssen :wink:), und du müsstest den bei den beiden o.g. Anweisungen angeben.

Aber der Vorteil wäre, dass du Probleme mit anderen Programmen vermeidest, bei denen die Form auch vielleicht TForm1 heißt. Stell es dir mal vor: du hast zwei verschiedene Programme geschrieben, die auch beide gerade (zufälligerweise) laufen.
Jetzt möchtest du Programm A mit o.g. Methode in den Vordergrund holen. Allerdings wäre es möglich, dass findwindow zuerst Programm B findet, das ja den selben Klassennamen (TForm1, eben) hat. Dann würde also das falsche Programm erscheinen. :(


Und zu guter Letzt -
Ich kenne diese TTrayIcon-Komponente nicht. Ich schreibe die paar Zeilen immer selbst in den Code. Es gab aber mal ein ähnliches Problem bei einem Programm von stefanstp.

Du musst ja folgendes bedenken: dein Programm kann also offensichtlich so minimiert werden, dass es nur noch als Icon in der TNA erscheint. In dem Fall solltest du beim Wiederherstellen des Programms (mit obiger Methode) die Möglichkeiten der Komponente nutzen.

Nehmen wir an, ein Doppelklick auf das TNA-Symbol bringt das Programm wieder zum Vorschein. Dann würde ich in dem Fall die Nachricht an mein Programm senden, die mit diesem Doppelklick identisch ist. Aber, wie gesagt!, das funktioniert nur in meinem Fall, weil ich den notwendigen TNA-Code ohne Komponente schreibe.
Bei dir (bei der TTrayIcon-Komponente) müsste es meiner Ansicht nach eine Funktion o.ä. geben, mit der du solche Aktionen auch manuell auslösen kannst.

Im Zweifelsfall schau mal hier www.delphi-forum.de/...der=asc&start=20 nach (Beiträge ab dem 26.09.2002), oder wende dich einfach mal an stefanstp mit der Frage, wie er das Problem letztlich gelöst hat.

Gruß.
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: Mo 21.04.03 13:42 
@Luckie: Nein, kein XP. -> Win98 SE :-)

@Mathias: Ich werd's mal probieren. Danke. Falls es (nicht) klappt, melde ich mich wieder. *g*

Grüße.

PS: Bin nicht so oft hier, meine Freundin hat nur 90 Stunden im Monat bei Telekom. Hier in diesem Kaff gibts kein DSL.. :-)

CU

_________________
Hasta La Victoria Siempre
Terra23 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 872

Win 8
Delphi 7
BeitragVerfasst: Mo 21.04.03 15:06 
Yo Mathias.

Es funktioniert. Vielen, vielen Dank für die Hilfe. Magst du's testen?

Grüße, Alex..

PS: Ich werd's mal im Forum freigeben, denke ich; nur so zu Testzwecken.

CU

:beer:

_________________
Hasta La Victoria Siempre