diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
index 314b13ff475a0..c8dcaa55b8936 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
@@ -1,26 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
-using System.IO;
-using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
-using System.Security;
using System.Threading;
using static Interop.Advapi32;
namespace System.ServiceProcess
{
- ///
+ ///
/// Provides a base class for a service that will exist as part of a service application.
/// must be derived when creating a new service class.
- ///
+ ///
public class ServiceBase : Component
{
private SERVICE_STATUS _status;
@@ -37,28 +33,27 @@ public class ServiceBase : Component
private bool _initialized;
private EventLog? _eventLog;
- ///
- ///
- /// Indicates the maximum size for a service name.
- ///
- ///
+ ///
+ /// Indicates the maximum size for a service name.
+ ///
public const int MaxNameLength = 80;
- ///
- /// Creates a new instance of the class.
- ///
+ ///
+ /// Creates a new instance of the class.
+ ///
public ServiceBase()
{
_acceptedCommands = AcceptOptions.ACCEPT_STOP;
- ServiceName = "";
+ ServiceName = string.Empty;
AutoLog = true;
}
- ///
+ ///
/// When this method is called from OnStart, OnStop, OnPause or OnContinue,
/// the specified wait hint is passed to the
/// Service Control Manager to avoid having the service marked as not responding.
- ///
+ ///
+ ///
public unsafe void RequestAdditionalTime(int milliseconds)
{
fixed (SERVICE_STATUS* pStatus = &_status)
@@ -77,16 +72,16 @@ public unsafe void RequestAdditionalTime(int milliseconds)
}
}
- ///
- /// Indicates whether to report Start, Stop, Pause, and Continue commands in the event
- ///
+ ///
+ /// Indicates whether to report Start, Stop, Pause, and Continue commands in the event.
+ ///
[DefaultValue(true)]
public bool AutoLog { get; set; }
- ///
+ ///
/// The termination code for the service. Set this to a non-zero value before
/// stopping to indicate an error to the Service Control Manager.
- ///
+ ///
public int ExitCode
{
get
@@ -99,10 +94,10 @@ public int ExitCode
}
}
- ///
+ ///
/// Indicates whether the service can be handle notifications on
/// computer power status changes.
- ///
+ ///
[DefaultValue(false)]
public bool CanHandlePowerEvent
{
@@ -126,9 +121,9 @@ public bool CanHandlePowerEvent
}
}
- ///
+ ///
/// Indicates whether the service can handle Terminal Server session change events.
- ///
+ ///
[DefaultValue(false)]
public bool CanHandleSessionChangeEvent
{
@@ -152,10 +147,9 @@ public bool CanHandleSessionChangeEvent
}
}
- ///
- /// Indicates whether the service can be paused
- /// and resumed.
- ///
+ ///
+ /// Indicates whether the service can be paused and resumed.
+ ///
[DefaultValue(false)]
public bool CanPauseAndContinue
{
@@ -179,10 +173,9 @@ public bool CanPauseAndContinue
}
}
- ///
- /// Indicates whether the service should be notified when
- /// the system is shutting down.
- ///
+ ///
+ /// Indicates whether the service should be notified when the system is shutting down.
+ ///
[DefaultValue(false)]
public bool CanShutdown
{
@@ -206,10 +199,9 @@ public bool CanShutdown
}
}
- ///
- /// Indicates whether the service can be
- /// stopped once it has started.
- ///
+ ///
+ /// Indicates whether the service can be stopped once it has started.
+ ///
[DefaultValue(true)]
public bool CanStop
{
@@ -233,9 +225,9 @@ public bool CanStop
}
}
- ///
+ ///
/// can be used to write notification of service command calls, such as Start and Stop, to the Application event log. This property is read-only.
- ///
+ ///
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual EventLog EventLog
{
@@ -262,9 +254,9 @@ protected IntPtr ServiceHandle
}
}
- ///
- /// Indicates the short name used to identify the service to the system.
- ///
+ ///
+ /// Indicates the short name used to identify the service to the system.
+ ///
public string ServiceName
{
get
@@ -304,12 +296,12 @@ internal static bool ValidServiceName(string serviceName)
return true;
}
- ///
+ ///
/// Disposes of the resources (other than memory ) used by
/// the .
/// This is called from when all
/// services in the process have entered the SERVICE_STOPPED state.
- ///
+ ///
protected override void Dispose(bool disposing)
{
_nameFrozen = false;
@@ -318,60 +310,60 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}
- ///
+ ///
/// When implemented in a
/// derived class,
/// executes when a Continue command is sent to the service
/// by the
/// Service Control Manager. Specifies the actions to take when a
/// service resumes normal functioning after being paused.
- ///
+ ///
protected virtual void OnContinue()
{
}
- ///
+ ///
/// When implemented in a
/// derived class, executes when a Pause command is sent
/// to
/// the service by the Service Control Manager. Specifies the
/// actions to take when a service pauses.
- ///
+ ///
protected virtual void OnPause()
{
}
- ///
+ ///
///
/// When implemented in a derived class, executes when the computer's
/// power status has changed.
///
- ///
+ ///
protected virtual bool OnPowerEvent(PowerBroadcastStatus powerStatus)
{
return true;
}
- ///
+ ///
/// When implemented in a derived class,
/// executes when a Terminal Server session change event is received.
- ///
+ ///
protected virtual void OnSessionChange(SessionChangeDescription changeDescription)
{
}
- ///
+ ///
/// When implemented in a derived class,
/// executes when the system is shutting down.
/// Specifies what should
/// happen just prior
/// to the system shutting down.
- ///
+ ///
protected virtual void OnShutdown()
{
}
- ///
+ ///
/// When implemented in a
/// derived class, executes when a Start command is sent
/// to the service by the Service
@@ -385,18 +377,18 @@ protected virtual void OnShutdown()
/// OnStart never be called if you use the SCM to start the service? What about
/// services that start automatically at boot-up?
///
- ///
+ ///
protected virtual void OnStart(string[] args)
{
}
- ///
+ ///
/// When implemented in a
/// derived class, executes when a Stop command is sent to the
/// service by the Service Control Manager. Specifies the actions to take when a
/// service stops
/// running.
- ///
+ ///
protected virtual void OnStop()
{
}
@@ -563,7 +555,7 @@ private unsafe void DeferredShutdown()
}
}
- ///
+ ///
/// When implemented in a derived class,
/// executes when a custom command is passed to
/// the service. Specifies the actions to take when
@@ -581,16 +573,16 @@ private unsafe void DeferredShutdown()
/// second paragraph below--what, if any, contact does the SCM have with a
/// custom command?
///
- ///
+ ///
protected virtual void OnCustomCommand(int command)
{
}
- ///
+ ///
/// Provides the main entry point for an executable that
/// contains multiple associated services. Loads the specified services into memory so they can be
/// started.
- ///
+ ///
public static unsafe void Run(ServiceBase[] services)
{
if (services == null || services.Length == 0)
@@ -621,13 +613,10 @@ public static unsafe void Run(ServiceBase[] services)
foreach (ServiceBase service in services)
{
- if (service._startFailedException != null)
- {
- // Propagate exceptions throw during OnStart.
- // Note that this same exception is also thrown from ServiceMainCallback
- // (so SCM can see it as well).
- service._startFailedException.Throw();
- }
+ // Propagate exceptions throw during OnStart.
+ // Note that this same exception is also thrown from ServiceMainCallback
+ // (so SCM can see it as well).
+ service._startFailedException?.Throw();
}
string errorMessage = string.Empty;
@@ -660,12 +649,12 @@ public static unsafe void Run(ServiceBase[] services)
}
}
- ///
+ ///
/// Provides the main
/// entry point for an executable that contains a single
/// service. Loads the service into memory so it can be
/// started.
- ///
+ ///
public static void Run(ServiceBase service)
{
if (service == null)
@@ -703,7 +692,7 @@ private void Initialize(bool multipleServices)
_status.checkPoint = 0;
_status.waitHint = 0;
- _mainCallback = this.ServiceMainCallback;
+ _mainCallback = ServiceMainCallback;
_commandCallbackEx = this.ServiceCommandCallbackEx;
_initialized = true;
@@ -752,12 +741,12 @@ private int ServiceCommandCallbackEx(int command, int eventType, IntPtr eventDat
return 0;
}
- ///
+ ///
/// Command Handler callback is called by NT .
/// Need to take specific action in response to each
/// command message. There is usually no need to override this method.
/// Instead, override OnStart, OnStop, OnCustomCommand, etc.
- ///
+ ///
///
private unsafe void ServiceCommandCallback(int command)
{
@@ -861,11 +850,11 @@ private void ServiceQueuedMainCallback(object state)
_startCompletedSignal!.Set();
}
- ///
+ ///
/// ServiceMain callback is called by NT .
/// It is expected that we register the command handler,
/// and start the service at this point.
- ///
+ ///
///
[EditorBrowsable(EditorBrowsableState.Never)]
public unsafe void ServiceMainCallback(int argCount, IntPtr argPointer)
diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs
index 72eebc88a9ca5..ba58f6174f374 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs
@@ -2,888 +2,971 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Win32.SafeHandles;
-using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
using System.Runtime.InteropServices;
-using System.Security;
using System.Text;
using System.Threading;
namespace System.ServiceProcess
{
- /// This class represents an NT service. It allows you to connect to a running or stopped service
- /// and manipulate it or get information about it.
- [Designer("System.ServiceProcess.Design.ServiceControllerDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
- public class ServiceController : Component
- {
- private string _machineName; // Never null
- private readonly ManualResetEvent _waitForStatusSignal = new ManualResetEvent(false);
- private const string DefaultMachineName = ".";
-
- private string? _name;
- private string? _eitherName;
- private string? _displayName;
-
- private int _commandsAccepted;
- private bool _statusGenerated;
- private bool _startTypeInitialized;
- private int _type;
- private bool _disposed;
- private SafeServiceHandle? _serviceManagerHandle;
- private ServiceControllerStatus _status;
- private ServiceController[]? _dependentServices;
- private ServiceController[]? _servicesDependedOn;
- private ServiceStartMode _startType;
-
- public ServiceController()
- {
- _machineName = DefaultMachineName;
- _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
- }
-
- /// Creates a ServiceController object, based on service name.
- public ServiceController(string name)
- : this(name, DefaultMachineName)
- {
- }
-
- /// Creates a ServiceController object, based on machine and service name.
- public ServiceController(string name, string machineName)
- {
- if (!CheckMachineName(machineName))
- throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
-
- if (string.IsNullOrEmpty(name))
- throw new ArgumentException(SR.Format(SR.InvalidParameter, nameof(name), name));
-
- _machineName = machineName;
- _eitherName = name;
- _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
- }
+ /// This class represents an NT service. It allows you to connect to a running or stopped service
+ /// and manipulate it or get information about it.
+ [Designer("System.ServiceProcess.Design.ServiceControllerDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+ public class ServiceController : Component
+ {
+ private string _machineName; // Never null
+ private readonly ManualResetEvent _waitForStatusSignal = new ManualResetEvent(false);
+ private const string DefaultMachineName = ".";
+
+ private string? _name;
+ private string? _eitherName;
+ private string? _displayName;
+
+ private int _commandsAccepted;
+ private bool _statusGenerated;
+ private bool _startTypeInitialized;
+ private int _type;
+ private bool _disposed;
+ private SafeServiceHandle? _serviceManagerHandle;
+ private ServiceControllerStatus _status;
+ private ServiceController[]? _dependentServices;
+ private ServiceController[]? _servicesDependedOn;
+ private ServiceStartMode _startType;
+
+ public ServiceController()
+ {
+ _machineName = DefaultMachineName;
+ _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
+ }
+ ///
+ /// Creates a ServiceController object, based on service name.
+ ///
+ /// Name of the service
+ public ServiceController(string name)
+ : this(name, DefaultMachineName)
+ {
+ }
- /// Used by the GetServices and GetDevices methods. Avoids duplicating work by the static
- /// methods and our own GenerateInfo().
- private ServiceController(string machineName, Interop.Advapi32.ENUM_SERVICE_STATUS status)
- {
- if (!CheckMachineName(machineName))
- throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
-
- _machineName = machineName;
- _name = status.serviceName;
- _displayName = status.displayName;
- _commandsAccepted = status.controlsAccepted;
- _status = (ServiceControllerStatus)status.currentState;
- _type = status.serviceType;
- _statusGenerated = true;
- }
- /// Used by the GetServicesInGroup method.
- private ServiceController(string machineName, Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS status)
- {
- if (!CheckMachineName(machineName))
- throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
-
- _machineName = machineName;
- _name = status.serviceName;
- _displayName = status.displayName;
- _commandsAccepted = status.controlsAccepted;
- _status = (ServiceControllerStatus)status.currentState;
- _type = status.serviceType;
- _statusGenerated = true;
- }
+ ///
+ /// Creates a ServiceController object, based on machine and service name.
+ ///
+ /// Name of the service
+ /// Name of the machine
+ public ServiceController(string name, string machineName)
+ {
+ if (!CheckMachineName(machineName))
+ throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
- /// Tells if the service referenced by this object can be paused.
- public bool CanPauseAndContinue
- {
- get
- {
- GenerateStatus();
- return (_commandsAccepted & Interop.Advapi32.AcceptOptions.ACCEPT_PAUSE_CONTINUE) != 0;
- }
- }
+ if (string.IsNullOrEmpty(name))
+ throw new ArgumentException(SR.Format(SR.InvalidParameter, nameof(name), name));
+ _machineName = machineName;
+ _eitherName = name;
+ _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
+ }
- /// Tells if the service is notified when system shutdown occurs.
- public bool CanShutdown
- {
- get
- {
- GenerateStatus();
- return (_commandsAccepted & Interop.Advapi32.AcceptOptions.ACCEPT_SHUTDOWN) != 0;
- }
- }
+ private ServiceController(string machineName, Interop.Advapi32.ENUM_SERVICE_STATUS status)
+ {
+ if (!CheckMachineName(machineName))
+ throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
+
+ _machineName = machineName;
+ _name = status.serviceName;
+ _displayName = status.displayName;
+ _commandsAccepted = status.controlsAccepted;
+ _status = (ServiceControllerStatus)status.currentState;
+ _type = status.serviceType;
+ _statusGenerated = true;
+ }
- /// Tells if the service referenced by this object can be stopped.
- public bool CanStop
- {
- get
- {
- GenerateStatus();
- return (_commandsAccepted & Interop.Advapi32.AcceptOptions.ACCEPT_STOP) != 0;
- }
- }
+ ///
+ /// Used by the GetServicesInGroup method.
+ ///
+ /// Name of the machine
+ /// Service process status
+ private ServiceController(string machineName, Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS status)
+ {
+ if (!CheckMachineName(machineName))
+ throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
+
+ _machineName = machineName;
+ _name = status.serviceName;
+ _displayName = status.displayName;
+ _commandsAccepted = status.controlsAccepted;
+ _status = (ServiceControllerStatus)status.currentState;
+ _type = status.serviceType;
+ _statusGenerated = true;
+ }
- /// The descriptive name shown for this service in the Service applet.
- public string DisplayName
- {
- get
- {
- if (string.IsNullOrEmpty(_displayName))
- GenerateNames();
- return _displayName;
- }
- set
- {
- if (value == null)
- throw new ArgumentNullException(nameof(value));
+ ///
+ /// Tells if the service referenced by this object can be paused.
+ ///
+ public bool CanPauseAndContinue
+ {
+ get
+ {
+ GenerateStatus();
+ return (_commandsAccepted & Interop.Advapi32.AcceptOptions.ACCEPT_PAUSE_CONTINUE) != 0;
+ }
+ }
- if (string.Equals(value, _displayName, StringComparison.OrdinalIgnoreCase))
- {
- // they're just changing the casing. No need to close.
- _displayName = value;
- return;
- }
+ ///
+ /// Tells if the service is notified when system shutdown occurs.
+ ///
+ public bool CanShutdown
+ {
+ get
+ {
+ GenerateStatus();
+ return (_commandsAccepted & Interop.Advapi32.AcceptOptions.ACCEPT_SHUTDOWN) != 0;
+ }
+ }
- Close();
- _displayName = value;
- _name = "";
- }
- }
+ ///
+ /// Tells if the service referenced by this object can be stopped.
+ ///
+ public bool CanStop
+ {
+ get
+ {
+ GenerateStatus();
+ return (_commandsAccepted & Interop.Advapi32.AcceptOptions.ACCEPT_STOP) != 0;
+ }
+ }
- /// The set of services that depend on this service. These are the services that will be stopped if
- /// this service is stopped.
- public ServiceController[] DependentServices
- {
- get
- {
- if (_dependentServices == null)
- {
- using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_ENUMERATE_DEPENDENTS);
- // figure out how big a buffer we need to get the info
- int bytesNeeded = 0;
- int numEnumerated = 0;
- bool result = Interop.Advapi32.EnumDependentServices(serviceHandle, Interop.Advapi32.ServiceState.SERVICE_STATE_ALL, IntPtr.Zero, 0,
- ref bytesNeeded, ref numEnumerated);
- if (result)
- {
- _dependentServices = Array.Empty();
- return _dependentServices;
- }
-
- int lastError = Marshal.GetLastWin32Error();
- if (lastError != Interop.Errors.ERROR_MORE_DATA)
- throw new Win32Exception(lastError);
-
- // allocate the buffer
- IntPtr enumBuffer = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
-
- try
- {
- // get all the info
- result = Interop.Advapi32.EnumDependentServices(serviceHandle, Interop.Advapi32.ServiceState.SERVICE_STATE_ALL, enumBuffer, bytesNeeded,
- ref bytesNeeded, ref numEnumerated);
- if (!result)
- throw new Win32Exception();
-
- // for each of the entries in the buffer, create a new ServiceController object.
- _dependentServices = new ServiceController[numEnumerated];
- for (int i = 0; i < numEnumerated; i++)
- {
- Interop.Advapi32.ENUM_SERVICE_STATUS status = new Interop.Advapi32.ENUM_SERVICE_STATUS();
- IntPtr structPtr = (IntPtr)((long)enumBuffer + (i * Marshal.SizeOf()));
- Marshal.PtrToStructure(structPtr, status);
- _dependentServices[i] = new ServiceController(_machineName, status);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(enumBuffer);
- }
- }
+ ///
+ /// The descriptive name shown for this service in the Service applet.
+ ///
+ public string DisplayName
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(_displayName))
+ GenerateNames();
+ return _displayName;
+ }
+ set
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (string.Equals(value, _displayName, StringComparison.OrdinalIgnoreCase))
+ {
+ // they're just changing the casing. No need to close.
+ _displayName = value;
+ return;
+ }
+
+ Close();
+ _displayName = value;
+ _name = "";
+ }
+ }
- return _dependentServices;
- }
- }
+ ///
+ /// The set of services that depend on this service. These are the services that will be stopped if this service is stopped.
+ ///
+ public ServiceController[] DependentServices
+ {
+ get
+ {
+ if (_dependentServices == null)
+ {
+ using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_ENUMERATE_DEPENDENTS);
+ // figure out how big a buffer we need to get the info
+ int bytesNeeded = 0;
+ int numEnumerated = 0;
+ bool result = Interop.Advapi32.EnumDependentServices(serviceHandle, Interop.Advapi32.ServiceState.SERVICE_STATE_ALL, IntPtr.Zero, 0,
+ ref bytesNeeded, ref numEnumerated);
+ if (result)
+ {
+ _dependentServices = Array.Empty();
+ return _dependentServices;
+ }
+
+ int lastError = Marshal.GetLastWin32Error();
+ if (lastError != Interop.Errors.ERROR_MORE_DATA)
+ throw new Win32Exception(lastError);
+
+ // allocate the buffer
+ IntPtr enumBuffer = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
+
+ try
+ {
+ // get all the info
+ result = Interop.Advapi32.EnumDependentServices(serviceHandle, Interop.Advapi32.ServiceState.SERVICE_STATE_ALL, enumBuffer, bytesNeeded,
+ ref bytesNeeded, ref numEnumerated);
+ if (!result)
+ throw new Win32Exception();
- /// The name of the machine on which this service resides.
- public string MachineName
- {
- get
- {
- return _machineName;
- }
- set
+ // for each of the entries in the buffer, create a new ServiceController object.
+ _dependentServices = new ServiceController[numEnumerated];
+ for (int i = 0; i < numEnumerated; i++)
{
- if (!CheckMachineName(value))
- throw new ArgumentException(SR.Format(SR.BadMachineName, value));
-
- if (string.Equals(_machineName, value, StringComparison.OrdinalIgnoreCase))
- {
- // no need to close, because the most they're changing is the
- // casing.
- _machineName = value;
- return;
- }
-
- Close();
- _machineName = value;
+ Interop.Advapi32.ENUM_SERVICE_STATUS status = new Interop.Advapi32.ENUM_SERVICE_STATUS();
+ IntPtr structPtr = (IntPtr)((long)enumBuffer + (i * Marshal.SizeOf()));
+ Marshal.PtrToStructure(structPtr, status);
+ _dependentServices[i] = new ServiceController(_machineName, status);
}
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(enumBuffer);
+ }
}
- /// Returns the short name of the service referenced by this object.
- public string ServiceName
- {
- get
- {
- if (string.IsNullOrEmpty(_name))
- GenerateNames();
- return _name;
- }
- set
- {
- if (value == null)
- throw new ArgumentNullException(nameof(value));
-
- if (string.Equals(value, _name, StringComparison.OrdinalIgnoreCase))
- {
- // they might be changing the casing, but the service we refer to
- // is the same. No need to close.
- _name = value;
- return;
- }
-
- if (!ServiceBase.ValidServiceName(value))
- throw new ArgumentException(SR.Format(SR.ServiceName, value, ServiceBase.MaxNameLength.ToString()));
-
- Close();
- _name = value;
- _displayName = "";
- }
- }
-
- public unsafe ServiceController[] ServicesDependedOn
- {
- get
- {
- if (_servicesDependedOn != null)
- return _servicesDependedOn;
+ return _dependentServices;
+ }
+ }
- using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_QUERY_CONFIG);
- bool success = Interop.Advapi32.QueryServiceConfig(serviceHandle, IntPtr.Zero, 0, out int bytesNeeded);
- if (success)
- {
- _servicesDependedOn = Array.Empty();
- return _servicesDependedOn;
- }
+ ///
+ /// The name of the machine on which this service resides.
+ ///
+ public string MachineName
+ {
+ get
+ {
+ return _machineName;
+ }
+ set
+ {
+ if (!CheckMachineName(value))
+ throw new ArgumentException(SR.Format(SR.BadMachineName, value));
+
+ if (string.Equals(_machineName, value, StringComparison.OrdinalIgnoreCase))
+ {
+ // no need to close, because the most they're changing is the
+ // casing.
+ _machineName = value;
+ return;
+ }
+
+ Close();
+ _machineName = value;
+ }
+ }
- int lastError = Marshal.GetLastWin32Error();
- if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
- throw new Win32Exception(lastError);
+ ///
+ /// Returns the short name of the service referenced by this object.
+ ///
+ public string ServiceName
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(_name))
+ GenerateNames();
+ return _name;
+ }
+ set
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (string.Equals(value, _name, StringComparison.OrdinalIgnoreCase))
+ {
+ // they might be changing the casing, but the service we refer to
+ // is the same. No need to close.
+ _name = value;
+ return;
+ }
+
+ if (!ServiceBase.ValidServiceName(value))
+ throw new ArgumentException(SR.Format(SR.ServiceName, value, ServiceBase.MaxNameLength.ToString()));
+
+ Close();
+ _name = value;
+ _displayName = "";
+ }
+ }
- // get the info
- IntPtr bufPtr = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
- try
+ ///
+ /// A set of services on which the given service object is depend upon.
+ ///
+ public unsafe ServiceController[] ServicesDependedOn
+ {
+ get
+ {
+ if (_servicesDependedOn != null)
+ return _servicesDependedOn;
+
+ using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_QUERY_CONFIG);
+ bool success = Interop.Advapi32.QueryServiceConfig(serviceHandle, IntPtr.Zero, 0, out int bytesNeeded);
+ if (success)
+ {
+ _servicesDependedOn = Array.Empty();
+ return _servicesDependedOn;
+ }
+
+ int lastError = Marshal.GetLastWin32Error();
+ if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
+ throw new Win32Exception(lastError);
+
+ // get the info
+ IntPtr bufPtr = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
+ try
+ {
+ success = Interop.Advapi32.QueryServiceConfig(serviceHandle, bufPtr, bytesNeeded, out bytesNeeded);
+ if (!success)
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+
+ Interop.Advapi32.QUERY_SERVICE_CONFIG config = new Interop.Advapi32.QUERY_SERVICE_CONFIG();
+ Marshal.PtrToStructure(bufPtr, config);
+ Dictionary? dependencyHash = null;
+
+ char* dependencyChar = config.lpDependencies;
+ if (dependencyChar != null)
+ {
+ // lpDependencies points to the start of multiple null-terminated strings. The list is
+ // double-null terminated.
+ int length = 0;
+ dependencyHash = new Dictionary();
+ while (*(dependencyChar + length) != '\0')
+ {
+ length++;
+ if (*(dependencyChar + length) == '\0')
+ {
+ string dependencyNameStr = new string(dependencyChar, 0, length);
+ dependencyChar = dependencyChar + length + 1;
+ length = 0;
+ if (dependencyNameStr.StartsWith("+", StringComparison.Ordinal))
{
- success = Interop.Advapi32.QueryServiceConfig(serviceHandle, bufPtr, bytesNeeded, out bytesNeeded);
- if (!success)
- throw new Win32Exception(Marshal.GetLastWin32Error());
-
- Interop.Advapi32.QUERY_SERVICE_CONFIG config = new Interop.Advapi32.QUERY_SERVICE_CONFIG();
- Marshal.PtrToStructure(bufPtr, config);
- Dictionary? dependencyHash = null;
-
- char* dependencyChar = config.lpDependencies;
- if (dependencyChar != null)
- {
- // lpDependencies points to the start of multiple null-terminated strings. The list is
- // double-null terminated.
- int length = 0;
- dependencyHash = new Dictionary();
- while (*(dependencyChar + length) != '\0')
- {
- length++;
- if (*(dependencyChar + length) == '\0')
- {
- string dependencyNameStr = new string(dependencyChar, 0, length);
- dependencyChar = dependencyChar + length + 1;
- length = 0;
- if (dependencyNameStr.StartsWith("+", StringComparison.Ordinal))
- {
- // this entry is actually a service load group
- Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS[] loadGroup = GetServicesInGroup(_machineName, dependencyNameStr.Substring(1));
- foreach (Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS groupMember in loadGroup)
- {
- if (!dependencyHash.ContainsKey(groupMember.serviceName!))
- dependencyHash.Add(groupMember.serviceName!, new ServiceController(MachineName, groupMember));
- }
- }
- else
- {
- if (!dependencyHash.ContainsKey(dependencyNameStr))
- dependencyHash.Add(dependencyNameStr, new ServiceController(dependencyNameStr, MachineName));
- }
- }
- }
- }
-
- if (dependencyHash != null)
- {
- _servicesDependedOn = new ServiceController[dependencyHash.Count];
- dependencyHash.Values.CopyTo(_servicesDependedOn, 0);
- }
- else
- {
- _servicesDependedOn = Array.Empty();
- }
-
- return _servicesDependedOn;
+ // this entry is actually a service load group
+ Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS[] loadGroup = GetServicesInGroup(_machineName, dependencyNameStr.Substring(1));
+ foreach (Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS groupMember in loadGroup)
+ {
+ if (!dependencyHash.ContainsKey(groupMember.serviceName!))
+ dependencyHash.Add(groupMember.serviceName!, new ServiceController(MachineName, groupMember));
+ }
}
- finally
+ else
{
- Marshal.FreeHGlobal(bufPtr);
+ if (!dependencyHash.ContainsKey(dependencyNameStr))
+ dependencyHash.Add(dependencyNameStr, new ServiceController(dependencyNameStr, MachineName));
}
+ }
}
- }
-
- public ServiceStartMode StartType
- {
- get
- {
- if (_startTypeInitialized)
- return _startType;
-
- using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_QUERY_CONFIG);
- bool success = Interop.Advapi32.QueryServiceConfig(serviceHandle, IntPtr.Zero, 0, out int bytesNeeded);
-
- int lastError = Marshal.GetLastWin32Error();
- if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
- throw new Win32Exception(lastError);
+ }
- // get the info
- IntPtr bufPtr = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
- try
- {
- success = Interop.Advapi32.QueryServiceConfig(serviceHandle, bufPtr, bytesNeeded, out bytesNeeded);
- if (!success)
- throw new Win32Exception(Marshal.GetLastWin32Error());
-
- Interop.Advapi32.QUERY_SERVICE_CONFIG config = new Interop.Advapi32.QUERY_SERVICE_CONFIG();
- Marshal.PtrToStructure(bufPtr, config);
-
- _startType = (ServiceStartMode)config.dwStartType;
- _startTypeInitialized = true;
- }
- finally
- {
- Marshal.FreeHGlobal(bufPtr);
- }
+ if (dependencyHash != null)
+ {
+ _servicesDependedOn = new ServiceController[dependencyHash.Count];
+ dependencyHash.Values.CopyTo(_servicesDependedOn, 0);
+ }
+ else
+ {
+ _servicesDependedOn = Array.Empty();
+ }
- return _startType;
- }
+ return _servicesDependedOn;
}
-
- public SafeHandle ServiceHandle
+ finally
{
- get
- {
- return GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_ALL_ACCESS);
- }
+ Marshal.FreeHGlobal(bufPtr);
}
+ }
+ }
- /// Gets the status of the service referenced by this object, e.g., Running, Stopped, etc.
- public ServiceControllerStatus Status
- {
- get
- {
- GenerateStatus();
- return _status;
- }
- }
+ public ServiceStartMode StartType
+ {
+ get
+ {
+ if (_startTypeInitialized)
+ return _startType;
- /// Gets the type of service that this object references.
- public ServiceType ServiceType
- {
- get
- {
- GenerateStatus();
- return (ServiceType)_type;
- }
- }
+ using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_QUERY_CONFIG);
+ bool success = Interop.Advapi32.QueryServiceConfig(serviceHandle, IntPtr.Zero, 0, out int bytesNeeded);
- private static bool CheckMachineName(string value)
- {
- // string.Contains(char) is .NetCore2.1+ specific
- return !string.IsNullOrWhiteSpace(value) && value.IndexOf('\\') == -1;
- }
+ int lastError = Marshal.GetLastWin32Error();
+ if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
+ throw new Win32Exception(lastError);
- ///
- /// Closes the handle to the service manager, but does not
- /// mark the class as disposed.
- ///
- ///
- /// Violates design guidelines by not matching Dispose() -- matches .NET Framework
- ///
- public void Close()
+ // get the info
+ IntPtr bufPtr = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
+ try
{
- if (_serviceManagerHandle != null)
- {
- _serviceManagerHandle.Dispose();
- _serviceManagerHandle = null;
- }
+ success = Interop.Advapi32.QueryServiceConfig(serviceHandle, bufPtr, bytesNeeded, out bytesNeeded);
+ if (!success)
+ throw new Win32Exception(Marshal.GetLastWin32Error());
- _statusGenerated = false;
- _startTypeInitialized = false;
- _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
- }
+ Interop.Advapi32.QUERY_SERVICE_CONFIG config = new Interop.Advapi32.QUERY_SERVICE_CONFIG();
+ Marshal.PtrToStructure(bufPtr, config);
- ///
- /// Closes the handle to the service manager, and disposes.
- ///
- protected override void Dispose(bool disposing)
- {
- Close();
- _disposed = true;
- base.Dispose(disposing);
+ _startType = (ServiceStartMode)config.dwStartType;
+ _startTypeInitialized = true;
}
-
- private unsafe void GenerateStatus()
+ finally
{
- if (!_statusGenerated)
- {
- using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_QUERY_STATUS);
- Interop.Advapi32.SERVICE_STATUS svcStatus = default;
- bool success = Interop.Advapi32.QueryServiceStatus(serviceHandle, &svcStatus);
- if (!success)
- throw new Win32Exception(Marshal.GetLastWin32Error());
-
- _commandsAccepted = svcStatus.controlsAccepted;
- _status = (ServiceControllerStatus)svcStatus.currentState;
- _type = svcStatus.serviceType;
- _statusGenerated = true;
- }
+ Marshal.FreeHGlobal(bufPtr);
}
- [MemberNotNull(nameof(_name))]
- [MemberNotNull(nameof(_displayName))]
- private void GenerateNames()
- {
- GetDataBaseHandleWithConnectAccess();
-
- if (string.IsNullOrEmpty(_name))
- {
- // Figure out the _name based on the information we have.
- // We must either have _displayName or the constructor parameter _eitherName.
- string? userGivenName = string.IsNullOrEmpty(_eitherName) ? _displayName : _eitherName;
-
- if (string.IsNullOrEmpty(userGivenName))
- throw new InvalidOperationException(SR.Format(SR.ServiceName, userGivenName, ServiceBase.MaxNameLength.ToString()));
-
- // Try it as a display name
- string? result = GetServiceKeyName(_serviceManagerHandle, userGivenName);
+ return _startType;
+ }
+ }
- if (result != null)
- {
- // Now we have both
- _name = result;
- _displayName = userGivenName;
- _eitherName = null;
- return;
- }
+ public SafeHandle ServiceHandle
+ {
+ get
+ {
+ return GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_ALL_ACCESS);
+ }
+ }
- // Try it as a service name
- result = GetServiceDisplayName(_serviceManagerHandle, userGivenName);
+ ///
+ /// Gets the status of the service referenced by this object, e.g., Running, Stopped, etc.
+ ///
+ ///
+ /// Please see for more available status.
+ ///
+ public ServiceControllerStatus Status
+ {
+ get
+ {
+ GenerateStatus();
+ return _status;
+ }
+ }
- if (result == null)
- {
- throw new InvalidOperationException(SR.Format(SR.NoService, userGivenName, _machineName), new Win32Exception(Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST));
- }
+ ///
+ /// Gets the type of service that this object references.
+ ///
+ ///
+ /// Please see for available list of Service types.
+ ///
+ public ServiceType ServiceType
+ {
+ get
+ {
+ GenerateStatus();
+ return (ServiceType)_type;
+ }
+ }
- _name = userGivenName;
- _displayName = result;
- _eitherName = null;
- }
- else if (string.IsNullOrEmpty(_displayName))
- {
- // We must have _name
- string? result = GetServiceDisplayName(_serviceManagerHandle, _name);
+ private static bool CheckMachineName(string value)
+ {
+ // string.Contains(char) is .NetCore2.1+ specific
+ return !string.IsNullOrWhiteSpace(value) && value.IndexOf('\\') == -1;
+ }
- if (result == null)
- {
- throw new InvalidOperationException(SR.Format(SR.NoService, _name, _machineName), new Win32Exception(Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST));
- }
+ ///
+ /// Closes the handle to the service manager, but does not
+ /// mark the class as disposed.
+ ///
+ ///
+ /// Violates design guidelines by not matching Dispose() -- matches .NET Framework
+ ///
+ public void Close()
+ {
+ if (_serviceManagerHandle != null)
+ {
+ _serviceManagerHandle.Dispose();
+ _serviceManagerHandle = null;
+ }
+
+ _statusGenerated = false;
+ _startTypeInitialized = false;
+ _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
+ }
- _displayName = result;
- _eitherName = null;
- }
- }
+ ///
+ /// Closes the handle to the service manager, and disposes.
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ Close();
+ _disposed = true;
+ base.Dispose(disposing);
+ }
- ///
- /// Gets service name (key name) from service display name.
- /// Returns null if service is not found.
- ///
- private unsafe string? GetServiceKeyName(SafeServiceHandle? SCMHandle, string serviceDisplayName)
- {
- var builder = new ValueStringBuilder(stackalloc char[256]);
- int bufLen;
- while (true)
- {
- bufLen = builder.Capacity;
- fixed (char* c = builder)
- {
- if (Interop.Advapi32.GetServiceKeyName(SCMHandle, serviceDisplayName, c, ref bufLen))
- break;
- }
+ private unsafe void GenerateStatus()
+ {
+ if (_statusGenerated)
+ {
+ return;
+ }
+
+ using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_QUERY_STATUS);
+ Interop.Advapi32.SERVICE_STATUS svcStatus = default;
+ bool success = Interop.Advapi32.QueryServiceStatus(serviceHandle, &svcStatus);
+ if (!success)
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+
+ _commandsAccepted = svcStatus.controlsAccepted;
+ _status = (ServiceControllerStatus)svcStatus.currentState;
+ _type = svcStatus.serviceType;
+ _statusGenerated = true;
+ }
- int lastError = Marshal.GetLastWin32Error();
- if (lastError == Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST)
- {
- return null;
- }
+ [MemberNotNull(nameof(_name))]
+ [MemberNotNull(nameof(_displayName))]
+ private void GenerateNames()
+ {
+ GetDataBaseHandleWithConnectAccess();
- if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
- {
- throw new InvalidOperationException(SR.Format(SR.NoService, serviceDisplayName, _machineName), new Win32Exception(lastError));
- }
+ if (string.IsNullOrEmpty(_name))
+ {
+ // Figure out the _name based on the information we have.
+ // We must either have _displayName or the constructor parameter _eitherName.
+ string? userGivenName = string.IsNullOrEmpty(_eitherName) ? _displayName : _eitherName;
- builder.EnsureCapacity(bufLen + 1); // Does not include null
- }
+ if (string.IsNullOrEmpty(userGivenName))
+ throw new InvalidOperationException(SR.Format(SR.ServiceName, userGivenName, ServiceBase.MaxNameLength.ToString()));
- builder.Length = bufLen;
- return builder.ToString();
- }
+ // Try it as a display name
+ string? result = GetServiceKeyName(_serviceManagerHandle, userGivenName);
- private unsafe string? GetServiceDisplayName(SafeServiceHandle? scmHandle, string serviceName)
+ if (result != null)
{
- var builder = new ValueStringBuilder(4096);
- int bufLen;
- while (true)
- {
- bufLen = builder.Capacity;
- fixed (char* c = builder)
- {
- if (Interop.Advapi32.GetServiceDisplayName(scmHandle, serviceName, c, ref bufLen))
- break;
- }
-
- int lastError = Marshal.GetLastWin32Error();
- if (lastError == Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST)
- {
- return null;
- }
- else if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
- {
- throw new InvalidOperationException(SR.Format(SR.NoService, serviceName, _machineName), new Win32Exception(lastError));
- }
-
- builder.EnsureCapacity(bufLen + 1); // Does not include null
- }
-
- builder.Length = bufLen;
- return builder.ToString();
+ // Now we have both
+ _name = result;
+ _displayName = userGivenName;
+ _eitherName = null;
+ return;
}
- private static SafeServiceHandle GetDataBaseHandleWithAccess(string machineName, int serviceControlManagerAccess)
- {
- SafeServiceHandle? databaseHandle;
- if (machineName.Equals(DefaultMachineName) || machineName.Length == 0)
- {
- databaseHandle = new SafeServiceHandle(Interop.Advapi32.OpenSCManager(null, null, serviceControlManagerAccess));
- }
- else
- {
- databaseHandle = new SafeServiceHandle(Interop.Advapi32.OpenSCManager(machineName, null, serviceControlManagerAccess));
- }
+ // Try it as a service name
+ result = GetServiceDisplayName(_serviceManagerHandle, userGivenName);
- if (databaseHandle.IsInvalid)
- {
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
- throw new InvalidOperationException(SR.Format(SR.OpenSC, machineName), inner);
- }
-
- return databaseHandle;
+ if (result == null)
+ {
+ throw new InvalidOperationException(SR.Format(SR.NoService, userGivenName, _machineName), new Win32Exception(Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST));
}
- private void GetDataBaseHandleWithConnectAccess()
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
+ _name = userGivenName;
+ _displayName = result;
+ _eitherName = null;
+ }
+ else if (string.IsNullOrEmpty(_displayName))
+ {
+ // We must have _name
+ string? result = GetServiceDisplayName(_serviceManagerHandle, _name);
- // get a handle to SCM with connect access and store it in serviceManagerHandle field.
- if (_serviceManagerHandle == null)
- {
- _serviceManagerHandle = GetDataBaseHandleWithAccess(_machineName, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_CONNECT);
- }
+ if (result == null)
+ {
+ throw new InvalidOperationException(SR.Format(SR.NoService, _name, _machineName), new Win32Exception(Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST));
}
- public static ServiceController[] GetDevices()
+ _displayName = result;
+ _eitherName = null;
+ }
+ }
+
+ ///
+ /// Gets service name (key name) from service display name.
+ /// Returns null if service is not found.
+ ///
+ private unsafe string? GetServiceKeyName(SafeServiceHandle? SCMHandle, string serviceDisplayName)
+ {
+ var builder = new ValueStringBuilder(stackalloc char[256]);
+ int bufLen;
+ while (true)
+ {
+ bufLen = builder.Capacity;
+ fixed (char* c = builder)
{
- return GetDevices(DefaultMachineName);
+ if (Interop.Advapi32.GetServiceKeyName(SCMHandle, serviceDisplayName, c, ref bufLen))
+ break;
}
- /// Gets all the device-driver services in the machine specified.
- public static ServiceController[] GetDevices(string machineName)
+ int lastError = Marshal.GetLastWin32Error();
+ if (lastError == Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST)
{
- return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_DRIVER);
+ return null;
}
- /// Opens a handle for the current service. The handle must be Dispose()'d.
- private SafeServiceHandle GetServiceHandle(int desiredAccess)
+ if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
{
- GetDataBaseHandleWithConnectAccess();
+ throw new InvalidOperationException(SR.Format(SR.NoService, serviceDisplayName, _machineName), new Win32Exception(lastError));
+ }
- var serviceHandle = new SafeServiceHandle(Interop.Advapi32.OpenService(_serviceManagerHandle, ServiceName, desiredAccess));
- if (serviceHandle.IsInvalid)
- {
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
- throw new InvalidOperationException(SR.Format(SR.OpenService, ServiceName, _machineName), inner);
- }
+ builder.EnsureCapacity(bufLen + 1); // Does not include null
+ }
- return serviceHandle;
- }
+ builder.Length = bufLen;
+ return builder.ToString();
+ }
- /// Gets the services (not including device-driver services) on the local machine.
- public static ServiceController[] GetServices()
+ private unsafe string? GetServiceDisplayName(SafeServiceHandle? scmHandle, string serviceName)
+ {
+ var builder = new ValueStringBuilder(4096);
+ int bufLen;
+ while (true)
+ {
+ bufLen = builder.Capacity;
+ fixed (char* c = builder)
{
- return GetServices(DefaultMachineName);
+ if (Interop.Advapi32.GetServiceDisplayName(scmHandle, serviceName, c, ref bufLen))
+ break;
}
- /// Gets the services (not including device-driver services) on the machine specified.
- public static ServiceController[] GetServices(string machineName)
+ int lastError = Marshal.GetLastWin32Error();
+ if (lastError == Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST)
{
- return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32);
+ return null;
}
-
- /// Helper function for ServicesDependedOn.
- private static Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS[] GetServicesInGroup(string machineName, string group)
+ else if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
{
- return GetServices(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32, group, status => status);
+ throw new InvalidOperationException(SR.Format(SR.NoService, serviceName, _machineName), new Win32Exception(lastError));
}
- /// Helper function for GetDevices and GetServices.
- private static ServiceController[] GetServicesOfType(string machineName, int serviceType)
- {
- if (!CheckMachineName(machineName))
- throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
+ builder.EnsureCapacity(bufLen + 1); // Does not include null
+ }
- return GetServices(machineName, serviceType, null, status => new ServiceController(machineName, status));
- }
+ builder.Length = bufLen;
+ return builder.ToString();
+ }
- /// Helper for GetDevices, GetServices, and ServicesDependedOn
- private static T[] GetServices(string machineName, int serviceType, string? group, Func selector)
- {
- int resumeHandle = 0;
-
- T[] services;
-
- using SafeServiceHandle databaseHandle = GetDataBaseHandleWithAccess(machineName, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_ENUMERATE_SERVICE);
- Interop.Advapi32.EnumServicesStatusEx(
- databaseHandle,
- Interop.Advapi32.ServiceControllerOptions.SC_ENUM_PROCESS_INFO,
- serviceType,
- Interop.Advapi32.StatusOptions.STATUS_ALL,
- IntPtr.Zero,
- 0,
- out int bytesNeeded,
- out int servicesReturned,
- ref resumeHandle,
- group);
-
- IntPtr memory = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
- try
- {
- //
- // Get the set of services
- //
- Interop.Advapi32.EnumServicesStatusEx(
- databaseHandle,
- Interop.Advapi32.ServiceControllerOptions.SC_ENUM_PROCESS_INFO,
- serviceType,
- Interop.Advapi32.StatusOptions.STATUS_ALL,
- memory,
- bytesNeeded,
- out bytesNeeded,
- out servicesReturned,
- ref resumeHandle,
- group);
-
- //
- // Go through the block of memory it returned to us and select the results
- //
- services = new T[servicesReturned];
- for (int i = 0; i < servicesReturned; i++)
- {
- IntPtr structPtr = (IntPtr)((long)memory + (i * Marshal.SizeOf()));
- Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS status = new Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS();
- Marshal.PtrToStructure(structPtr, status);
- services[i] = selector(status);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(memory);
- }
+ private static SafeServiceHandle GetDataBaseHandleWithAccess(string machineName, int serviceControlManagerAccess)
+ {
+ SafeServiceHandle? databaseHandle;
+ if (machineName.Equals(DefaultMachineName) || machineName.Length == 0)
+ {
+ databaseHandle = new SafeServiceHandle(Interop.Advapi32.OpenSCManager(null, null, serviceControlManagerAccess));
+ }
+ else
+ {
+ databaseHandle = new SafeServiceHandle(Interop.Advapi32.OpenSCManager(machineName, null, serviceControlManagerAccess));
+ }
+
+ if (databaseHandle.IsInvalid)
+ {
+ Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ throw new InvalidOperationException(SR.Format(SR.OpenSC, machineName), inner);
+ }
+
+ return databaseHandle;
+ }
- return services;
- }
+ private void GetDataBaseHandleWithConnectAccess()
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(GetType().Name);
+ }
+
+ // get a handle to SCM with connect access and store it in serviceManagerHandle field.
+ if (_serviceManagerHandle == null)
+ {
+ _serviceManagerHandle = GetDataBaseHandleWithAccess(_machineName, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_CONNECT);
+ }
+ }
- /// Suspends a service's operation.
- public unsafe void Pause()
- {
- using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_PAUSE_CONTINUE);
- Interop.Advapi32.SERVICE_STATUS status = default;
- bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_PAUSE, &status);
+ ///
+ /// Gets all the device-driver services with .
+ ///
+ /// Set of service controllers
+ public static ServiceController[] GetDevices()
+ {
+ return GetDevices(DefaultMachineName);
+ }
- if (!result)
- {
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
- throw new InvalidOperationException(SR.Format(SR.PauseService, ServiceName, _machineName), inner);
- }
- }
+ ///
+ /// Gets all the device-driver services in the machine specified.
+ ///
+ /// Name of the machine.
+ /// Set of service controllers
+ public static ServiceController[] GetDevices(string machineName)
+ {
+ return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_DRIVER);
+ }
- /// Continues a service after it has been paused.
- public unsafe void Continue()
- {
- using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_PAUSE_CONTINUE);
- Interop.Advapi32.SERVICE_STATUS status = default;
- bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_CONTINUE, &status);
- if (!result)
- {
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
- throw new InvalidOperationException(SR.Format(SR.ResumeService, ServiceName, _machineName), inner);
- }
- }
+ ///
+ /// Opens a handle for the current service. The handle must be Dispose()'d.
+ ///
+ /// Access level to pass to OpenService()
+ ///
+ private SafeServiceHandle GetServiceHandle(int desiredAccess)
+ {
+ GetDataBaseHandleWithConnectAccess();
- public unsafe void ExecuteCommand(int command)
- {
- using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_USER_DEFINED_CONTROL);
- Interop.Advapi32.SERVICE_STATUS status = default;
- bool result = Interop.Advapi32.ControlService(serviceHandle, command, &status);
- if (!result)
- {
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
- throw new InvalidOperationException(SR.Format(SR.ControlService, ServiceName, MachineName), inner);
- }
- }
+ var serviceHandle = new SafeServiceHandle(Interop.Advapi32.OpenService(_serviceManagerHandle, ServiceName, desiredAccess));
+ if (serviceHandle.IsInvalid)
+ {
+ Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ throw new InvalidOperationException(SR.Format(SR.OpenService, ServiceName, _machineName), inner);
+ }
- /// Refreshes all property values.
- public void Refresh()
- {
- _statusGenerated = false;
- _startTypeInitialized = false;
- _dependentServices = null;
- _servicesDependedOn = null;
- }
+ return serviceHandle;
+ }
- /// Starts the service.
- public void Start()
- {
- Start(Array.Empty());
- }
+ ///
+ /// Gets the services (not including device-driver services) on the local machine.
+ ///
+ /// Set of service controllers
+ public static ServiceController[] GetServices()
+ {
+ return GetServices(DefaultMachineName);
+ }
- /// Starts a service in the machine specified.
- public void Start(string[] args)
- {
- if (args == null)
- throw new ArgumentNullException(nameof(args));
+ ///
+ /// Gets the services (not including device-driver services) on the given machine name.
+ /// ///
+ /// Name of the machine
+ ///
+ public static ServiceController[] GetServices(string machineName)
+ {
+ return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32);
+ }
- using SafeServiceHandle serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_START);
- IntPtr[] argPtrs = new IntPtr[args.Length];
- int i = 0;
- try
- {
- for (i = 0; i < args.Length; i++)
- {
- if (args[i] == null)
- throw new ArgumentNullException($"{nameof(args)}[{i}]", SR.ArgsCantBeNull);
+ ///
+ /// Helper function for ServicesDependedOn.
+ ///
+ /// Name of the machine.
+ /// Name of the group.
+ ///
+ private static Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS[] GetServicesInGroup(string machineName, string group)
+ {
+ return GetServices(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32, group, status => status);
+ }
- argPtrs[i] = Marshal.StringToHGlobalUni(args[i]);
- }
- }
- catch
- {
- for (int j = 0; j < i; j++)
- Marshal.FreeHGlobal(argPtrs[i]);
- throw;
- }
+ ///
+ /// Helper function for GetDevices and GetServices.
+ ///
+ /// Name of the machine.
+ /// Type of service.
+ ///
+ private static ServiceController[] GetServicesOfType(string machineName, int serviceType)
+ {
+ if (!CheckMachineName(machineName))
+ throw new ArgumentException(SR.Format(SR.BadMachineName, machineName));
- GCHandle argPtrsHandle = default;
- try
- {
- argPtrsHandle = GCHandle.Alloc(argPtrs, GCHandleType.Pinned);
- bool result = Interop.Advapi32.StartService(serviceHandle, args.Length, argPtrsHandle.AddrOfPinnedObject());
- if (!result)
- {
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
- throw new InvalidOperationException(SR.Format(SR.CannotStart, ServiceName, _machineName), inner);
- }
- }
- finally
- {
- for (i = 0; i < args.Length; i++)
- Marshal.FreeHGlobal(argPtrs[i]);
- if (argPtrsHandle.IsAllocated)
- argPtrsHandle.Free();
- }
- }
+ return GetServices(machineName, serviceType, null, status => new ServiceController(machineName, status));
+ }
- /// Stops the service. If any other services depend on this one for operation,
- /// they will be stopped first. The DependentServices property lists this set
- /// of services.
- public unsafe void Stop()
- {
- using SafeServiceHandle serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_STOP);
- // Before stopping this service, stop all the dependent services that are running.
- // (It's OK not to cache the result of getting the DependentServices property because it caches on its own.)
- for (int i = 0; i < DependentServices.Length; i++)
- {
- ServiceController currentDependent = DependentServices[i];
- currentDependent.Refresh();
- if (currentDependent.Status != ServiceControllerStatus.Stopped)
- {
- currentDependent.Stop();
- currentDependent.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 30));
- }
- }
+ /// Helper for GetDevices, GetServices, and ServicesDependedOn
+ private static T[] GetServices(string machineName, int serviceType, string? group, Func selector)
+ {
+ int resumeHandle = 0;
+
+ T[] services;
+
+ using SafeServiceHandle databaseHandle = GetDataBaseHandleWithAccess(machineName, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_ENUMERATE_SERVICE);
+ Interop.Advapi32.EnumServicesStatusEx(
+ databaseHandle,
+ Interop.Advapi32.ServiceControllerOptions.SC_ENUM_PROCESS_INFO,
+ serviceType,
+ Interop.Advapi32.StatusOptions.STATUS_ALL,
+ IntPtr.Zero,
+ 0,
+ out int bytesNeeded,
+ out int servicesReturned,
+ ref resumeHandle,
+ group);
+
+ IntPtr memory = Marshal.AllocHGlobal((IntPtr)bytesNeeded);
+ try
+ {
+ //
+ // Get the set of services
+ //
+ Interop.Advapi32.EnumServicesStatusEx(
+ databaseHandle,
+ Interop.Advapi32.ServiceControllerOptions.SC_ENUM_PROCESS_INFO,
+ serviceType,
+ Interop.Advapi32.StatusOptions.STATUS_ALL,
+ memory,
+ bytesNeeded,
+ out bytesNeeded,
+ out servicesReturned,
+ ref resumeHandle,
+ group);
+
+ //
+ // Go through the block of memory it returned to us and select the results
+ //
+ services = new T[servicesReturned];
+ for (int i = 0; i < servicesReturned; i++)
+ {
+ IntPtr structPtr = (IntPtr)((long)memory + (i * Marshal.SizeOf()));
+ Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS status = new Interop.Advapi32.ENUM_SERVICE_STATUS_PROCESS();
+ Marshal.PtrToStructure(structPtr, status);
+ services[i] = selector(status);
+ }
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(memory);
+ }
+
+ return services;
+ }
- Interop.Advapi32.SERVICE_STATUS status = default;
- bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_STOP, &status);
- if (!result)
- {
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
- throw new InvalidOperationException(SR.Format(SR.StopService, ServiceName, _machineName), inner);
- }
- }
+ ///
+ /// Suspends a service's operation.
+ ///
+ public unsafe void Pause()
+ {
+ using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_PAUSE_CONTINUE);
+ Interop.Advapi32.SERVICE_STATUS status = default;
+ bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_PAUSE, &status);
+
+ if (!result)
+ {
+ Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ throw new InvalidOperationException(SR.Format(SR.PauseService, ServiceName, _machineName), inner);
+ }
+ }
- /// Waits infinitely until the service has reached the given status.
- public void WaitForStatus(ServiceControllerStatus desiredStatus)
- {
- WaitForStatus(desiredStatus, TimeSpan.MaxValue);
- }
+ ///
+ /// Continues a service after it has been paused.
+ ///
+ public unsafe void Continue()
+ {
+ using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_PAUSE_CONTINUE);
+ Interop.Advapi32.SERVICE_STATUS status = default;
+ bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_CONTINUE, &status);
+ if (!result)
+ {
+ Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ throw new InvalidOperationException(SR.Format(SR.ResumeService, ServiceName, _machineName), inner);
+ }
+ }
- /// Waits until the service has reached the given status or until the specified time
- /// has expired
- public void WaitForStatus(ServiceControllerStatus desiredStatus, TimeSpan timeout)
- {
- if (!Enum.IsDefined(typeof(ServiceControllerStatus), desiredStatus))
- throw new ArgumentException(SR.Format(SR.InvalidEnumArgument, nameof(desiredStatus), (int)desiredStatus, typeof(ServiceControllerStatus)));
+ ///
+ /// Executes the command.
+ ///
+ /// The command
+ public unsafe void ExecuteCommand(int command)
+ {
+ using var serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_USER_DEFINED_CONTROL);
+ Interop.Advapi32.SERVICE_STATUS status = default;
+ bool result = Interop.Advapi32.ControlService(serviceHandle, command, &status);
+ if (!result)
+ {
+ Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ throw new InvalidOperationException(SR.Format(SR.ControlService, ServiceName, MachineName), inner);
+ }
+ }
- DateTime start = DateTime.UtcNow;
- Refresh();
- while (Status != desiredStatus)
- {
- if (DateTime.UtcNow - start > timeout)
- throw new System.ServiceProcess.TimeoutException(SR.Format(SR.Timeout, ServiceName));
+ ///
+ /// Refreshes all property values.
+ ///
+ public void Refresh()
+ {
+ _statusGenerated = false;
+ _startTypeInitialized = false;
+ _dependentServices = null;
+ _servicesDependedOn = null;
+ }
- _waitForStatusSignal.WaitOne(250);
- Refresh();
- }
- }
+ ///
+ /// Starts the service.
+ ///
+ public void Start()
+ {
+ Start(Array.Empty());
+ }
+
+ ///
+ /// Starts a service in the machine specified.
+ ///
+ public void Start(string[] args)
+ {
+ if (args == null)
+ throw new ArgumentNullException(nameof(args));
+
+ using SafeServiceHandle serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_START);
+ IntPtr[] argPtrs = new IntPtr[args.Length];
+ int i = 0;
+ try
+ {
+ for (i = 0; i < args.Length; i++)
+ {
+ if (args[i] == null)
+ throw new ArgumentNullException($"{nameof(args)}[{i}]", SR.ArgsCantBeNull);
+
+ argPtrs[i] = Marshal.StringToHGlobalUni(args[i]);
+ }
+ }
+ catch
+ {
+ for (int j = 0; j < i; j++)
+ Marshal.FreeHGlobal(argPtrs[i]);
+ throw;
+ }
+
+ GCHandle argPtrsHandle = default;
+ try
+ {
+ argPtrsHandle = GCHandle.Alloc(argPtrs, GCHandleType.Pinned);
+ bool result = Interop.Advapi32.StartService(serviceHandle, args.Length, argPtrsHandle.AddrOfPinnedObject());
+ if (!result)
+ {
+ Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ throw new InvalidOperationException(SR.Format(SR.CannotStart, ServiceName, _machineName), inner);
+ }
+ }
+ finally
+ {
+ for (i = 0; i < args.Length; i++)
+ Marshal.FreeHGlobal(argPtrs[i]);
+ if (argPtrsHandle.IsAllocated)
+ argPtrsHandle.Free();
+ }
+ }
+
+ ///
+ /// Stops the service. If any other services depend on this one for operation,
+ /// they will be stopped first. The DependentServices property lists this set
+ /// of services.
+ ///
+ public unsafe void Stop()
+ {
+ using SafeServiceHandle serviceHandle = GetServiceHandle(Interop.Advapi32.ServiceOptions.SERVICE_STOP);
+ // Before stopping this service, stop all the dependent services that are running.
+ // (It's OK not to cache the result of getting the DependentServices property because it caches on its own.)
+ for (int i = 0; i < DependentServices.Length; i++)
+ {
+ ServiceController currentDependent = DependentServices[i];
+ currentDependent.Refresh();
+ if (currentDependent.Status != ServiceControllerStatus.Stopped)
+ {
+ currentDependent.Stop();
+ currentDependent.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 30));
+ }
+ }
+
+ Interop.Advapi32.SERVICE_STATUS status = default;
+ bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_STOP, &status);
+ if (!result)
+ {
+ Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ throw new InvalidOperationException(SR.Format(SR.StopService, ServiceName, _machineName), inner);
+ }
+ }
+
+ ///
+ /// Waits infinitely until the service has reached the given status.
+ ///
+ /// The status for which to wait.
+ public void WaitForStatus(ServiceControllerStatus desiredStatus)
+ {
+ WaitForStatus(desiredStatus, TimeSpan.MaxValue);
+ }
+
+ ///
+ /// Waits until the service has reached the given status or until the specified time has expired.
+ ///
+ /// The status for which to wait.
+ /// Wait for specific timeout
+ public void WaitForStatus(ServiceControllerStatus desiredStatus, TimeSpan timeout)
+ {
+ if (!Enum.IsDefined(typeof(ServiceControllerStatus), desiredStatus))
+ throw new ArgumentException(SR.Format(SR.InvalidEnumArgument, nameof(desiredStatus), (int)desiredStatus, typeof(ServiceControllerStatus)));
+
+ DateTime start = DateTime.UtcNow;
+ Refresh();
+ while (Status != desiredStatus)
+ {
+ if (DateTime.UtcNow - start > timeout)
+ throw new System.ServiceProcess.TimeoutException(SR.Format(SR.Timeout, ServiceName));
+
+ _waitForStatusSignal.WaitOne(250);
+ Refresh();
+ }
}
+ }
}
diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeDescription.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeDescription.cs
index b46be025400ba..449b2cc1939e4 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeDescription.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeDescription.cs
@@ -5,18 +5,15 @@ namespace System.ServiceProcess
{
public readonly struct SessionChangeDescription
{
- private readonly SessionChangeReason _reason;
- private readonly int _id;
-
internal SessionChangeDescription(SessionChangeReason reason, int id)
{
- _reason = reason;
- _id = id;
+ Reason = reason;
+ SessionId = id;
}
- public SessionChangeReason Reason => _reason;
+ public SessionChangeReason Reason { get; }
- public int SessionId => _id;
+ public int SessionId { get; }
public override bool Equals(object? obj)
{
@@ -30,12 +27,12 @@ public override bool Equals(object? obj)
public override int GetHashCode()
{
- return (int)_reason ^ _id;
+ return (int)Reason ^ SessionId;
}
public bool Equals(SessionChangeDescription changeDescription)
{
- return (_reason == changeDescription._reason) && (_id == changeDescription._id);
+ return (Reason == changeDescription.Reason) && (SessionId == changeDescription.SessionId);
}
public static bool operator ==(SessionChangeDescription a, SessionChangeDescription b)
diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeReason.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeReason.cs
index e22a167f127de..cb16e6c1c417d 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeReason.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/SessionChangeReason.cs
@@ -3,43 +3,54 @@
namespace System.ServiceProcess
{
+ ///
+ /// Enum containing various session change reason
+ ///
public enum SessionChangeReason
{
- ///
- /// A session was connected to the console session.
- ///
- ConsoleConnect = Interop.Advapi32.SessionStateChange.WTS_CONSOLE_CONNECT,
- ///
- /// A session was disconnected from the console session.
- ///
- ConsoleDisconnect = Interop.Advapi32.SessionStateChange.WTS_CONSOLE_DISCONNECT,
- ///
- /// A session was connected to the remote session.
- ///
- RemoteConnect = Interop.Advapi32.SessionStateChange.WTS_REMOTE_CONNECT,
- ///
- /// A session was disconnected from the remote session.
- ///
- RemoteDisconnect = Interop.Advapi32.SessionStateChange.WTS_REMOTE_DISCONNECT,
- ///
- /// A user has logged on to the session.
- ///
- SessionLogon = Interop.Advapi32.SessionStateChange.WTS_SESSION_LOGON,
- ///
- /// A user has logged off the session.
- ///
- SessionLogoff = Interop.Advapi32.SessionStateChange.WTS_SESSION_LOGOFF,
- ///
- /// A session has been locked.
- ///
- SessionLock = Interop.Advapi32.SessionStateChange.WTS_SESSION_LOCK,
- ///
- /// A session has been unlocked.
- ///
- SessionUnlock = Interop.Advapi32.SessionStateChange.WTS_SESSION_UNLOCK,
- ///
- /// A session has changed its remote controlled status.
- ///
- SessionRemoteControl = Interop.Advapi32.SessionStateChange.WTS_SESSION_REMOTE_CONTROL
+ ///
+ /// A session was connected to the console session.
+ ///
+ ConsoleConnect = Interop.Advapi32.SessionStateChange.WTS_CONSOLE_CONNECT,
+
+ ///
+ ///A session was disconnected from the console session.
+ ///
+ ConsoleDisconnect = Interop.Advapi32.SessionStateChange.WTS_CONSOLE_DISCONNECT,
+
+ ///
+ /// A session was connected to the remote session.
+ ///
+ RemoteConnect = Interop.Advapi32.SessionStateChange.WTS_REMOTE_CONNECT,
+
+ ///
+ /// A session was disconnected from the remote session.
+ ///
+ RemoteDisconnect = Interop.Advapi32.SessionStateChange.WTS_REMOTE_DISCONNECT,
+
+ ///
+ /// A user has logged on to the session.
+ ///
+ SessionLogon = Interop.Advapi32.SessionStateChange.WTS_SESSION_LOGON,
+
+ ///
+ /// A user has logged off the session.
+ ///
+ SessionLogoff = Interop.Advapi32.SessionStateChange.WTS_SESSION_LOGOFF,
+
+ ///
+ /// A session has been locked.
+ ///
+ SessionLock = Interop.Advapi32.SessionStateChange.WTS_SESSION_LOCK,
+
+ ///
+ /// A session has been unlocked.
+ ///
+ SessionUnlock = Interop.Advapi32.SessionStateChange.WTS_SESSION_UNLOCK,
+
+ ///
+ /// A session has changed its remote controlled status.
+ ///
+ SessionRemoteControl = Interop.Advapi32.SessionStateChange.WTS_SESSION_REMOTE_CONTROL
}
}
diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/TimeoutException.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/TimeoutException.cs
index 7cc5ce4e4e160..7648e50a27dc6 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/TimeoutException.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/TimeoutException.cs
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.Runtime.Serialization;
namespace System.ServiceProcess
@@ -12,7 +11,7 @@ public class TimeoutException : SystemException
{
private const int ServiceControllerTimeout = unchecked((int)0x80131906);
- public TimeoutException() : base()
+ public TimeoutException()
{
HResult = ServiceControllerTimeout;
}