I was reading the answer to another question here about the need to run coinitialize and couninitialize to connect to ADO objects. I need to do something similar to perform soap calls in a thread.
Is there a way to override a TThread object to have something automatically run before and after execute inside the thread?
For this example, we're converting to a SOAP backend and have to do a ton of that and it would save a bit of time to just override a new SOAP friendly TThread than to add coinitialize and couninitialze to every thread. But in general, initializing and cleaning up the thread inside the thread sometimes seems like a good idea. Right now it seems like you can only do one or the other.
Perhaps you want something like this:
type
TMyThread = class sealed(TThread)
private
FOnBeforeExecute: TProc;
FOnExecute: TProc;
FOnAfterExecute: TProc;
protected
procedure Execute; override;
public
property OnBeforeExecute: TProc read FOnBeforeExecute write FOnBeforeExecute;
property OnExecute: TProc read FOnExecute write FOnExecute;
property OnAfterExecute: TProc read FOnAfterExecute write FOnAfterExecute;
end;
procedure TMyThread.Execute;
begin
if Assigned(OnBeforeExecute) then
OnBeforeExecute;
try
if Assigned(OnExecute) then
OnExecute;
finally
if Assigned(OnAfterExecute) then
OnAfterExecute;
end;
end;
I made it a sealed class so that you cannot replace Execute
with something that breaks the design. The added benefit is that you can decouple the thread procedure from the implementing class using events.
If you want to take care on specific initialization and finalization doing it with events like in David's answer means that you have to assign those events for every thread you create. And that means either adding a specific constructor to pass them in or creating the threads in suspended mode.
Personally I don't really like having to remember to do all those things and would therefore go for a more polymorphic solution:
type
TInitializeFinalizeThread = class(TThread)
protected
procedure InitializeExecution; virtual;
procedure FinalizeExecution; virtual;
procedure InternalExecute; virtual;
procedure Execute; override;
end;
procedure TInitializeFinalizeThread.Execute;
begin
InitializeExecution;
try
InternalExecute;
finally
FinalizeExecution;
end;
end;
Threads needing to do Ole Stuff could then have a common base that takes care of the initialization and finialization:
type
TOleThread = class(TInitializeFinalizeThread)
protected
procedure InitializeExecution; override;
procedure FinalizeExecution; override;
end;
procedure TOleThread.InitializeExecution;
begin
CoInitialize;
end;
procedure TOleThread.FinalizeExecution;
begin
CoUninitialize;
end;
This means that classes that are actually going to do something can just inherit from TOleThread
and be assured that the initialization and finalization have been taken care of, so they only need to override InternalExecute
.
type
TWordMailMergeThread = class(TInitializeFinalizeThread)
protected
procedure InternalExecute; override;
end;
procedure TWordMailMergeThread.InternalExecute;
begin
// Whatever you need this to do.
end;
Though they are of course free to override the InitializeExecution
and FinalizeExecution
methods to set up and quit the connection to the OleServer (Word in this example) instead of doing it in the InternalExecute
.
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