2using System.ComponentModel;
3using System.Reflection;
5using System.Security.AccessControl;
6using System.Security.Principal;
7using System.ServiceProcess;
14#pragma warning disable CA1416
18 internal delegate
void ServiceMainFunction(
int numArs, IntPtr argPtrPtr);
25 private readonly
string serviceName;
26 private readonly
string instanceName;
30 this.serviceName = ServiceName;
31 this.instanceName = InstanceName;
33 if (!
string.IsNullOrEmpty(InstanceName))
34 this.serviceName +=
" " + InstanceName;
56 ServiceFailureActions FailureActions, Win32ServiceCredentials Credentials)
58 string Path = Assembly.GetExecutingAssembly().Location.Replace(
".dll",
".exe");
60 if (!
string.IsNullOrEmpty(this.instanceName))
61 Path +=
" -instance \"" + this.instanceName +
"\"";
65 using ServiceControlManager mgr = ServiceControlManager.Connect(
null,
null, ServiceControlManagerAccessRights.All);
67 if (mgr.TryOpenService(
this.serviceName, ServiceControlAccessRights.All, out ServiceHandle existingService,
68 out Win32Exception errorException))
70 using (existingService)
72 existingService.ChangeConfig(DisplayName, Path, ServiceType.Win32OwnProcess, StartType,
75 if (!
string.IsNullOrEmpty(Description))
76 existingService.SetDescription(Description);
78 if (FailureActions is not
null)
80 existingService.SetFailureActions(FailureActions);
81 existingService.SetFailureActionFlag(
true);
84 existingService.SetFailureActionFlag(
false);
88 existingService.Start(throwIfAlreadyRunning:
false);
97 if (errorException.NativeErrorCode ==
Win32.ERROR_SERVICE_DOES_NOT_EXIST)
99 using ServiceHandle svc = mgr.CreateService(this.serviceName, DisplayName, Path, ServiceType.Win32OwnProcess,
102 if (!
string.IsNullOrEmpty(Description))
103 svc.SetDescription(Description);
105 if (FailureActions is not
null)
107 svc.SetFailureActions(FailureActions);
108 svc.SetFailureActionFlag(
true);
111 svc.SetFailureActionFlag(
false);
119 using ServiceController Service =
new(this.serviceName);
121 bool HandleRetrieved =
false;
122 Service.ServiceHandle.DangerousAddRef(ref HandleRetrieved);
126 IntPtr ServiceHandle = Service.ServiceHandle.DangerousGetHandle();
128 QueryServiceObjectSecurity(ServiceHandle, SecurityInfos.DiscretionaryAcl,
null, 0, out uint Size);
130 if (Size <= 0 || Size >
int.MaxValue)
131 throw new Exception(
"Unable to get Service Security Object");
133 byte[] Buffer =
new byte[Size];
134 if (!QueryServiceObjectSecurity(ServiceHandle, SecurityInfos.DiscretionaryAcl, Buffer, Size, out Size))
135 throw new Win32Exception(Marshal.GetLastWin32Error());
137 RawSecurityDescriptor Descriptor =
new(Buffer, 0);
139 if (Descriptor.DiscretionaryAcl is not
null)
144 foreach (
object Item
in Descriptor.DiscretionaryAcl)
146 if (Item is CommonAce Ace)
148 if (Ace.SecurityIdentifier.IsWellKnown(WellKnownSidType.LocalServiceSid))
150 if (Ace.AceQualifier != AceQualifier.AccessAllowed || (Ace.AccessMask & (
int)ServiceAccessRights.Start) == 0)
151 Descriptor.DiscretionaryAcl.RemoveAce(i);
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);
169 int Len = Descriptor.BinaryLength;
170 byte[] Bin =
new byte[Len];
172 Descriptor.GetBinaryForm(Bin, 0);
174 if (!SetServiceObjectSecurity(ServiceHandle, SecurityInfos.DiscretionaryAcl, Bin))
175 throw new Win32Exception(Marshal.GetLastWin32Error());
182 Service.ServiceHandle.DangerousRelease();
190 if (StartImmediately)
199 throw errorException;
202 catch (DllNotFoundException dllException)
204 throw new PlatformNotSupportedException(
"Unable to call windows service management API.", dllException);
217 using ServiceControlManager mgr = ServiceControlManager.Connect(
null,
null, ServiceControlManagerAccessRights.All);
219 if (mgr.TryOpenService(
this.serviceName, ServiceControlAccessRights.All, out ServiceHandle existingService,
220 out Win32Exception errorException))
222 using (existingService)
224 existingService.Delete();
230 if (errorException.NativeErrorCode ==
Win32.ERROR_SERVICE_DOES_NOT_EXIST)
233 throw errorException;
236 catch (DllNotFoundException dllException)
238 throw new PlatformNotSupportedException(
"Unable to call windows service management API.", dllException);
245#pragma warning restore CA1416
Static class managing the application event log. Applications and services log events on this static ...
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.
Handles interaction with Windows Service API.
bool Uninstall()
Uninstalls the service.
int Install(string DisplayName, string Description, ServiceStartType StartType, bool StartImmediately, ServiceFailureActions FailureActions, Win32ServiceCredentials Credentials)
Installs the service.
Handles interaction with Windows Service API.
ErrorSeverity
Error severity
ServiceStartType
How the windows service should be started.