Schließen eines Fensters/Programmes verhindern

Rund um die LCL und andere Komponenten
Antworten
MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Schließen eines Fensters/Programmes verhindern

Beitrag von MitjaStachowiak »

Hallo,
ich habe zu diesem Thema schon viel im Internet gelesen, jedoch keine Lösung gefunden. Aber vielleicht hat ja hier noch jemand eine Idee:
Ich versuche zu verhindern, dass man ein Fenster über den X-Button von Windows schließen kann. Erstmal an einem selbst erstellen Programm, später soll dies für ein fremdes Fenster funktionieren. Ich habe definitiv schon Programme gesehen, bei denen dieser Button deaktiviert war, aber mit der BorderIcons-Eigenschaft von Lazarus bekomme ich es allenfalls hin, dass alle Buttons weg sind. :(

Dann habe ich es mit Hooks versucht (Weil viele hier das nicht leiden können, lasse ich mal den Quelltext weg): Ich setze zweimal einen Hook mit WH_CALLWNDPROC. Das Programm enthält einen Timer, der nach einer Sekunde eine Bool-Variable auf true setzt und dann per SendMessage(Handle,WM_CLOSE,0,0) das Fenster schließt. Sobald die Bool-Variable true ist, werden ALLE empfangenen Messages (lParam) in eine Datei geschrieben; in der OnClose-Eigenschaft der Form dann noch ein [recived]. In der Datei steht dann:

Code: Alles auswählen

[CallWndProc1: 33029148]  [CallWndProc2: 33028788]  [received]
Das Message 3302 kommt also (Mit unterschiedlichem Anhängsel) erst beim ersten Hook, dann beim zweiten Hook und dann bei der Form an. Wenn ich im ersten Hook auf dieses Message mit einem exit reagiere (Wodurch CallNextHookEx nicht mehr aufgerufen wird und das Message eigentlich geschluckt werden sollte), steht in der Datei folgendes:

Code: Alles auswählen

[received]
Das Message kommt also beim ersten Hook an, wird dann geschluckt (Landet folglich nicht mehr beim zweiten -) aber kommt am Ende trotzdem bei der Form an :shock:
Anscheinend hat Windows hier eine zusätzliche Sicherheit eingebaut...

Ich habe irgendwo gelesen, dass man eine Form so einstellen kann, dass sie nicht auch diesen Befehl reagiert - weiß dazu jemand Näheres?

Und davon abgesehen: Normaler Weise bekommen die Windows-Buttons (Minimieren, Maximieren/Normalisieren und Schließen) beim überfahren mit der Maus eine Aura (Win 7). Bei Opera und Lazarus und allen Programmen, die ich mit Lazarus erstellt habe, beobachte ich jedoch, dass diese Aura sofort wieder verschwindet. Bei Mausbewegungen auf diesen Buttons flackert es dann...
Hat von euch jemand dieses Phänomen schon beobachtet?

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: Schließen eines Fensters/Programmes verhindern

Beitrag von Scotty »

Werte das OnCanClose()-Ereignis aus und setzte den Rückgabewert einfach auf caNone, um ein Schließen zu verbieten. Abschießen per Taskmanager geht dann trotzdem noch. Allerdings würde ich ein Programm, das Standardereignisse verhindert, nur ungern benutzen. Zumindest ein MessageDlg() sollte also abgefragt und bestätigt werden können.

Bora4d
Beiträge: 290
Registriert: Mo 24. Dez 2007, 13:14
OS, Lazarus, FPC: WinXP-Pro-Sp3, Xubuntu 12.04, (Laz 1.1-SVN Mai2012, FPC 2.6.1 / 2.6.0-Linux)
CPU-Target: AMD64X2

Re: Schließen eines Fensters/Programmes verhindern

Beitrag von Bora4d »

Du mußt verhindern, dass wm_close weiter geleitet wird. Wenn du mittels Hook-Functionen in Nachrichtenschleife von Fremdprogramm eingeklick hast leitest du ja Nachrichten an das Programm weiter so etwa:

function DEIN_HOOK_WndProc(hWnd: HWND; uMsg: UINT; wParam: wParam; lParam: LParam):lresult; stdcall;
begin
//hier machst irgendwas

Leite_Msgs_An_Fremd_WndProc(hWnd, uMsg, wParam,lParam);
end;

Wenn du aber verhindern willst dass das Programm geschlossen wird dann mußt du etwa so machen:
if uMsg<>WM_CLOSE then Leite_Msgs_An_Fremd_WndProc(hWnd, uMsg, wParam,lParam);

Vielleicht mußt Handle überprüfen und nur wm_close-Nachricht des Hauptfensters verhindern, damit Unterfenster geschlossen werden kann. Ich würde erstmal alle wm_close unterbinden um zuprüfen ob es funktioniert.

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Schließen eines Fensters/Programmes verhindern

Beitrag von MitjaStachowiak »

So, ich hab' das ganze mal (mit Quellcode) hier hochgeladen:
http://www.mitjastachowiak.de/?File=pro ... raHide.zip" onclick="window.open(this.href);return false;
bzw.
http://www.mitjastachowiak.de/projects/OperaHide.zip" onclick="window.open(this.href);return false;
Da kann ich es dann für die Hook-Allergiker wieder herausnehmen :P

Jedenfalls setzt das Programm 4 Hooks, je 2 mit WH_CALLWNDPROC und 2 mit WH_GETMESSAGE. Jenachdem, ob man Send- oder PostMessage verwendet, kommt die Message bei dem einen oder anderen Hook an. Das ganze ist doppelt, damit man besser verfolgen kann, ob das Message weitergegeben wurde. Aber egal was ich mache: Am Ende kommt es bei der Form an :roll:
Wenn jemand die Callback-Prozeduren so hinbiegen kann, dass das Programm offen bleibt, würde ich mich freuen. Streng genommen muss da auch noch ein if (... >= HC_ACTION) rein...

@Scotty: Ich habe nur ein OnCloseQuery-Ereigniss gefunden. Wenn ich darin CanClose := false; setze, bleibt das Programm geöffnet. Aber ich glaube, dieses Konzept lässt sich nicht auf eine fremde Anwendung übertragen...

Notfalls könnte ich noch meine Form zu einem Child des Zielprogrammes machen, den Alpha-Wert auf 1 stellen und über den Button schieben...

[PS:] Ich versuche mit diesem Programm, dieses Problem in den Griff zu bekommen: http://opera-info.de/forum/index.php?pa ... tID=222901" onclick="window.open(this.href);return false;

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Schließen eines Fensters/Programmes verhindern

Beitrag von MitjaStachowiak »

So, ich mache das jetzt mit einer kleinen Form, die ich über den Button schiebe (Als Child-Window bekomme ich es nicht über den Button). Ich habe es geschafft, mich in das Zielfenster "einzuhooken". Aber auf welche Messages muss ich reagieren? Ich habe in der Callback-Funktion folgende Zeile:

Code: Alles auswählen

if (PMsg(lParam)^.Message = WM_DIE_MESSAGE) then SendMessage(p^.Proc,WM_PAINT,0,0);
Das Sendmessage geht an meine Button-Form; diese setzt sich bei jedem PAINT-Vorgang an die passende Stelle auf dem Zielfenster. Ich weiß nur nicht, welche Messages ich bei WM_DIE_MESSAGE einsetzen soll. Wenn ich die if-Bedingung weg lasse, geht es, aber dann habe ich auch eine hohe CPU-Auslastung. Wenn ich WM_PAINT einsetze, reagiert mein Button nur, wenn man das Fenster vergrößert oder maximiert. Eigentlich sollten doch Messages, wie WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED, WM_MOVE oder WM_SIZE den gewünschten Erfolg bringen, aber das tun sie nicht :(

Mein Hook ist vom Typ WH_GETMESSAGE; mit WH_CALLWNDPROC funktioniert dann auch das WM_PAINT nicht mehr...

Was muss ich da einstellen?

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Schließen eines Fensters/Programmes verhindern

Beitrag von MitjaStachowiak »

Hm... Jetzt habe ich das erstmal provisorisch ohne die if-Bedingung gemacht. Der Button erscheint jetzt immer ein Stück Rechts des Fensters um dieses nicht zu überdecken. Beim Paint-Vorgang wird der Button immer abwechselnd um 0 und um 10 Pixel nach unten verschoben gezeichnet (Um zu sehen, wann Messages eingehen). Auch wenn ich nichts mache, springt der Button ständig hin- und her. Anscheinend sendet sich das Programm selber Messages - oder gibt es wirklich Messages, die im Leerlauf gesendet werden?

Naja egal, das merkwürdige ist: Ich hatte doch am Anfang dieses eigenartige Flackern der Windows-Buttons-Aura bei Opera und Lazarus beschrieben. Wenn ich jetzt mein Hook-Programm starte, flackern die Buttons von Opera nicht mehr, die von dem Lazarus-Fenster, in dem ich die DLL schreibe gehen immer nur kurz aus und die, von dem Lazarus-Fenster, von dem aus ich das Programm debugge, flackern ständig, auch wenn sich die Maus nur darüber befindet, ohne sich zu bewegen. :shock:
Kann mir das mal jemand erklären?

[EDIT:] Das Flackern scheint bei allen mit Pascal geschriebenen Programmen aufzutreten. Ich mache dazu mal ein neues Thema...
Hier also weiterhin die Frage, welche Messages ich abfangen muss.

Straightdog
Beiträge: 10
Registriert: Mo 1. Aug 2011, 18:52

Re: Schließen eines Fensters/Programmes verhindern

Beitrag von Straightdog »

Wenn ich die MSDN Dokumentation zu Hooks richtig verstehe, dann hast du mit WH_CALLWNDPROC keine Chance (leider gibt es dies alles auf MSDN nur in Englisch):

Code: Alles auswählen

The CallWndProc hook procedure can examine the message, [b][i][color=#BF0000]but it cannot modify it[/color][/i][/b]. After the hook procedure returns control to the system, the message is passed to the window procedure.
(Hervorhebungen von mir)

Mit WH_GETMESSAGE hast du eine Chance, denn:

Code: Alles auswählen

The GetMsgProc hook procedure can examine [b][i][color=#BF0000]or modify[/color][/i][/b] the message. After the hook procedure returns control to the system, the GetMessage or PeekMessage function returns the message, [b][i][color=#BF0000]along with any modifications[/color][/i][/b], to the application that originally called it.
(Hervorhebungen von rate-mal-wem)

LParam ist ein Zeiger auf die Botschaft, die später an das Programm übergeben wird, deshalb kannst du den Inhalt der Botschaft ändern. Du musst also "nur" testen, ob es sich um eine Close-Message handelt und dann PMsg(LParam)^.message := WM_NULL setzen (das "nur" kann ganz schön heftig sein).

Oder du setzt einen WH_CBT Hook, testest auf HCBT_SYSCOMMAND mit WParam = SC_CLOSE und lässt deine CBTProc eine 1 zurückliefern. Genaueres hier, wieder auf MSDN.

Antworten