In meiner Software UpdateRepair war es nötig bestimmte Windows-Dienste zu steuern. Das heißt Dienst starten, beenden und konfigurieren. Zu diesem Zweck habe ich mir eine Klasse geschrieben.
Download Klasse – Unit – Download Demo App – Download Demo Code
Die Anwendung ist denkbar einfach:
// Via statische Methoden
TCsWindowsService.Start('Dienst name');
TCsWindowsService.Stop('Dienst name');
TCsWindowsService.Restart('Dienst name');
oder
// Via Klassen-Instanz
var
WinService : TCsWindowsService;
begin
WinService := TCsWindowsService.Create('Dienst Name');
try
WinService.Start;
WinService.Stop;
WinService.Restart;
finally
FreeAndNil(WinService);
end;
end;
Die Unit „CapSystems.Framework.Windows.Service.pas“:
unit CapSystems.Framework.Windows.Service;
interface
uses
SysUtils, Classes, Windows, WinSvc;
type
TCsWindowsService = class;
{ -------------------------------------------------------------------------- }
{ Enumeratoren ------------------------------------------------------------- }
{ -------------------------------------------------------------------------- }
TCsWindowsServiceStartMode = (
wssmDisabled,
wssmAuto,
wssmAutoDelay,
wssmManual
);
{ -------------------------------------------------------------------------- }
{ TCsWindowsService -------------------------------------------------------- }
{ -------------------------------------------------------------------------- }
TCsWindowsService = class(TPersistent)
const
SERVICES_REGISTRY_ROOT = HKEY_LOCAL_MACHINE;
SERVICES_REGISTRY_PATH = '\SYSTEM\CurrentControlSet\services\';
SERVICES_REGISTRY_STARTMODE_AUTO = 2;
SERVICES_REGISTRY_STARTMODE_AUTODELAY = 2;
SERVICES_REGISTRY_STARTMODE_MANUEL = 3;
SERVICES_REGISTRY_STARTMODE_DISABLED = 4;
private
FName: String;
FDescription: String;
FStartMode: TCsWindowsServiceStartMode;
FImagePath: String;
FDisplayName: String;
protected
class function StartModeToDWORD(AStartMode: TCsWindowsServiceStartMode): DWORD;
public
constructor Create(AServiceName: String;
ALoadProperties: Boolean = False);
class procedure OpenServices; virtual;
class procedure LoadServiceProperties(AName: string; var ADisplayName: string;
var ADescription: string; var AImagePath: string;
var AStartMode: TCsWindowsServiceStartMode); overload;
procedure LoadServiceProperties; overload;
class function Start(AName: String): Boolean; overload;
function Start: Boolean; overload;
class function Stop(AName: String): Boolean; overload;
function Stop: Boolean; overload;
class function Restart(AName: String): Boolean; overload;
function Restart: Boolean; overload;
class function IsRunning(AName: String): Boolean; overload;
function IsRunning: Boolean; overload;
class function SetStartMode(AName: String;
AStartMode: TCsWindowsServiceStartMode): Boolean; overload;
function SetStartMode(
AStartMode: TCsWindowsServiceStartMode): Boolean; overload;
class function GetStartMode(AName: String): TCsWindowsServiceStartMode; overload;
published
property Name: String read FName;
property StartMode: TCsWindowsServiceStartMode read FStartMode;
property Description: String read FDescription;
property ImagePath: String read FImagePath;
property DisplayName: String read FDisplayName;
end;
implementation
uses
Registry,
CapSystems.Framework.Windows.Process,
CapSystems.Framework.FileSystem;
{ ---------------------------------------------------------------------------- }
{ TCsService------------------------------------------------------------------ }
{ ---------------------------------------------------------------------------- }
constructor TCsWindowsService.Create(AServiceName: string;
ALoadProperties: Boolean = False);
begin
inherited Create;
FName := AServiceName;
if ALoadProperties then
Self.LoadServiceProperties;
end;
class procedure TCsWindowsService.OpenServices;
begin
//TCsProcess.Start('msc.exe', 'open', 'services.msc');
TCsProcess.Start(TCsPath.GetSystemRootDirectory + 'services.msc');
end;
class procedure TCsWindowsService.LoadServiceProperties(AName: string;
var ADisplayName: string; var ADescription: string; var AImagePath: string;
var AStartMode: TCsWindowsServiceStartMode);
begin
//
end;
procedure TCsWindowsService.LoadServiceProperties;
begin
Self.LoadServiceProperties(
FName,
FDisplayName,
FDescription,
FImagePath,
FStartMode
);
end;
class function TCsWindowsService.StartModeToDWORD(
AStartMode: TCsWindowsServiceStartMode): DWORD;
begin
Result := Self.SERVICES_REGISTRY_STARTMODE_DISABLED;
case AStartMode of
wssmAuto: Result := Self.SERVICES_REGISTRY_STARTMODE_AUTO;
wssmAutoDelay: Result := Self.SERVICES_REGISTRY_STARTMODE_AUTODELAY;
wssmManual: Result := Self.SERVICES_REGISTRY_STARTMODE_MANUEL;
end;
end;
class function TCsWindowsService.Start(AName: string): Boolean;
var
SCManager, SCService: THandle;
ServiceStatus: TServiceStatus;
p: PChar;
begin
Result := False;
SCManager := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SCManager = 0 then Exit;
try
SCService := OpenService(SCManager, PChar(AName),
SERVICE_START or SERVICE_STOP or SERVICE_QUERY_STATUS);
if SCService = 0 then Exit;
try
ZeroMemory(@ServiceStatus, SizeOf(ServiceStatus));
p := nil;
if StartService(SCService, 0, p) then
begin
// warten bis der Service gestartet ist
repeat
if not QueryServiceStatus(SCService, ServiceStatus) then Break;
until ServiceStatus.dwCurrentState <> SERVICE_START_PENDING;
end else Exit;
Result := True;
finally
CloseServiceHandle(SCService);
end;
finally
CloseServiceHandle(SCManager);
end;
end;
function TCsWindowsService.Start: Boolean;
begin
Result := Self.Start(FName);
end;
class function TCsWindowsService.Stop(AName: string): Boolean;
var
SCManager, SCService: THandle;
ServiceStatus: TServiceStatus;
p: PChar;
begin
Result := False;
SCManager := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SCManager = 0 then Exit;
try
SCService := OpenService(SCManager, PChar(AName),
SERVICE_START or SERVICE_STOP or SERVICE_QUERY_STATUS);
if SCService = 0 then Exit;
try
ZeroMemory(@ServiceStatus, SizeOf(ServiceStatus));
// Service beenden
if not ControlService(SCService, SERVICE_CONTROL_STOP, ServiceStatus) then
begin
if GetLastError <> ERROR_SERVICE_NOT_ACTIVE then Exit;
end else
begin
// warten bis der Service beendet ist
repeat
if not QueryServiceStatus(SCService, ServiceStatus) then Break;
until ServiceStatus.dwCurrentState <> SERVICE_STOP_PENDING;
end;
Result := True;
finally
CloseServiceHandle(SCService);
end;
finally
CloseServiceHandle(SCManager);
end;
end;
function TCsWindowsService.Stop: Boolean;
begin
Result := Self.Stop(FName);
end;
class function TCsWindowsService.Restart(AName: string): Boolean;
var
SCManager, SCService: THandle;
ServiceStatus: TServiceStatus;
p: PChar;
begin
Result := False;
SCManager := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SCManager = 0 then Exit;
try
SCService := OpenService(SCManager, PChar(AName),
SERVICE_START or SERVICE_STOP or SERVICE_QUERY_STATUS);
if SCService = 0 then Exit;
try
ZeroMemory(@ServiceStatus, SizeOf(ServiceStatus));
// Service beenden
if not ControlService(SCService, SERVICE_CONTROL_STOP, ServiceStatus) then
begin
if GetLastError <> ERROR_SERVICE_NOT_ACTIVE then Exit;
end else
begin
// warten bis der Service beendet ist
repeat
if not QueryServiceStatus(SCService, ServiceStatus) then Break;
until ServiceStatus.dwCurrentState <> SERVICE_STOP_PENDING;
end;
// Service starten
p := nil;
if StartService(SCService, 0, p) then
begin
// warten bis der Service gestartet ist
repeat
if not QueryServiceStatus(SCService, ServiceStatus) then Break;
until ServiceStatus.dwCurrentState <> SERVICE_START_PENDING;
end else Exit;
Result := True;
finally
CloseServiceHandle(SCService);
end;
finally
CloseServiceHandle(SCManager);
end;
end;
function TCsWindowsService.Restart: Boolean;
begin
Result := Self.Restart(FName);
end;
class function TCsWindowsService.IsRunning(AName: string): Boolean;
var
SCManager, SCService: THandle;
ServiceStatus: TServiceStatus;
p: PChar;
begin
Result := False;
SCManager := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SCManager = 0 then Exit;
try
SCService := OpenService(SCManager, PChar(AName),
SERVICE_START or SERVICE_STOP or SERVICE_QUERY_STATUS);
if SCService = 0 then Exit;
try
ZeroMemory(@ServiceStatus, SizeOf(ServiceStatus));
QueryServiceStatus(SCService, ServiceStatus);
Result := ServiceStatus.dwCurrentState = SERVICE_RUNNING;
finally
CloseServiceHandle(SCService);
end;
finally
CloseServiceHandle(SCManager);
end;
end;
function TCsWindowsService.IsRunning: Boolean;
begin
Result := Self.IsRunning(FName);
end;
class function TCsWindowsService.SetStartMode(AName: string;
AStartMode: TCsWindowsServiceStartMode): Boolean;
var
Reg: TRegistry;
StartModeWord: DWORD;
begin
Result := False;
Reg := TRegistry.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKey(Self.SERVICES_REGISTRY_PATH, False) then
begin
if Reg.OpenKey(AName, False) then
begin
StartModeWord := 4;
case AStartMode of
wssmDisabled: StartModeWord := 4;
wssmAuto: StartModeWord := 2;
wssmAutoDelay: StartModeWord := 2;
wssmManual: StartModeWord := 3;
end;
Reg.WriteInteger('Start', StartModeWord);
if AStartMode = wssmAutoDelay then
Reg.WriteInteger('DelayedAutoStart', 1)
else
Reg.WriteInteger('DelayedAutoStart', 0);
Result := True;
end;
end;
finally
FreeAndNil(Reg);
end;
end;
function TCsWindowsService.SetStartMode(
AStartMode: TCsWindowsServiceStartMode): Boolean;
begin
Result := Self.SetStartMode(FName, AStartMode);
end;
class function TCsWindowsService.GetStartMode(AName: string): TCsWindowsServiceStartMode;
var
TempStartMode: TCsWindowsServiceStartMode;
TempDescription: String;
TempImagePath: String;
TempDisplayName: String;
begin
Self.LoadServiceProperties(
AName,
TempDisplayName,
TempDescription,
TempImagePath,
TempStartMode
);
Result := TempStartMode;
end;
end.
Wichtig: Nur mit Admin-Rechten kann man auf die Dienste zu greifen. Hat man nicht Berechtigung geben die Funktionen False zurück. Du musst also deiner Anwendung ein Manifest hinzufügen.