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