Как в консольном приложении получать события от Timer?

В консольном приложении, создаю объект, в котором есть Timer. Но его событие OnTimer не срабатывает и я ни как не пойму, почему?

Project2:

program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils, Unit1 in 'Unit1.pas';
var
  MyObject: TMyObject;
begin
  MyObject := TMyObject.Create;
  Readln;
  FreeAndNil(MyObject);
end.

Unit1:

unit Unit1;
interface
uses
  System.SysUtils, System.Classes, FMX.Types;

type
  TMyObject = class
  protected
    FTimer: TTimer; // class(TFmxObject)
    procedure OnTimer(Sender: TObject);
  public
    constructor Create();
    destructor Destroy; override;
  end;

implementation

constructor TMyObject.Create();
begin
  inherited Create;
  Self.FTimer := TTimer.Create(nil);
  Self.FTimer.Interval := 1000;
  Self.FTimer.OnTimer := OnTimer;
  Self.FTimer.Enabled := True;
end;

procedure TMyObject.OnTimer(Sender: TObject);
begin
  writeln(DateTimeToStr(Now));
end;

destructor TMyObject.Destroy;
begin
  Self.FTimer.Enabled := False;
  FreeAndNil(Self.FTimer);
  inherited;
end;

Ответы (2 шт):

Автор решения: MBo

TTimer работает с использованием сообщения WM_TIMER, которое отправляется в очередь сообщений. А этой очереди у консольного приложения нет. Выход - создать очередь сообщений, запустив цикл выборки и диспетчеризации сообщений. Вариант - использовать свою реализацию таймера, работающую в дополнительном потоке (например, на основе WaitableTimer или просто WaitForMultipleObjects)

Примерно так: (не проверял, мог что-то упустить)

procedure MakeMsgQueue;  //вызвать после запуска таймера
var
   Msg: TMsg;
begin
  while GetMessage(Msg, 0, 0, 0) do begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
end;
→ Ссылка
Автор решения: Lem0nti

Ещё вариант - мультимедиа таймер:

uses
    ...MMSystem...

...

mmResult: MMRESULT;

...

//обработчик таймера
procedure TimeCallBack(TimerID, Msg: Uint; dwUser, dw1, dw2: DWORD); pascal;
begin
  //параметр dw2 будет содержать тот хендл, который выдался при выполнении timeSetEvent
end;

...

mmResult:=timeSetEvent(8000,0,@TimeCallBack,0,TIME_PERIODIC);  //создание таймера

...

timeKillEvent(mmResult);  //удаление таймера
→ Ссылка