I have a Windows service written in Delphi. One of the third-party resources it uses occasionally gets corrupted, and the only way I've found to fix the situation is to exit and restart the program. I can detect when the resource is corrupted from within the program, and I can tell Windows to restart the service after it stops, but I can't figure out how to have the service tell itself to stop.
The program is pretty simple. I created a service application in what seems to be the normal way. I have a subclass of TService to manage the service, while all of the functionality occurs in a separate thread. The TService subclass pretty much just manages the execution of the subthread, and it's in the subthread that I would be detecting the corruption.
For reference, here's the header info for the service and subthread.
type
TScannerThread = class(TThread)
private
Scanner : TScanner;
DefaultDir : String;
ImageDir : String;
procedure CheckScanner;
public
Parent : TComponent;
procedure Execute; override;
end;
TCardScanSvc = class(TService)
procedure ServiceCreate(Sender: TObject);
procedure ServiceExecute(Sender: TService);
procedure ServiceStart(Sender: TService; var Started: Boolean);
procedure ServiceStop(Sender: TService; var Stopped: Boolean);
procedure ServicePause(Sender: TService; var Paused: Boolean);
procedure ServiceContinue(Sender: TService; var Continued: Boolean);
private
ScannerThread : TScannerThread;
public
function GetServiceController: TServiceController; override;
end;
var
CardScanSvc : TCardScanSvc;
In a GUI application, I'd call Application.Terminate, but TServiceApplication doesn't seem to have that method. I can terminate the subthread, but the main thread never notices, and Windows thinks the service is still running. I can't really think of much else to try.
The program was originally created in Delphi 5, and I'm currently using Delphi 2007, in case that makes a difference.
Edit:
With mghie's code, I can stop the service, but Windows will only restart the service if it fails unexpectedly, not if it's stopped normally. What I'm going to do is make a separate service application, have the first signal the second if it has problems, and then have the second restart the first.
-
You should be able to use WMI (Windows Management Instrumentation) to restart a service, even from within the service itself. Don't know if this would cause any strange problems but it should work. Here's an article on doing WMI with Delphi.
UPDATE: Well well, I assumed (my mistake) that there is a single WMI service restart command, such as the button you can click in the services maangement listing. Apparently not.
You could instead write a console app that the service starts when the data is corrupted. The console app would restart the service from a separate process.Rob Kennedy : Don't leave us hanging! What's the WMI command to restart a service? -
There is no problem having the service stop itself - I just tried with one of my own services, written with Delphi 4 (without using the TService class). The following routine works for me:
procedure TTestService.StopService; var Scm, Svc: SC_Handle; Status: SERVICE_STATUS; begin Scm := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS); if Scm <> 0 then begin Svc := OpenService(Scm, PChar(ServiceName), SERVICE_ALL_ACCESS); if Svc <> 0 then begin ControlService(Svc, SERVICE_CONTROL_STOP, Status); // handle Status.... CloseServiceHandle(Svc); end; CloseServiceHandle(Scm); end; end;
You need to check whether it will also work from your worker thread.
0 comments:
Post a Comment