ServiceManager.pas

Top  Previous  Next

 

unit ServiceStarter;

 

interface

 

uses

WinSvc, Windows, Messages, SysUtils, Classes;

 

type

TServiceState = (svsStopped, svsStarting, svsStopping, svsRunning, scvContinueing, svsPausing, svsPaused);

 

TServiceStarter = class(TComponent)

private

FSCHandle: THandle;

FState: TServiceState;

FServiceName: string;

FHandle: THandle;

FMachineName: string;

FActive: Boolean;

procedure SetState(const Value: TServiceState);

function GetState: TServiceState;

procedure SetServiceName(const Value: string);

procedure SetMachineName(const Value: string);

function GetHandle: THandle;

procedure SetActive(const Value: Boolean);

procedure CloseDependendServices(Handle: THandle);

{ Private declarations }

protected

{ Protected declarations }

procedure CloseHandle;

procedure CloseHandleSC;

procedure HandleNeeded;

public

{ Public declarations }

destructor Destroy; override;

property Handle: THandle read GetHandle;

published

{ Published declarations }

property ServiceName: string read FServiceName write SetServiceName;

property MachineName: string read FMachineName write SetMachineName;

property State: TServiceState read GetState write SetState;

property Active: Boolean read FActive write SetActive;

end;

 

procedure Register;

 

implementation

 

procedure Register;

begin

RegisterComponents('AppGadgets', [TServiceStarter]);

end;

 

{ TServiceStarter }

 

 

procedure TServiceStarter.CloseHandle;

begin

if FHandle <> 0 then

begin

CloseServiceHandle(FHandle);

FHandle := 0;

end;

end;

 

procedure TServiceStarter.CloseHandleSC;

begin

if FSCHandle <> 0 then

begin

CloseServiceHandle(FSCHandle);

FSCHandle := 0;

end;

end;

 

destructor TServiceStarter.Destroy;

begin

CloseHandle;

inherited;

end;

 

function TServiceStarter.GetHandle: THandle;

begin

HandleNeeded;

Result := FHandle;

end;

 

function TServiceStarter.GetState: TServiceState;

var

ServiceStatus: TServiceStatus;

begin

if FActive then

begin

if (FServiceName = '') then

begin

Result := svsStopped;

Exit;

end;

HandleNeeded;

if not QueryServiceStatus(FHandle, ServiceStatus) then

RaiseLastOSError;

Result := TServiceState(ServiceStatus.dwCurrentState - 1);

end

else

Result := FState;

end;

 

procedure TServiceStarter.HandleNeeded;

begin

if FHandle = 0 then

begin

if FSCHandle = 0 then

begin

FSCHandle := OpenSCManager(Pointer(FMachineName), nil, GENERIC_EXECUTE);

if FSCHandle = 0 then

RaiseLastOSError;

end;

FHandle := OpenService(FSCHandle, PChar(FServiceName), GENERIC_EXECUTE+SERVICE_QUERY_STATUS+SERVICE_ENUMERATE_DEPENDENTS);

if FHandle = 0 then

RaiseLastOSError;

end;

end;

 

 

procedure TServiceStarter.SetActive(const Value: Boolean);

begin

if FActive = Value then

Exit;

 

FActive := Value;

if FActive then

State := FState

else

begin

CloseHandle;

CloseHandleSC;

end;

end;

 

procedure TServiceStarter.SetMachineName(const Value: string);

begin

if FMachineName = Value then

Exit;

 

CloseHandle;

 

FMachineName := Value;

end;

 

procedure TServiceStarter.SetServiceName(const Value: string);

begin

if FServiceName = Value then

Exit;

 

CloseHandle;

CloseHandleSC;

 

FServiceName := Value;

end;

 

procedure TServiceStarter.CloseDependendServices(Handle: THandle);

type

TEnumServiceStatusArray = array[0..$FFFF] of TEnumServiceStatus;

PEnumServiceStatusArray = ^TEnumServiceStatusArray;

var

Ok: boolean;

DependendHandle: THandle;

I: Integer;

ServicesCount: Cardinal;

NeededBytes: Cardinal;

DependendServices : PEnumServiceStatusArray;

ServiceStatus: TServiceStatus;

begin

NeededBytes := 1 * SizeOf(TEnumServiceStatusArray);

Ok := True;

GetMem(DependendServices, NeededBytes);

while not EnumDependentServices(Handle, SERVICE_ACTIVE, DependendServices^[0], NeededBytes, NeededBytes, ServicesCount) do

begin

if GetLastError = ERROR_MORE_DATA then

begin

FreeMem(DependendServices);

Ok:= False;

GetMem(DependendServices, NeededBytes);

end

else

RaiseLastOSError;

end;

for I := 0 to ServicesCount - 1 do

with DependendServices^[I] do

begin

DependendHandle := OpenService(FSCHandle, lpServiceName, GENERIC_EXECUTE+SERVICE_QUERY_STATUS+SERVICE_ENUMERATE_DEPENDENTS);

while not ControlService(DependendHandle, SERVICE_CONTROL_STOP, ServiceStatus) do

case GetLastError of

ERROR_DEPENDENT_SERVICES_RUNNING:

CloseDependendServices(DependendHandle);

ERROR_SERVICE_NOT_ACTIVE:

Break;

ERROR_SERVICE_CANNOT_ACCEPT_CTRL: ;

else

RaiseLastOSError;

end;

CloseServiceHandle(DependendHandle);

end;

FreeMem(DependendServices);

end;

 

procedure TServiceStarter.SetState(const Value: TServiceState);

const

{

SERVICE_CONTROL_STOP

Requests the service to stop. The hService handle must have SERVICE_STOP access.

SERVICE_CONTROL_PAUSE

Requests the service to pause. The hService handle must have SERVICE_PAUSE_CONTINUE access.

SERVICE_CONTROL_CONTINUE

Requests the paused service to resume. The hService handle must have SERVICE_PAUSE_CONTINUE access.

SERVICE_CONTROL_INTERROGATE

Requests the service to update immediately its current status information to the service control manager. The hService handle must have SERVICE_INTERROGATE access.

SERVICE_CONTROL_SHUTDOWN

}

StateControlMap: array[TServiceState] of Integer = (SERVICE_CONTROL_STOP, SERVICE_CONTROL_CONTINUE, SERVICE_CONTROL_STOP, SERVICE_CONTROL_CONTINUE, SERVICE_CONTROL_CONTINUE, SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_PAUSE);

var

Error: Cardinal;

StateSet: boolean;

Arg: PChar;

ServiceStatus: TServiceStatus;

begin

FState := Value;

if Active then

begin

HandleNeeded;

Arg := nil;

StateSet := False;

// svsStopped, svsStarting, svsStopping, svsRunning, scvContinueing, svsPausing, svsPaused

repeat

if not ControlService(FHandle, StateControlMap[Value], ServiceStatus) then

begin

Error := GetLastError;

case Error of

ERROR_SERVICE_CANNOT_ACCEPT_CTRL:

begin

Sleep(10);

end;

ERROR_SERVICE_NOT_ACTIVE:

if not (Value in [svsStopped, svsStopping]) then

begin

if not StartService(FHandle, 0, Arg) then

begin

Error := GetLastError;

if Error <> ERROR_SERVICE_CANNOT_ACCEPT_CTRL then

RaiseLastOSError

else

Sleep(10);

end;

StateSet := Value in [svsRunning, scvContinueing];

end

else

StateSet := True;

ERROR_DEPENDENT_SERVICES_RUNNING:

CloseDependendServices(FHandle);

else

RaiseLastOSError;

end;

end

else

StateSet := True;

until StateSet;

end;

end;

 

end.

 

 

 

2.

 

unit ServiceManager;

 

interface

 

uses

  SysUtils, Windows, WinSvc;

 

type

 

  TServiceManager = class

  private

    { Private declarations }

    ServiceControlManager: SC_Handle;

    ServiceHandle: SC_Handle;

  protected

    function DoStartService(NumberOfArgument: DWORD; ServiceArgVectors: PChar): Boolean;

  public

    { Public declarations }

    function Connect(MachineName: PChar = nil; DatabaseName: PChar = nil;

      Access: DWORD = SC_MANAGER_ALL_ACCESS): Boolean;  // Access may be SC_MANAGER_ALL_ACCESS

    function OpenServiceConnection(ServiceName: PChar): Boolean;

    function StartService: Boolean; overload; // Simple start

    function StartService(NumberOfArgument: DWORD; ServiceArgVectors: PChar): Boolean;

      overload; // More complex start

    function StopService: Boolean;

    procedure PauseService;

    procedure ContinueService;

    procedure ShutdownService;

    procedure DisableService;

    function GetStatus: DWORD;

    function ServiceRunning: Boolean;

    function ServiceStopped: Boolean;

  end;

 

implementation

 

{ TServiceManager }

 

function TServiceManager.Connect(MachineName, DatabaseName: PChar;

  Access: DWORD): Boolean;

begin

  Result := False;

  { open a connection to the windows service manager }

  ServiceControlManager := OpenSCManager(MachineName, DatabaseName, Access);

  Result := (ServiceControlManager <> 0);

end;

 

 

function TServiceManager.OpenServiceConnection(ServiceName: PChar): Boolean;

begin

  Result := False;

  { open a connetcion to a specific service }

  ServiceHandle := OpenService(ServiceControlManager, ServiceName, SERVICE_ALL_ACCESS);

  Result := (ServiceHandle <> 0);

end;

 

procedure TServiceManager.PauseService;

var

  ServiceStatus: TServiceStatus;

begin

  { Pause the service: attention not supported by all services }

  ControlService(ServiceHandle, SERVICE_CONTROL_PAUSE, ServiceStatus);

end;

 

function TServiceManager.StopService: Boolean;

var

  ServiceStatus: TServiceStatus;

begin

  { Stop the service }

  Result := ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus);

end;

 

procedure TServiceManager.ContinueService;

var

  ServiceStatus: TServiceStatus;

begin

  { Continue the service after a pause: attention not supported by all services }

  ControlService(ServiceHandle, SERVICE_CONTROL_CONTINUE, ServiceStatus);

end;

 

procedure TServiceManager.ShutdownService;

var

  ServiceStatus: TServiceStatus;

begin

  { Shut service down: attention not supported by all services }

  ControlService(ServiceHandle, SERVICE_CONTROL_SHUTDOWN, ServiceStatus);

end;

 

function TServiceManager.StartService: Boolean;

begin

  Result := DoStartService(0, '');

end;

 

function TServiceManager.StartService(NumberOfArgument: DWORD;

  ServiceArgVectors: PChar): Boolean;

begin

  Result := DoStartService(NumberOfArgument, ServiceArgVectors);

end;

 

function TServiceManager.GetStatus: DWORD;

var

 ServiceStatus:Â TServiceStatus;

begin

{ Returns the status of the service. Maybe you want to check this

  more than once, so just call this function again.

  Results may be: SERVICE_STOPPED

                  SERVICE_START_PENDING

                  SERVICE_STOP_PENDING

                  SERVICE_RUNNING

                  SERVICE_CONTINUE_PENDING

                  SERVICE_PAUSE_PENDING

                  SERVICE_PAUSED   }

  Result := 0;

  QueryServiceStatus(ServiceHandle, ServiceStatus);

  Result := ServiceStatus.dwCurrentState;

end;

 

procedure TServiceManager.DisableService;

begin

  { Implementation is following... }

end;

 

function TServiceManager.ServiceRunning: Boolean;

begin

  Result := (GetStatus = SERVICE_RUNNING);

end;

 

function TServiceManager.ServiceStopped: Boolean;

begin

  Result := (GetStatus = SERVICE_STOPPED);

end;

 

function TServiceManager.DoStartService(NumberOfArgument: DWORD;

  ServiceArgVectors: PChar): Boolean;

var

  err: integer;

begin

  Result := WinSvc.StartService(ServiceHandle, NumberOfArgument, ServiceArgVectors);

end;

 

end.