Solved

How to write a service to restart another service?

Posted on 2001-08-07
24
2,672 Views
Last Modified: 2007-11-27
Hi,
    May I know how to write a NT service to restart another NT service?
    I will give a lot more point for working solution with source code. Thanks a lot.

Yours sincerely,
Mike
0
Comment
Question by:mikemhc
  • 11
  • 10
  • 2
  • +1
24 Comments
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6360350
When and which srevice you want to restart? It is incommon a service to interact with the desktop... I have a client/server program, using Francois Piette's WSocket for TCP/IP, which starts/stops services, queries their state and some othe things. About a year ago. The commands I've implemented are:

CONNECT - connects to Service Control Manager (SCM)
DISCONNECT - disconnects from SCM
START service_name - starts the service 'service_name'
STOP service_name - stops the service 'service_name'
RESTART service_name - restarts the service 'service_name'
QUERY service_name - queries the SCM for service_name's state
DUMP - sends back commands dump

The server is NT service. The client sends commands, receives answers, and can start a thread of Pings to the server.

Rgds,
Frodo
0
 

Author Comment

by:mikemhc
ID: 6361435
Hi Frodo,
    I had one service that still become zombi (not working but is not stop). The service will scanner one folder and read the file and then delete the file it read. When it become zombi, it is just do not scan the folder anymore.
    What I want is a service to scan this folder can find out whether is there any more file left in the folder (if there is file, means the original service had failed). If there is file in that folder, I need to restart the original service.
    Are you able to help me on this? Thanks a lot in advance.

Yours sincerely,
Mike
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6361495
I'm thinking about service that scans the directory for files every X seconds, and if there is a file, restart service Y. Is that what you want? :)

The directory, the period and the zombie-service-name will be in .ini file.

Rgds,
Frodo
0
 

Author Comment

by:mikemhc
ID: 6361560
Hi Frodo,
    That's exactly what I want. Could you help me on that?


Yours sincerely,
Mike
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 6362169
Why a service? For this, I'd prefer using a batch file which issues the NET STOP and NET START commands. With the command AT, you can also shedule it to be done daily or whenever you want.
0
 

Expert Comment

by:New2Delphi
ID: 6362536
Listening...
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6362802
AvonWyss: the .Bat file cannot be started if noone is logged on. The services start nomather the login.
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 6363121
FrodoBeggins: the AT command is a sheduler which runs commands out of a service, so that it IS executed even if noone is logged on.
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6363462
Exactly. But with my own service I have some advantageg. Like I can do whatever I want. Example: write log. Or anything :)

mikemhc: Start Delphi, choose File - New - Service Application. Go to Object Inspector and write 'ZombieServiceRestarter' for Name and DisplaName. Insert a Timer in the service. Make events for ZombieServiceRestarter.ServiceStart and Timer1.Timer. Then paste the folowing in the unit:

0
 
LVL 2

Accepted Solution

by:
FrodoBeggins earned 300 total points
ID: 6363465
unit zService;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs, IniFiles,
  ExtCtrls, WinSvc;

const INI = 'ZService.ini';
      LOG = 'zomb_svc.log';

type
  TZombieServiceRestarter = class(TService)
    Timer1: TTimer;
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure Timer1Timer(Sender: TObject);
  private
    szDir,            // path to the file
    szFMask,          // file mask (e.g. '*.ini'
    szSName : string; // zombie-service name
    function FileIsFound : Boolean;
    procedure RestartService;
  public
    function GetServiceController: TServiceController; override;
    procedure ShowError(szError:String);
  end;

var
  ZombieServiceRestarter: TZombieServiceRestarter;

implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  ZombieServiceRestarter.Controller(CtrlCode);
end;

function TZombieServiceRestarter.FileIsFound: Boolean;
var SearchRec: TSearchRec;
begin
  FileIsFound := False;
  if FindFirst(szDir+szFMask,faAnyFile, SearchRec) = 0 then // file is found!
    FileIsFound := True;
  FindClose(SearchRec);
end;

function TZombieServiceRestarter.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TZombieServiceRestarter.RestartService;
var hSCMan, hService : THandle;
    sss : PChar;
    Err : Integer;
    ssService : TServiceStatus;
begin
  // connect to the SCM
  hSCMan:=OpenSCManager('', Nil, SC_MANAGER_CONNECT);
  if hSCMan<>0 then
    ShowError('Connected to service control manager! '+ #13 + #10)
  else //error occured
  begin
    Err:=GetLastError();
    case err of
      ERROR_ACCESS_DENIED          : ShowError('The requested access was denied. '+ #13 + #10);
      ERROR_DATABASE_DOES_NOT_EXIST : ShowError('The specified database does not exist. '+ #13 + #10);
      ERROR_INVALID_PARAMETER          : ShowError('A parameter that was specified is invalid. '+ #13 + #10)
    else
      ShowError('Could not connect to service control manager!');
      exit;
    end;
  end;

  sss := PChar(szSName);

  // stop the service
  hService:=OpenService(hSCMan, sss, GENERIC_EXECUTE);
  if hService=0 then
  begin
    case GetLastError() of
      ERROR_ACCESS_DENIED              : ShowError('The specified service control manager database handle does not have access to the service.');
      ERROR_INVALID_HANDLE              : ShowError('The specified handle is invalid.');
      ERROR_INVALID_NAME              : ShowError('The specified service name is invalid.');
      ERROR_SERVICE_DOES_NOT_EXIST      : ShowError('The specified service does not exist.');
    else
      ShowError('Error! Could not take service handle.');
    end;
    CloseHandle(hService);
    Exit;
  end;
  if ControlService(hService, SERVICE_CONTROL_STOP, ssService)=False then //error
  begin
    case GetLastError() of
      ERROR_ACCESS_DENIED               : ShowError('The specified handle was not opened with the necessary access.');
      ERROR_DEPENDENT_SERVICES_RUNNING  : ShowError('The service cannot be stopped because other running services are dependent on it.');
      ERROR_INVALID_SERVICE_CONTROL     : ShowError('The requested control code is not valid, or it is unacceptable to the service.');
      ERROR_SERVICE_CANNOT_ACCEPT_CTRL  : ShowError('The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.');
      ERROR_SERVICE_NOT_ACTIVE          : ShowError('The service has not been started.');
      ERROR_SERVICE_REQUEST_TIMEOUT     : ShowError('The service did not respond to the start request in a timely fashion.')
    else
      ShowError('Error! Could not stop service.');
      CloseHandle(hService);
      exit;
    end;
  end
  else
    ShowError('Service stopped.');

  // start the service
  if StartService(hService, 1, sss)=False then //error!
  begin
    case GetLastError() of
      ERROR_ACCESS_DENIED              : ShowError('The specified handle was not opened with SERVICE_START access.');
      ERROR_INVALID_HANDLE              : ShowError('The specified handle is invalid.');
      ERROR_PATH_NOT_FOUND              : ShowError('The service binary file could not be found.');
      ERROR_SERVICE_ALREADY_RUNNING      : ShowError('An instance of the service is already running.');
      ERROR_SERVICE_DATABASE_LOCKED      : ShowError('The database is locked.');
      ERROR_SERVICE_DEPENDENCY_DELETED      : ShowError('The service depends on a service that does not exist or has been marked for deletion.');
      ERROR_SERVICE_DEPENDENCY_FAIL      : ShowError('The service depends on another service that has failed to start.');
      ERROR_SERVICE_DISABLED              : ShowError('The service has been disabled.');
      ERROR_SERVICE_LOGON_FAILED      : ShowError('The service could not be logged on.');
      ERROR_SERVICE_MARKED_FOR_DELETE      : ShowError('The service has been marked for deletion.');
      ERROR_SERVICE_NO_THREAD              : ShowError('A thread could not be created for the Win32 service.');
      ERROR_SERVICE_REQUEST_TIMEOUT      : ShowError('The service did not respond to the start request in a timely fashion.');
    else
      ShowError('Error! Could not start service.');
    end;
  end
  else
    ShowError('Service started.');
  CloseHandle(hService);
  CloseHandle(hSCMan);
end;

procedure TZombieServiceRestarter.ServiceStart(Sender: TService;
  var Started: Boolean);
var FIni : TIniFile;
    Per : integer;
begin
  FIni := TIniFile.Create(INI);
  try
    szDir := FIni.ReadString('OPTIONS', 'Path', 'c:\');
    if Pos('\\\', szDir+'\\')  = 0 then // there is no '\' at the end
      szDir := szDir + '\';
    szSName := FIni.ReadString('OPTIONS', 'SName', 'ServiceName');
    szFMask := FIni.ReadString('OPTIONS', 'FileMask', '*.ini');
    Per := FIni.ReadInteger('OPTIONS', 'Period', 10);
  finally
    FIni.Free;
  end;
  Timer1.Interval:=Per*1000;// in miliseconds!
  ShowError('Started with filowing parameters:');
  ShowError('Path: '+szdir);
  ShowError('FileMask: '+szFMask);
  ShowError('SName: '+szSName);
  ShowError('Period: '+IntToStr(per));
end;

procedure TZombieServiceRestarter.ShowError(szError: String);
var sLog : TStringList;
begin
  sLog := TStringList.Create;
  try
    sLog.LoadFromFile(LOG);
    sLog.Add(DateTimeToStr(NOW)+': '+szError);
    sLog.SaveToFile(LOG);
  finally
    sLog.Free
  end;
end;

procedure TZombieServiceRestarter.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  if FileIsFound then
    RestartService;
  Timer1.Enabled := True;
end;

end.
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6363516
1. Create a file ZService.ini in your windows directory. It should look like this:

[OPTIONS]
Path=c:\
FileMask=*.ini
SName=ServiceName
Period=10

2. create an empty text file called
zomb_svc.log

3. Compile the .exe.

4. Start the .exe file with /INSTALL option

5. Start the service from SCM

5. Enjoy :)


Rgds,
Frodo
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6363537
The ".log" thing can be made better. But it works as it is.
The period in the .ini file is in seconds

You can download the .exe and the source from
http://bygcho.hit.bg/zServ.zip

Rgds,
Frodo
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:mikemhc
ID: 6364627
Thanks a lot. I am going to try. Once again, thanks a lot.

Yours sincerely,
Mike
0
 

Author Comment

by:mikemhc
ID: 6526196
Hi Frodo,
    Sorry for such a long delay. I haven't got time to test out this program. I followed your instruction and I managed to compile and install the service but I am not able to start the service. I tested it on Win 2k professional. I got the error message saying:
Microsoft Management Console:
Could not start the ZombieService Restarter service on Local Computer. The service did not return an error. This could be an internal Windows error or an internal service error. If the problem persists, contact your system administrator.
    Then there is an 'ok' button.
    Please advice on what went wrong. Thanks a lot.

Yours sincerely,
Mikemhc
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6529680
Have you made ZService.ini and zomb_svc.log files? As long as I remember it was some of them missing when I got that error...
0
 

Author Comment

by:mikemhc
ID: 6530036
Frodo,
    I found out that it because I didn't turn on the interactive with desktop. Now, the problem is resolved. The problem now is that the timer is not working. So, I used sleep instead in the onExecute event. One thing bad about the sleep is that the service can not be stopped. Any idea why this happens? After I use sleep(), I can restart service with display name on Service MMC without space char. For those services with space in their display name, I can not restart it.
    Please help me on these problem.

Yours sincerely,
Mike
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6530056
Hey, man, with the source given you DO NOT NEED interacting with desktop. If you change the ShowError method to do some ShowMessage then you'll need it.

Now I see i don't enable the timer at the first start. You may put
Timer1.Enabled := True;
at the end of TZombieServiceRestarter.ServiceStart. Then evetyrhing should be ok.

Rgds,
Frodo
0
 

Author Comment

by:mikemhc
ID: 6534289
Hi Frodo,
    I can't download the program from the website you specified above.
    My timer is already enable. I need to download the files and see what is the difference.
    Can you tell me how to restart service with space in the service display name? After I change to sleep method (although it has bugs, it can restart service like 'messenger' but not service with space in the service name like 'Fax Service'. I can use command prompt 'net start "Fax Service"' to restart the service but not the program.
    Please advice. Thanks

Yours sincerely,
Mike
0
 

Author Comment

by:mikemhc
ID: 6534319
Hi Frodo,
    I can't download the program from the website you specified above.
    My timer is already enable. I need to download the files and see what is the difference.
    Can you tell me how to restart service with space in the service display name? After I change to sleep method (although it has bugs, it can restart service like 'messenger' but not service with space in the service name like 'Fax Service'. I can use command prompt 'net start "Fax Service"' to restart the service but not the program.
    Please advice. Thanks

Yours sincerely,
Mike
0
 

Author Comment

by:mikemhc
ID: 6534355
Hi Frodo,
    I can't download the program from the website you specified above.
    My timer is already enable. I need to download the files and see what is the difference.
    Can you tell me how to restart service with space in the service display name? After I change to sleep method (although it has bugs, it can restart service like 'messenger' but not service with space in the service name like 'Fax Service'. I can use command prompt 'net start "Fax Service"' to restart the service but not the program.
    Please advice. Thanks

Yours sincerely,
Mike
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6535279
 Mike,
  I think "Fax service" is not the real name of the service, but the display name.
  I can download th zip with no problems. Maybe it iz because I'm in BG, hit.bg is in BG and you are in USA. I'll email it to you.

  Rgds,
  Frodo
0
 
LVL 2

Expert Comment

by:FrodoBeggins
ID: 6535284
 If you give me your e-mail :)
  Rgds,
  Frodo
0
 

Author Comment

by:mikemhc
ID: 6536183
Hi Frodo,
    My email account is mikemhc@hotmail.com.
    Can you tell me how to get the name of the service, please? Some how, I can use 'net start' or 'net stop' command on dos prompt to start and stop using the service display name in the 'services' mmc.

Yours sincerely,
Mike
0
 

Author Comment

by:mikemhc
ID: 6624787
Hi,
    Sorry for taking so long as I am amateur. I tested it and it is working now. Thanks a lot.

Yours sincerely,
Mike
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now