Einzelnen Beitrag anzeigen

Blamaster

Registriert seit: 20. Jul 2007
230 Beiträge
 
#1

Indy Thread wie Download abbrechen ?

  Alt 13. Mai 2010, 18:36
Hi,

ich komme momentan bei einem kleinen Problem bei abbrechen von Downloads mit IndyThreads nicht weiter.

Vorweg erstmal der Thread Source:

Delphi-Quellcode:
unit ThreadUnit;

interface

uses
  Classes, Dialogs, SysUtils, Windows, IdBaseComponent, IdComponent, IdTCPConnection, IdHTTP;

type
  TWorkBeginEvent = procedure(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64) of object;
  TWorkEvent = procedure(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64) of object;
  TWorkEndEvent = procedure(ASender: TObject; AWorkMode: TWorkMode) of object;

  TDownloadThread = class(TThread)
  private
    { Private-Deklarationen }
    FURL: string;
    FID: string;
    FID_backup: string;
    FFMessage: string;
    FFilePath: string;
    FFileName: string;
    FRsUsername: string;
    FRsPassword: string;
    FWorkCountMax: Integer;
    FWorkCount: Integer;

    Percent: Integer;
    Kb_loaded, Kb_size: LongInt;
    FTime, FBytes: LongWord;
    Speed: Extended;
    //TimeToEnd: string;

    IdHTTPDownload: TIdHTTP;
    filestream: TFileStream;

    procedure ShowStatus;
    procedure ShowEnd;
    procedure Error;
    procedure Successful;
    procedure FWorkBeginEvent(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
    procedure FWorkEvent(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
    function Get_Timestring(Seconds: integer): string;
    function FormatFileSize(const Size: int64): string;
  public
    property ID: string read FID;
    property URL: string read FURL write FURL;
    property FileName: string read FFileName write FFileName;
    property FilePath: string read FFilePath write FFilePath;
    property RsUsername: string read FRsUsername write FRsUsername;
    property RsPassword: string read FRsPassword write FRsPassword;

    procedure Do_Abort;
  protected
    procedure Execute; override;
  end;

implementation

uses
  MainU, GlobalsU;

{ TDownloadThread }


procedure TDownloadThread.Execute;
begin
  IdHTTPDownload := TIdHTTP.Create(nil);

  try
    //Proxy?
    if ProxyEnabled = 'truethen
    begin
      if ProxyServer <> 'then IdHTTPDownload.ProxyParams.ProxyServer := ProxyServer;
      if ProxyPort <> 0 then IdHTTPDownload.ProxyParams.ProxyPort := ProxyPort;
      if ProxyUsername <> 'then IdHTTPDownload.ProxyParams.ProxyUsername := ProxyUsername;
      if ProxyPassword <> 'then IdHTTPDownload.ProxyParams.ProxyPassword := ProxyPassword;
    end;

    IdHTTPDownload.OnWorkBegin := FWorkBeginEvent;
    IdHTTPDownload.OnWork := FWorkEvent;
    IdHTTPDownload.HandleRedirects := True;
    IdHTTPDownload.Request.BasicAuthentication := true;
    IdHTTPDownload.Request.Username := FRsUsername;
    IdHTTPDownload.Request.Password := FRsPassword;

    FID := FFileName;

    filestream := TFileStream.Create(FFilePath + FFileName + '.part', fmCreate);
    //filestream := TFileStream.Create(FFilePath + 'bla' + '.part', fmCreate);

    try
      IdHTTPDownload.Head(FURL);

      if Pos('html', IdHTTPDownload.Response.ContentType) = 0 then
      begin
        IdHTTPDownload.Get(FURL, filestream);
        FreeAndNil(filestream);
        Synchronize(Successful);
      end
      else
        Synchronize(Error);
    except
      on E: Exception do
      begin
        FFMessage := E.Message;
        Synchronize(Error);
      end;
    end;

  finally
    try
      FreeAndNil(IdHTTPDownload);
      FreeAndNil(filestream);
    finally
      Synchronize(ShowEnd);
    end;
  end;

end;


procedure TDownloadThread.FWorkBeginEvent(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
begin
  FWorkCountMax := AWorkCountMax;

  Kb_size := AWorkCountMax div 1024;
  FTime := GetTickCount;
  Fbytes := 0;

  Synchronize(ShowStatus);
end;


procedure TDownloadThread.FWorkEvent(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
  FWorkCount := AWorkCount;

  Kb_loaded := AWorkCount div 1024;
  //Percent := (100 * ((AWorkCount + 1) div 1024)) div (Kb_size + 1);
  Percent := round((100 / FWorkCountMax) * AWorkCount);

  //TimeToEnd := Get_Timestring(Kb_size - (AWorkCount div 1024)) div round(Speed + 1));

  if ((GetTickCount - FTime) >= 300) then
  begin
    try
      Speed := ((AWorkCount - FBytes) / (GetTickCount - FTime));
      FTime := GetTickCount;
      FBytes := AWorkCount;
    except
    end;
  end;

  Synchronize(ShowStatus);
end;


procedure TDownloadThread.ShowStatus;
var
  ID, verbleibend, restzeit, speed_out, percent_out, fortschritt: string;
  progress_position, progress_max: integer;
begin
  ID := FID;
  verbleibend := FormatFileSize(FWorkCountMax - FWorkCount);
  restzeit := Get_Timestring((Kb_size - (FWorkCount div 1024)) div round(Speed + 1));
  speed_out := Format('%.2f KB/s', [Speed]);
  percent_out := IntToStr(Percent) + ' %';
  fortschritt := '';
  progress_position := FWorkCount;
  progress_max := FWorkCountMax;

  frmMain.ThreadStatus(ID, verbleibend, restzeit, speed_out, percent_out, fortschritt, progress_position, progress_max);
end;

procedure TDownloadThread.Do_Abort; // Public procedure wird zum beenden des Downloads aufgerufen
begin
  IdHTTPDownload.Disconnect;
end;

procedure TDownloadThread.Successful;
begin
  frmMain.ThreadSuccessful(FID);
end;

procedure TDownloadThread.ShowEnd;
begin
  FID_backup := FID;
  FID := '';
  frmMain.ThreadEnd(FID_backup);
end;

procedure TDownloadThread.Error;
begin
  frmMain.ThreadError(FID, FURL, FFMessage);
end;


end.
Das Programm startet nun 3 gleichzeitige Downloads die ich nun abbrechen möchte. Das ganze sieht im Hauptprogramm so aus:

Delphi-Quellcode:
procedure TfrmMain.Downloadabbrechen1Click(Sender: TObject);
var
  i: integer;
begin
  try
    if Assigned(IndyThread[i]) then
      IndyThread[i].Do_Abort;
  except
    //
  end;
end;
IndyThread ist dabei als IndyThread: array of TDownloadThread deklariert.

Das ganze funktioniert nun aber extrem unzuverlässig. Beim ersten Klick auf den abbrechen Button geht meist noch alles gut. Wenn dann aber wieder 3 neue Downloads gestartet werden und ich auf abbrechen klicke werden beispielsweise nur zwei beendet und einer läuft normal weiter.

Ein weiteres Problem ist das mal beim abbrechen eine exception abgefangen wird:

Delphi-Quellcode:
    except
      on E: Exception do
      begin
        FFMessage := E.Message;
        Synchronize(Error);
      end;
Sprich Synchronize(Error) auch aufgerufen wird. (So ist es auch gewünscht) Mal scheint beim abbrechen allerdings diese exception garnicht ausgelöst zu werden. Dann springt der Thread die Synchronize(Successful) an.

Hat jemand von euch eine Idee woher diese Probleme kommen können ?

Mfg Yannic
  Mit Zitat antworten Zitat