Hello,
I don't know the possibilities offered by Lazarus/FPC, but if your application is intended to run only on Windows, you could use Events in a dedicated thread (using only the Windows API).
For instance, this is a quick sample for a console program, emulating the function of a timer with this kind of solution. I guess it should also work the same way in a windows service.
program ttest;
{$mode objfpc}{$H+}
uses Windows;
const TIMER_INTERVAL = 5000; // (ms)
const TIMER_NBREVENTS = 1; // Number of External Events to look for in the Timer Thread (Only 1 in this sample)
const TIMER_MAXTICKS = 4; // Maximum Number of Timer Ticks (To simulate a way to exit from the test program)
var
HandEvGloEnd: Longword = 0; // Handle for Event : Global End
HandEvReqEnd: Longword = 0; // Handle for Event : Request End
HandleThread: Longword = 0; // Handle for Timer Thread
NbrTimerTicks: Integer = 0; // Current Number of Timer Ticks
// Called on Each Timer Tick
procedure ProcToCall();
begin
Writeln('Timer Tick');
Inc(NbrTimerTicks);
if NbrTimerTicks>=TIMER_MAXTICKS then
SetEvent(HandEvGloEnd); // Ask to quit the main infinite waiting
end;
function TimerThread(PP: Pointer): Integer;
var ArrEvHandle: array [0..Pred(TIMER_NBREVENTS)] of Longword; // Array of Events to Look for
begin
ArrEvHandle[0]:=HandEvReqEnd;
while True do
begin
Write('Waiting ... ');
WaitForMultipleObjects(TIMER_NBREVENTS,@ArrEvHandle,False,TIMER_INTERVAL);
if WaitforSingleObject(HandEvReqEnd,0)<>WAIT_TIMEOUT then // Request to End ?
begin
Writeln('No more waiting');
Break;
end;
ProcToCall();
end;
Result:=0;
EndThread(0);
end;
procedure StartTimerThread();
var i1: Longword;
begin
Writeln();
Writeln('Start Timer Thread');
HandEvReqEnd:=CreateEvent(Nil,True,False,PChar('MyEventNames_ReqEnd'));
HandleThread:=BeginThread(Nil,0,TThreadFunc(@TimerThread),Nil,0,i1);
end;
procedure StopTimerThread(Const ExitForced: Integer);
begin
Writeln('Stop Timer Thread');
if ExitForced=0 then
begin
SetEvent(HandEvReqEnd);
WaitForSingleObject(HandleThread,3000); // Wait 3s mawimum for the "real" ending of the thread (it should be quite enough)
end;
CloseHandle(HandEvReqEnd);
CloseHandle(HandleThread);
end;
begin
HandEvGloEnd:=CreateEvent(Nil,True,False,PChar('MyEventNames_GloEnd'));
StartTimerThread();
WaitforSingleObject(HandEvGloEnd,INFINITE); // Simulate an infinite waiting
StopTimerThread(0);
CloseHandle(HandEvGloEnd);
end.
Here, a dedicated timer thread is created, which is responsible of calling various functions (only 1 function in this sample) each time it falls down (5s interval in this sample).
For the sample purposes, the main program simulates a infinite waiting, and finally ends after 4 timer ticks. Note that all this part in only for the sample purposes, and has nothing to do really with the timer thread itself.
The most important thing in this sample, is the fact that the concerned targeted function (i.e. ProcToCall) is called on each timer ticks (each 5s here).
To make it simple, there are no controls made on the return values given by the Windows API: which is of course quite incorrect. They should be always be tested. For instance:
...
MyEvent:=CreateEvent( ... Parameters... );
if MyEvent=0 then // Error
begin
// Code To Process The Error
end
...
[code]
**Edit**: code modified for a better comprehension.