Recent

Author Topic: [Solved] *Tip* request to shunt WndProc + Dispatch + msgHandler  (Read 2661 times)

devEric69

  • Hero Member
  • *****
  • Posts: 644
[Solved] *Tip* request to shunt WndProc + Dispatch + msgHandler
« on: October 28, 2021, 10:36:58 pm »
Hello,

I've got a TEdit with its sequence of events triggered, being:
- OnKeyPress
- OnChange

If in the OnKeyPress event, I return a Chr(0) i.e. no change. In this case, I would to shunt \ escape the following OnChange event. So I've coded (in OnKeyPress, i.e. before OnChange)...

Code: Pascal  [Select][+][-]
  1. if Key = chr(0) then
  2.     SysUtils.Abort;

...which generates the exception EAbort: I should be happy. But, I still have the OnChange event that is fired after, triggered via this call stack:
Code: Pascal  [Select][+][-]
  1. function GtkEntryDelayCursorPos(AGtkWidget: Pointer): GBoolean; cdecl;function gtkchanged_editbox( widget: PGtkWidget; data: gPointer) : GBoolean; cdecl; ➔ DeliverMessage(const Target: TObject; var AMessage): PtrInt; ➔ TWinControl.WndProc(var Message: TLMessage);procedure TObject.Dispatch(var message); ➔ msgHandler(message);procedure TControl.CMTextChanged(var Message: TLMessage); ➔ DoEditForSearch_Change


The Abort \ EAbort exception documentation says:
Quote
Abort is raised by the Abort procedure. It is not displayed in GUI applications, and serves only to immediately abort the current procedure, and return control to the main program loop.


My question is: is there a way (in the message handling layer API) to remove \ reset all the messages from the main program loop (here, SysUtils.Abort doesn't prevent the message CM_TEXTCHANGED - already posted \ sent, it seems, hence - from being peeked and processed by the main program loop despite and after a call to Abort)?

Regards.
« Last Edit: November 01, 2021, 07:58:37 pm by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

howardpc

  • Hero Member
  • *****
  • Posts: 3833
Re: *Tip* request to shunt WndProc + Dispatch + msgHandler
« Reply #1 on: October 28, 2021, 10:49:38 pm »
Would it not be simpler to do something like the following?
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: char);
  2. begin
  3.   if Key = Chr(0) then
  4.     begin
  5.       Edit1.OnChange := Nil;
  6.       Key := Chr(0);
  7.       Edit1.OnChange := @Edit1Change;
  8.     end;
  9. end;


devEric69

  • Hero Member
  • *****
  • Posts: 644
Re: *Tip* request to shunt WndProc + Dispatch + msgHandler
« Reply #2 on: October 29, 2021, 09:47:36 am »
Would it not be simpler to do something like the following?

This is a trick that works very well. Thank you very much :D 8) .



Now, my question was theoretical \ technical. EAbort says it's done to abandon the current procedure (so, first of all, what is the "current" procedure?).
Basically, I have this sequence of calls, that could be like this like one:

Code: Pascal  [Select][+][-]
  1. procedure TEdit.keyPressedDetected; LM_Key_Pressed
  2. begin
  3.     Self.DoObjectCaretBlinkingInMyself;
  4.     Self.Perform(LM_key_will_be_processed);
  5.     PostMessage(LM_objet_caret_must_no_longer_blink_in_me);
  6.     if Assigned(FOnKeyPressed) then FOnKeyPressed(Self);
  7.     Self.AOwner.DoThis;
  8.     Self.DoObjectCaretStopBlinkingInMyself;
  9.     SendMessage(LM_object_beep_please_answer_me_you_will_not_buzz);
  10.     if Assigned(FOnChanged) then FOnChanged(Self)
  11.     Self.DoObjectCaretBlinkingInMyself;
  12. end;


Shouldn't EAbort make it possible to shunt everything \ completely clean the calls stack and the messages sent by this latter (i.e. calls via pointers, or via synchronous messages or via asynch. messages) that is \ are after FOnKeyPressed(Self)? I wonder because I don't see \ anderstand the difference - in my case  - between a call to EAbort and a call to Exit (but I don't know much about the Lazarus message processing loop :-[; I know, I imagine that to " glue " in the same loop of treatment, all the messages of many operating systems is not simple; so, I don't know if what I'm saying \ asking is "science fiction" %) , or a miss that could be done in a sense i.e. a possible "Todo" among many others already existing :) )...
« Last Edit: October 29, 2021, 10:21:40 am by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1021
    • Lebeau Software
Re: *Tip* request to shunt WndProc + Dispatch + msgHandler
« Reply #3 on: October 30, 2021, 08:28:20 pm »
Would it not be simpler to do something like the following?

Such code is completely useless.  First, because Key will never be #0 on entry, you return #0 to cancel further processing of the current key stroke.  And second, setting the Key is just a variable assignment, so it will not trigger a nested OnChange event, so setting the OnChange property just before assigning the Key and then resetting the property immediately afterwards has no effect at all.

If you want to ignore the next OnChange event, you will have to flag that manually, eg:

Code: Pascal  [Select][+][-]
  1. var
  2.   SkipNextChangeEvent: Boolean = False;
  3.  
  4. procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: char);
  5. begin
  6.   if Key = ... then
  7.   begin
  8.     SkipNextChangeEvent := True;
  9.     ...
  10.   end;
  11. end;
  12.  
  13. procedure TForm1.Edit1Change(Sender: TObject);
  14. begin
  15.   if SkipNextChangeEvent then
  16.   begin
  17.     SkipNextChangeEvent := False;
  18.     Exit;
  19.   end;
  20.   ...
  21. end;



Now, my question was theoretical \ technical. EAbort says it's done to abandon the current procedure (so, first of all, what is the "current" procedure?).

The procedure that is calling Abort().

Basically, I have this sequence of calls, that could be like this like one:
...
Shouldn't EAbort make it possible to shunt everything \ completely clean the calls stack and the messages sent by this latter (i.e. calls via pointers, or via synchronous messages or via asynch. messages) that is \ are after FOnKeyPressed(Self)?

Abort() simply raises an EAbort exception, nothing more.  And like any raised exception, any further procedure calls in the raising thread are bypassed until the exception is caught, or it escapes the thread, terminating it.  In the case of EAbort, the main message loop will catch it so it doesn't terminate the app completely, but the currently running message handler will certainly be ended, yes.  But any pending window messages will still be pending, and will be processed at a later time.  The only way to skip those messages is to manually retrieve them from the message queue and discard them without dispatching them, using a PeekMessage(PM_REMOVE) loop (which I don't advise you do, unless you REALLY know what you are doing).

I wonder because I don't see \ anderstand the difference - in my case  - between a call to EAbort and a call to Exit

Exit merely exits the procedure that is calling it, returning flow to the caller so it can continue on with its work.

Abort() raises an exception, jumping flow to the nearest matching exception handler on the call stack.
« Last Edit: November 01, 2021, 06:55:27 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

devEric69

  • Hero Member
  • *****
  • Posts: 644
Re: *Tip* request to shunt WndProc + Dispatch + msgHandler
« Reply #4 on: November 01, 2021, 10:03:38 am »
If you want to ignore the next OnChange event, you will have to flag that manually, eg:

Code: Pascal  [Select][+][-]
  1. var
  2.   SkipNextChangeEvent: Boolean = False;
  3. [snip]
  4.  

Hello Remy,

Thank you for your explanations. Well, your solution is more semantic and contains less code than those of @howardpc's: so, I like it. However, it contains a global variable, which I avoid using as much as possible :-\ .

Nevertheless, this global variable + your explanations about the technicality (oriented MS-Windows) of the messages distribution loop ( 'happy to know PeekMessage(PM_REMOVE); ), seems to reinforce me, that the procedure syUtils.Abort could be "improved" (in Lazarus) by doing (porting) something like..:
Code: Pascal  [Select][+][-]
  1. SendMessage(ieHighestPriority, LM_ABORT_PROCESS_ANY_NEW_MESSAGE);
  2. PostMessage(ieLowestPriority, LM_STOP_ABORT_PROCESS_ANY_NEW_MESSAGE);
  3. Raise EAbort.Create(SAbortError)
... and that in the polymorphic (inter-OSes) " glue " loop of messages (in Lazarus) could process it like this:
Code: Pascal  [Select][+][-]
  1. while fpPeekMessage(reMessage) do begin
  2.     if (reMessage^.iMessage = LM_ABORT_PROCESS_ANY_NEW_MESSAGE) {having reMessage^.priority = ieHighestPriority} then  
  3.         bAbort_process_any_new_message:= True;
  4.     if (reMessage^.iMessage = LM_STOP_ABORT_PROCESS_ANY_NEW_MESSAGE) {having reMessage^.priority = ieLowestPriority} then  
  5.         bAbort_process_any_new_message:= False;
  6.     if bAbort_process_any_new_message then Continue {or any other equivalent of PeekMessage(PM_REMOVE)};
  7. ...\...

AMHO.
« Last Edit: November 01, 2021, 10:15:40 am by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1021
    • Lebeau Software
Re: *Tip* request to shunt WndProc + Dispatch + msgHandler
« Reply #5 on: November 01, 2021, 07:05:34 pm »
Thank you for your explanations. Well, your solution is more semantic and contains less code than those of @howardpc's: so, I like it. However, it contains a global variable, which I avoid using as much as possible :-\ .

It doesn't have to be global, it could be a data member of the Form class instead.  Or, you could simply use the TEdit.Tag property instead, if you are not using it for something else.

Nevertheless, this global variable + your explanations about the technicality (oriented MS-Windows) of the messages distribution loop ( 'happy to know PeekMessage(PM_REMOVE); ), seems to reinforce me, that the procedure syUtils.Abort could be "improved" (in Lazarus) by doing (porting) something like..:

No, it can't.  It breaks Delphi compatibility. It is not cross-platform. And it is RARELY desirable to discard messages in this manner anyway.  It reeks of bad and unstable UI design.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

devEric69

  • Hero Member
  • *****
  • Posts: 644
Re: *Tip* request to shunt WndProc + Dispatch + msgHandler
« Reply #6 on: November 01, 2021, 07:58:00 pm »

Nevertheless, this global variable + your explanations about the technicality (oriented MS-Windows) of the messages distribution loop ( 'happy to know PeekMessage(PM_REMOVE); ), seems to reinforce me, that the procedure syUtils.Abort could be "improved" (in Lazarus) by doing (porting) something like..:

No, it can't.  It breaks Delphi compatibility. It is not cross-platform. And it is RARELY desirable to discard messages in this manner anyway.  It reeks of bad and unstable UI design.

All right: I defer to your expertise (and I've finally the answer to my primary questioning :) ).
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

 

TinyPortal © 2005-2018