![]() |
Problem bei der Verarbeitung von Systemnachrichten
Hallo,
Mit einem Hilfsprogramm sende ich meinem Hauptprogramm die message WM_QUIT. Diese möchte ich nun abfangen, und als Reaktion ShowMessage('text') aufrufen. Das Problem: Wenn ich im Hilfsprogramm die Nachricht mit SendMessage() verschicke, kann ich sie im Hauptprogramm mit der WndProc-Prozedur abfangen. Wenn ich WM_QUIT allerdings mittels PostMessage versende, dann schließt sich das Programm sofort, dabei möchte ich, dass nur meine Nachricht erscheint. Ich habe es im Fall PostMessage bisher so versucht:
Delphi-Quellcode:
Damit sollte es doch eigentlich funktionieren... Jedenfalls wird nie die MessageBox angezeigt, und ich weiß nicht wieso ...
procedure TForm1.FormCreate(Sender: TObject);
begin Application.OnMessage := ApplicationEvents1Message; end; procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean); begin if Msg.Message = WM_QUIT then begin Handled := True; ShowMessage('WM_QUIT ist eingegangen'); end; end; Achja, WndProc hab ich auch probiert, aber hab erfahren, dass die mit PostMessage gesendete Nachrichten nicht erhält. Und noch was: WM_CLOSE oder WM_DESTROY lassen sich damit abfangen und anzeigen, aber WM_QUIT geht immer sofort durch und beendet das Programm OHNE vorher meine MessageBox anzuzeigen. Ich hoffe mal hier weiß einer, wie man das Problem lösen kann :? |
Re: Problem bei der Verarbeitung von Systemnachrichten
Zitat:
|
Re: Problem bei der Verarbeitung von Systemnachrichten
Gibt es dann überhaupt eine Möglichkeit, sein Programm so umzuschreiben, dass es diese Nachricht erhält, bevor es terminiert wird? Ich kenn mich da so genau jetzt nicht aus, aber dass man was mit PostQuitMessage anstellen kann, oder mit GetMessage, so dass auch bei WM_QUIT nicht 0 zurückgegeben wird? Vll. diese Funktion in seinem Programm überschreiben, denn wie ich das verstanden hab, gehen da die Nachrichten ein, und alle außer WM_QUIT gehen nicht sofort durch, nur WM_QUIT wird 0 zurckgeliefert und sofort abgebrochen.
Wenn einer diese Idee (falls es überhaupt geht) in einem kleinen Codebeispiel darstellen würde, wäre ich sehr dankbar ;) |
Re: Problem bei der Verarbeitung von Systemnachrichten
Wie es im MSDN stand:
Dein programm wird terminiert, BEVOR es die Message erhält. Du müsstest dein OS umschreiben, damit es vorher die Message noch bekommt. |
Re: Problem bei der Verarbeitung von Systemnachrichten
Hmm wenn ich Linus Torvalds Programmierskills hätte würde ich das jetzt tun ;)
Also gibt es keine Möglichkeit, diese GetMessage-Funktion so zu ändern (nur für mein Programm, nicht systemweit), dass sie bei WM_QUIT nicht NULL ausgibt? Denn es heißt zwar, das Programm wird terminiert bevor es die message erhält, jedoch irgendwo muss diese ja ankommen, und zwar in dieser Message-Schleife ... Hmm aber so wichtig ist es nun auch wieder nicht ;) Dann mach ich es lieber anders, mit WM_DESTROY oder so ... So ein Problem wie das mit WM_QUIT reizt mich einfach delphitechnisch, allein durch die Beschäftigung in diesem Zusammenhang mit den Systemnachrichten hab ich viel über WinAPI, WndProc und so gelernt ;) |
Re: Problem bei der Verarbeitung von Systemnachrichten
Nein, leider nicht.
Du musst wohl was anderes als WM_QUIT senden, vielleicht, .. WM_PRINT? |
Re: Problem bei der Verarbeitung von Systemnachrichten
Mich hatte einfach Nachrichtenbehandlung, die message-Direktive usw. interessiert, dann hab ich im Delphi-Forum ein paar Beiträge dazu gelesen, und dann was pber SendMessage, PostMessage und WndProc ;)
Als ich dann rausgefunden hab, wie man SendMessage-Nachrichten behandelt, und dass man mit der gleichen Methode keine PostMessage-Nachrichten behandeln kann, hab ich nach einer Lösung für dieses problem gesucht usw. Dann hab ich herausgefunden, dass dies bei WM_QUIT nicht funktioniert und wollte schauen, ob es dafür auch eine solche Lösung gibt, dass die Message anders behandelt wird, aber dem war wohl nicht so ... ;) Danke dann mal :-D |
Re: Problem bei der Verarbeitung von Systemnachrichten
Noch mal im Klartext:
![]()
Delphi-Quellcode:
Das heißt TranslateMessage bzw. in diesem Fall das wichtigere DispatchMessage wird nicht mehr aufgerufen und somit kann DispatchMessage die Nachricht nicht an die Zuständige Fensterprozedur weiterleiten. Du wirst also nie eine WM_QUIT zu sehen bekommen.
while GetMessage(msg,0,0,0) do
begin TranslateMessage(msg); DispatchMessage(msg); end; Wozu brauchst du denn das überhaupt? |
Re: Problem bei der Verarbeitung von Systemnachrichten
Zitat:
|
Re: Problem bei der Verarbeitung von Systemnachrichten
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Johannes,
ich habe mal bei mir im Archiv nachgeschaut und ein kleines aber feines Testprogramm rausgebuddelt. Wenn du das Programm verstanden hast, versteht du auch die Hierarchie der Message-Verarbeitung durch die VCL. Das WM_QUIT-Ereingis wird innerhalb der VLC im Objekt TApplication einfach auf das Property Terminated umgesetzt :drunken: . Erhält dein Programm diese Nachricht, ist Application.Terminated immer True. Generell kannst du aber die Auswirkungen des Ereignisses nicht aufheben - also das Beenden des Programms. Du kannst es aber - siehe Beispielprogramm - abfangen und noch letzte arbeiten ganz in Ruhe durchführen lassen. Das Testprogramm ist als Anhang ebenfalls dabei. Grüße Kay :gruebel: :P :angel:
Delphi-Quellcode:
unit Main;
interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; const MyMesage = {WM_QUIT} WM_USER; //test also WM_USER message to see the full functionality type TMainForm = class(TForm) SendBtn: TButton; PostBtn: TButton; procedure SendBtnClick(Sender: TObject); procedure PostBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private OldWndProc: Pointer; WndProcPtr: Pointer; procedure HandleAppIdleState(Sender: TObject; var Done: Boolean); procedure WndMethod(var Msg: TMessage); procedure HandleAppMessage(var Msg: TMsg; var Handled: Boolean); procedure AppDeactivate(Sender: TObject); end; var MainForm: TMainForm; implementation {$R *.DFM} var WProc: Pointer; function NewWndProc(Handle: hWnd; Msg, wParam, lParam: Longint): Longint; stdcall; {Description: This is a Win32 API-level window procedure. It handles the messages received by the Application window. } begin {If it's our user-defined message, then alert the user. } if Msg = MyMesage then MessageBox(0, PChar(Format('Message seen by NewWndProc! Value is: %u', [Msg])), PChar('Check WM_QUIT Message'), MB_OK); {Pass message on to old window procedure } Result := CallWindowProc(WProc, Handle, Msg, wParam, lParam); end; procedure TMainForm.HandleAppMessage(var Msg: TMsg; var Handled: Boolean); {Description: OnMessage handler for Application object. } begin {if it's the user-defined message, then alert the user. } if Msg.Message = MyMesage then MessageBox(0, PChar(Format('Message seen by OnMessage! Value is: %u', [Msg.Message])), PChar('Check WM_QUIT Message'), MB_OK); end; procedure TMainForm.WndMethod(var Msg: TMessage); begin {if it's the user-defined message, then alert the user. } if Msg.Msg = MyMesage then MessageBox(0, PChar(Format('Message seen by WndMethod! Value is: %u', [Msg.Msg])), PChar('Check WM_QUIT Message'), MB_OK); {Pass message on to old window procedure. } with Msg do Result := CallWindowProc(OldWndProc, Application.Handle, Msg, wParam, lParam); end; procedure TMainForm.HandleAppIdleState(Sender: TObject; var Done: Boolean); var Msg: TMsg; begin {Get the message from the queue. } if PeekMessage(Msg, 0, 0, 0, PM_NoREMOVE) then begin if Msg.Message = MyMesage then MessageBox(0, PChar(Format('Message seen by HandleAppIdleState! Value is: %u', [Msg.Message])), PChar('Check WM_QUIT Message'), MB_OK); end; end; procedure TMainForm.AppDeactivate(Sender: TObject); begin if Application.Terminated then MessageBox(0, PChar('Message seen by AppDeactivate! WM_QUIT'), PChar('Check WM_QUIT Message'), MB_OK); end; procedure TMainForm.SendBtnClick(Sender: TObject); begin {The SendMessage function sends the specified message to a window or windows. The function calls the window procedure for the specified window and does not return until the window procedure has processed the message. The PostMessage function, in contrast, posts a message to a thread's message queue and returns immediately. } SendMessage(Application.Handle, MyMesage {WM_QUIT}, 0, 0); end; procedure TMainForm.PostBtnClick(Sender: TObject); begin {The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window and then returns without waiting for the thread to process the message. } PostMessage(Application.Handle, MyMesage {WM_QUIT}, 0, 0); end; procedure TMainForm.FormCreate(Sender: TObject); begin Application.OnDeactivate := AppDeactivate; Application.OnIdle := HandleAppIdleState; Application.OnMessage := HandleAppMessage; // set OnMessage handler WndProcPtr := MakeObjectInstance(WndMethod); // make window proc {Set window procedure of application window. } OldWndProc := Pointer(SetWindowLong(Application.Handle, GWL_WNDPROC, Integer(WndProcPtr))); end; procedure TMainForm.FormDestroy(Sender: TObject); begin if Application.Terminated then MessageBox(0, PChar('Message seen by FormDestroy! WM_QUIT'), PChar('Check WM_QUIT Message'), MB_OK); {Restore old window procedure for Application window } SetWindowLong(Application.Handle, GWL_WNDPROC, Longint(OldWndProc)); {Free our user-created window procedure } FreeObjectInstance(WndProcPtr); end; initialization {Set window procedure of Application window. } WProc := Pointer(SetWindowLong(Application.Handle, GWL_WNDPROC, Integer(@NewWndProc))); end. |
Re: Problem bei der Verarbeitung von Systemnachrichten
Hi, noch ein Hinweis zur Bearbeitung von WM_QUIT.
Johannes nutzt zur Ausgabe einer Messagebox "ShowMessage". Ist ein WM_QUIT-Ereignis eingetroffen, wird verschiedene VCL-Methode nicht mehr ausgeführt :gruebel: , zu diesen zählt auch WM_QUIT. Mit ShowMessage kann ich also generell, egal an welcher Stelle des Programms, keine Messagebox mehr aufblenden, wenn das Programm WM_QUIT empfangen hat :cry: . Das geht nur noch mit der im Beispiel genutzten API-Methode :wall: Kay |
Re: Problem bei der Verarbeitung von Systemnachrichten
Danke Kay ;)
Auch dafür, dass du es nochmal in der PN geschickt hast, sonst hätte ich es vll noch übersehen :stupid: |
Re: Problem bei der Verarbeitung von Systemnachrichten
Hier mal eine Lösung wie du mit SetWindowsHookEx die WM_QUIT Nachricht abfangen kannst.
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } procedure SetMsgHook; procedure Unhook; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} var MsgHook: HHOOK; {--------------------------------------------------------------------------------------------------} function GetMsgProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; const S_MSG = 'Eine WM_QUIT Nachricht wird an dieses Programm geschickt.' + #13#10 + 'Soll die Nachricht verarbeitet werden?'; var Msg: PMsg; begin if Code = HC_ACTION then begin Msg := PMsg(lParam); if Msg^.message = WM_QUIT then if Application.MessageBox(S_MSG, nil, MB_YESNO or MB_ICONINFORMATION) = IDNO then begin Msg^.message := WM_COMMAND; Msg.wParam := WM_NULL; Msg.lParam := 0; Result := 1; Exit; end; end; Result := CallNextHookEx(MsgHook, Code, wParam, lParam); end; {--------------------------------------------------------------------------------------------------} procedure TForm1.SetMsgHook; begin if MsgHook <> 0 then Exit; MsgHook := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, 0, GetCurrentThreadId); if MsgHook = 0 then Application.MessageBox(PChar(SysErrorMessage(GetLastError)), nil, MB_OK or MB_ICONQUESTION); end; {--------------------------------------------------------------------------------------------------} procedure TForm1.Unhook; begin if MsgHook = 0 then Exit; UnhookWindowsHookEx(MsgHook); MsgHook := 0; end; {--------------------------------------------------------------------------------------------------} procedure TForm1.FormCreate(Sender: TObject); begin SetMsgHook; end; {--------------------------------------------------------------------------------------------------} procedure TForm1.FormDestroy(Sender: TObject); begin Unhook; end; {--------------------------------------------------------------------------------------------------} end. |
Re: Problem bei der Verarbeitung von Systemnachrichten
So vielen Dank euch beiden für die ausführlichen Antworten :thumb:
Jetzt noch einmal auf die Frage, wieso ich das brauche: Ich bin einfach von Natur aus jemand, der, wenn er ein Problem hat, und dieses lösen kann, allerdings nur mit Hilfe einer Formel die er noch nicht kennt, auch wissen will wo diese Formel herkommt usw, bzw. alles über die "näheren Umstände" dieser Formel erfahren will ;) Auf Formel komme ich jetzt nur, da es ein gutes Beispiel für meine Vorgehensweise ist, und ganz nebenbei auch für meine Interessen (Mathematik gehört dazu ;)). Ich kam auf das Problem mit WM_QUIT nur dadurch, dass ich meinem "Programm" (genaugenommen macht es gar nichts) Systemnachrichten zukommen ließ, da ich aber SendMessage nicht kannte, dies mit PostMessage erledigte. Bis dahin dachte ich, man könne diese mit der WndProc abfangen und verarbeiten, aber das ging nicht, nur mit SendMessage-Nachrichten. Dann suchte ich dafür eine Lösung, die fand sich mit dem Code ganz oben, als ich dann einmal WM_QUIT sendete (statt WM_CLOSE) ging es plötzlich nicht mehr. Jetzt da ich weiß, dass es dafür auch eine Lösung gibt und wie sie aussieht, bin ich (fast) zufrieden. Ich werde mich jetzt nur noch mit den Lösungen beschäftigen um herauszufinden wie sie funktionieren ;) Denn zu wissen, mit welchem Code man ein programmiertechnisches Problem lösen kann, reicht mir nicht aus, ich möchte ihn auch gerne verstehen ;) Brauchen werde ich diesen Code wohl kaum ... Zum Glück gibt es ja MSDN, um die verschiedenen Systemfunktionen erklärt zu bekommen. Falls ich dann doch irgendetwas dort sprach- oder begriffbedingt nicht verstehen sollte, so gibt es ja immer noch drei Foren, wo ich nachfragen kann ;) MfG |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:39 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz