Reputation: 1967
In our software we have issues with asynchronous execution of events. Sometimes one function will "break into" another one with all kinds of weird results.
I'm dealing here with user-input and timers that fire events.
The issue is that rather then executing the code tied to the events one by one, it's done at the first possible moment that Delphi gives a window for it: application.processmessages. This gives problems in that sometimes half of function A gets done, then function B "breaks in", gets done and after that , the last half of function A gets done. This can give "surprising" results.
Are there good ways to deal with this?
Things I tried:
--
Next I was thinking of trying building some kind of "command-queue" where I can receive my events and fire them in a fifo way.
Apart from rebuilding everything we have from the ground up, are there other/better ways to tackle these issues?
Upvotes: 2
Views: 2068
Reputation: 34899
Are there good ways to deal with this?
First eliminate all your use of ProcessMessages
. As you discovered, it screws up timer event handlers when called from there. Used in other places, it is often subject to race conditions and may hide the real problem. Find out what that problem is and solve it.
But we're relying on some 3rd party components which I found out also fire application.processmessages.
Timer Event handlers are supposed to do only short time work. If you are calling ProcessMessages
via a call to a 3rd party library inside a timer event handler, eliminate that call. There is no other cure, except rewriting the library or calling it in another way.
Apart from rebuilding everything we have from the ground up, are there other/better ways to tackle these issues?
Normally you can do background work in threads as well, providing the rules of not calling any VCL RTL methods directly are followed. Here it is not possible if the 3rd party component is calling ProcessMessages
.
If you can't alter the 3rd party component, there is possibility to post a message to your form, and put the call in the method that handles this message. With a modern Delphi you could use DelayedAction by @MasonWheeler. But I really recommend you to take the "hard" way and fix the 3rd party lib instead.
Upvotes: 4
Reputation: 4730
The best way is to eliminate the call to Application.ProcessMessages
. Most of the time there is other ways to do what Application.ProcessMessages
is supposed to do. You'll need to take a closer look why you need that call, and then find a better solution. For example, you don't need Application.ProcessMessages
to update the UI. There is other ways to do that.
If a 3rd party component is calling Application.ProcessMessages
then contact that vendor that they should replace this call with a better suited function. If this is not an option, you can try using workarounds like using that component in a thread (if possible). Or create an invisible modal window and execute the methods of the component inside the ShowModal function. That will at least avoid user input messages. (The "invisible modal window" is a Form with BorderStyle=bsNone
, size=1×1 and 100% transparency).
Upvotes: 4