2011. január 10., hétfő

Access and control a NT service


Problem/Question/Abstract:

The unit described in this article show how we can start or stop a NT service by programming, or getting the location of its binary implentation.

Answer:

unit SvcUtils;

// Written by Bertrand Goetzmann (http://www.object-everywhere.com)
// Keywords : Service, OpenSCManager, OpenService, CloseServiceHandle, QueryServiceConfig, StartService, QueryServiceStatus, ControlService

interface

// This function returns the entire path location of the implementation of the given name service
function GetBinaryPathName(const ServiceName: string): string;

// This function starts the service with the given service name
procedure StartService(const ServiceName: string);

// This function stops the service with the given service name
procedure StopService(const ServiceName: string);

implementation

uses SysUtils, WinSvc;

function GetBinaryPathName(const ServiceName: string): string;
var
  SvcMgr, Svc: Integer;
  QuerySvc: TQueryServiceConfig;
  BytesNeeded: Cardinal;

  Buffer: PQueryServiceConfig;
begin
  // Establish a connection to the service control manager
  SvcMgr := OpenSCManager(nil {*MachineName*}, nil {*DatabaseName*},
    SC_MANAGER_ALL_ACCESS);
  try
    if SvcMgr = 0 then
      RaiseLastOSError;

    Svc := OpenService(SvcMgr, PChar(ServiceName), SERVICE_ALL_ACCESS);
    if Svc = 0 then
      RaiseLastOSError;
    try
      // Make a call to know the number of bytes needed
      QueryServiceConfig(Svc, @QuerySvc, 0, BytesNeeded);

      GetMem(Buffer, BytesNeeded);
      try
        if not QueryServiceConfig(Svc, Buffer, BytesNeeded, BytesNeeded) then
          RaiseLastOSError;

        Result := PQueryServiceConfig(Buffer).lpBinaryPathName;
      finally
        FreeMem(Buffer);
      end;
    finally
      CloseServiceHandle(Svc);
    end;
  finally
    CloseServiceHandle(SvcMgr);
  end;
end;

procedure StartService(const ServiceName: string);
var
  SvcMgr, Svc: Integer;
  ServiceArgVectors: PChar;
begin
  // Establish a connection to the service control manager
  SvcMgr := OpenSCManager(nil {*MachineName*}, nil {*DatabaseName*},
    SC_MANAGER_ALL_ACCESS);
  try
    if SvcMgr = 0 then
      RaiseLastOSError;

    Svc := OpenService(SvcMgr, PChar(ServiceName), SERVICE_ALL_ACCESS);
    if Svc = 0 then
      RaiseLastOSError;
    try
      if not WinSvc.StartService(Svc, 0 {*NumServiceArgs*}, ServiceArgVectors) then
        RaiseLastOSError;
    finally
      CloseServiceHandle(Svc);
    end;
  finally
    CloseServiceHandle(SvcMgr);
  end;
end;

procedure StopService(const ServiceName: string);
var
  SvcMgr, Svc: Integer;
  ServiceStatus: _SERVICE_STATUS;
begin
  // Establish a connection to the service control manager
  SvcMgr := OpenSCManager(nil {*MachineName*}, nil {*DatabaseName*},
    SC_MANAGER_ALL_ACCESS);
  try
    if SvcMgr = 0 then
      RaiseLastOSError;

    Svc := OpenService(SvcMgr, PChar(ServiceName), SERVICE_ALL_ACCESS);
    if Svc = 0 then
      RaiseLastOSError;
    try
      // if not QueryServiceStatus(Svc, ServiceStatus) then
      //  RaiseLastOSError;
      // You can test the ServiceStatus.dwCurrentState field

      if not ControlService(Svc, SERVICE_CONTROL_STOP, ServiceStatus) then
        RaiseLastOSError;
    finally
      CloseServiceHandle(Svc);
    end;
  finally
    CloseServiceHandle(SvcMgr);
  end;
end;

end.

FAQ:

As do to register my application as a service?

You can register your service application simply by executing it with the /INSTALL option.

How to pass multi-arguments to StartService?

You can pass some argument with the starting of a service with the call of the StartService function of the Win32 API. The StartService procedure of the SvcUtils unit makes a such call with 0 argument :

WinSvc.StartService(Svc, 0 (*NumServiceArgs*), ServiceArgVectors)

What is RaiseLastOSError?

RaiseLastOSError is a function from the SysUtils unit that permits to raise an exception for the last operating system error or library system error.

I did know how to manage this, but I'm looking for a way to have the list of all installed services. Do you have a solution for that?

I think that the EnumServicesStatus function from the Windows API is the solution.
The function enumerates services in the specified service control manager database. The name and status of each service are provided.

The code looks very nice, but one problem; what is it suposed to do?? Any insight on what this program can do to benefit us would be greatly apprecaited!

On the Windows NT plateform you can look all the installed services by executing MMC (Microsoft Managment Console). All these services can be handled by this GUI application (start, stop, suspend, etc.).
This article show the use of some of the Service Functions from the Window API to do the same things by programming

Nincsenek megjegyzések:

Megjegyzés küldése