Autor |
Beitrag |
Terra23
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: 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:
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:
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
      
Beiträge: 322
|
Verfasst: So 20.04.03 15:17
OK,
so geht das in den Vordergrund Holen:
Quelltext 1: 2:
| Windows.ShowWindow(h, SW_ShowNormal); windows.SetForegroundWindow(h); |
Und hier mal das ganze Unit(muss nur eingebunden werden):
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
|
Verfasst: 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'"..
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:
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 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: So 20.04.03 17:19
Direkt in den Quelltext heißt, nicht als Unit, oder?
Ich bekomme jetzt folgende Meldung:
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
|
Verfasst: So 20.04.03 17:36
Nee, du hast meine Konstanze ... äh, Konstante übersehen:
Quelltext 1:
| szClassname = 'TUninstallMainForm'; |
Schreib stattdessen einfach den Namen deiner Form rein, also "TForm1" oder wie dein Hauptformular heißt ...
|
|
Terra23 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: 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
|
Verfasst: 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:
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 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: 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:
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:
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
|
Verfasst: 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:
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)
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 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: 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:
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ä?
Wäre aber nie ohne deine Hilfe zustande gekommen..
CU
_________________ Hasta La Victoria Siempre
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 21.04.03 04:06
Windows XP? 
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: 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: | 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
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
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
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  ), 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 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: 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 
      
Beiträge: 872
Win 8
Delphi 7
|
Verfasst: 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

_________________ Hasta La Victoria Siempre
|
|
|