I'm back to coding Windows applications and I'm using Delphi 10.4. Everything is working: no memory leak, no race conditions, no deadlocks... I'm pretty sure everything is OK but since it's my first time (seriously) using TThread in a Windows application I want to double check that I didn't do something bad!
Code simplified for readability:
type
TDirectoryWorkerThread = class(TThread)
private
Parameters: TDirectoryWorkerParams; //Record
Target: TStrings;
procedure AddToTarget(const Item: String);
procedure ListFilesDir(Directory: String);
public
constructor Create(CreateSuspended: Boolean; Buffer: TStrings; Params: TDirectoryWorkerParams; OnTerminateEvent: TNotifyEvent = nil); overload;
destructor Destroy(); override;
procedure Execute(); override;
end;
TFormMain = class(TForm)
procedure FormDestroy(Sender: TObject);
private
DirWorker: TDirectoryWorkerThread;
function DirWorkerBusy(): Boolean;
procedure DirWorkerFinished(Sender: TObject);
protected
procedure WndProc(var Message: TMessage); override;
implementation
const
APPWM_FREE_DIRWORKER = WM_APP + 1;
constructor TDirectoryWorkerThread.Create(CreateSuspended: Boolean; Buffer: TStrings; Params: TDirectoryWorkerParams; OnTerminateEvent: TNotifyEvent = nil);
begin
inherited Create(CreateSuspended);
if Assigned(OnTerminateEvent) then
Self.OnTerminate := OnTerminateEvent;
//Do more initialization...
Self.Target := Buffer;
end;
destructor TDirectoryWorkerThread.Destroy();
begin
Self.Parameters.AllowedExtensions.Free; //TStringList
inherited;
end;
procedure TDirectoryWorkerThread.Execute;
begin
Self.FreeOnTerminate := False;
ListFilesDir(Self.Parameters.Directory);
end;
procedure TFormMain.DirWorkerFinished(Sender: TObject);
begin
PostMessage(Self.Handle, APPWM_FREE_DIRWORKER, 0, 0);
end;
function TFormMain.DirWorkerBusy(): Boolean;
begin
Result := Self.DirWorker <> nil; //Once finished the worker will send a message to be freed so no need to check for status
end;
procedure TFormMain.DirWorkerFinished(Sender: TObject);
begin
PostMessage(Self.Handle, APPWM_FREE_DIRWORKER, 0, 0);
end;
procedure TFormMain.WndProc(var Message: TMessage);
begin
if Message.Msg = APPWM_FREE_DIRWORKER then
FreeAndNil(Self.DirWorker)
else
inherited;
end;
procedure TFormMain.FormDestroy(Sender: TObject);
begin
if DirWorkerBusy() then
FreeAndNil(Self.DirWorker);
end;
//Thread created on a user event:
Self.DirWorker := TDirectoryWorkerThread.Create(False, ListBoxPrograms.Items, ThreadParams, DirWorkerFinished);
//Thread can be cancelled like this:
if (Key = VK_ESCAPE) and DirWorkerBusy() then
FreeAndNil(Self.DirWorker);