![]() |
Message korrekt behandeln
Hallo Gemeinde, ich teste mich weiter in non-Vcl vor, nun erlerne ich den Umgang mit Messages.
Um das alles besser zu Verstehen habe ich mir ein Beispiel erstellt was nichts weiter tut als mir eine ShowMessage zu zeigen. Warum beendet
Delphi-Quellcode:
nicht in das Programm? ShowMessage kommt und danach ist App in Endlos-Schleife.
SendMessage(Wnd, WM_QUIT, 0, 0);
Warum kann ich
Delphi-Quellcode:
nicht in meinem Hook abfangen? ShowMessage kommt nicht, App ist beendet.
PostMessage(Wnd, WM_QUIT, 0, 0);
Delphi-Quellcode:
program Projekt1;
uses SysUtils, Windows, Messages, Classes, Dialogs; type TMyApp = Class FWnd: HWND; Constructor Create; Destructor Destroy; override; Procedure WndProc(var Msg: TMessage); end; { TMyApp } Constructor TMyApp.Create; begin FWnd := AllocateHWnd(WndProc); //unsichtbares Fenster erzeugen end; Destructor TMyApp.Destroy; begin DeallocateHWnd(FWnd); inherited; end; procedure TMyApp.WndProc(var Msg: TMessage); begin //hier kommen die Messages an (SendMessage direkt, PostMessage über Funktion DispatchMessage) case Msg.Msg of WM_USER: ShowMessage('catched WM_USER Msg!'); WM_QUIT: ShowMessage('catched WM_QUIT Msg!'); end; // case Dispatch(Msg); end; function ThreadProc(Wnd :HWND): Integer; begin Sleep(1000); PostMessage(Wnd, WM_USER, 0, 0); SendMessage(Wnd, WM_USER, 0, 0); Sleep(1000); // SendMessage(Wnd, WM_QUIT, 0, 0); //Programm beenden PostMessage(Wnd, WM_QUIT, 0, 0); //Programm beenden end; procedure Start; var Msg: TMsg; App: TMyApp; Id: Cardinal; begin App := TMyapp.Create; CloseHandle(BeginThread(nil, 0, @ThreadProc, Pointer(App.FWnd), 0, Id)); while GetMessage(Msg, 0, 0, 0) do //auf Message in der Queue warten begin //Message an Fenster verteilen DispatchMessage(Msg); end; App.Free; end; begin Start; end. |
AW: Message korrekt behandeln
SendMessage wird direkt im GetMessage verarbeitet ... nur PostMessage wird zurückgegeben und anschließend im DispatchMessage verarbeitet.
An SendMessage kommt man nur via Hooks an WndProc/GWL_WNDPROC oder ala ![]() Noch besser sind Timer-Messages, welche man in der MessageQueue vergebens sucht, da sie erst im GetMessage/PeekMessage erzugt werden. Und ja, ich dachte mir auch erst, was das denn für ein Schwachsinn sei, denn im Application. TApplicationEvents.OnMessage kommen so viele der Events garnicht erst an. Ach ja, WM_QUIT beendet garnichts. Es sagt nur, dass sich der Empfänger doch bitte beenden möge, was er nur macht, wenn der Entwickler (hier Du oder Emba in der VCL) dieses dort auch eingebaut hat. Aus diesen beiden Gründen wird nun auch klar, warum viele Messages auch mit dem jeweils richtigen Befehl verschickt werden müssen (SendMessage, PostMessage oder PostThreadMessage) |
AW: Message korrekt behandeln
Zitat:
Ich hab mal ein wenig umgeschrieben das man sieht das mein Hook beides verdaut.
Delphi-Quellcode:
program Projekt1;
uses SysUtils, Windows, Messages, Classes; type TMyApp = Class FWnd: HWND; Constructor Create; Destructor Destroy; override; Procedure WndProc(var Msg: TMessage); end; { TMyApp } Constructor TMyApp.create; begin FWnd := AllocateHWnd(WndProc); //unsichtbares Fenster erzeugen end; Destructor TMyApp.Destroy; begin DeallocateHWnd(FWnd); inherited; end; procedure TMyApp.WndProc(var Msg: TMessage); begin //hier kommen die Messages an (SendMessage direkt, PostMessage über Funktion DispatchMessage) case Msg.Msg of WM_USER: case Msg.WParam of 1: Messagebox(FWnd, 'catched WM_USER Msg!', 'PostMessage Catched', MB_ICONINFORMATION or MB_OK); 2: Messagebox(FWnd, 'catched WM_USER Msg!', 'SendMessage Catched', MB_ICONINFORMATION or MB_OK); else Messagebox(FWnd, 'catched WM_USER Msg!', 'Unknown Message Catched', MB_ICONINFORMATION or MB_OK); end; WM_QUIT: case Msg.WParam of 1: Messagebox(FWnd, 'catched WM_QUIT Msg!', 'PostMessage Catched', MB_ICONWARNING or MB_OK); 2: Messagebox(FWnd, 'catched WM_QUIT Msg!', 'SendMessage Catched', MB_ICONWARNING or MB_OK); else Messagebox(FWnd, 'catched WM_QUIT Msg!', 'Unknown Message Catched', MB_ICONWARNING or MB_OK); end; end; // case Dispatch(Msg); // Das besagt das Msg abgearbeitet wurde und aus der Queue entfernt wird. end; function ThreadProc(Wnd :HWND): Integer; begin Sleep(50); PostMessage(Wnd, WM_USER, 1, 0); SendMessage(Wnd, WM_USER, 2, 0); Sleep(5000); PostMessage(Wnd, WM_QUIT, 1, 0); //Programm beenden SendMessage(Wnd, WM_QUIT, 2, 0); //Programm beenden Sleep(1000); end; procedure Start; var Msg: TMsg; App: TMyApp; Id: Cardinal; begin App := TMyapp.Create; CloseHandle(BeginThread(nil, 0, @ThreadProc, Pointer(App.FWnd), 0, Id)); while GetMessage(Msg, 0, 0, 0) do //auf message in der Queue warten begin //Message an Fenster verteilen DispatchMessage(Msg); end; App.Free; end; begin Start; end. |
AW: Message korrekt behandeln
Ich stelle mir gerade auch die Frage wie man eine Message korrekt abarbeitet.
In einem TThread sende ich mit PostMessage den aktuellen Progress in % an WndProc
Delphi-Quellcode:
Mein WndProc
if ProgressPercent > ProgressPercentOld then
begin PostMessage(FDestinationWindowHandle, WM_PB_MAIN, ProgressPercent, WM_PB_SET_HINT); ProgressPercentOld := ProgressPercent; end;
Delphi-Quellcode:
Es gibt auf anderen Computern, wohl sehr selten, das Problem, dass der Progress direkt auf 100% springt.
procedure TForm1.WndProc(var msg: TMessage);
begin if TMessageHandlerThreads.WndProc(msg) then Dispatch(msg); inherited; end; function TMessageHandlerThreads.WndProc(msg: TMessage): Boolean; begin Result := False; case msg.msg of WM_PB_MAIN: begin MainForm.ProgressBar1.Position := msg.WParam; case msg.LParam of WM_PB_SET_HINT: MainForm.ProgressBar1.Hint := IntToStr(msg.WParam) + '%'; end; Result := True; end; end; end; Da mir die Leute die das Problem haben aber nie alle Details nennen und ich alles mühselig erfragen muss, habe ich sonst keine Ahnung wie das Problem bei denen aussieht. Das DispatchMessage(msg); in WndProc habe ich eben hinzugefügt in der Hoffnung, dass das problem weg ist. Fehlt da sonst noch irgendwas? Es kommt in den Logs auch Fehler #1444 - aber nur auf manchen Rechnern, nicht bei allen. Ich vermute das sind alles Win11 PCs. In einem anderen Thread lese ich: Zitat:
|
AW: Message korrekt behandeln
Warum behandelst du nicht einfach gezielt diese eine Message und überlässt Delphi den Rest?
Delphi-Quellcode:
procedure WmPbMain(var msg: TMessage); message WM_PB_MAIN;
... procedure TForm1.WmPbMain(var msg: TMessage); begin ProgressBar1.Position := msg.WParam; case msg.LParam of WM_PB_SET_HINT: ProgressBar1.Hint := IntToStr(msg.WParam) + '%'; end; end; |
AW: Message korrekt behandeln
Die Position könnte man auch direkt an das ProgressBar-Handle schicken,
Delphi-Quellcode:
falls es auch mit PostMessage geht. (vermutlich)
SendMessage(Handle, PBM_SETPOS, Value, 0)
Zitat:
PostMessage arbeitet garnicht mit Exceptions. Wie man in der "Hilfe" lesen kann, ist es wie bei dein meisten WinAPI's: Result und eventuell noch GetLastError, jenachdem ob Result sagt dort wäre was. Zitat:
Was soll Dispatch/DispatchMessage mit "deiner" Message anfangen? Es kennt deine Message garnicht, also kann es auch nichts machen. Schonmal auf die Idee gekommen zu schauen was 1444 ist? ERROR_INVALID_THREAD_ID Hier sieht man nichts dazu, aber nun weißt du ja, in welcher Richtung du im restlichen Code suchen kannst. Aber natürlich hast du garnicht gesagt, "was" das für ein Fehlercode ist, bzw. wo er her kommt. Ist es kein Win32-LastError, dann kann es auch was anderes bedeuten. Zum Springen: Es kann sein, dass du schneller schickst, als die Messages verarbeitet werden, also kann es sein, dass alle Messages praktisch gleichzeitig (ganz schnell nacheinander) verarbeitet wird. Und wie jeder weiß, animiert Windows die ProgrssBars, also nach oben dauert es etwas, bzw. wenn ganz viele Messages gleichzeitig eintreffen, kann es ruckzuck in einem Schritt auf 100 gehn. |
AW: Message korrekt behandeln
Zitat:
Ich habe nicht nur eine Message sondern 5, deswegen habe ich ein case in WndProc. Mein Problem hierbei ist, dass das bei nur einer einzigen Person passiert. Was 1444 bedeutet habe ich schon nachgeguckt, kann damit aber nix anfangen und auch nicht sehen, wo ich anfangen soll zu suchen. |
AW: Message korrekt behandeln
Zitat:
|
AW: Message korrekt behandeln
Natürlich verstehe ich das! Aber wo soll ich anfangen zu suchen, wenn der Fehler bei mir nicht auftritt und ich auch sonst keine Informationen habe.
|
AW: Message korrekt behandeln
Logging einbauen. Von allen Threads die IDs reinschreiben und jeweils wenn er beendet wird. Damit müsste man finden welcher Threads früher als gedacht beendet wird.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:33 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