Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Reporting Data and Control.

Services

Reporting Data and Control.

by  Glenn9999  Posted    (Edited  )
This FAQ is intended to share some rudimentary code which demonstrates reporting of the services on the system. In addition, it has functions which should work to demonstrate basic tasks regarding setting the service Startup Type and starting and stopping services.

The following code uses the winsvc unit in my Delphi 3 install, but also has additional code which that file didn't support. The following is a unit that I put additional constants and definitions in as well as some of the functions that I have to start and stop services, change service type, and return whether a service is running or not.

Services are viewable in Windows XP in Control Panel/Administrative Tools/Services. Your mileage may vary on this code, especially given the UAC restrictions that are in Vista and Seven. But these should be a good start for those that want to get into the services API to do some basic tasks.

Code:
unit winsvc2;

interface
  uses winsvc, windows;

const
 // A service started automatically by the service control manager during system startup.
  SERVICE_AUTO_START   = $00000002;
// A device driver started by the system loader. This value is valid only for driver services.
  SERVICE_BOOT_START   = $00000000;
//A service started by the service control manager when a process calls the StartService function.
  SERVICE_DEMAND_START = $00000003;
//A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.
  SERVICE_DISABLED =     $00000004;
  SERVICE_SYSTEM_START = $00000001;
  SERVICE_KERNEL_DRIVER       = $00000001;
  SERVICE_FILE_SYSTEM_DRIVER  = $00000002;
  SERVICE_ADAPTER             = $00000004;
  SERVICE_RECOGNIZER_DRIVER   = $00000008;

  SERVICE_DRIVER              =
    (SERVICE_KERNEL_DRIVER or
     SERVICE_FILE_SYSTEM_DRIVER or
     SERVICE_RECOGNIZER_DRIVER);

  SERVICE_WIN32_OWN_PROCESS   = $00000010;
  SERVICE_WIN32_SHARE_PROCESS = $00000020;
  SERVICE_WIN32               =
    (SERVICE_WIN32_OWN_PROCESS or
     SERVICE_WIN32_SHARE_PROCESS);

  SERVICE_INTERACTIVE_PROCESS = $00000100;

  SERVICE_TYPE_ALL            =
    (SERVICE_WIN32 or
     SERVICE_ADAPTER or
     SERVICE_DRIVER  or
     SERVICE_INTERACTIVE_PROCESS);

  // constants for QueryServiceConfig2
  SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3;
  SERVICE_CONFIG_DESCRIPTION = 1;
  SERVICE_CONFIG_FAILURE_ACTIONS = 2;
  SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4;
  SERVICE_CONFIG_PREFERRED_NODE = 9;
  SERVICE_CONFIG_PRESHUTDOWN_INFO = 7;
  SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6;
  SERVICE_CONFIG_SERVICE_SID_INFO = 5;
  SERVICE_CONFIG_TRIGGER_INFO = 8;

type
  // for QueryServiceConfig2, Description.
  TSvcDescription = record
    Length: DWord;
    Desc: array[1..4096] of char;
  end;


function ChangeServiceType(ServiceName: String; TypeID: DWord): Boolean;
function GetServiceStatus(ServiceName: String; ErrorState: Boolean): Boolean;
function StartService2(ServiceName: string): boolean;
function StopService(ServiceName: string): boolean;

function QueryServiceConfig2(hService: THandle; dwInfoLevel: DWord;
      lpBuffer: Pointer; bufsize: DWord; var BytesNeeded: DWord): BOOL;
      stdcall; external 'advapi32.dll' name 'QueryServiceConfig2A';

implementation

function ChangeServiceType(ServiceName: String; TypeID: DWord): Boolean;
// changes service type (eg Automatic, Manual, Disabled)
// returns true if service type successfully changed, false if a problem.
var
  schandle: THandle;
  scService: THandle;
begin
  try
    schandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
    Result := (schandle <> 0);
    if not Result then exit;
    scService := OpenService(schandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);
    Result := (scService <> 0);
    if not Result then exit;
    Result := ChangeServiceConfig(scService, SERVICE_NO_CHANGE, TypeID,
        SERVICE_NO_CHANGE, nil, nil, nil, nil, nil, nil, nil);
    if not Result then exit;
  finally
    CloseServiceHandle(scService);
    CloseServiceHandle(scHandle);
  end;
end;

function GetServiceStatus(ServiceName: String; ErrorState: Boolean): Boolean;
// returns whether the specified service name is started or not.
// ErrorState is true or false based on error.
// Function return is true if service is started, false if service is stopped.
var
  schandle: THandle;
  scService: THandle;
  ServiceStatus: TServiceStatus;
begin
  try
    Result := false;
    schandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
    ErrorState := (schandle = 0);
    if ErrorState then exit;
    scService := OpenService(schandle, PChar(ServiceName), SERVICE_ALL_ACCESS);
    ErrorState := (scService = 0);
    if ErrorState then exit;
    ErrorState := not QueryServiceStatus(scService, ServiceStatus);
    if ErrorState then exit;
    if (ServiceStatus.dwCurrentState <> SERVICE_STOPPED) and
       (ServiceStatus.dwCurrentState <> SERVICE_STOP_PENDING) then
      Result := true
    else
      Result := false;
  finally
    CloseServiceHandle(scService);
    CloseServiceHandle(scHandle);
  end;
end;

function StartService2(ServiceName: string): boolean;
// starts service listed by service name.
// Result true if started, false if not for some reason
var
  schandle: THandle;
  scService: THandle;
  ServiceStatus: TServiceStatus;
  args: PChar;
begin
  try
    schandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
    Result := (schandle = 0);
    if Result then exit;
    scService := OpenService(schandle, PChar(ServiceName), SERVICE_ALL_ACCESS);
    Result := (scService = 0);
    if Result then exit;

    Result := QueryServiceStatus(scService, ServiceStatus);
    if not Result then exit;
    // if service is not stopped, don't bother trying to start it.
    Result := (ServiceStatus.dwCurrentState = SERVICE_STOPPED);
    if not Result then exit;
    // now start service
    args := nil;
    Result := StartService(scService, 0, args);
    if not Result then exit;
    repeat
      QueryServiceStatus(scService, ServiceStatus);
      sleep(20);
    until (ServiceStatus.dwCurrentState <> SERVICE_START_PENDING);
    Result := (ServiceStatus.dwCurrentState = SERVICE_RUNNING);
  finally
    CloseServiceHandle(scService);
    CloseServiceHandle(scHandle);
  end;
end;

function StopDependentServices(scService: THandle): Boolean;
// stops all dependent services for the service handle given, no error checking
type
  TSvcStatus = array[0..512] of TEnumServiceStatus;
  PSvcStatus = ^TSvcStatus;
var
  EnumRec: PSvcStatus;
  bytesNeeded, numservices: integer;
  i: integer;
begin
  New(ENumRec);
  Result := EnumDependentServices(scService, SERVICE_ACTIVE or SERVICE_INACTIVE, ENumRec^[0],
          sizeof(TSvcStatus), BytesNeeded, numServices);
  for i := 0 to NumServices-1 do
    begin
      StopService(String(ENumRec^[i].lpServiceName));
    end;
  Dispose(ENumRec);
end;

function StopService(ServiceName: string): boolean;
// stops service listed by service name.
// Result true if started, false if not for some reason
var
  schandle: THandle;
  scService: THandle;
  ServiceStatus: TServiceStatus;
begin
  try
    schandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
    Result := (schandle = 0);
    if Result then exit;
    scService := OpenService(schandle, PChar(ServiceName), SERVICE_ALL_ACCESS);
    Result := (scService = 0);
    if Result then exit;

    Result := QueryServiceStatus(scService, ServiceStatus);
    if not Result then exit;
    // if service is not started, don't bother trying to start it.
    Result := (ServiceStatus.dwCurrentState = SERVICE_RUNNING);
    if not Result then exit;
    // now stop service, starting with dependent services.
    StopDependentServices(scService);
    // Send a stop code to the service.
    ControlService(scService, SERVICE_CONTROL_STOP, ServiceStatus);
    if not Result then exit;
    repeat
      QueryServiceStatus(scService, ServiceStatus);
      sleep(20);
    until (ServiceStatus.dwCurrentState <> SERVICE_STOP_PENDING);
    Result := (ServiceStatus.dwCurrentState = SERVICE_STOPPED);
  finally
    CloseServiceHandle(scService);
    CloseServiceHandle(scHandle);
  end;
end;

end.

Usage examples:

Code:
var
  ServiceName: string;

ServiceName := 'wuauserv';  // the Automatic Updates service.
ChangeServiceType(ServiceName, SERVICE_DISABLED);  // disable
ChangeServiceType(ServiceName, SERVICE_DEMAND_START); // manual start
ChangeServiceType(ServiceName, SERVICE_AUTO_START); // automatic start

// start a service by name
if StartService2(ServiceName) then
  ShowMessage('Service Is Started')
else
  ShowMessage('Service Is Not Started For Some Reason');

// stop a service by name.
if StopService(ServiceName) then
  ShowMessage('Service Is Stopped')
else
  ShowMessage('Service Is Not Stopped For Some Reason');

Reporting: This is within a VCL app and the button for it is shown below:

Code:
procedure TForm1.Button6Click(Sender: TObject);
{ lists service infos into Memo1.  Should produce the entire list of information that is available in the Windows service applet }
type
  TSvcStatus = array[0..512] of TEnumServiceStatus;
  PSvcStatus = ^TSvcStatus;
var
  ScHandle: THandle;
  lpServices: PSvcStatus;
  BytesNeeded, ServicesReturned, ResumeHandle: DWord;
  i: integer;

  svcHandle: THandle;
  ServiceConfig: TQueryServiceConfig;
  SvcDesc: TSvcDescription;
begin
  Memo1.Clear;
  schandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
//  Result := (schandle <> 0);
  ResumeHandle := 0;
  New(lpServices);
  try
    ENumServicesStatus(ScHandle, SERVICE_WIN32,
           SERVICE_ACTIVE or SERVICE_INACTIVE, lpServices^[0], Sizeof(lpServices^),
           BytesNeeded, ServicesReturned, ResumeHandle);
    for i := 0 to ServicesReturned-1 do
      with lpServices^[i] do
        begin
          Memo1.Lines.Add('Display Name: ' + String(lpDisplayName));
          Memo1.Lines.Add('System Name: ' + String(lpServiceName));
          case ServiceStatus.dwCurrentState of
            SERVICE_STOPPED: Memo1.Lines.Add('Status: Stopped');
            SERVICE_START_PENDING: Memo1.Lines.Add('Status: Startup Pending');
            SERVICE_STOP_PENDING: Memo1.Lines.Add('Status: Stop Pending');
            SERVICE_RUNNING: Memo1.Lines.Add('Status: Running');
            SERVICE_CONTINUE_PENDING: Memo1.Lines.Add('Status: Continue Pending');
            SERVICE_PAUSE_PENDING: Memo1.Lines.Add('Status: Pause Pending');
            SERVICE_PAUSED: Memo1.Lines.Add('Status: Paused');
          else
            Memo1.Lines.Add('Status: Unknown');
          end;
          svcHandle := OpenService(ScHandle, lpServiceName, SERVICE_ALL_ACCESS);
          QueryServiceConfig(svcHandle, ServiceConfig, Sizeof(ServiceConfig), bytesNeeded);
          case ServiceConfig.dwStartType of
             SERVICE_AUTO_START: Memo1.Lines.Add('Startup Type: Auto Start');
             SERVICE_BOOT_START: Memo1.Lines.Add('Startup Type: Boot Start');
             SERVICE_DEMAND_START: Memo1.Lines.Add('Startup Type: Manual');
             SERVICE_DISABLED: Memo1.Lines.Add('Startup Type: Disabled');
             SERVICE_SYSTEM_START: Memo1.Lines.Add('Startup Type: Automatic');
          else
            Memo1.Lines.Add('Startup Type: Unknown');
          end;
          QueryServiceConfig2(svcHandle, SERVICE_CONFIG_DESCRIPTION, @SvcDesc, Sizeof(SvcDesc), bytesNeeded);
          CloseServiceHandle(svcHandle);
          Memo1.Lines.Add('Description: ' + String(SvcDesc.Desc));
          Memo1.Lines.Add('');
          Memo1.Lines.Add('');          
        end;
  finally
    Dispose(lpservices);
    CloseServiceHandle(ScHandle);
  end;
end;

HTH as a good start into services and service control.
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top