2

The Application.Run procedure calls an infinite loop that handles windows messages:

  repeat
    try
      HandleMessage;
    except
      HandleException(Self);
    end;
  until Terminated;

The Terminated property can be set to true only through Application.Terminate procedure, which sends PostQuitMesage. I would like to change the message handling loop so that I can directly stop it using the global variable (without using messages queue):

var MyTerminated:Boolean
....
  repeat
    try
      HandleMessage;
    except
      HandleException(Self);
    end;
  until Terminated or MyTerminated;

The question is, is it possible to make the program use your own version of Application.Run?

Molochnik
  • 704
  • 5
  • 23
  • I've tried this once, and would not recommend it. It entails making a complete copy of `Vcl.Forms`, and most importantly, making sure everything references that instead of the main one. – Jerry Dodge May 15 '17 at 23:54
  • ("tried **this**" as in implementing my own message queue in place of the default one.) – Jerry Dodge May 16 '17 at 00:11
  • 2
    For the life of me I cannot imagine why you would want to do this. My guess is that whatever is motivating the question, is the wrong solution to the real problem – David Heffernan May 16 '17 at 10:43

2 Answers2

6

"Terminated" property is read-only. However it is a direct getter of the FTerminated field, therefore Application.Terminated directly reads from the boolean field. While the language disallows setting Application.Terminated, you can set the boolean value at that address using a pointer:

PBoolean(@Application.Terminated)^ := True;

You may also consider using Halt, which will pass over the message loop completely, for a more abrupt but less hacky solution.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Wow, what a hack. I've never seen this one before. Does this work on any read-only literal property? – Jerry Dodge May 15 '17 at 23:55
  • @Jerry - Yes, if by "literal" you mean a prop that references a field. I think we've discussed this here, it was about changing Application.MainForm. – Sertac Akyuz May 15 '17 at 23:58
  • Yep, here: http://stackoverflow.com/questions/25666626/delphi-change-main-form-while-application-is-running – Sertac Akyuz May 15 '17 at 23:58
  • 1
    @Jerry - Sorry, I didn't mean you were involved. I just wanted to note this is not original. – Sertac Akyuz May 16 '17 at 00:03
  • Well, I meant literal as in types like string, integer, float, record... as opposed to classes and interfaces, etc.... But apparently you mean it works on any property which directly reads its underlying field. – Jerry Dodge May 16 '17 at 00:05
  • @Sertac Perfect solution! Thank you very much! – Molochnik May 16 '17 at 00:06
  • @Molochnik - You're welcome. Be aware that this is not nice. I expect at least one downvote. – Sertac Akyuz May 16 '17 at 00:07
  • 1
    What happens if the implementation changes and the property no longer references a field but a getmethod? – Pieter B May 16 '17 at 08:15
  • 1
    @Pieter - You corrupt memory. – Sertac Akyuz May 16 '17 at 10:27
  • Depending on Delphi version he could also use `class helper` to change FTerminated. Personally I would just replace binary implementation of `.Terminate` method, so it would only post that quit message if I did not prohibited it, and then just would just call it. But I agree this requests looks very weird and hardly compatible with the rest of VCL.... – Arioch 'The May 16 '17 at 15:24
0

Yes, you can make your application use own version of Application run, but this practice is discouraged, because it changes normal program flow, designed by the architects of Delphi.

Directly stopping Application.Run signifies that there is a need to restart Application.Run later, for example, after some action that is wanted to be done from the main thread. This makes the program puzzled, harder to understand by peer programmers and more error prone as a whole.

The program design should be simple and straightforward. If an application is big, for example two million lines of code, the overall design of the execution flow should be simple anyway:

  • If you need to do some longer actions, do them from the worker threads;
  • If you need to do an instant actions, do them from your main form or from the other forms.

So a Delphi application main loop should only be exited on the overall application exit, which is done by the PostQuitMessage. We don't have to avoid this message.

The reason why PostQuitMessage is wanted to be avoided, is probably an instantaneous exit. This is not how VCL applications are supposed to run. If one doesn't need forms (for example for a Windows Service application), just don't use the TApplication class an don't run forms, just make your own message loop based on MsgWaitForMultipleObjects.

Maxim Masiutin
  • 3,991
  • 4
  • 55
  • 72