Entwickler-Ecke
Windows API - TService - Dienst stoppen/pause geht nicht
holgerbremen - Mi 20.12.06 14:47
Titel: TService - Dienst stoppen/pause geht nicht
Ich habe eine TService-Applikation. Soweit läuft auch alles, jedenfalls installieren und starten kann ich sie.
Nur Stoppen und Pause des Dienstes funktioniert nicht. Die Eigenschaften AllowPause/Stop sind auf true, daran kann es nicht liegen.
Hat jemand eine Ahnung, wo das Problem ist.
Gruß Holger
wdbee - Mi 20.12.06 15:46
Was treibt dein Dienst denn so? Wenn er eine Anforderung zum Stoppen oder zur Pause bekommt, muss er (auch in der Arbeitsschleife) darauf reagieren.
Wir haben auch Dienste, die wir intern verwenden, bei denen das nicht beachtet wird. Nach dem Start bzw. um bestimmte Zeiten legen die los und arbeiten einige Zeit. Während der Bearbeitung reagieren sie nicht auf Stop/Pause. Wenn die Arbeit abgeschlossen ist, dann klappt es.
Als Ergebnis bekommt man eine Fehlermeldung, wenn versucht wird, den Dienst zu beenden.
Da aber klar ist, wann er arbeitet, stört das niemand.
holgerbremen - Mi 20.12.06 16:45
Das Programm erzeugt Timer-Gesteuert alle 60 Sekunden PDF-Dateien. Die Daten werden aus einem MS-SQLServer gelesen. In der Procedure ServiceExecute() mache ich eigentlich gar nichts, außer zu sleepen. Ich versuche den Dienst schon zu stoppen, wenn gerade keine Verarbeitung läuft, aber auch dann gehts nicht.
Kann es an der ServiceExecute()-Funktion liegen.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TTQMSaverFabo.ServiceExecute(Sender: TService); begin
while not Terminated do begin Sleep(200); end;
end; |
Gruß
PS: Wie füge ich hier eigentlich Code ein?
Moderiert von
Tino: Delphi-Tags hinzugefügt
wdbee - Do 21.12.06 11:15
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; |
holgerbremen - Do 21.12.06 15:14
@wdbee
Danke, das war es doch schon. Die Funktion ProcessRequests() fehlte mir noch. Jetzt läßt sich der Service starten/stoppen und pausen.
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:
| procedure TXYZ_Service.ServiceExecute(Sender: TService); begin while not Terminated do begin ServiceThread.ProcessRequests(False); ...
Sleep(200); end;
end; |
Besten Dank noch für das ganze Programmgerüst. Muss ich mir mal in Ruhe anschauen.
Gruß
Holger
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!