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 record or pack a few information. On the off chance 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 slammed. 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 primary string at whatever point an occasion occured. The remainder of the time the primary string is taking care of framework messages and different things like structure and part taking care of capacities. Thus, on the off chance that you dont finish your occasion taking care of by accomplishing some extensive work, you will forestall the application to deal with those messages. A typical answer for such sort 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 ordinarily utilized as a straightforward answer for keep your application working. Tragically the system behind ProcessMessages has its own attributes, which may create huge 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 cooperation 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 in the event that you doled out 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-explanation mimics a long handling activity with certain calls to ProcessMessages occasionally. This is streamlined for better meaningfulness: {in MyForm:}   WorkLevel : whole number; {OnCreate:}   WorkLevel : 0; method 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 method 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 altogether 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 cooperation. So the catch is squeezed most of the way during your first specialist work AGAIN, which will be taken care of right away. Every single approaching occasion are taken care of 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. In the event 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 methodology comes up short. Possibly your application will do some blunder recuperation like liberating the cradles. As a potential outcome Datablock will be liberated and the main code will out of nowhere 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 obstructs all client input, yet doesn't demonstrate this to the client (all Buttons are not grayed). A superior way is set all catches to impaired, however this may be mind boggling on the off chance that you need to keep one Cancel button for instance. Additionally you have to experience all the segments to impair 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 cripple a holder youngster controls when the Enabled property changes. As the class name TNotifyEvent proposes, it should just be utilized for momentary 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 or potentially the empowering and incapacitating of segments, the use of a subsequent string is by all accounts not very convoluted by any stretch of the imagination. Recollect that even basic and quick lines of code may hang for a considerable length of time, for example opening a record on a plate drive may need to hold up until the drive turn up has wrapped up. It doesnt look generally 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.