|
@@ -0,0 +1,965 @@
|
|
|
+{$mode objfpc}
|
|
|
+{$h+}
|
|
|
+unit ServiceManager;
|
|
|
+
|
|
|
+interface
|
|
|
+
|
|
|
+uses
|
|
|
+ Windows, SysUtils, Classes, jwawinnt, jwawinsvc;
|
|
|
+
|
|
|
+type
|
|
|
+
|
|
|
+ TServiceEntry = Class(TCollectionItem)
|
|
|
+ Private
|
|
|
+ FServiceName,
|
|
|
+ FDisplayName : String;
|
|
|
+ FServiceType,
|
|
|
+ FCurrentState,
|
|
|
+ FControlsAccepted,
|
|
|
+ FWin32ExitCode,
|
|
|
+ FServiceSpecificExitCode,
|
|
|
+ FCheckPoint,
|
|
|
+ FWaitHint: DWORD;
|
|
|
+ Private
|
|
|
+ Procedure SetStatusFields(Const Status : TServiceStatus);
|
|
|
+ Public
|
|
|
+ Property ServiceName : String Read FServiceName;
|
|
|
+ Property DisplayName : String read FDIsplayName;
|
|
|
+ Property ServiceType : DWord Read FServiceType;
|
|
|
+ Property CurrentState : DWord Read FCurrentState;
|
|
|
+ Property ControlsAccepted : DWord Read FControlsAccepted;
|
|
|
+ Property Win32ExitCode : DWord Read FWin32ExitCode;
|
|
|
+ Property ServiceSpecificExitCode : DWord Read FServiceSpecificExitCode;
|
|
|
+ Property CheckPoint : DWord Read FCheckPoint;
|
|
|
+ Property WaitHint: DWORD Read FWaitHint;
|
|
|
+ end;
|
|
|
+
|
|
|
+ TServiceEntries = Class(TOwnedCollection)
|
|
|
+ Private
|
|
|
+ Function GetService (Index : Integer) : TServiceEntry;
|
|
|
+ Public
|
|
|
+ Function FindService(ServiceName : String) : TServiceEntry;
|
|
|
+ Function ServiceByName(ServiceName : String) : TServiceEntry;
|
|
|
+ Property Items [index : Integer] : TServiceEntry Read GetService;default;
|
|
|
+ end;
|
|
|
+
|
|
|
+ { Record used in
|
|
|
+ registerservice,
|
|
|
+ configservice or
|
|
|
+ queryserviceconfig
|
|
|
+ }
|
|
|
+
|
|
|
+ TServiceDescriptor = Record
|
|
|
+ Name : ShortString;
|
|
|
+ DisplayName : ShortString;
|
|
|
+ DesiredAccess : DWord;
|
|
|
+ ServiceType : DWord;
|
|
|
+ StartType : DWord;
|
|
|
+ ErrorControl : DWord;
|
|
|
+ CommandLine : String;
|
|
|
+ LoadOrderGroup : String;
|
|
|
+ TagID : DWord;
|
|
|
+ Dependencies : String; // Separated by slash signs (/)
|
|
|
+ UserName : String;
|
|
|
+ Password : String;
|
|
|
+ end;
|
|
|
+
|
|
|
+ TServiceManager = class(TComponent)
|
|
|
+ private
|
|
|
+ { Private declarations }
|
|
|
+ FReconnect : Boolean;
|
|
|
+ FMachineName : String;
|
|
|
+ FAccess : DWord;
|
|
|
+ FHandle : THandle;
|
|
|
+ FDBLock : SC_LOCK;
|
|
|
+ FServices : TServiceEntries;
|
|
|
+ FAfterRefresh : TNotifyEvent;
|
|
|
+ FAfterConnect: TNotifyEvent;
|
|
|
+ FRefreshOnConnect: Boolean;
|
|
|
+ FBeforeDisConnect: TNotifyEvent;
|
|
|
+ function GetConnected: Boolean;
|
|
|
+ procedure SetConnected(const Value: Boolean);
|
|
|
+ procedure SetMachineName(const Value: string);
|
|
|
+ protected
|
|
|
+ { Protected declarations }
|
|
|
+ procedure Loaded;override;
|
|
|
+ Procedure SMError(Msg : String);
|
|
|
+ Procedure CheckConnected(Msg : String);
|
|
|
+ Procedure DoBeforeDisConnect; virtual;
|
|
|
+ Procedure DoAfterConnect; virtual;
|
|
|
+ Procedure DoAfterRefresh; virtual;
|
|
|
+ public
|
|
|
+ { Public declarations }
|
|
|
+ Constructor Create(AOwner: TComponent); override;
|
|
|
+ Destructor Destroy; override;
|
|
|
+ Procedure ClearServices;
|
|
|
+ Procedure Refresh;
|
|
|
+ Procedure Connect;
|
|
|
+ Procedure Disconnect;
|
|
|
+ function GetServiceHandle(ServiceName: String; SAccess: DWord): THandle;
|
|
|
+ procedure ContinueService(SHandle: THandle); overload;
|
|
|
+ procedure ContinueService(ServiceName : String); overload;
|
|
|
+ procedure StartService(SHandle: THandle; Args: TStrings);overload;
|
|
|
+ procedure StartService(ServiceName : String; Args: TStrings); overload;
|
|
|
+ procedure StopService(ServiceName: String; StopDependent: Boolean); overload;
|
|
|
+ procedure StopService(SHandle : THandle; StopDependent: Boolean); overload;
|
|
|
+ procedure PauseService(SHandle: THandle);overload;
|
|
|
+ procedure PauseService(ServiceName: String);Overload;
|
|
|
+ procedure CustomControlService(ServiceName : String; ControlCode : DWord); overload;
|
|
|
+ procedure CustomControlService(Shandle : THandle; ControlCode : DWord); overload;
|
|
|
+ procedure ListDependentServices(SHandle: THandle; ServiceState: DWord; List: TStrings); overload;
|
|
|
+ procedure ListDependentServices(ServiceName : String; ServiceState : DWord; List : TStrings); overload;
|
|
|
+ Procedure LockServiceDatabase;
|
|
|
+ Procedure UnlockServiceDatabase;
|
|
|
+ procedure QueryServiceConfig(SHandle : THandle; Var Config : TServiceDescriptor);overload;
|
|
|
+ procedure QueryServiceConfig(ServiceName : String; Var Config : TServiceDescriptor);overload;
|
|
|
+ Function RegisterService(Var Desc : TServiceDescriptor) : THandle;
|
|
|
+ procedure SetStartupType(ServiceName: String; StartupType: DWord); overload;
|
|
|
+ procedure SetStartupType(SHandle : THandle; StartupType: DWord); overload;
|
|
|
+ Procedure UnregisterService(ServiceName : String);
|
|
|
+ procedure ConfigService(SHandle: THandle; Config: TServiceDescriptor); overload;
|
|
|
+ procedure ConfigService(ServiceName : string; Config: TServiceDescriptor); overload;
|
|
|
+ procedure RefreshServiceStatus(ServiceName: String);
|
|
|
+ procedure GetServiceStatus(SHandle : THandle; Var Status : TServiceStatus); overload;
|
|
|
+ procedure GetServiceStatus(ServiceName : String; Var Status : TServiceStatus); overload;
|
|
|
+ Property Handle : THandle Read FHandle;
|
|
|
+ Property Acces : DWord read FAccess Write FAccess;
|
|
|
+ Property Services : TServiceEntries Read FServices;
|
|
|
+ published
|
|
|
+ { Published declarations }
|
|
|
+ Property Connected : Boolean Read GetConnected Write SetConnected;
|
|
|
+ Property MachineName : string Read FMachineName Write SetMachineName;
|
|
|
+ Property RefreshOnConnect : Boolean Read FRefreshOnConnect Write FrefreshOnConnect;
|
|
|
+ Property AfterRefresh : TNotifyEvent Read FAfterRefresh Write FAfterRefresh;
|
|
|
+ Property AfterConnect : TNotifyEvent Read FAfterConnect Write FAfterConnect;
|
|
|
+ Property BeforeDisConnect : TNotifyEvent Read FBeforeDisConnect Write FBeforeDisConnect;
|
|
|
+ end;
|
|
|
+
|
|
|
+ EServiceManager = Class(Exception);
|
|
|
+
|
|
|
+Const
|
|
|
+ StartTypes : Array[0..4] of DWord = (
|
|
|
+ SERVICE_AUTO_START,SERVICE_BOOT_START, SERVICE_DEMAND_START,
|
|
|
+ SERVICE_SYSTEM_START, SERVICE_DISABLED );
|
|
|
+ ServiceTypes : Array[0..3] of DWord = (
|
|
|
+ SERVICE_FILE_SYSTEM_DRIVER, SERVICE_KERNEL_DRIVER,
|
|
|
+ SERVICE_WIN32_OWN_PROCESS, SERVICE_WIN32_SHARE_PROCESS );
|
|
|
+ StartErrors : Array[0..3] of DWord = (
|
|
|
+ SERVICE_ERROR_IGNORE, SERVICE_ERROR_NORMAL,
|
|
|
+ SERVICE_ERROR_SEVERE, SERVICE_ERROR_CRITICAL);
|
|
|
+
|
|
|
+Function ServiceTypeToString(AType : Dword) : String;
|
|
|
+Function ServiceStateToString(AState : DWord) : String;
|
|
|
+Function ControlsAcceptedToString(AValue : DWord) : String;
|
|
|
+Function IsInteractiveService(AType : Dword) : Boolean;
|
|
|
+
|
|
|
+implementation
|
|
|
+
|
|
|
+
|
|
|
+ResourceString
|
|
|
+ SErrConnected = 'Operation not permitted while connected to Service Control Manager';
|
|
|
+ SErrNotConnected = 'Not connected to Service control manager. Cannot %s';
|
|
|
+ SErrInvalidControlCode = 'Invalid custom control code : %d';
|
|
|
+ SQueryServiceList = 'Query service list';
|
|
|
+ SActive = 'Active';
|
|
|
+ SInactive = 'Inactive';
|
|
|
+ SStopped = 'Stopped';
|
|
|
+ SStartPending = 'Start pending';
|
|
|
+ SStopPending = 'Stop pending';
|
|
|
+ SRunning = 'Running';
|
|
|
+ SContinuePending = 'Continue pending';
|
|
|
+ SPausePending = 'Pause pending';
|
|
|
+ SPaused = 'Paused';
|
|
|
+ SUnknownState = 'Unknown State (%d)';
|
|
|
+ SUnknownType = 'Unknown type (%d)';
|
|
|
+ SStop = 'Stop';
|
|
|
+ SPauseContinue = 'Pause/continue';
|
|
|
+ SShutDown = 'Shutdown';
|
|
|
+ SDeviceDriver = 'Device driver';
|
|
|
+ SFileSystemDriver = 'Filesystem driver';
|
|
|
+ SAdapter = 'Adapter';
|
|
|
+ SRecognizer = 'Recognizer';
|
|
|
+ SService = 'Service';
|
|
|
+ SSHaredService = 'Service (shared)';
|
|
|
+ SErrServiceNotFound = 'Service "%s" not found.';
|
|
|
+
|
|
|
+
|
|
|
+{ TServiceManager }
|
|
|
+
|
|
|
+{$ifdef ver130}
|
|
|
+
|
|
|
+Type
|
|
|
+ PPChar = ^PChar;
|
|
|
+ PCharArray = Array[Word] of PChar;
|
|
|
+ PPCharArray = ^PCharArray;
|
|
|
+
|
|
|
+Procedure RaiseLastOSError;
|
|
|
+
|
|
|
+begin
|
|
|
+ RaiseLastWin32Error;
|
|
|
+end;
|
|
|
+{$endif}
|
|
|
+
|
|
|
+procedure TServiceManager.CheckConnected(Msg: String);
|
|
|
+begin
|
|
|
+ If Not Connected then
|
|
|
+ SMError(Format(SErrNotConnected,[Msg]));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.ClearServices;
|
|
|
+begin
|
|
|
+ FServices.Clear;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.Connect;
|
|
|
+
|
|
|
+Var
|
|
|
+ P : PChar;
|
|
|
+
|
|
|
+begin
|
|
|
+ If (FHandle=0) then
|
|
|
+ begin
|
|
|
+ P:=Nil;
|
|
|
+ If (MachineName<>'') then
|
|
|
+ P:=PChar(MachineName);
|
|
|
+ FHandle:=OpenSCManager(P,Nil,FAccess);
|
|
|
+ If (FHandle=0) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ DoAfterConnect;
|
|
|
+ If RefreshOnConnect then
|
|
|
+ Refresh;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+constructor TServiceManager.Create(AOwner: TComponent);
|
|
|
+begin
|
|
|
+ inherited;
|
|
|
+ FServices:=TServiceEntries.Create(Self,TServiceEntry);
|
|
|
+ FAccess:=SC_MANAGER_ALL_ACCESS;
|
|
|
+end;
|
|
|
+
|
|
|
+destructor TServiceManager.Destroy;
|
|
|
+begin
|
|
|
+ FServices.Free;
|
|
|
+ Inherited;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.Disconnect;
|
|
|
+begin
|
|
|
+ IF (FHandle<>0) then
|
|
|
+ begin
|
|
|
+ DoBeforeDisConnect;
|
|
|
+ CloseServiceHandle(FHandle);
|
|
|
+ FHandle:=0;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+function TServiceManager.GetConnected: Boolean;
|
|
|
+begin
|
|
|
+ Result:=(Handle<>0);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.Refresh;
|
|
|
+
|
|
|
+Var
|
|
|
+ BytesNeeded,
|
|
|
+ ServicesReturned,
|
|
|
+ ResumeHandle : DWord;
|
|
|
+ Info,P : PEnumServiceStatus;
|
|
|
+ E : TServiceEntry;
|
|
|
+ I : integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ ClearServices;
|
|
|
+ CheckConnected(SQueryServiceList);
|
|
|
+ BytesNeeded:=0;
|
|
|
+ ServicesReturned:=0;
|
|
|
+ ResumeHandle:=0;
|
|
|
+ Info:=Nil;
|
|
|
+ EnumServicesStatus(FHandle,SERVICE_WIN32,SERVICE_STATE_ALL,Info,0,
|
|
|
+ BytesNeeded,ServicesReturned,Resumehandle);
|
|
|
+ if (GetLastError<>ERROR_MORE_DATA) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ Getmem(Info,BytesNeeded);
|
|
|
+ Try
|
|
|
+ P:=Info;
|
|
|
+ If Not EnumServicesStatus(FHandle,SERVICE_WIN32,SERVICE_STATE_ALL,Info,BytesNeeded,
|
|
|
+ BytesNeeded,ServicesReturned,Resumehandle) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ For I:=1 to Servicesreturned do
|
|
|
+ begin
|
|
|
+ E:=FServices.Add as TServiceEntry;
|
|
|
+ With E,P^ do
|
|
|
+ begin
|
|
|
+ FServiceName:=StrPas(lpServiceName);
|
|
|
+ FDisplayName:=StrPas(lpDisplayName);
|
|
|
+ SetStatusFields(ServiceStatus);
|
|
|
+ end;
|
|
|
+ PChar(P):=Pchar(P)+SizeOf(TEnumServiceStatus);
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ FreeMem(Info);
|
|
|
+ end;
|
|
|
+ DoAfterRefresh;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.SetConnected(const Value: Boolean);
|
|
|
+begin
|
|
|
+ If (([csLoading,csdesigning] * ComponentState)<>[]) then
|
|
|
+ FReconnect:=Value
|
|
|
+ else
|
|
|
+ If Value<>GetConnected then
|
|
|
+ If Value then
|
|
|
+ Connect
|
|
|
+ Else
|
|
|
+ Disconnect;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.Loaded;
|
|
|
+
|
|
|
+begin
|
|
|
+ Inherited;
|
|
|
+ If FReconnect then
|
|
|
+ Connect;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.SetMachineName(const Value: string);
|
|
|
+begin
|
|
|
+ If Connected then
|
|
|
+ SMError(SErrConnected);
|
|
|
+ FMachineName := Value;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.SMError(Msg: String);
|
|
|
+begin
|
|
|
+ raise EServiceManager.Create(Msg);
|
|
|
+end;
|
|
|
+
|
|
|
+Function ServiceTypeToString(AType : Dword) : String;
|
|
|
+
|
|
|
+begin
|
|
|
+ Case (AType and $FF) of
|
|
|
+ SERVICE_KERNEL_DRIVER : Result:=SDeviceDriver;
|
|
|
+ SERVICE_FILE_SYSTEM_DRIVER : Result:=SFileSystemDriver;
|
|
|
+ SERVICE_ADAPTER : Result:=SAdapter;
|
|
|
+ SERVICE_RECOGNIZER_DRIVER : Result:=SRecognizer;
|
|
|
+ SERVICE_WIN32_OWN_PROCESS : Result:=SService;
|
|
|
+ SERVICE_WIN32_SHARE_PROCESS : Result:=SSHaredService;
|
|
|
+ else
|
|
|
+ Result:=Format(SUnknownType,[AType]);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Function IsInteractiveService(AType : Dword) : Boolean;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=(Atype and SERVICE_INTERACTIVE_PROCESS)<>0;
|
|
|
+end;
|
|
|
+
|
|
|
+Function ServiceStateToString(AState : Dword) : String;
|
|
|
+
|
|
|
+begin
|
|
|
+ Case AState of
|
|
|
+ SERVICE_STOPPED : Result:=SStopped;
|
|
|
+ SERVICE_START_PENDING : Result:=SStartPending;
|
|
|
+ SERVICE_STOP_PENDING : Result:=SStopPending;
|
|
|
+ SERVICE_RUNNING : Result:=SRunning;
|
|
|
+ SERVICE_CONTINUE_PENDING : Result:=SContinuePending;
|
|
|
+ SERVICE_PAUSE_PENDING : Result:=SPausePending;
|
|
|
+ SERVICE_PAUSED : Result:=SPaused;
|
|
|
+ else
|
|
|
+ Result:=Format(SUnknownState,[AState]);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Function ControlsAcceptedToString(AValue : DWord) : String;
|
|
|
+
|
|
|
+ Procedure AddToResult(S : String);
|
|
|
+ begin
|
|
|
+ If (Result='') then
|
|
|
+ Result:=S
|
|
|
+ else
|
|
|
+ Result:=Result+','+S
|
|
|
+ end;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:='';
|
|
|
+ If (AValue and SERVICE_ACCEPT_STOP)<>0 then
|
|
|
+ AddToResult(SStop);
|
|
|
+ If (AValue and SERVICE_ACCEPT_PAUSE_CONTINUE)<>0 then
|
|
|
+ AddToResult(SPauseContinue);
|
|
|
+ If (AValue and SERVICE_ACCEPT_SHUTDOWN)<>0 then
|
|
|
+ AddToResult(SShutDown)
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.DoAfterConnect;
|
|
|
+begin
|
|
|
+ If Assigned(FAfterConnect) then
|
|
|
+ FAfterConnect(Self);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.DoAfterRefresh;
|
|
|
+begin
|
|
|
+ If Assigned(FAfterRefresh) then
|
|
|
+ FAfterRefresh(Self);
|
|
|
+
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.DoBeforeDisConnect;
|
|
|
+begin
|
|
|
+ If Assigned(FBeforeDisconnect) then
|
|
|
+ FBeforeDisconnect(Self);
|
|
|
+end;
|
|
|
+
|
|
|
+Function AllocDependencyList (Const S : String) : PChar;
|
|
|
+
|
|
|
+Var
|
|
|
+ I,L : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=Nil;
|
|
|
+ If (S<>'') then
|
|
|
+ begin
|
|
|
+ // Double Null terminated list of null-terminated strings.
|
|
|
+ L:=Length(S);
|
|
|
+ GetMem(Result,L+3);
|
|
|
+ Move(S[1],Result^,L+1); // Move terminating null as well.
|
|
|
+ Result[L+1]:=#0;
|
|
|
+ Result[L+2]:=#0;
|
|
|
+ For I:=0 to L-1 do
|
|
|
+ If Result[i]='/' then // Change / to #0.
|
|
|
+ Result[i]:=#0;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Function TServiceManager.RegisterService(var Desc: TServiceDescriptor) : Thandle;
|
|
|
+
|
|
|
+Var
|
|
|
+ PDep,PLO,PUser,PPWd : PChar; // We need Nil for some things.
|
|
|
+ N,D : String;
|
|
|
+ ReturnTag : DWord;
|
|
|
+
|
|
|
+begin
|
|
|
+ With Desc do
|
|
|
+ begin
|
|
|
+ N:=Name;
|
|
|
+ D:=DisplayName;
|
|
|
+ If (LoadOrderGroup='') then
|
|
|
+ PLO:=Nil
|
|
|
+ else
|
|
|
+ PLO:=PChar(LoadOrderGroup);
|
|
|
+ PPwd:=Nil;
|
|
|
+ PUser:=Nil;
|
|
|
+ If (UserName<>'') then
|
|
|
+ begin
|
|
|
+ PUser:=PChar(UserName);
|
|
|
+ If (Password<>'') then
|
|
|
+ PPWd:=PChar(Password);
|
|
|
+ end;
|
|
|
+ PDep:=AllocDependencyList(Dependencies);
|
|
|
+ Try
|
|
|
+ Result:=CreateService(Self.Handle,PChar(N),PChar(D),DesiredAccess,ServiceType,
|
|
|
+ StartType,ErrorControl,PChar(CommandLine),PLO,Nil,
|
|
|
+ PDep,PUser,PPwd);
|
|
|
+ If (Result=0) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ Finally
|
|
|
+ If PDep<>Nil then
|
|
|
+ FreeMem(PDep);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.ListDependentServices(ServiceName : String; ServiceState : DWord; List : TStrings);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=OpenService(Handle,PChar(ServiceName),SERVICE_ENUMERATE_DEPENDENTS);
|
|
|
+ try
|
|
|
+ ListDependentServices(H,ServiceState,List);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
+procedure TServiceManager.ListDependentServices(SHandle: THandle; ServiceState : DWord; List : TStrings);
|
|
|
+
|
|
|
+Var
|
|
|
+ P,E : PEnumServiceStatus;
|
|
|
+ I,BytesNeeded,Count : DWord;
|
|
|
+
|
|
|
+begin
|
|
|
+ P:=Nil;
|
|
|
+ List.Clear;
|
|
|
+ // If call succeeds with size 0, then there are no dependent services...
|
|
|
+ if Not EnumDependentServices(SHandle,ServiceState,P,0,BytesNeeded,Count) then
|
|
|
+ begin
|
|
|
+ If (GetLastError<>ERROR_MORE_DATA) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ GetMem(P,BytesNeeded);
|
|
|
+ Try
|
|
|
+ If Not EnumDependentServices(SHandle,ServiceState,P,bytesNeeded,BytesNeeded,Count) Then
|
|
|
+ RaiseLastOSError;
|
|
|
+ E:=P;
|
|
|
+ For I:=0 to Count-1 do
|
|
|
+ begin
|
|
|
+ List.Add(StrPas(E^.lpServiceName));
|
|
|
+ Pchar(E):=PChar(E)+SizeOf(TEnumServiceStatus);
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ FreeMem(P);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
+Procedure TServiceManager.StopService(SHandle : THandle; StopDependent : Boolean);
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+ List : TStrings;
|
|
|
+ Status : TServiceStatus;
|
|
|
+
|
|
|
+begin
|
|
|
+ If Not QueryServiceStatus(SHandle,Status) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ If Not (Status.dwCurrentState=SERVICE_STOPPED) then
|
|
|
+ begin
|
|
|
+ If StopDependent then
|
|
|
+ begin
|
|
|
+ List:=TStringList.Create;
|
|
|
+ Try
|
|
|
+ ListDependentServices(SHandle,SERVICE_ACTIVE,List);
|
|
|
+ For I:=0 to List.Count-1 do
|
|
|
+ StopService(List[i],False); // Do not recurse !!
|
|
|
+ Finally
|
|
|
+ List.Free;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ If Not ControlService(SHandle,SERVICE_CONTROL_STOP,Status) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure TServiceManager.StopService(ServiceName : String; StopDependent : Boolean);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+ A : DWORD;
|
|
|
+
|
|
|
+begin
|
|
|
+ A:=SERVICE_STOP or SERVICE_QUERY_STATUS;
|
|
|
+ If StopDependent then
|
|
|
+ A:=A or SERVICE_ENUMERATE_DEPENDENTS;
|
|
|
+ H:=OpenService(Handle,PChar(ServiceName),A);
|
|
|
+ Try
|
|
|
+ StopService(H,StopDependent);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
+Function TServiceManager.GetServiceHandle(ServiceName : String; SAccess : DWord) : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=OpenService(Handle,PChar(ServiceName),SAccess);
|
|
|
+ If (Result=0) then
|
|
|
+ RaiseLastOSError;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.UnregisterService(ServiceName: String);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+ Status : TServiceStatus;
|
|
|
+
|
|
|
+begin
|
|
|
+ StopService(ServiceName,True);
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_STOP or SERVICE_QUERY_STATUS or SERVICE_DELETE);
|
|
|
+ Try
|
|
|
+ If Not DeleteService(H) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure TServiceManager.PauseService(SHandle : THandle);
|
|
|
+
|
|
|
+Var
|
|
|
+ Status : TServiceStatus;
|
|
|
+
|
|
|
+begin
|
|
|
+ If Not ControlService(SHandle,SERVICE_CONTROL_PAUSE,Status) then
|
|
|
+ RaiseLastOSError;
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure TServiceManager.PauseService(ServiceName : String);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_PAUSE_CONTINUE);
|
|
|
+ Try
|
|
|
+ PauseService(H);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure TServiceManager.ContinueService(SHandle : THandle);
|
|
|
+
|
|
|
+Var
|
|
|
+ Status : TServiceStatus;
|
|
|
+
|
|
|
+begin
|
|
|
+ If Not ControlService(SHandle,SERVICE_CONTROL_CONTINUE,Status) then
|
|
|
+ RaiseLastOSError;
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure TServiceManager.ContinueService(ServiceName : String);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_PAUSE_CONTINUE);
|
|
|
+ Try
|
|
|
+ ContinueService(H);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Function StringsToPCharList(List : TStrings) : PPChar;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+ S : String;
|
|
|
+
|
|
|
+begin
|
|
|
+ I:=(List.Count)+1;
|
|
|
+ GetMem(Result,I*sizeOf(PChar));
|
|
|
+ PPCharArray(Result)^[List.Count]:=Nil;
|
|
|
+ For I:=0 to List.Count-1 do
|
|
|
+ begin
|
|
|
+ S:=List[i];
|
|
|
+ PPCharArray(Result)^[i]:=StrNew(PChar(S));
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure FreePCharList(List : PPChar);
|
|
|
+
|
|
|
+Var
|
|
|
+ I : integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ I:=0;
|
|
|
+ While PPChar(List)[i]<>Nil do
|
|
|
+ begin
|
|
|
+ StrDispose(PPChar(List)[i]);
|
|
|
+ Inc(I);
|
|
|
+ end;
|
|
|
+ FreeMem(List);
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure TServiceManager.StartService(SHandle : THandle; Args : TStrings);
|
|
|
+
|
|
|
+Var
|
|
|
+ Argc : DWord;
|
|
|
+ PArgs : PPchar;
|
|
|
+
|
|
|
+begin
|
|
|
+ If (Args=Nil) or (Args.Count>0) then
|
|
|
+ begin
|
|
|
+ Argc:=0;
|
|
|
+ Pargs:=Nil;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ ArgC:=Args.Count;
|
|
|
+ Pargs:=StringsToPcharList(Args);
|
|
|
+ end;
|
|
|
+ Try
|
|
|
+ If not jwawinsvc.StartService(SHandle,Argc,PArgs^) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ Finally
|
|
|
+ If (PArgs<>Nil) then
|
|
|
+ FreePCharList(PArgs);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
+Procedure TServiceManager.StartService(ServiceName : String; Args : TStrings);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_START);
|
|
|
+ Try
|
|
|
+ StartService(H,Args);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+Procedure TServiceManager.LockServiceDatabase;
|
|
|
+
|
|
|
+begin
|
|
|
+ FDBLock:=jwawinsvc.LockServiceDatabase(Handle);
|
|
|
+ If FDBLock=Nil then
|
|
|
+ RaiseLastOSError;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.UnlockServiceDatabase;
|
|
|
+begin
|
|
|
+ If (FDBLock<>Nil) then
|
|
|
+ begin
|
|
|
+ Try
|
|
|
+ If Not jwawinsvc.UnLockServiceDatabase(FDBLock) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ Finally
|
|
|
+ FDBLock:=Nil;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.QueryServiceConfig(SHandle : THandle; Var Config : TServiceDescriptor);
|
|
|
+
|
|
|
+Var
|
|
|
+ SvcCfg : PQueryServiceConfig;
|
|
|
+ BytesNeeded : DWord;
|
|
|
+
|
|
|
+begin
|
|
|
+ jwawinsvc.QueryServiceConfig(SHandle,Nil,0,BytesNeeded);
|
|
|
+ If (GetLastError<>ERROR_INSUFFICIENT_BUFFER) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ GetMem(SvcCfg,BytesNeeded);
|
|
|
+ Try
|
|
|
+ If Not jwawinsvc.QueryServiceConfig(SHandle,SvcCfg,BytesNeeded,BytesNeeded) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ With config,SvcCfg^ do
|
|
|
+ begin
|
|
|
+ Password:='';
|
|
|
+ Name:='';
|
|
|
+ DesiredAccess:=0;
|
|
|
+ ErrorControl:=dwErrorControl;
|
|
|
+ ServiceType:=dwServiceType;
|
|
|
+ StartType:=dwStartType;
|
|
|
+ TagID:=dwTagID;
|
|
|
+ CommandLine:=lpBinaryPathName;
|
|
|
+ LoadOrderGroup:=lpLoadOrderGroup;
|
|
|
+ Dependencies:=lpDependencies;
|
|
|
+ UserName:=lpServiceStartName;
|
|
|
+ DisplayName:=lpDisplayName;
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ FreeMem(SvcCfg,BytesNeeded);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.QueryServiceConfig(ServiceName : String; Var Config : TServiceDescriptor);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_QUERY_CONFIG);
|
|
|
+ Try
|
|
|
+ QueryServiceConfig(H,Config);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.SetStartupType(ServiceName : String; StartupType : DWord);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_CHANGE_CONFIG);
|
|
|
+ Try
|
|
|
+ SetStartupType(H,StartupType);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.SetStartupType(SHandle : THandle; StartupType: DWord);
|
|
|
+
|
|
|
+Const
|
|
|
+ SNC = SERVICE_NO_CHANGE; // Shortcut
|
|
|
+
|
|
|
+begin
|
|
|
+ If Not ChangeServiceConfig(SHandle,SNC,StartupType,SNC,Nil,Nil,Nil,Nil,Nil,Nil,Nil) then
|
|
|
+ RaiseLastOSError;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.ConfigService(SHandle : THandle ; Config : TServiceDescriptor);
|
|
|
+
|
|
|
+ Function SToPchar(Var S : String) : PChar;
|
|
|
+
|
|
|
+ begin
|
|
|
+ If (S='') then
|
|
|
+ Result:=Nil
|
|
|
+ else
|
|
|
+ Result:=PChar(S);
|
|
|
+ end;
|
|
|
+
|
|
|
+Var
|
|
|
+ PDep,PLO,PUser,PPWd,PCmd,PDisp : PChar; // We need Nil for some things.
|
|
|
+ D : String;
|
|
|
+ ReturnTag : DWord;
|
|
|
+
|
|
|
+begin
|
|
|
+ With Config do
|
|
|
+ begin
|
|
|
+ PCmd:=SToPChar(CommandLine);
|
|
|
+ D:=DisplayName;
|
|
|
+ PDisp:=StoPChar(D);
|
|
|
+ PLO:=SToPChar(LoadOrderGroup);
|
|
|
+ PUser:=SToPChar(UserName);
|
|
|
+ PPwd:=SToPchar(Password);
|
|
|
+ PDep:=AllocDependencyList(Dependencies);
|
|
|
+ Try
|
|
|
+ If Not ChangeServiceConfig(SHandle,ServiceType,StartType,ErrorControl,
|
|
|
+ PCmd,PLO,Nil,PDep,PUser,PPwd,PDisp) then
|
|
|
+ RaiseLastOSError;
|
|
|
+ Finally
|
|
|
+ If PDep<>Nil then
|
|
|
+ FreeMem(PDep);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.GetServiceStatus(SHandle : THandle; Var Status: TServiceStatus);
|
|
|
+
|
|
|
+begin
|
|
|
+ If Not QueryServiceStatus(SHandle,Status) then
|
|
|
+ RaiseLastOSError;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.GetServiceStatus(ServiceName : String; Var Status: TServiceStatus);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_QUERY_STATUS);
|
|
|
+ Try
|
|
|
+ GetServiceStatus(H,Status);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.RefreshServiceStatus(ServiceName : String);
|
|
|
+
|
|
|
+Var
|
|
|
+ Status : TServiceStatus;
|
|
|
+ SE : TServiceEntry;
|
|
|
+
|
|
|
+
|
|
|
+begin
|
|
|
+ SE:=Services.ServiceByName(ServiceName);
|
|
|
+ GetServiceStatus(ServiceName,Status);
|
|
|
+ SE.SetStatusFields(Status);
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
+procedure TServiceManager.ConfigService(ServiceName : String; Config : TServiceDescriptor);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_CHANGE_CONFIG);
|
|
|
+ Try
|
|
|
+ ConfigService(H,Config);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
+procedure TServiceManager.CustomControlService(ServiceName: String; ControlCode: DWord);
|
|
|
+
|
|
|
+Var
|
|
|
+ H : THandle;
|
|
|
+
|
|
|
+begin
|
|
|
+ H:=GetServiceHandle(ServiceName,SERVICE_USER_DEFINED_CONTROL);
|
|
|
+ Try
|
|
|
+ CustomControlService(H,ControlCode);
|
|
|
+ Finally
|
|
|
+ CloseServiceHandle(H);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TServiceManager.CustomControlService(Shandle: THandle;
|
|
|
+ ControlCode: DWord);
|
|
|
+
|
|
|
+Var
|
|
|
+ Status : TServiceStatus;
|
|
|
+
|
|
|
+begin
|
|
|
+ If (ControlCode<128) or (ControlCode>255) then
|
|
|
+ Raise EServiceManager.CreateFmt(SErrInvalidControlCode,[ControlCode]);
|
|
|
+ If Not ControlService(SHandle,ControlCode,Status) then
|
|
|
+ RaiseLastOSError;
|
|
|
+end;
|
|
|
+
|
|
|
+{ TServiceEntries }
|
|
|
+
|
|
|
+function TServiceEntries.FindService(ServiceName: String): TServiceEntry;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=Nil;
|
|
|
+ I:=Count-1;
|
|
|
+ While (I>=0) and (Result=Nil) do
|
|
|
+ If CompareText(Items[i].ServiceName,ServiceName)=0 then
|
|
|
+ Result:=Items[i]
|
|
|
+ else
|
|
|
+ Dec(I);
|
|
|
+end;
|
|
|
+
|
|
|
+function TServiceEntries.GetService(Index: Integer): TServiceEntry;
|
|
|
+begin
|
|
|
+ Result:=inherited Items[Index] as TServiceEntry;
|
|
|
+end;
|
|
|
+
|
|
|
+function TServiceEntries.ServiceByName(ServiceName: String): TServiceEntry;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=FindService(ServiceName);
|
|
|
+ If Result=Nil then
|
|
|
+ Raise EServiceManager.CreateFmt(SErrServiceNotFound,[ServiceName]);
|
|
|
+end;
|
|
|
+
|
|
|
+{ TServiceEntry }
|
|
|
+
|
|
|
+procedure TServiceEntry.SetStatusFields(const Status: TServiceStatus);
|
|
|
+begin
|
|
|
+ With Status do
|
|
|
+ begin
|
|
|
+ FServiceType:=dwServiceType;
|
|
|
+ FCurrentState:=dwCurrentState;
|
|
|
+ FControlsAccepted:=dwControlsAccepted;
|
|
|
+ FWin32ExitCode:=dwWin32ExitCode;
|
|
|
+ FServiceSpecificExitCode:=dwServiceSpecificExitCode;
|
|
|
+ FCheckPoint:=dwCheckPoint;
|
|
|
+ FWaitHint:=dwWaitHint;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+end.
|