Delphi – Timer queue in Windows service

For Windows services, I need a timer to perform a certain task on a regular basis. Of course, there are many options that seem to be better than timers (multithreaded, calling methods directly from the main thread of the service) , But they all have their shortcomings in this particular case.

However, for obvious reasons, SetTimer() will not work without GUI’s message queue. What I did (In Free Pascal) is the following:

Create a timer:

MyTimerID := SetTimer(0, 0, 3333, @MyTimerProc); 

In the main loop of the service, run the timer queue:

procedure TMyServiceThread.Execute;
var
AMessage: TMsg ;
begin
repeat
// Some calls
if PeekMessage(AMessage, -1, WM_TIMER, WM_TIMER, PM_REMOVE) then begin
TranslateMessage(AMessage);
DispatchMessage(AMessage);
end;
// Some more calls
TerminateEventObject.WaitFor(1000);
until Terminated;
end;

Finally, kill the timer:

KillTimer(0, MyTimerID)

Except that KillTimer always returns False, this works as expected Work.

I’m very interested in your feedback, but if my implementation is correct-I just want to avoid messing up other apps’ messages and other side effects that I don’t know about, because I am Insufficient experience in message processing.

Thank you!

As discussed in the comments, you may not need a timer at all. You can simply use Event wait timeout to create a regular pulse:

while not Terminated do
begin
case TerminateEventObject.WaitFor(Interval) of
wrSignaled:
break;
wrTimeout:
// your periodic work goes here
wrError:
RaiseLastOSError;
end;
end;

The period of the pulse will be the interval plus the time required to complete the work. If you need a specific interval and the work takes a long time, then Remy recommends using a wait timer. p>

At all costs, what you really don’t want to do is to use a message loop-based timer. This is not suitable for services.

For Windows services, I need one Timers are used to periodically perform a certain task. Of course, there are many options that seem to be superior to timers (multi-threaded, calling methods directly from the main thread of the service), but they all have their disadvantages in this particular case.

However, for obvious reasons, SetTimer() will not work without GUI message queue. What I did (in Free Pascal) is the following:

Create Timer:

MyTimerID := SetTimer(0, 0, 3333, @MyTimerProc);

In the main loop of the service, run the timer queue :

procedure TMyServiceThread.Execute;
var
AMessage: TMsg;
begin
repeat
// Some calls
if PeekMessage(AMessage, -1, WM_TIMER, WM_TIMER, PM_REMOVE) the n begin
TranslateMessage(AMessage);
DispatchMessage(AMessage);
end;
// Some more calls
TerminateEventObject.WaitFor(1000);
until Terminated;
end;

Finally, kill the timer:

KillTimer(0, MyTimerID)

Except that KillTimer always returns False, this works as expected.

I am interested in your feedback, but if my implementation is correct-I just want to avoid messing up other applications And other side effects that I don’t know about because I’m inexperienced in message handling.

Thank you!

As discussed in the comments, you may not need a timer at all. You can simply use the timeout of the event wait to create a regular pulse:

while not Terminated do
begin
case TerminateEventObject.WaitFor(Interval) of
wrSignaled:
break;
wrTimeout:
// your periodic work goes here
wrError:
RaiseLastOSError;
end;
end;

The period of the pulse will be The interval plus the time required to complete the work. If you need a specific interval and the work takes a long time, then Remy recommends using a wait timer.

At all costs, you don’t really want to What I did was to use a timer based on a message loop. This is not suitable for services.

Leave a Comment

Your email address will not be published.