I have a problem with threads in Delphi. When using TIdHashMessageDigest5 in order to get MD5 from a big file, I have noticed that it takes too much time, and ends up in an application freeze.
I'm thinking about using a separate thread. So I have made a little form where I insert a simple message, a button and a progress bar in style pbstMarquee. I start a thread on the show event of this form.
My problem is: I want to close this form when HashStreamAsHex has finished reading successfully, but how can I do this? I tried calling the Close method on synchronize, but then the form is closed without waiting for that thread to finish. I also tried to use the waitfor method, without success.
Someone can help me with this, giving me some example, or link or similar?
Thanks very much and sorry for my bad english.
About form:
-----------
procedure TFormProgress.FormProgressOnShow(Sender: TObject);
begin
ProgressThread := TProgressThread.Create(True);
ProgressThread.Form := FormProgress;
ProgressThread.FileSrc := uFileSrc;
ProgressThread.Start;
end;
About thread:
-------------
procedure TProgressThread.Execute;
begin
FreeOnTerminate := True;
uFileMD5 := GetFileMd5 (uFileSrc) // function is definited in other unit.
Self.WaitFor;
Synchronize(DoSync);
end;
procedure TProgressThread.DoSync;
begin
oForm.Close;
end;
GetFileMd5 è so defined:
function GetFileMD5(const Src: TFileName): UnicodeString;
var
Md5: TIdHashMessageDigest5;
FileSrc: TFileStream;
StrMd5: UnicodeString;
begin
Md5 := TIdHashMessageDigest5.Create;
try
FileSrc := TFileStream.Create(Src, fmOpenRead);
try
StrMd5 := Md5.HashStreamAsHex(FileSrc);
finally
FileSrc.Free;
end;
finally
Md5.Free;
end;
end;
No one has pointed this out, inside the function no value was returned.
function GetFileMD5(const Src: TFileName): UnicodeString;
var
Md5: TIdHashMessageDigest5;
FileSrc: TFileStream;
StrMd5: UnicodeString;
begin
Md5 := TIdHashMessageDigest5.Create;
try
FileSrc := TFileStream.Create(Src, fmOpenRead);
try
StrMd5 := Md5.HashStreamAsHex(FileSrc);
finally
FileSrc.Free;
end;
finally
Md5.Free;
end;
// You are missing this line, calculated md5 was never returned
Result := StrMd5;
end;
In the code you posted, Self.WaitFor
will never return. That waits until the thread has terminated, i.e. its Execute
method has completed. But that can't happen because it stops and waits for itself. You should simply remove the call to WaitFor
.
I also wonder whether or not Close
is the correct way to terminate the form. If it really is a modal form then you should use oForm.ModalResult := mrOK
.
I've just seen your edit which includes the definition of GetFileMD5
. This function doesn't return a value. You should receive a compiler warning telling you of this—read the compiler warnings, they are very valuable. Write GetFileMD5
like this:
function GetFileMD5(const Src: TFileName): string;
var
Md5: TIdHashMessageDigest5;
FileSrc: TFileStream;
begin
Md5 := TIdHashMessageDigest5.Create;
try
FileSrc := TFileStream.Create(Src, fmOpenRead);
try
Result := Md5.HashStreamAsHex(FileSrc);
finally
FileSrc.Free;
end;
finally
Md5.Free;
end;
end;
My guess: the form is opened in Modal mode (form.ShowModal) and there is something that assigns the form.ModalResult before the calculation has completed. This would cause the istantaneus closing of the form.
Maybe did you place a TBitButton having the modalresult propery set to mrOk? if you have done so, pressing that button will close the form as soon as the onClick event handler terminates, no matter if there is a running thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With