Danke für die Tipps und Hinweise.
Bin ein kleines Stück weiter gekommen.
Da ich während des schreibens abgemeldet wurde, dass ganze nocheinmal.
Ich habe den Code ein wenig an die Hinweise angepasst.
Die Thread-Klasse:
Delphi-Quellcode:
TCustomThread = class(TThread)
strict private
Stream : TFileStream;
StreamSize : Int64;
ReadSize : Int64;
iSize : Integer;
private
FCancel : Boolean;
FFileName : string;
FIsOpen : Boolean;
FOnLog : TLogEvent;
FOnProgress : TProgressEvent;
procedure SetCancel(const Value : Boolean);
procedure SetFileName(const Value : string);
protected
procedure DoLog(Value : string);
procedure DoProgress;
procedure Execute; override;
procedure Extract;
{$IFDEF VER200}
procedure Terminate; reintroduce;
procedure TerminatedSet;
{$ELSE}
procedure TerminatedSet; override;
{$ENDIF}
public
constructor Create; reintroduce;
destructor Destroy; override;
property Cancel : Boolean read FCancel write SetCancel;
property FileName : string read FFileName write SetFileName;
property OnProgress : TProgressEvent read FOnProgress write FOnProgress;
property OnLog : TLogEvent read FOnLog write FOnLog;
end;
constructor TCustomThread.Create;
begin
inherited Create(True);
iSize := 0;
ReadSize := 0;
StreamSize := 0;
FCancel := False;
FFileName := EmptyStr;
FIsOpen := False;
end;
destructor TCustomThread.Destroy;
begin
inherited Destroy;
end;
procedure TCustomThread.Execute;
var
I : Integer;
begin
if not FIsOpen then
begin
Stream := TFileStream.Create(FFileName, fmOpenRead);
FIsOpen:= Stream.Handle <> INVALID_HANDLE_VALUE;
if FIsOpen then
begin
StreamSize := Stream.Size;
I := 10;
while (StreamSize div I) > MaxInteger do
I := I * 10;
iSize := StreamSize div I;
end;
end;
Extract;
end;
procedure TCustomThread.Extract;
var
iRead : Int64;
begin
if FIsOpen then
begin
while (ReadSize <> StreamSize) and (not Terminated) do
begin
iRead:= iSize;
Inc(ReadSize, iRead);
if (StreamSize - ReadSize) < iSize then
iSize := StreamSize - ReadSize;
if Assigned(FOnProgress) then
Synchronize(DoProgress);
Sleep(50);
if (StreamSize = ReadSize) or FCancel then
Terminate;
end;
end;
end;
procedure TCustomThread.TerminatedSet;
begin
if FIsOpen then
begin
Stream.Free;
FIsOpen := False;
iSize := 0;
ReadSize := 0;
StreamSize := 0;
end;
end;
Erzeugt, gestartet und gestoppt wird sie so:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
LogMemo.Lines.Clear;
CT := TCustomThread.Create;
CT.OnProgress := ProgressEvent;
CT.OnLog := LogEvent;
CT.OnTerminate:= TerminateEvent;
end;
procedure TForm1.btnStartClick(Sender: TObject);
begin
if Assigned(CT) then
begin
CT.FileName := EditFile.Text;
{$IFDEF VER200}
CT.Resume;
{$ELSE}
CT.Start;
{$ENDIF}
end;
end;
procedure TForm1.btnCancelClick(Sender: TObject);
begin
if Assigned(CT) and CT.Started then
CT.Cancel := true;
end;
Interessant wird es hier:
Delphi-Quellcode:
procedure TForm1.TerminateEvent(Sender : TObject);
begin
CT.Free;
Log('TerminateEvent');
end;
Setze ich auf CT.Free einen Breakpoint und steppe rein, geht es zu
TCustomThread.Destroy.
Als nächstest wird
TCustomThread.TerminatedSet angesprungen und dort ist FIsOpen = False!
Was ja richtig ist, denn laut System.Classes und Log-Ausgabe wird TerminatedSet doch schon vorher
durch Terminate aufgerufen. Warum also der erneute Aufruf von Destroy?