AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Message korrekt behandeln

Ein Thema von KodeZwerg · begonnen am 21. Mai 2018 · letzter Beitrag vom 19. Sep 2022
Antwort Antwort
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#1

Message korrekt behandeln

  Alt 21. Mai 2018, 11:34
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 SendMessage(Wnd, WM_QUIT, 0, 0); nicht in das Programm? ShowMessage kommt und danach ist App in Endlos-Schleife.
Warum kann ich PostMessage(Wnd, WM_QUIT, 0, 0); nicht in meinem Hook abfangen? ShowMessage kommt nicht, App ist beendet.

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.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Message korrekt behandeln

  Alt 21. Mai 2018, 12:40
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 WH_GETMESSAGE dran.

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)
$2B or not $2B

Geändert von himitsu (21. Mai 2018 um 13:19 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Message korrekt behandeln

  Alt 21. Mai 2018, 13:12
An SendMessage kommt man nur via Hooks ala WH_GETMESSAGE dran.
Benutzt mein Code das bereits?
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.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#4

AW: Message korrekt behandeln

  Alt 18. Sep 2022, 14:37
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:
if ProgressPercent > ProgressPercentOld then
 begin
  PostMessage(FDestinationWindowHandle, WM_PB_MAIN, ProgressPercent, WM_PB_SET_HINT);
  ProgressPercentOld := ProgressPercent;
 end;
Mein WndProc
Delphi-Quellcode:
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;
Es gibt auf anderen Computern, wohl sehr selten, das Problem, dass der Progress direkt auf 100% springt.
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:
Auf MSDN erfährt man zu Postthreadmessage: "The function fails if the specified thread does not have a message queue."
Ein try-except um mein PostMessage, wäre das eine Idee?

Geändert von DieDolly (18. Sep 2022 um 16:05 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Message korrekt behandeln

  Alt 18. Sep 2022, 16:22
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;
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#6

AW: Message korrekt behandeln

  Alt 18. Sep 2022, 16:25
Die Position könnte man auch direkt an das ProgressBar-Handle schicken,
SendMessage(Handle, PBM_SETPOS, Value, 0) falls es auch mit PostMessage geht. (vermutlich)


Ein try-except um mein PostMessage, wäre das eine Idee?
Natürlich nicht.

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:
Das DispatchMessage(msg); in WndProc habe ich eben hinzugefügt in der Hoffnung, dass das problem weg ist.
Fehlt da sonst noch irgendwas?
Da ist eher zuviel.

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.
$2B or not $2B

Geändert von himitsu (18. Sep 2022 um 16:28 Uhr)
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#7

AW: Message korrekt behandeln

  Alt 18. Sep 2022, 16:45
Zitat:
Warum behandelst du nicht einfach gezielt diese eine Message und überlässt Delphi den Rest?
Ich verstehe den Kontext nicht. Wo soll diese Prozedur hin und sein? Was ist der Unterschied zu meiner WndProc?
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.

Geändert von DieDolly (18. Sep 2022 um 17:02 Uhr)
  Mit Zitat antworten Zitat
venice2
(Gast)

n/a Beiträge
 
#8

AW: Message korrekt behandeln

  Alt 18. Sep 2022, 17:04
Zitat:
kann damit aber nix anfangen
Hmmm.. Du verstehst nicht das die Thread ID ungültig ist?
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#9

AW: Message korrekt behandeln

  Alt 18. Sep 2022, 17:06
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.
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
2.960 Beiträge
 
Delphi 12 Athens
 
#10

AW: Message korrekt behandeln

  Alt 19. Sep 2022, 22:16
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.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz