Reputation: 862
Remark: IdAntiFreeze is active
procedure Tform_update.button_downloadClick(Sender: TObject);
var
FS: TFileStream;
url, file_name: String;
begin
//execute download
if button_download.Tag = 0 then
begin
Fdone:= False;
Fcancel:= False;
url:= APP_DOMAIN + '/downloads/Setup.exe';
file_name:= 'C:\Temp\Setup.exe';
if FileExists(file_name) then DeleteFile(file_name);
try
FS:= TFileStream.Create(file_name, fmCreate);
Http:= TIdHTTP.Create(nil);
Http.OnWorkBegin:= HttpWorkBegin;
Http.OnWork:= HttpWork;
Http.Get(url, FS);
finally
FS.Free;
Http.Free;
if Fdone then ModalResult:= mrOk;
end;
end
else
//cancel download
begin
Fcancel:= True;
end;
end;
procedure Tform_update.HttpWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
var
ContentLength: Int64;
Percent: Integer;
begin
ContentLength:= Http.Response.ContentLength;
if AWorkCount = ContentLength then Fdone:= True; //
if (Pos('chunked', LowerCase(Http.Response.TransferEncoding)) = 0) and (ContentLength > 0) then
begin
sleep(15);
Percent := 100 * AWorkCount div ContentLength;
progress_bar.Position:= Percent;
end;
//stop download
if Fcancel and Http.Connected then
begin
Http.IOHandler.InputBuffer.Clear;
Http.Disconnect;
Fcancel:= False;
button_download.Caption:= _('Download and Install');
button_download.Tag:= 0;
progress_bar.Position:= 0;
end;
end;
procedure Tform_update.HttpWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
begin
if AWorkMode <> wmRead then Exit;
button_download.Tag:= 1;
button_download.Caption:= _('Cancel');
end;
procedure Tform_update.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Fcancel:= True;
end;
Upvotes: 0
Views: 1261
Reputation: 196
A different approach is to use TThread to control the execution. Something like this:
ThreadUpdate = class(TThread)
protected
procedure Execute; override;
public
procedure ThreadUpdate.Execute;
begin
inherited;
while (not terminated) do
begin
//YOUR CODE HERE - maybe your button_download Click
Terminate;
end;
end;
Also you may try to let Windows process messages for your app.
if (Pos('chunked', LowerCase(Http.Response.TransferEncoding)) = 0) and (ContentLength > 0) then
begin
sleep(15);
Percent := 100 * AWorkCount div ContentLength;
progress_bar.Position:= Percent;
**Application.ProcessMessages;**
end;
Upvotes: 1
Reputation: 26
Regarding Q1 and Q2, a thread is certainly better. If you decide to keep using Indy Antifreeze, you should make sure the OnlyWhenIdle flag is set to False so it can process messages whenever work is done.
Upvotes: 0
Reputation: 6013
Q1. Indy is blocking. All Antifreeze does invoke windows messages processing regularly. It doesn't stop the blocking nature of Indy and so unless you explicitly have a way to handle errors it won't behave how you want. You need to do the download in a different thread and use your form to monitor the status of that thread rather than try and rely on antifreeze. Don't put any UI actions in that thread, leave them in the main thread, so don't try and update the progress bar from within the thread. Set a synchronised variable to the progress percentage and read that from a timer in the main thread, for example. Remember that UI components are not thread safe and so should only ever be updated from a single thread.
Q2. I've seen that too. Nothing to do with Indy. I think that when you set the status bar to 100% the component does not immediately respond but tries to move smoothly to that point (but doesn't have time). That is just a guess, though. I am not sure. Or it may be the frequency with which antifreeze processes messages I guess (in which case it is to do with Indy).
Q3. Really the same as Q1, with the same solution. Put in a separate thread and monitor the status of that thread from the main thread.
Once you have moved the Indy actions to a separate thread, you should not need Antifreeze.
Upvotes: 1