1 {
2 License Agreement
3 
4 This content is subject to the Mozilla Public License Version 1.1 (the "License");
5 You may not use this plugin except in compliance with the License. You may
6 obtain a copy of the License at http://www.mozilla.org/MPL.
7 
8 Alternatively, you may redistribute this library, use and/or modify it
9 under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version. You may obtain a copy
12 of the LGPL at www.gnu.org/copyleft.
13 
14 Software distributed under the License is distributed on an "AS IS" basis,
15 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 for the specific language governing rights and limitations under the License.
17 
18 The original code is ServiceControl.pas, released April 16, 2007.
19 
20 The initial developer of the original code is Rainer Budde (http://www.speed-soft.de).
21 
22 SimpleSC - NSIS Service Control Plugin is written, published and maintaned by
23 Rainer Budde (rainer@speed-soft.de).
24 }
25 unit ServiceControl;
26 
27 interface
28 
29 uses
30   Windows, SysUtils, WinSvc;
31 
InstallServicenull32   function InstallService(ServiceName, DisplayName: String; ServiceType: DWORD; StartType: DWORD; BinaryPathName: String; Dependencies: String; Username: String; Password: String): Integer;
RemoveServicenull33   function RemoveService(ServiceName: String): Integer;
GetServiceNamenull34   function GetServiceName(DisplayName: String; var Name: String): Integer;
GetServiceDisplayNamenull35   function GetServiceDisplayName(ServiceName: String; var Name: String): Integer;
GetServiceStatusnull36   function GetServiceStatus(ServiceName: String; var Status: DWORD): Integer;
GetServiceBinaryPathnull37   function GetServiceBinaryPath(ServiceName: String; var BinaryPath: String): Integer;
GetServiceStartTypenull38   function GetServiceStartType(ServiceName: String; var StartType: DWORD): Integer;
GetServiceDescriptionnull39   function GetServiceDescription(ServiceName: String; var Description: String): Integer;
GetServiceLogonnull40   function GetServiceLogon(ServiceName: String; var Username: String): Integer;
SetServiceStartTypenull41   function SetServiceStartType(ServiceName: String; StartType: DWORD): Integer;
SetServiceDescriptionnull42   function SetServiceDescription(ServiceName: String; Description: String): Integer;
SetServiceLogonnull43   function SetServiceLogon(ServiceName: String; Username: String; Password: String): Integer;
SetServiceBinaryPathnull44   function SetServiceBinaryPath(ServiceName: String; BinaryPath: String): Integer;
ServiceIsRunningnull45   function ServiceIsRunning(ServiceName: String; var IsRunning: Boolean): Integer;
ServiceIsStoppednull46   function ServiceIsStopped(ServiceName: String; var IsStopped: Boolean): Integer;
ServiceIsPausednull47   function ServiceIsPaused(ServiceName: String; var IsPaused: Boolean): Integer;
StartServicenull48   function StartService(ServiceName: String; ServiceArguments: String): Integer;
StopServicenull49   function StopService(ServiceName: String): Integer;
PauseServicenull50   function PauseService(ServiceName: String): Integer;
ContinueServicenull51   function ContinueService(ServiceName: String): Integer;
RestartServicenull52   function RestartService(ServiceName: String; ServiceArguments: String): Integer;
ExistsServicenull53   function ExistsService(ServiceName: String): Integer;
GetErrorMessagenull54   function GetErrorMessage(ErrorCode: Integer): String;
55 
56 implementation
57 
WaitForStatusnull58 function WaitForStatus(ServiceName: String; Status: DWord): Integer;
59 var
60   CurrentStatus: DWord;
61   StatusResult: Integer;
62   StatusReached: Boolean;
63   TimeOutReached: Boolean;
64   StartTickCount: Cardinal;
65 const
66   STATUS_TIMEOUT = 30000;
67   WAIT_TIMEOUT = 250;
68 begin
69   Result := 0;
70 
71   StatusReached := False;
72   TimeOutReached := False;
73 
74   StartTickCount := GetTickCount;
75 
76   while not StatusReached and not TimeOutReached do
77   begin
78     StatusResult := GetServiceStatus(ServiceName, CurrentStatus);
79 
80     if StatusResult = 0 then
81     begin
82       if Status = CurrentStatus then
83         StatusReached := True
84       else
85         Sleep(WAIT_TIMEOUT);
86     end
87     else
88       Result := StatusResult;
89 
90     if (StartTickCount + STATUS_TIMEOUT) < GetTickCount then
91     begin
92       TimeOutReached := True;
93       Result := ERROR_SERVICE_REQUEST_TIMEOUT;
94     end;
95   end;
96 
97 end;
98 
ExistsServicenull99 function ExistsService(ServiceName: String): Integer;
100 var
101   ManagerHandle: SC_HANDLE;
102   ServiceHandle: SC_HANDLE;
103 begin
104   Result := 0;
105 
106   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
107 
108   if ManagerHandle > 0 then
109   begin
110     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);
111 
112     if ServiceHandle > 0 then
113       CloseServiceHandle(ServiceHandle)
114     else
115       Result := System.GetLastError;
116 
117     CloseServiceHandle(ManagerHandle);
118   end
119   else
120     Result := System.GetLastError;
121 end;
122 
StartServicenull123 function StartService(ServiceName: String; ServiceArguments: String): Integer;
124 type
125   TArguments = Array of PChar;
126 var
127   ManagerHandle: SC_HANDLE;
128   ServiceHandle: SC_HANDLE;
129   ServiceArgVectors: TArguments;
130   NumServiceArgs: DWORD;
131 const
132   ArgDelimitterQuote: String = '"';
133   ArgDelimitterWhiteSpace: String = ' ';
134 
135   procedure GetServiceArguments(ServiceArguments: String; var NumServiceArgs: DWORD; var ServiceArgVectors: TArguments);
136   var
137     Param: String;
138     Split: Boolean;
139     Quoted: Boolean;
140     CharIsDelimitter: Boolean;
141   begin
142     ServiceArgVectors := nil;
143     NumServiceArgs := 0;
144 
145     Quoted := False;
146 
147     while Length(ServiceArguments) > 0 do
148     begin
149       Split := False;
150       CharIsDelimitter := False;
151 
152       if ServiceArguments[1] = ' ' then
153         if not Quoted then
154         begin
155           CharIsDelimitter := True;
156           Split := True;
157         end;
158 
159       if ServiceArguments[1] = '"' then
160       begin
161         Quoted := not Quoted;
162         CharIsDelimitter := True;
163 
164         if not Quoted then
165           Split := True;
166       end;
167 
168       if not CharIsDelimitter then
169         Param := Param + ServiceArguments[1];
170 
171       if Split or (Length(ServiceArguments) = 1) then
172       begin
173         SetLength(ServiceArgVectors, Length(ServiceArgVectors) + 1);
174         GetMem(ServiceArgVectors[Length(ServiceArgVectors) -1], Length(Param) + 1);
175         StrPCopy(ServiceArgVectors[Length(ServiceArgVectors) -1], Param);
176 
177         Param := '';
178 
179         Delete(ServiceArguments, 1, 1);
180         ServiceArguments := Trim(ServiceArguments);
181       end
182       else
183         Delete(ServiceArguments, 1, 1);
184 
185     end;
186 
187     if Length(ServiceArgVectors) > 0 then
188       NumServiceArgs := Length(ServiceArgVectors);
189   end;
190 
191   procedure FreeServiceArguments(ServiceArgVectors: TArguments);
192   var
193     i: Integer;
194   begin
195     if Length(ServiceArgVectors) > 0 then
196       for i := 0 to Length(ServiceArgVectors) -1 do
197         FreeMem(ServiceArgVectors[i]);
198   end;
199 
200 begin
201   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
202 
203   if ManagerHandle > 0 then
204   begin
205     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_START);
206 
207     if ServiceHandle > 0 then
208     begin
209       GetServiceArguments(ServiceArguments, NumServiceArgs, ServiceArgVectors);
210 
211       if WinSvc.StartService(ServiceHandle, NumServiceArgs, ServiceArgVectors[0]) then
212         Result := WaitForStatus(ServiceName, SERVICE_RUNNING)
213       else
214         Result := System.GetLastError;
215 
216       FreeServiceArguments(ServiceArgVectors);
217 
218       CloseServiceHandle(ServiceHandle);
219     end
220     else
221       Result := System.GetLastError;
222 
223 
224     CloseServiceHandle(ManagerHandle);
225   end
226   else
227     Result := System.GetLastError;
228 end;
229 
StopServicenull230 function StopService(ServiceName: String): Integer;
231 var
232   ManagerHandle: SC_HANDLE;
233   ServiceHandle: SC_HANDLE;
234   ServiceStatus: TServiceStatus;
235   Dependencies: PEnumServiceStatus;
236   BytesNeeded: Cardinal;
237   ServicesReturned: Cardinal;
238   ServicesEnumerated: Boolean;
239   EnumerationSuccess: Boolean;
240   i: Cardinal;
241 begin
242   Result := 0;
243 
244   BytesNeeded := 0;
245   ServicesReturned := 0;
246 
247   Dependencies := nil;
248   ServicesEnumerated := False;
249 
250   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT or SC_MANAGER_ENUMERATE_SERVICE);
251 
252   if ManagerHandle > 0 then
253   begin
254     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_STOP or SERVICE_ENUMERATE_DEPENDENTS);
255 
256     if ServiceHandle > 0 then
257     begin
258       if not EnumDependentServices(ServiceHandle, SERVICE_ACTIVE, Dependencies^, 0, BytesNeeded, ServicesReturned) then
259       begin
260         ServicesEnumerated := True;
261         GetMem(Dependencies, BytesNeeded);
262 
263         EnumerationSuccess := EnumDependentServices(ServiceHandle, SERVICE_ACTIVE, Dependencies^, BytesNeeded, BytesNeeded, ServicesReturned);
264 
265         if EnumerationSuccess and (ServicesReturned > 0) then
266         begin
267           for i := 1 to ServicesReturned do
268           begin
269             Result := StopService(Dependencies.lpServiceName);
270 
271             if Result <> 0 then
272               Break;
273 
274             Inc(Dependencies);
275           end;
276         end
277         else
278           Result := System.GetLastError;
279       end;
280 
281       if (ServicesEnumerated and (Result = 0)) or not ServicesEnumerated then
282       begin
283         if ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus) then
284           Result := WaitForStatus(ServiceName, SERVICE_STOPPED)
285         else
286           Result := System.GetLastError
287       end;
288 
289       CloseServiceHandle(ServiceHandle);
290     end
291     else
292       Result := System.GetLastError;
293 
294     CloseServiceHandle(ManagerHandle);
295   end
296   else
297     Result := System.GetLastError;
298 end;
299 
PauseServicenull300 function PauseService(ServiceName: String): Integer;
301 var
302   ManagerHandle: SC_HANDLE;
303   ServiceHandle: SC_HANDLE;
304   ServiceStatus: TServiceStatus;
305 begin
306   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
307 
308   if ManagerHandle > 0 then
309   begin
310     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_PAUSE_CONTINUE);
311 
312     if ServiceHandle > 0 then
313     begin
314 
315       if ControlService(ServiceHandle, SERVICE_CONTROL_PAUSE, ServiceStatus) then
316         Result := WaitForStatus(ServiceName, SERVICE_PAUSED)
317       else
318         Result := System.GetLastError;
319 
320       CloseServiceHandle(ServiceHandle);
321     end
322     else
323       Result := System.GetLastError;
324 
325     CloseServiceHandle(ManagerHandle);
326   end
327   else
328     Result := System.GetLastError;
329 end;
330 
ContinueServicenull331 function ContinueService(ServiceName: String): Integer;
332 var
333   ManagerHandle: SC_HANDLE;
334   ServiceHandle: SC_HANDLE;
335   ServiceStatus: TServiceStatus;
336 begin
337   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
338 
339   if ManagerHandle > 0 then
340   begin
341     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_PAUSE_CONTINUE);
342 
343     if ServiceHandle > 0 then
344     begin
345 
346       if ControlService(ServiceHandle, SERVICE_CONTROL_CONTINUE, ServiceStatus) then
347         Result := WaitForStatus(ServiceName, SERVICE_RUNNING)
348       else
349         Result := System.GetLastError;
350 
351       CloseServiceHandle(ServiceHandle);
352     end
353     else
354       Result := System.GetLastError;
355 
356     CloseServiceHandle(ManagerHandle);
357   end
358   else
359     Result := System.GetLastError;
360 end;
361 
GetServiceNamenull362 function GetServiceName(DisplayName: String; var Name: String): Integer;
363 var
364   ManagerHandle: SC_HANDLE;
365   ServiceName: PChar;
366   ServiceBuffer: Cardinal;
367 begin
368   Result := 0;
369 
370   ServiceBuffer := 255;
371   ServiceName := StrAlloc(ServiceBuffer+1);
372 
373   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
374 
375   if ManagerHandle > 0 then
376   begin
377     if WinSvc.GetServiceKeyName(ManagerHandle, PChar(DisplayName), ServiceName, ServiceBuffer) then
378       Name := ServiceName
379     else
380       Result := System.GetLastError;
381 
382     CloseServiceHandle(ManagerHandle);
383   end
384   else
385     Result := System.GetLastError;
386 end;
387 
GetServiceDisplayNamenull388 function GetServiceDisplayName(ServiceName: String; var Name: String): Integer;
389 var
390   ManagerHandle: SC_HANDLE;
391   DisplayName: PChar;
392   ServiceBuffer: Cardinal;
393 begin
394   Result := 0;
395 
396   ServiceBuffer := 255;
397   DisplayName := StrAlloc(ServiceBuffer+1);
398 
399   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
400 
401   if ManagerHandle > 0 then
402   begin
403     if WinSvc.GetServiceDisplayName(ManagerHandle, PChar(ServiceName), DisplayName, ServiceBuffer) then
404       Name := DisplayName
405     else
406       Result := System.GetLastError;
407 
408     CloseServiceHandle(ManagerHandle);
409   end
410   else
411     Result := System.GetLastError;
412 end;
413 
GetServiceStatusnull414 function GetServiceStatus(ServiceName: String; var Status: DWORD): Integer;
415 var
416   ManagerHandle: SC_HANDLE;
417   ServiceHandle: SC_HANDLE;
418   ServiceStatus: TServiceStatus;
419 begin
420   Result := 0;
421 
422   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
423 
424   if ManagerHandle > 0 then
425   begin
426     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_STATUS);
427 
428     if ServiceHandle > 0 then
429     begin
430       if QueryServiceStatus(ServiceHandle, ServiceStatus) then
431         Status := ServiceStatus.dwCurrentState
432       else
433         Result := System.GetLastError;
434 
435       CloseServiceHandle(ServiceHandle);
436     end
437     else
438       Result := System.GetLastError;
439 
440     CloseServiceHandle(ManagerHandle);
441   end
442   else
443     Result := System.GetLastError;
444 end;
445 
GetServiceBinaryPathnull446 function GetServiceBinaryPath(ServiceName: String; var BinaryPath: String): Integer;
447 var
448   ManagerHandle: SC_HANDLE;
449   ServiceHandle: SC_HANDLE;
450   BytesNeeded: DWORD;
451   ServiceConfig: PQueryServiceConfig;
452 begin
453   Result := 0;
454   ServiceConfig := nil;
455 
456   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
457 
458   if ManagerHandle > 0 then
459   begin
460     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);
461 
462     if ServiceHandle > 0 then
463     begin
464 
465       if not QueryServiceConfig(ServiceHandle, ServiceConfig, 0, BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then
466       begin
467         GetMem(ServiceConfig, BytesNeeded);
468 
469         if QueryServiceConfig(ServiceHandle, ServiceConfig, BytesNeeded, BytesNeeded) then
470           BinaryPath := ServiceConfig^.lpBinaryPathName
471         else
472           Result := System.GetLastError;
473 
474         FreeMem(ServiceConfig);
475       end
476       else
477         Result := System.GetLastError;
478 
479       CloseServiceHandle(ServiceHandle);
480     end
481     else
482       Result := System.GetLastError;
483 
484     CloseServiceHandle(ManagerHandle);
485   end
486   else
487     Result := System.GetLastError;
488 end;
489 
GetServiceStartTypenull490 function GetServiceStartType(ServiceName: String; var StartType: DWORD): Integer;
491 var
492   ManagerHandle: SC_HANDLE;
493   ServiceHandle: SC_HANDLE;
494   BytesNeeded: DWORD;
495   ServiceConfig: PQueryServiceConfig;
496 begin
497   Result := 0;
498   ServiceConfig := nil;
499 
500   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
501 
502   if ManagerHandle > 0 then
503   begin
504     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);
505 
506     if ServiceHandle > 0 then
507     begin
508 
509       if not QueryServiceConfig(ServiceHandle, ServiceConfig, 0, BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then
510       begin
511         GetMem(ServiceConfig, BytesNeeded);
512 
513         if QueryServiceConfig(ServiceHandle, ServiceConfig, BytesNeeded, BytesNeeded) then
514           StartType := ServiceConfig^.dwStartType
515         else
516           Result := System.GetLastError;
517 
518         FreeMem(ServiceConfig);
519       end
520       else
521         Result := System.GetLastError;
522 
523       CloseServiceHandle(ServiceHandle);
524     end
525     else
526       Result := System.GetLastError;
527 
528     CloseServiceHandle(ManagerHandle);
529   end
530   else
531     Result := System.GetLastError;
532 end;
533 
GetServiceDescriptionnull534 function GetServiceDescription(ServiceName: String; var Description: String): Integer;
535 const
536   SERVICE_CONFIG_DESCRIPTION = 1;
537 type
538   TServiceDescription = record
539     lpDescription: PAnsiChar;
540   end;
541   PServiceDescription = ^TServiceDescription;
542 var
Servicenull543   QueryServiceConfig2: function(hService: SC_HANDLE; dwInfoLevel: DWORD; pBuffer: Pointer; cbBufSize: DWORD; var cbBytesNeeded: Cardinal): BOOL; stdcall;
544   ManagerHandle: SC_HANDLE;
545   ServiceHandle: SC_HANDLE;
546   LockHandle: SC_LOCK;
547   ServiceDescription: PServiceDescription;
548   BytesNeeded: Cardinal;
549 begin
550   Result := 0;
551 
552   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);
553 
554   if ManagerHandle > 0 then
555   begin
556     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);
557 
558     if ServiceHandle > 0 then
559     begin
560       LockHandle := LockServiceDatabase(ManagerHandle);
561 
562       if LockHandle <> nil then
563       begin
564         @QueryServiceConfig2 := GetProcAddress(GetModuleHandle(advapi32), 'QueryServiceConfig2A');
565 
566         if Assigned(@QueryServiceConfig2) then
567         begin
568 
569           if not QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_DESCRIPTION, nil, 0, BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then
570           begin
571             GetMem(ServiceDescription, BytesNeeded);
572 
573             if QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_DESCRIPTION, ServiceDescription, BytesNeeded, BytesNeeded) then
574               Description := ServiceDescription.lpDescription
575             else
576               Result := System.GetLastError;
577 
578             FreeMem(ServiceDescription);
579           end
580           else
581             Result := System.GetLastError;
582 
583         end
584         else
585           Result := System.GetLastError;
586 
587         UnlockServiceDatabase(LockHandle);
588       end
589       else
590         Result := System.GetLastError;
591 
592       CloseServiceHandle(ServiceHandle);
593     end
594     else
595       Result := System.GetLastError;
596 
597     CloseServiceHandle(ManagerHandle);
598   end
599   else
600     Result := System.GetLastError;
601 end;
602 
GetServiceLogonnull603 function GetServiceLogon(ServiceName: String; var Username: String): Integer;
604 var
605   ManagerHandle: SC_HANDLE;
606   ServiceHandle: SC_HANDLE;
607   BytesNeeded: DWORD;
608   ServiceConfig: PQueryServiceConfig;
609 begin
610   Result := 0;
611   ServiceConfig := nil;
612 
613   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);
614 
615   if ManagerHandle > 0 then
616   begin
617     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);
618 
619     if ServiceHandle > 0 then
620     begin
621 
622       if not QueryServiceConfig(ServiceHandle, ServiceConfig, 0, BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then
623       begin
624         GetMem(ServiceConfig, BytesNeeded);
625 
626         if QueryServiceConfig(ServiceHandle, ServiceConfig, BytesNeeded, BytesNeeded) then
627           Username := ServiceConfig^.lpServiceStartName
628         else
629           Result := System.GetLastError;
630 
631         FreeMem(ServiceConfig);
632       end
633       else
634         Result := System.GetLastError;
635 
636       CloseServiceHandle(ServiceHandle);
637     end
638     else
639       Result := System.GetLastError;
640 
641     CloseServiceHandle(ManagerHandle);
642   end
643   else
644     Result := System.GetLastError;
645 end;
646 
SetServiceDescriptionnull647 function SetServiceDescription(ServiceName: String; Description: String): Integer;
648 const
649   SERVICE_CONFIG_DESCRIPTION = 1;
650 var
Servicenull651   ChangeServiceConfig2: function(hService: SC_HANDLE; dwInfoLevel: DWORD; lpInfo: Pointer): BOOL; stdcall;
652   ManagerHandle: SC_HANDLE;
653   ServiceHandle: SC_HANDLE;
654   LockHandle: SC_LOCK;
655 begin
656   Result := 0;
657 
658   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);
659 
660   if ManagerHandle > 0 then
661   begin
662     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);
663 
664     if ServiceHandle > 0 then
665     begin
666       LockHandle := LockServiceDatabase(ManagerHandle);
667 
668       if LockHandle <> nil then
669       begin
670         @ChangeServiceConfig2 := GetProcAddress(GetModuleHandle(advapi32), 'ChangeServiceConfig2A');
671 
672         if Assigned(@ChangeServiceConfig2) then
673         begin
674           if not ChangeServiceConfig2(ServiceHandle, SERVICE_CONFIG_DESCRIPTION, @Description) then
675             Result := System.GetLastError;
676         end
677         else
678           Result := System.GetLastError;
679 
680         UnlockServiceDatabase(LockHandle);
681       end
682       else
683         Result := System.GetLastError;
684 
685       CloseServiceHandle(ServiceHandle);
686     end
687     else
688       Result := System.GetLastError;
689 
690     CloseServiceHandle(ManagerHandle);
691   end
692   else
693     Result := System.GetLastError;
694 end;
695 
SetServiceStartTypenull696 function SetServiceStartType(ServiceName: String; StartType: DWORD): Integer;
697 var
698   ManagerHandle: SC_HANDLE;
699   ServiceHandle: SC_HANDLE;
700   LockHandle: SC_LOCK;
701 begin
702   Result := 0;
703 
704   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);
705 
706   if ManagerHandle > 0 then
707   begin
708     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);
709 
710     if ServiceHandle > 0 then
711     begin
712       LockHandle := LockServiceDatabase(ManagerHandle);
713 
714       if LockHandle <> nil then
715       begin
716         if not ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, StartType, SERVICE_NO_CHANGE, nil, nil, nil, nil, nil, nil, nil) then
717           Result := System.GetLastError;
718 
719         UnlockServiceDatabase(LockHandle);
720       end
721       else
722         Result := System.GetLastError;
723 
724       CloseServiceHandle(ServiceHandle);
725     end
726     else
727       Result := System.GetLastError;
728 
729     CloseServiceHandle(ManagerHandle);
730   end
731   else
732     Result := System.GetLastError;
733 end;
734 
SetServiceLogonnull735 function SetServiceLogon(ServiceName: String; Username: String; Password: String): Integer;
736 var
737   ManagerHandle: SC_HANDLE;
738   ServiceHandle: SC_HANDLE;
739   LockHandle: SC_LOCK;
740 begin
741   Result := 0;
742 
743   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);
744 
745   if Pos('\', Username) = 0 then
746     Username := '.\' + Username;
747 
748   if ManagerHandle > 0 then
749   begin
750     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);
751 
752     if ServiceHandle > 0 then
753     begin
754       LockHandle := LockServiceDatabase(ManagerHandle);
755 
756       if LockHandle <> nil then
757       begin
758         if not ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, nil, nil, nil, nil, PChar(Username), PChar(Password), nil) then
759           Result := System.GetLastError;
760 
761         UnlockServiceDatabase(LockHandle);
762       end
763       else
764         Result := System.GetLastError;
765 
766       CloseServiceHandle(ServiceHandle);
767     end
768     else
769       Result := System.GetLastError;
770 
771     CloseServiceHandle(ManagerHandle);
772   end
773   else
774     Result := System.GetLastError;
775 end;
776 
SetServiceBinaryPathnull777 function SetServiceBinaryPath(ServiceName: String; BinaryPath: String): Integer;
778 var
779   ManagerHandle: SC_HANDLE;
780   ServiceHandle: SC_HANDLE;
781   LockHandle: SC_LOCK;
782 begin
783   Result := 0;
784 
785   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);
786 
787   if ManagerHandle > 0 then
788   begin
789     ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);
790 
791     if ServiceHandle > 0 then
792     begin
793       LockHandle := LockServiceDatabase(ManagerHandle);
794 
795       if LockHandle <> nil then
796       begin
797         if not ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, PChar(BinaryPath), nil, nil, nil, nil, nil, nil) then
798           Result := System.GetLastError;
799 
800         UnlockServiceDatabase(LockHandle);
801       end
802       else
803         Result := System.GetLastError;
804 
805       CloseServiceHandle(ServiceHandle);
806     end
807     else
808       Result := System.GetLastError;
809 
810     CloseServiceHandle(ManagerHandle);
811   end
812   else
813     Result := System.GetLastError;
814 end;
815 
ServiceIsRunningnull816 function ServiceIsRunning(ServiceName: String; var IsRunning: Boolean): Integer;
817 var
818   Status: DWORD;
819 begin
820   Result := GetServiceStatus(ServiceName, Status);
821 
822   if Result = 0 then
823     IsRunning := Status = SERVICE_RUNNING
824   else
825     IsRunning := False;
826 end;
827 
ServiceIsStoppednull828 function ServiceIsStopped(ServiceName: String; var IsStopped: Boolean): Integer;
829 var
830   Status: DWORD;
831 begin
832   Result := GetServiceStatus(ServiceName, Status);
833 
834   if Result = 0 then
835     IsStopped := Status = SERVICE_STOPPED
836   else
837     IsStopped := False;
838 end;
839 
ServiceIsPausednull840 function ServiceIsPaused(ServiceName: String; var IsPaused: Boolean): Integer;
841 var
842   Status: DWORD;
843 begin
844   Result := GetServiceStatus(ServiceName, Status);
845 
846   if Result = 0 then
847     IsPaused := Status = SERVICE_PAUSED
848   else
849     IsPaused := False;
850 end;
851 
RestartServicenull852 function RestartService(ServiceName: String; ServiceArguments: String): Integer;
853 begin
854   Result := StopService(ServiceName);
855 
856   if Result = 0 then
857     Result := StartService(ServiceName, ServiceArguments);
858 end;
859 
InstallServicenull860 function InstallService(ServiceName, DisplayName: String; ServiceType: DWORD;
861   StartType: DWORD; BinaryPathName: String; Dependencies: String;
862   Username: String; Password: String): Integer;
863 var
864   ManagerHandle: SC_HANDLE;
865   ServiceHandle: SC_HANDLE;
866   PDependencies: PChar;
867   PUsername: PChar;
868   PPassword: PChar;
869 const
870   ReplaceDelimitter: String = '/';
871 
Replacenull872   function Replace(Value: String): String;
873   begin
874     while Pos(ReplaceDelimitter, Value) <> 0 do
875     begin
876       Result := Result + Copy(Value, 1, Pos(ReplaceDelimitter, Value) -1) + Chr(0);
877       Delete(Value, 1, Pos(ReplaceDelimitter, Value));
878     end;
879 
880     Result := Result + Value + Chr(0) + Chr(0);
881   end;
882 
883 begin
884   Result := 0;
885 
886   if Dependencies = '' then
887     PDependencies := nil
888   else
889     PDependencies := PChar(Replace(Dependencies));
890 
891   if UserName = '' then
892     PUsername := nil
893   else
894     PUsername := PChar(Username);
895 
896   if Password = '' then
897     PPassword := nil
898   else
899     PPassword := PChar(Password);
900 
901   ManagerHandle := OpenSCManager('', nil, SC_MANAGER_ALL_ACCESS);
902 
903   if ManagerHandle > 0 then
904   begin
905     ServiceHandle := CreateService(ManagerHandle,
906                                    PChar(ServiceName),
907                                    PChar(DisplayName),
908                                    SERVICE_START or SERVICE_QUERY_STATUS or _DELETE,
909                                    ServiceType,
910                                    StartType,
911                                    SERVICE_ERROR_NORMAL,
912                                    PChar(BinaryPathName),
913                                    nil,
914                                    nil,
915                                    PDependencies,
916                                    PUsername,
917                                    PPassword);
918 
919     if ServiceHandle <> 0 then
920       CloseServiceHandle(ServiceHandle)
921     else
922       Result := System.GetLastError;
923 
924     CloseServiceHandle(ManagerHandle);
925   end
926   else
927     Result := System.GetLastError;
928 end;
929 
RemoveServicenull930 function RemoveService(ServiceName: String): Integer;
931 var
932   ManagerHandle: SC_HANDLE;
933   ServiceHandle: SC_HANDLE;
934   LockHandle: SC_LOCK;
935   IsStopped: Boolean;
936   Deleted: Boolean;
937 begin
938   IsStopped := False;
939 
940   Result := ServiceIsStopped(ServiceName, IsStopped);
941 
942   if Result = 0 then
943     if not IsStopped then
944       Result := StopService(ServiceName);
945 
946   if Result = 0 then
947   begin
948     ManagerHandle := OpenSCManager('', nil, SC_MANAGER_ALL_ACCESS);
949 
950     if ManagerHandle > 0 then
951     begin
952       ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_ALL_ACCESS);
953 
954       if ServiceHandle > 0 then
955       begin
956         LockHandle := LockServiceDatabase(ManagerHandle);
957 
958         if LockHandle <> nil then
959         begin
960           Deleted := DeleteService(ServiceHandle);
961 
962           if not Deleted then
963             Result := System.GetLastError;
964 
965           UnlockServiceDatabase(LockHandle);
966         end
967         else
968           Result := System.GetLastError;
969 
970         CloseServiceHandle(ServiceHandle);
971       end
972       else
973         Result := System.GetLastError;
974 
975       CloseServiceHandle(ManagerHandle);
976     end
977     else
978       Result := System.GetLastError;
979   end;
980 end;
981 
GetErrorMessagenull982 function GetErrorMessage(ErrorCode: Integer): String;
983 begin
984   Result := SysErrorMessage(ErrorCode);
985 end;
986 
987 end.
988