Can TOmniEventMonitor be used in the background thread?

Original question

In our Delphi XE4 application, we use TOmniEventMonitor to receive messages from other tasks. While this works in the main thread, it works fine, but as soon as I put the same code into the task, TOmniEventMonitor stops receiving messages. I included a simple example from this below - clicking the Button_TestInMainThread button causes the file to be written as expected by clicking Button_TestInBackgroundThread, no. Is it by design, or is there some way to make it work while continuing to use TOmniEventMonitor?

unit mainform;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  OtlTask, OtlTaskControl, OtlComm, OtlEventMonitor;

const
  MY_OMNI_MESSAGE = 134;

type
  TOmniEventMonitorTester = class(TObject)
    fName : string;
    fOmniEventMonitor : TOmniEventMonitor;
    fOmniTaskControl : IOmniTaskControl;
    constructor Create(AName : string);
    destructor Destroy(); override;
    procedure HandleOmniTaskMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
  end;

  TTestLauncherTask = class(TOmniWorker)
    fOmniTaskMonitorTester : TOmniEventMonitorTester;
    function Initialize() : boolean; override;
  end;

  TForm1 = class(TForm)
    Button_TestInMainThread: TButton;
    Button_TestInBackgroundThread: TButton;
    procedure Button_TestInMainThreadClick(Sender: TObject);
    procedure Button_TestInBackgroundThreadClick(Sender: TObject);
  private
    fOmniEventMonitorTester : TOmniEventMonitorTester;
    fTestLauncherTask : IOmniTaskControl;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure OmniTaskProcedure_OneShotTimer(const task: IOmniTask);
begin
  Sleep(1000);
  task.Comm.Send(MY_OMNI_MESSAGE);
end;

constructor TOmniEventMonitorTester.Create(AName : string);
begin
  inherited Create();
  fName := AName;
  fOmniEventMonitor := TOmniEventMonitor.Create(nil);
  fOmniEventMonitor.OnTaskMessage := HandleOmniTaskMessage;
  fOmniTaskControl := fOmniEventMonitor.Monitor(CreateTask(OmniTaskProcedure_OneShotTimer)).Run();
end;

destructor TOmniEventMonitorTester.Destroy();
begin
  fOmniEventMonitor.Free();
  inherited Destroy();
end;

procedure TOmniEventMonitorTester.HandleOmniTaskMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
var
  Filename : string;
  F : TextFile;
begin
  Filename := IncludeTrailingPathDelimiter(ExtractFileDir(ParamStr(0))) + fName + '.txt';
  AssignFile(F, Filename);
  Rewrite(F);
  Writeln(F, fName);
  CloseFile(F);
end;

function TTestLauncherTask.Initialize() : boolean;
begin
  result := inherited Initialize();
  if result then begin
    fOmniTaskMonitorTester := TOmniEventMonitorTester.Create('background');
  end;
end;

procedure TForm1.Button_TestInMainThreadClick(Sender: TObject);
begin
  fOmniEventMonitorTester := TOmniEventMonitorTester.Create('main');
end;

procedure TForm1.Button_TestInBackgroundThreadClick(Sender: TObject);
begin
  fTestLauncherTask := CreateTask(TTestLauncherTask.Create()).Run();
end;

end.

Additional observations

TOmniEventMonitor . - IOmniTwoWayChannel , - , , " !", HandleTaskMessage doesn . - , ?

unit mainform;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  DSiWin32, GpLists, OtlTask, OtlTaskControl, OtlCommon, OtlComm, OtlEventMonitor;

const
  MY_OMNI_MESSAGE = 134;

type

  TOmniEventMonitorTestTask = class(TOmniWorker)
    fOmniTaskControl : IOmniTaskControl;
    fOmniTwoWayChannel : IOmniTwoWayChannel;
    fOmniEventMonitor : TOmniEventMonitor;
    function  Initialize() : boolean; override;
    procedure HandleTaskMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
    procedure HandleTaskTerminated(const task: IOmniTaskControl);
  end;

  TForm1 = class(TForm)
    Button_TestInBackgroundThread: TButton;
    procedure Button_TestInBackgroundThreadClick(Sender: TObject);
  private
    fTestTask : IOmniTaskControl;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure OmniTaskProcedure_OneShotTimer(const task: IOmniTask);
begin
  Sleep(1000);
  task.Comm.Send(MY_OMNI_MESSAGE); // don't remove!
  (task.Param['Comm'].AsInterface as IOmniCommunicationEndpoint).Send(MY_OMNI_MESSAGE);
end;

procedure TOmniEventMonitorTestTask.HandleTaskMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
var
  Filename : string;
  F : TextFile;
begin
  Filename := IncludeTrailingPathDelimiter(ExtractFileDir(ParamStr(0))) + 'HandleTaskMessage.txt';
  AssignFile(F, Filename);
  Rewrite(F);
  Writeln(F, 'HandleTaskMessage!');
  CloseFile(F);
end;

procedure TOmniEventMonitorTestTask.HandleTaskTerminated(const task: IOmniTaskControl);
var
  Filename : string;
  F : TextFile;
begin
  Filename := IncludeTrailingPathDelimiter(ExtractFileDir(ParamStr(0))) + 'HandleTaskTerminated.txt';
  AssignFile(F, Filename);
  Rewrite(F);
  Writeln(F, 'HandleTaskTerminated!');
  CloseFile(F);
end;

function TOmniEventMonitorTestTask.Initialize() : boolean;
begin
  result := inherited Initialize();
  if result then begin
    fOmniEventMonitor := TOmniEventMonitor.Create(nil);
    fOmniEventMonitor.OnTaskMessage := HandleTaskMessage;
    fOmniEventMonitor.OnTaskTerminated := HandleTaskTerminated;
    fOmniTwoWayChannel := CreateTwoWayChannel();
    Task.RegisterComm(fOmniTwoWayChannel.Endpoint1); // don't remove!
    fOmniTaskControl := fOmniEventMonitor.Monitor( CreateTask(OmniTaskProcedure_OneShotTimer) ).SetParameter('Comm', fOmniTwoWayChannel.Endpoint2).Run();
  end;
end;

procedure TForm1.Button_TestInBackgroundThreadClick(Sender: TObject);
begin
  fTestTask := CreateTask(TOmniEventMonitorTestTask.Create()).Run();
end;

end.
+4
1

IntmniEventMonitor , , . , . .

procedure TMyThread.Execute;
var
  Message: TMsg;
begin
  FreeOnTerminate := True;
  fOmniEventMonitor := TOmniEventMonitor.Create(nil);
  fOmniEventMonitor.OnTaskMessage := HandleOmniTaskMessage;
  fOmniTaskControl := fOmniEventMonitor.Monitor(CreateTask(OmniTaskProcedure_OneShotTimer)).Run();
  try
    while not Terminated do
    begin
      if MsgWaitForMultipleObjects(0, nil^, False, 1000, QS_ALLINPUT) = WAIT_OBJECT_0 then
      begin
        while PeekMessage(Message, 0, 0, 0, PM_REMOVE) do
        begin
          TranslateMessage(Message);
          DispatchMessage(Message);
        end;
      end;
    end;
  finally
    fOmniTaskControl := nil;
    fOmniEventMonitor.Free;
  end;
end;

, , TOmniTaskExecutor . . TOmniEventMonitor .

TTestLauncherTask.Initialize , . DoNothingProc - .

function TTestLauncherTask.Initialize() : boolean;
begin
  result := inherited Initialize();
  if result then begin
    fOmniTaskMonitorTester := TOmniEventMonitorTester.Create('background');
    // Tell the task about the event monitor
    Task.RegisterWaitObject(fOmniTaskMonitorTester.fOmniEventMonitor.MessageWindow, DoNothingProc);
  end;
end;

TOmniEventMonitor WaitObject, MsgWaitForMultipleObjectsEx , :)

+3

Source: https://habr.com/ru/post/1542871/


All Articles