Saturday, August 22, 2020

The Dark Side of Application.ProcessMessages

The Dark Side of Application.ProcessMessages Article put together by Marcus Junglas When programming an occasion handler in Delphi (like the OnClick occasion of a TButton), there comes when your application should be occupied for some time, for example the code needs to compose a major document or pack a few information. In the event that you do that youll notice that your application is by all accounts bolted. Your structure can't be moved any longer and the catches are giving no indication of life. It is by all accounts smashed. The explanation is that a Delpi application is single strung. The code you are composing speaks to only a lot of strategies which are called by Delphis principle string at whatever point an occasion occured. The remainder of the time the fundamental string is dealing with framework messages and different things like structure and part taking care of capacities. In this way, in the event that you dont finish your occasion dealing with by accomplishing some protracted work, you will forestall the application to deal with those messages. A typical answer for such kind of issues is to call Application.ProcessMessages. Application is a worldwide object of the TApplication class. The Application.Processmessages handles every single holding up message like window developments, button clicks, etc. It is usually utilized as a straightforward answer for keep your application working. Lamentably the instrument behind ProcessMessages has its own qualities, which may create enormous turmoil! What does ProcessMessages? PprocessMessages handles all holding up framework messages in the applications message line. Windows utilizes messages to converse with every single running application. Client communication is brought to the structure by means of messages and ProcessMessages handles them. On the off chance that the mouse is going down on a TButton, for instance, ProgressMessages does all what ought to occur on this occasion like the repaint of the catch to a squeezed state and, obviously, a call to the OnClick() dealing with methodology on the off chance that you allocated one. That is the issue: any call to ProcessMessages may contain a recursive call to any occasion handler once more. Heres a model: Utilize the accompanying code for a catches OnClick even handler (work). The for-proclamation reenacts a long handling activity with certain calls to ProcessMessages once in a while. This is streamlined for better meaningfulness: {in MyForm:}   WorkLevel : number; {OnCreate:}   WorkLevel : 0; methodology TForm1.WorkBtnClick(Sender: TObject) ; var  â cycle : whole number; start   inc(WorkLevel) ;  â for cycle : 1 to 5 do  â begin     Memo1.Lines.Add(- Work IntToStr(WorkLevel) , Cycle IntToStr(cycle) ;     Application.ProcessMessages;  â â â sleep(1000) ;/or some other work  â end;   Memo1.Lines.Add(Work IntToStr(WorkLevel) finished.) ;   dec(WorkLevel) ; end; WITHOUT ProcessMessages the accompanying lines are kept in touch with the reminder, if the Button was squeezed TWICE in a brief timeframe: - Work 1, Cycle 1 - Work 1, Cycle 2 - Work 1, Cycle 3 - Work 1, Cycle 4 - Work 1, Cycle 5 Work 1 finished. - Work 1, Cycle 1 - Work 1, Cycle 2 - Work 1, Cycle 3 - Work 1, Cycle 4 - Work 1, Cycle 5 Work 1 finished. While the methodology is occupied, the structure doesn't show any response, yet the subsequent snap was placed into the message line by Windows. Directly after the OnClick has completed it will be called once more. Counting ProcessMessages, the yield may be totally different: - Work 1, Cycle 1 - Work 1, Cycle 2 - Work 1, Cycle 3 - Work 2, Cycle 1 - Work 2, Cycle 2 - Work 2, Cycle 3 - Work 2, Cycle 4 - Work 2, Cycle 5 Work 2 finished. - Work 1, Cycle 4 - Work 1, Cycle 5 Work 1 finished. This time the structure is by all accounts working again and acknowledges any client communication. So the catch is squeezed most of the way during your first specialist work AGAIN, which will be taken care of in a split second. Every approaching occasion are dealt with like some other capacity call. In principle, during each call to ProgressMessages ANY measure of snaps and client messages may occur set up. So be cautious with your code! Diverse model (in straightforward pseudo-code!): technique OnClickFileWrite() ; var myfile : TFileStream; start  â myfile : TFileStream.create(myOutput.txt) ;  â try  â â â while BytesReady 0 do  â â â begin       myfile.Write(DataBlock) ;       dec(BytesReady,sizeof(DataBlock)) ;       DataBlock[2] : #13; {test line 1}       Application.ProcessMessages;       DataBlock[2] : #13; {test line 2}  â â â end;  â finally  â â â myfile.free;  â end; end; This capacity composes a lot of information and attempts to open the application by utilizing ProcessMessages each time a square of information is composed. On the off chance that the client taps on the catch once more, a similar code will be executed while the document is as yet being composed to. So the document can't be opened a second time and the system fizzles. Possibly your application will do some mistake recuperation like liberating the cushions. As a potential outcome Datablock will be liberated and the primary code will abruptly raise an Access Violation when it gets to it. For this situation: test line 1 will work, test line 2 will crash. The better way: To make it simple you could set the entire Form empowered : bogus, which hinders all client input, yet doesn't demonstrate this to the client (all Buttons are not grayed). A superior way is set all catches to crippled, yet this may be unpredictable in the event that you need to keep one Cancel button for instance. Likewise you have to experience all the segments to debilitate them and when they are empowered once more, you have to check if there ought to be some staying in the crippled state. You could impair a compartment youngster controls when the Enabled property changes. As the class name TNotifyEvent proposes, it should just be utilized for transient responses to the occasion. For tedious code the most ideal way is IMHO to place all the moderate code into an own Thread. Concerning issues with PrecessMessages as well as the empowering and handicapping of parts, the utilization of a subsequent string is by all accounts not very confused by any stretch of the imagination. Recollect that even basic and quick lines of code may hang for quite a long time, for example opening a record on a circle drive may need to hold up until the drive turn up has wrapped up. It doesnt look excellent if your application appear to crash in light of the fact that the drive is excessively moderate. That is it. Whenever you include Application.ProcessMessages, reconsider ;)

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.