Was bei dir fehlt, ist die Bearbeitung von Nachrichten (ProcessRequests).
Das muss über den ServiceThread erfolgen, der dem Dienst zugeordnet ist.
Ein Timer ist nicht notwendig, aber möglich.
Für einfache Fälle:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TXYZ_Service.ServiceExecute(Sender: TService); begin while not Terminated do begin ServiceThread.ProcessRequests(False); ...
Sleep(200); end;
end; |
Das sollte für viele Fälle schon ausreichen. Probleme gibt es, wenn die Arbeit (bzw. ein Durchlauf der while-Schleife) länger dauert, als die Wartezeit des Dienstecontrollers es akzeptiert.
Hier mal ein Gerüst, dass auch für kompliziertere Fälle geeignet ist. Die eigentliche Arbeit erfolgt im Datenmodul (Execute).
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| type TPCbCS_Service = class(TService) procedure ServiceExecute(Sender: TService); private procedure ProcessRequests(Sender: TObject); procedure Terminate;
public function GetServiceController: TServiceController; override; end;
var PCbCS_Service: TPCbCS_Service; |
Wir wollen als erste erfahren, dass der Dienst beendet werden soll. Deshalb schleifen wir uns hier ein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure ServiceController(CtrlCode: DWord); stdcall; begin if CtrlCode = 1 then PCBCS_Service.Terminate; PCBCS_Service.Controller(CtrlCode); end; |
Das was bei dir gefehlt hatte, wird in der eigentlichen Arbeitsschleife des Datenmoduls
zyklisch aufgerufen, so dass der Dienst schnell genug auf Anforderungen des Controllers reagieren kann.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TPCbCS_Service.ProcessRequests(Sender: TObject); begin ServiceThread.ProcessRequests(False); end; |
An dieser Stelle wird die Arbeit einfach delegiert.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TPCbCS_Service.ServiceExecute(Sender: TService); begin DMGlobal.OnProcessRequests := ProcessRequests; DMGlobal.Execute; end; |
Die eigentliche Arbeit ist im Datenmodul bequemer unterzubringen, wenn dort Komponenten abgelegt werden müssen.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| function TDMGlobal.Execute: Boolean; begin while not oTerminated do begin ... if Assigned(OnProcessRequests) then OnProcessRequests(self); if oTerminated then break;
... if Assigned(OnProcessRequests) then OnProcessRequests(self); if oTerminated then break; end;
Result := True; end; |
Anforderung des Controllers umsetzen lassen.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TPCbCS_Service.Terminate; begin DMGlobal.Terminate; end; |
Dabei ist wichtig, dass nicht alle diese Funktionen im gleichen Kontext ausgeführt werden! Der Aufruf von TDMGlobal.Terminate läuft im Kontext des Controllers, weshalb die Anweisung Sleep(xyz) nicht die Arbeitsschleife blockiert.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TDMGlobal.Terminate; begin oTerminated := True; Sleep(xyz); end; |