Inside a TidHTTPServer.OnCommandGet
I create a new object. This Object has a timer that should start immediately but doesnt. The TimerEVent never fires!
When I create the object somewhere else it works...
Some code
TVolumeFader=Class(TObject)
...
constructor TVolumeFader.Create(...);
begin
inherited Create;
...
VolTimer:=TTimer.Create(NIL);
VolTimer.Enabled:=FALSE;
VolTimer.Interval:=100;
VolTimer.OnTimer:=DoTimerTick;
end;
procedure TVolumeFader.DoTimerTick(Sender:TObject);
begin
LogWrite('TimerTick in VolumeFader',Debug);
If Assigned(VolTimer)then Begin;
VolTimer.Enabled:=FALSE;
End;
try
LogWrite('Executing VolumeFade in VolumeFader',Debug);
VolumeFade;
finally
If Assigned(VolTimer)then
VolTimer.Enabled:=TRUE;
end;
end;
procedure TMain.OnCommandGet;
Begin;
TVolumeFader.Create(...);
End;
In your object's constructor, you are creating a TTimer
ok, but you are setting its Enabled
property to False
. So make sure you actually activate the timer once the constructor has exited. Or else change False
to True
in the constructor.
That being said, your code still won't work as shown. This is because TIdHTTPServer
is a multi-threaded component, its OnCommand...
events are fired in the context of worker threads that TIdHTTPServer
creates for itself when clients connect to the server. But TTimer
is a message-based timer, it creates an internal HWND
for itself which is tied to the thread that it is created in, and that thread must have a message loop in order for TTimer
to process WM_TIMER
messages. The worker thread that you are creating your TTimer
in does not have a message loop, so the TTimer
will not be able to fire its OnTimer
event.
So, you will have to either:
OnCommand...
event handler after creating your object, and then free the object before the event handler exits. There is no guarantee that the calling thread will continue running once the OnCommand...
event handler has exited. Just note that the client will be blocked from sending any further HTTP commands to the server while the timer is running:procedure TMain.OnCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
fader: TVolumeFader;
msg: tagMSG;
begin
...
fader := TVolumeFader.Create(...);
try
while (timer should keep running) do
begin
//Application.ProcessMessages;
if PeekMessage(@msg, 0, 0, 0, PM_REMOVE) then
begin
TranslateMessage(@msg);
DispatchMessage(@msg);
end else
Sleep(100);
end;
finally
fader.Free;
end;
...
end;
TTimer
, to your main UI thread, so that your OnTimer
event handler will be fired in the context of that thread rather than in the context of the server's worker thread. Just make sure that your OnTimer
code is thread-safe, if it needs to access anything that is shared with the server:procedure TMain.OnCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
...
TThread.Synchronize(nil, // or TThread.Queue()
procedure
begin
TVolumeFader.Create(...); // when do you destroy this object?
end
);
...
end;