NT-Services
Ein eigener Service
Wie schreibe ich nun einen Service?
Das ist nicht so schwer wie man glauben mag. Man binde die WinSVC Unit in sein Projekt ein (das im besten Falle ein Konsolenprogramm sein sollte, da nur interaktive Services mit dem Benutzer interagieren können).
Wir gehen also erstmal von einem Konsolenprogramm aus.
program svc;
uses
windows,
winsvc;
const
servicename='testservice';
displayname='assarbad''s testservice';
procedure service_main;forward;
{$include consolehlp.pas}
{$include service.pas}
procedure service_main;
begin
repeat
if not paused then begin
end;
until stopped;
end;
begin
prog_main;
end.
Die Prozedur PROG_MAIN ist in SERVICE.PAS definiert und CONSOLEHLP.PAS enthält einige Hilfroutinen für Konsolenprogramme die zum Teil der CRT Unit von Turbo Pascal nachempfunden sind.
Da eine jede eingebundene Unit extra Overhead mit sich bringt (das entsteht durch die Compilertechnologie, die verschiedene Informationen bei Units zwischenspeichert, die dann nicht mehr entfernt werden), nutzen wir INCLUDE Dateien.
PROG_MAIN sieht wie folgt aus:
procedure PROG_MAIN;
begin
case paramcount OF
0:startasservice;
else begin
GetModuleFileName(hInstance, @modname[0], MAX_PATH);
Getlasterror;
param:=paramstr(1);
case param[1]='/' OF
true: begin
currtextattr:=textattribute;
settextattribute(FOREGROUND_GREEN or FOREGROUND_INTENSITY);
writeln(cmd_header);
settextattribute(currtextattr);
case param[2] of
'I', 'i':begin
currtextattr:=textattribute;
settextattribute(FOREGROUND_BLUE or
FOREGROUND_INTENSITY);
StartupMode:=SERVICE_DEMAND_START;
if length(param)>2 then
case param[3] of
'A', 'a':startupMode:=SERVICE_AUTO_START;
end
else StartupMode:=SERVICE_DEMAND_START;
case startupMode of
SERVICE_AUTO_START:writeln(cmd_install+
'n autostart service');
SERVICE_DEMAND_START:writeln(cmd_install+
' manual start service');
end;
settextattribute(currtextattr);
hSCM:=OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
case hSCM of
0:FatalError;
else begin
hService:=CreateService(hSCM,
PChar(ServiceName),
PChar(DisplayName),
SERVICE_START OR SERVICE_QUERY_STATUS OR _DELETE,
SERVICE_WIN32_OWN_PROCESS,
StartupMode,
SERVICE_ERROR_NORMAL,
@modname[0],
NIL, NIL, NIL, NIL, NIL);
case hService of
0:begin
CloseServiceHandle(hSCM);
FatalError;
end;
else begin
CloseServiceHandle(hSCM);
CloseServiceHandle(hService);
writeln(frmt(cmd_installed, [pchar(servicename),
NIL]));
end;
end;
end;
end;
end;
'U', 'u':begin
currtextattr:=textattribute;
settextattribute(FOREGROUND_BLUE or
FOREGROUND_INTENSITY);
writeln('Attempting to uninstall "'+servicename+'"');
settextattribute(currtextattr);
hSCM:=OpenSCManager(NIL, NIL, SC_MANAGER_ALL_ACCESS);
case hSCM of
0:FatalError;
else begin
hService:=OpenService(hSCM, PChar(Servicename),
SERVICE_ALL_ACCESS);
case hService of
0:begin
CloseServiceHandle(hSCM);
FatalError;
end;
else begin
startupMode:=
integer(DeleteService(hService));
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
case startupMode of
0:FatalError;
else
writeln(frmt(cmd_installed,
[pchar(servicename), PChar('un')]));
end;//case
end;
end;//case
end;
end;//case
end;
else showsyntax;
begin
end;
end;//case
end;
false:startasservice;
end;
end;
end;
end;
Es überprüft die übergebenen Parameter und installiert/deinstalliert gegebenenfalls den Service oder eben startet diesen als Service:
procedure startasservice;
begin
dispatchtable[0].lpservicename:=pchar(servicename);
dispatchtable[0].lpserviceproc:=@serviceproc;
dispatchtable[1].lpservicename:=NIL;
dispatchtable[1].lpserviceproc:=NIL;
startservicectrldispatcher(dispatchtable[0]);
end;
startservicectrldispatcher() übergibt den Hauptthread des Prozesses an den Service Control Manager (SCM).
Auffällig im Hauptprogramm ist noch die Prozedur SERVICE_MAIN. Sie enthält die eigentliche Hauptschleife des Services, wobei die Variablen STOPPED und PAUSED innerhalb des Programms vordefiniert sind.
Alles innerhalb dieser Prozedur wird also ausgeführt, während der Service als Service läuft.
Download des Beispielservices (Service-Skelett) (ca. 14 KB)