Delphi:使用Indy(TidHttp)下载更新文件时出现的问题 问题1:为什么在下载过程中无法关闭模式表单 问题2:为什么下载完成后进度条没有100%丰富(这是一种重新绘制的方式?) 问题3:为什么我在运行期间停止并重新启动与web服务器的连接 下载传输正在停止,但未显示任何错误和错误 永不继续?我能做些什么来获取并捕获错误并继续 返回初始状态(下载并安装,进度条位于 位置0)

Delphi:使用Indy(TidHttp)下载更新文件时出现的问题 问题1:为什么在下载过程中无法关闭模式表单 问题2:为什么下载完成后进度条没有100%丰富(这是一种重新绘制的方式?) 问题3:为什么我在运行期间停止并重新启动与web服务器的连接 下载传输正在停止,但未显示任何错误和错误 永不继续?我能做些什么来获取并捕获错误并继续 返回初始状态(下载并安装,进度条位于 位置0),delphi,download,indy,idhttp,Delphi,Download,Indy,Idhttp,备注:IdAntiFreeze处于活动状态 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;

备注:IdAntiFreeze处于活动状态

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;
procedure Tform\u update.按钮下载点击(发送方:TObject);
变量
FS:TFileStream;
url,文件名:字符串;
开始
//执行下载
如果button_download.Tag=0,则
开始
Fdone:=假;
Fcancel:=假;
url:=APP_DOMAIN+'/downloads/Setup.exe';
文件名:=“C:\Temp\Setup.exe”;
如果文件存在(文件名),则删除文件(文件名);
尝试
FS:=TFileStream.Create(文件名,fmCreate);
Http:=TIdHTTP.Create(nil);
Http.OnWorkBegin:=HttpWorkBegin;
Http.OnWork:=HttpWork;
Get(url,FS);
最后
财政司司长:免费;
Http.Free;
如果为Fdone,则ModalResult:=mrOk;
结束;
结束
其他的
//取消下载
开始
Fcancel:=真;
结束;
结束;
过程Tform_update.HttpWork(ASender:TObject;AWorkMode:TWorkMode;AWorkCount:Int64);
变量
ContentLength:Int64;
百分比:整数;
开始
ContentLength:=Http.Response.ContentLength;
如果AWorkCount=ContentLength,则Fdone:=True//
如果(Pos('chunked',小写(Http.Response.transferncoding))=0)和(ContentLength>0),则
开始
睡眠(15);
百分比:=100*AWorkCount div ContentLength;
进度条位置:=百分比;
结束;
//停止下载
如果Fcancel和Http.Connected,则
开始
Http.IOHandler.InputBuffer.Clear;
Http.Disconnect;
Fcancel:=假;
按钮下载。标题:=[下载并安装];
按钮\下载。标签:=0;
进度条位置:=0;
结束;
结束;
过程Tform_update.HttpWorkBegin(ASender:TObject;AWorkMode:TWorkMode;AWorkCountMax:Int64);
开始
如果工作模式为wmRead,则退出;
按钮下载。标签:=1;
按钮下载。标题:==“(取消”);
结束;
过程Tform_update.FormClose(发送方:TObject;var操作:TCloseAction);
开始
Fcancel:=真;
结束;

另一种方法是使用TThread控制执行。大概是这样的:

  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;   
您也可以尝试让Windows处理应用程序的消息

  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;

问题1。印地正在阻塞。所有防冻液都会定期调用windows消息处理。它不会停止Indy的阻塞特性,因此除非您明确地有一种方法来处理错误,否则它不会按照您想要的方式运行。您需要在另一个线程中进行下载,并使用表单监视该线程的状态,而不是尝试依赖防冻剂。不要在该线程中放置任何UI操作,将它们留在主线程中,因此不要尝试从线程中更新进度条。例如,将同步变量设置为进度百分比,并从主线程中的计时器读取该百分比。请记住,UI组件不是线程安全的,因此只能从单个线程更新

问题2。我也看到了。与印第无关。我认为,当您将状态栏设置为100%时,组件不会立即响应,而是尝试平稳地移动到该点(但没有时间)。不过,这只是一个猜测。我不确定。或者可能是防冻剂处理信息的频率,我猜(在这种情况下,这与Indy有关)

第三季度。与Q1完全相同,使用相同的解决方案。放入一个单独的线程,并从主线程监视该线程的状态


一旦将Indy actions移动到单独的线程,就不需要防冻液。

关于Q1和Q2,线程当然更好。如果您决定继续使用Indy防冻液,则应确保将OnlyWhenIdle标志设置为False,以便在工作完成时可以处理消息。

此答案充其量是基本答案。例如,当涉及到非UI线程的UI访问时,必须考虑线程安全性。您显然错过了该站点的工作方式。这是一个问答网站(单数),不是多个问答(复数)。帖子应该包含一个问题。如果您有多个帖子,请创建单独的帖子;您可以随时链接到一个或多个其他网站,以提供参考资料。感谢大家的快速回复!所有答案都很有帮助。我将用线程来完成它@肯怀特:我会记住接下来的问题。