I strongly suggest that you look at Example #4 first, as this post only lists the differences between those two examples.
Firstly, we don't need TAsyncHello.Initialize. We'll set initial message text in the constructor. [Admittedly, this is something that can also be done when using IOmniWorker approach.] Message handlers are identical to the Example #4.
TAsyncHello = class(TOmniWorker)
constructor Create(const initialMessage: string);
procedure OMChangeMessage(var msg: TOmniMessage); message MSG_CHANGE_MESSAGE;
procedure OMSendMessage(var msg: TOmniMessage); message MSG_SEND_MESSAGE;
constructor TAsyncHello.Create(const initialMessage: string);
aiMessage := initialMessage;
Secondly, we have to tweak the task creation.
procedure TfrmTestOTL.actStartHelloExecute(Sender: TObject);
TAsyncHello object can now be passed directly to the CreateTask method. There is no need to set the Message parameter. Also new is the FreeOnTerminate call which tells the task manager to destroy the worker object when task is terminated. Alternatively, you can store away the worker object and destroy it "manually" after the FHelloTask is terminated.
The rest of the code does not differ from the Example #4.