Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ServiceInstaller.cs
1using System;
2using System.ComponentModel;
3using System.Reflection;
5using System.Security.AccessControl;
6using System.Security.Principal;
7using System.ServiceProcess;
8using Waher.Events;
13
14#pragma warning disable CA1416 // Validate platform compatibility
15
17{
18 internal delegate void ServiceMainFunction(int numArs, IntPtr argPtrPtr);
19
23 public class ServiceInstaller
24 {
25 private readonly string serviceName;
26 private readonly string instanceName;
27
28 internal ServiceInstaller(string ServiceName, string InstanceName)
29 {
30 this.serviceName = ServiceName;
31 this.instanceName = InstanceName;
32
33 if (!string.IsNullOrEmpty(InstanceName))
34 this.serviceName += " " + InstanceName;
35 }
36
55 public int Install(string DisplayName, string Description, ServiceStartType StartType, bool StartImmediately,
56 ServiceFailureActions FailureActions, Win32ServiceCredentials Credentials)
57 {
58 string Path = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".exe");
59
60 if (!string.IsNullOrEmpty(this.instanceName))
61 Path += " -instance \"" + this.instanceName + "\"";
62
63 try
64 {
65 using ServiceControlManager mgr = ServiceControlManager.Connect(null, null, ServiceControlManagerAccessRights.All);
66
67 if (mgr.TryOpenService(this.serviceName, ServiceControlAccessRights.All, out ServiceHandle existingService,
68 out Win32Exception errorException))
69 {
70 using (existingService)
71 {
72 existingService.ChangeConfig(DisplayName, Path, ServiceType.Win32OwnProcess, StartType,
73 ErrorSeverity.Normal, Credentials);
74
75 if (!string.IsNullOrEmpty(Description))
76 existingService.SetDescription(Description);
77
78 if (FailureActions is not null)
79 {
80 existingService.SetFailureActions(FailureActions);
81 existingService.SetFailureActionFlag(true);
82 }
83 else
84 existingService.SetFailureActionFlag(false);
85
86 if (StartImmediately)
87 {
88 existingService.Start(throwIfAlreadyRunning: false);
89 return 3;
90 }
91 else
92 return 2;
93 }
94 }
95 else
96 {
97 if (errorException.NativeErrorCode == Win32.ERROR_SERVICE_DOES_NOT_EXIST)
98 {
99 using ServiceHandle svc = mgr.CreateService(this.serviceName, DisplayName, Path, ServiceType.Win32OwnProcess,
100 StartType, ErrorSeverity.Normal, Credentials);
101
102 if (!string.IsNullOrEmpty(Description))
103 svc.SetDescription(Description);
104
105 if (FailureActions is not null)
106 {
107 svc.SetFailureActions(FailureActions);
108 svc.SetFailureActionFlag(true);
109 }
110 else
111 svc.SetFailureActionFlag(false);
112
113 try
114 {
115 // Attempt to give the local service account access rights to start
116 // the service. This will be used by the update procedure to trigger
117 // a start of the service after installation has completed.
118
119 using ServiceController Service = new(this.serviceName);
120
121 bool HandleRetrieved = false;
122 Service.ServiceHandle.DangerousAddRef(ref HandleRetrieved);
123
124 try
125 {
126 IntPtr ServiceHandle = Service.ServiceHandle.DangerousGetHandle();
127
128 QueryServiceObjectSecurity(ServiceHandle, SecurityInfos.DiscretionaryAcl, null, 0, out uint Size);
129
130 if (Size <= 0 || Size > int.MaxValue)
131 throw new Exception("Unable to get Service Security Object");
132
133 byte[] Buffer = new byte[Size];
134 if (!QueryServiceObjectSecurity(ServiceHandle, SecurityInfos.DiscretionaryAcl, Buffer, Size, out Size))
135 throw new Win32Exception(Marshal.GetLastWin32Error());
136
137 RawSecurityDescriptor Descriptor = new(Buffer, 0);
138
139 if (Descriptor.DiscretionaryAcl is not null)
140 {
141 int i = 0;
142 bool Found = false;
143
144 foreach (object Item in Descriptor.DiscretionaryAcl)
145 {
146 if (Item is CommonAce Ace)
147 {
148 if (Ace.SecurityIdentifier.IsWellKnown(WellKnownSidType.LocalServiceSid))
149 {
150 if (Ace.AceQualifier != AceQualifier.AccessAllowed || (Ace.AccessMask & (int)ServiceAccessRights.Start) == 0)
151 Descriptor.DiscretionaryAcl.RemoveAce(i);
152 else
153 {
154 Found = true;
155 break;
156 }
157 }
158 }
159
160 i++;
161 }
162
163 if (!Found)
164 {
165 SecurityIdentifier LocalServiceSid = new(WellKnownSidType.LocalServiceSid, null);
166 CommonAce LocalServiceAce = new(AceFlags.None, AceQualifier.AccessAllowed, (int)ServiceAccessRights.Start, LocalServiceSid, false, null);
167 Descriptor.DiscretionaryAcl.InsertAce(Descriptor.DiscretionaryAcl.Count, LocalServiceAce);
168
169 int Len = Descriptor.BinaryLength;
170 byte[] Bin = new byte[Len];
171
172 Descriptor.GetBinaryForm(Bin, 0);
173
174 if (!SetServiceObjectSecurity(ServiceHandle, SecurityInfos.DiscretionaryAcl, Bin))
175 throw new Win32Exception(Marshal.GetLastWin32Error());
176 }
177 }
178 }
179 finally
180 {
181 if (HandleRetrieved)
182 Service.ServiceHandle.DangerousRelease();
183 }
184 }
185 catch (Exception ex)
186 {
187 Log.Exception(ex);
188 }
189
190 if (StartImmediately)
191 {
192 svc.Start();
193 return 1;
194 }
195 else
196 return 0;
197 }
198 else
199 throw errorException;
200 }
201 }
202 catch (DllNotFoundException dllException)
203 {
204 throw new PlatformNotSupportedException("Unable to call windows service management API.", dllException);
205 }
206 }
207
213 public bool Uninstall()
214 {
215 try
216 {
217 using ServiceControlManager mgr = ServiceControlManager.Connect(null, null, ServiceControlManagerAccessRights.All);
218
219 if (mgr.TryOpenService(this.serviceName, ServiceControlAccessRights.All, out ServiceHandle existingService,
220 out Win32Exception errorException))
221 {
222 using (existingService)
223 {
224 existingService.Delete();
225 return true;
226 }
227 }
228 else
229 {
230 if (errorException.NativeErrorCode == Win32.ERROR_SERVICE_DOES_NOT_EXIST)
231 return false;
232 else
233 throw errorException;
234 }
235 }
236 catch (DllNotFoundException dllException)
237 {
238 throw new PlatformNotSupportedException("Unable to call windows service management API.", dllException);
239 }
240 }
241
242 }
243}
244
245#pragma warning restore CA1416 // Validate platform compatibility
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1657
Handles interaction with Windows Service API.
int Install(string DisplayName, string Description, ServiceStartType StartType, bool StartImmediately, ServiceFailureActions FailureActions, Win32ServiceCredentials Credentials)
Installs the service.
Handles interaction with Windows Service API.
Definition: Win32.cs:16
ServiceStartType
How the windows service should be started.
Definition: App.xaml.cs:4