diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ServiceProcessOptions.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ServiceProcessOptions.cs
index d7d9d5eae2c4a6..46db6d9173812f 100644
--- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ServiceProcessOptions.cs
+++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ServiceProcessOptions.cs
@@ -65,25 +65,24 @@ internal static partial class ServiceOptions
internal static partial class ServiceTypeOptions
{
- internal const int SERVICE_TYPE_ADAPTER = 0x00000004;
- internal const int SERVICE_TYPE_FILE_SYSTEM_DRIVER = 0x00000002;
- internal const int SERVICE_TYPE_INTERACTIVE_PROCESS = 0x00000100;
- internal const int SERVICE_TYPE_KERNEL_DRIVER = 0x00000001;
- internal const int SERVICE_TYPE_RECOGNIZER_DRIVER = 0x00000008;
- internal const int SERVICE_TYPE_WIN32_OWN_PROCESS = 0x00000010;
- internal const int SERVICE_TYPE_WIN32_SHARE_PROCESS = 0x00000020;
- internal const int SERVICE_TYPE_WIN32 =
- SERVICE_TYPE_WIN32_OWN_PROCESS |
- SERVICE_TYPE_WIN32_SHARE_PROCESS;
- internal const int SERVICE_TYPE_DRIVER =
- SERVICE_TYPE_KERNEL_DRIVER |
- SERVICE_TYPE_FILE_SYSTEM_DRIVER |
- SERVICE_TYPE_RECOGNIZER_DRIVER;
- internal const int SERVICE_TYPE_ALL =
- SERVICE_TYPE_WIN32 |
- SERVICE_TYPE_ADAPTER |
- SERVICE_TYPE_DRIVER |
- SERVICE_TYPE_INTERACTIVE_PROCESS;
+ internal const int SERVICE_KERNEL_DRIVER = 0x00000001;
+ internal const int SERVICE_FILE_SYSTEM_DRIVER = 0x00000002;
+ internal const int SERVICE_ADAPTER = 0x00000004;
+ internal const int SERVICE_RECOGNIZER_DRIVER = 0x00000008;
+
+ internal const int SERVICE_DRIVER =
+ SERVICE_KERNEL_DRIVER |
+ SERVICE_FILE_SYSTEM_DRIVER |
+ SERVICE_RECOGNIZER_DRIVER;
+
+ internal const int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
+ internal const int SERVICE_WIN32_SHARE_PROCESS = 0x00000020;
+
+ internal const int SERVICE_WIN32 =
+ SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_WIN32_SHARE_PROCESS;
+
+ internal const int SERVICE_INTERACTIVE_PROCESS = 0x00000100;
}
internal static partial class ServiceAccessOptions
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 74e95338d51a73..905af30eaa1f5c 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
@@ -577,22 +577,8 @@ 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
+ /// executes when a custom command is passed to the service. Specifies the actions to take when
/// a command with the specified parameter value occurs.
- ///
- /// Previously had "Passed to the
- /// service by
- /// the SCM", but the SCM doesn't pass custom commands. Do we want to indicate an
- /// agent here? Would it be the ServiceController, or is there another way to pass
- /// the int into the service? I thought that the SCM did pass it in, but
- /// otherwise ignored it since it was an int it doesn't recognize. I was under the
- /// impression that the difference was that the SCM didn't have default processing, so
- /// it transmitted it without examining it or trying to performs its own
- /// default behavior on it. Please correct where my understanding is wrong in the
- /// second paragraph below--what, if any, contact does the SCM have with a
- /// custom command?
- ///
///
protected virtual void OnCustomCommand(int command)
{
@@ -698,11 +684,11 @@ private void Initialize(bool multipleServices)
if (!multipleServices)
{
- _status.serviceType = ServiceTypeOptions.SERVICE_TYPE_WIN32_OWN_PROCESS;
+ _status.serviceType = ServiceTypeOptions.SERVICE_WIN32_OWN_PROCESS;
}
else
{
- _status.serviceType = ServiceTypeOptions.SERVICE_TYPE_WIN32_SHARE_PROCESS;
+ _status.serviceType = ServiceTypeOptions.SERVICE_WIN32_SHARE_PROCESS;
}
_status.currentState = ServiceControlStatus.STATE_START_PENDING;
@@ -885,10 +871,15 @@ public unsafe void ServiceMainCallback(int argCount, IntPtr argPointer)
if (argCount > 0)
{
- char** argsAsPtr = (char**)argPointer.ToPointer();
+ char** argsAsPtr = (char**)argPointer;
+
+ // The first arg is always the service name. We don't want to pass that in,
+ // but we can use it to set the service name on ourselves if we don't already know it.
+ if (string.IsNullOrEmpty(_serviceName))
+ {
+ _serviceName = Marshal.PtrToStringUni((IntPtr)(*argsAsPtr))!;
+ }
- //Lets read the arguments
- // the first arg is always the service name. We don't want to pass that in.
args = new string[argCount - 1];
for (int index = 0; index < args.Length; ++index)
@@ -954,7 +945,8 @@ public unsafe void ServiceMainCallback(int argCount, IntPtr argPointer)
statusOK = SetServiceStatus(_statusHandle, pStatus);
if (!statusOK)
{
- WriteLogEntry(SR.Format(SR.StartFailed, new Win32Exception().Message), EventLogEntryType.Error);
+ string errorMessage = new Win32Exception().Message;
+ WriteLogEntry(SR.Format(SR.StartFailed, errorMessage), EventLogEntryType.Error);
_status.currentState = ServiceControlStatus.STATE_STOPPED;
SetServiceStatus(_statusHandle, pStatus);
}
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 9d78898292a904..b1819d0a2ef6fb 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs
@@ -19,6 +19,11 @@ public class ServiceController : Component
private string _machineName; // Never null
private const string DefaultMachineName = ".";
+ // Note that ServiceType currently does not include all of SERVICE_TYPE_ALL; see see Interop.Advapi32.ServiceTypeOptions
+ private const int AllServiceTypes = (int)(ServiceType.Adapter | ServiceType.FileSystemDriver | ServiceType.InteractiveProcess |
+ ServiceType.KernelDriver | ServiceType.RecognizerDriver | ServiceType.Win32OwnProcess |
+ ServiceType.Win32ShareProcess);
+
private string? _name;
private string? _eitherName;
private string? _displayName;
@@ -37,7 +42,7 @@ public class ServiceController : Component
public ServiceController()
{
_machineName = DefaultMachineName;
- _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
+ _type = AllServiceTypes;
}
///
@@ -65,7 +70,7 @@ public ServiceController(string name, string machineName)
_machineName = machineName;
_eitherName = name;
- _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
+ _type = AllServiceTypes;
}
private ServiceController(string machineName, Interop.Advapi32.ENUM_SERVICE_STATUS status)
@@ -310,7 +315,7 @@ public unsafe ServiceController[] ServicesDependedOn
{
success = Interop.Advapi32.QueryServiceConfig(serviceHandle, bufPtr, bytesNeeded, out bytesNeeded);
if (!success)
- throw new Win32Exception(Marshal.GetLastWin32Error());
+ throw new Win32Exception();
Interop.Advapi32.QUERY_SERVICE_CONFIG config = new Interop.Advapi32.QUERY_SERVICE_CONFIG();
Marshal.PtrToStructure(bufPtr, config);
@@ -389,7 +394,7 @@ public ServiceStartMode StartType
{
success = Interop.Advapi32.QueryServiceConfig(serviceHandle, bufPtr, bytesNeeded, out bytesNeeded);
if (!success)
- throw new Win32Exception(Marshal.GetLastWin32Error());
+ throw new Win32Exception();
Interop.Advapi32.QUERY_SERVICE_CONFIG config = new Interop.Advapi32.QUERY_SERVICE_CONFIG();
Marshal.PtrToStructure(bufPtr, config);
@@ -467,7 +472,7 @@ public void Close()
_statusGenerated = false;
_startTypeInitialized = false;
- _type = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ALL;
+ _type = AllServiceTypes;
}
///
@@ -491,7 +496,7 @@ private unsafe void GenerateStatus()
Interop.Advapi32.SERVICE_STATUS svcStatus = default;
bool success = Interop.Advapi32.QueryServiceStatus(serviceHandle, &svcStatus);
if (!success)
- throw new Win32Exception(Marshal.GetLastWin32Error());
+ throw new Win32Exception();
_commandsAccepted = svcStatus.controlsAccepted;
_status = (ServiceControllerStatus)svcStatus.currentState;
@@ -632,7 +637,7 @@ private static SafeServiceHandle GetDataBaseHandleWithAccess(string machineName,
if (databaseHandle.IsInvalid)
{
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ Exception inner = new Win32Exception();
throw new InvalidOperationException(SR.Format(SR.OpenSC, machineName), inner);
}
@@ -669,7 +674,7 @@ public static ServiceController[] GetDevices()
/// Set of service controllers
public static ServiceController[] GetDevices(string machineName)
{
- return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_DRIVER);
+ return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_DRIVER);
}
///
@@ -684,7 +689,7 @@ private SafeServiceHandle GetServiceHandle(int desiredAccess)
var serviceHandle = new SafeServiceHandle(Interop.Advapi32.OpenService(_serviceManagerHandle, ServiceName, desiredAccess));
if (serviceHandle.IsInvalid)
{
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ Exception inner = new Win32Exception();
throw new InvalidOperationException(SR.Format(SR.OpenService, ServiceName, _machineName), inner);
}
@@ -707,7 +712,7 @@ public static ServiceController[] GetServices()
///
public static ServiceController[] GetServices(string machineName)
{
- return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32);
+ return GetServicesOfType(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_WIN32);
}
///
@@ -718,7 +723,7 @@ public static ServiceController[] GetServices(string machineName)
///
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);
+ return GetServices(machineName, Interop.Advapi32.ServiceTypeOptions.SERVICE_WIN32, group, status => status);
}
///
@@ -804,7 +809,7 @@ public unsafe void Pause()
if (!result)
{
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ Exception inner = new Win32Exception();
throw new InvalidOperationException(SR.Format(SR.PauseService, ServiceName, _machineName), inner);
}
}
@@ -819,7 +824,7 @@ public unsafe void Continue()
bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_CONTINUE, &status);
if (!result)
{
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ Exception inner = new Win32Exception();
throw new InvalidOperationException(SR.Format(SR.ResumeService, ServiceName, _machineName), inner);
}
}
@@ -835,7 +840,7 @@ public unsafe void ExecuteCommand(int command)
bool result = Interop.Advapi32.ControlService(serviceHandle, command, &status);
if (!result)
{
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ Exception inner = new Win32Exception();
throw new InvalidOperationException(SR.Format(SR.ControlService, ServiceName, MachineName), inner);
}
}
@@ -891,7 +896,7 @@ public void Start(string[] args!!)
bool result = Interop.Advapi32.StartService(serviceHandle, args.Length, argPtrsHandle.AddrOfPinnedObject());
if (!result)
{
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ Exception inner = new Win32Exception();
throw new InvalidOperationException(SR.Format(SR.CannotStart, ServiceName, _machineName), inner);
}
}
@@ -952,7 +957,7 @@ unsafe void Stop(bool stopDependentServices)
bool result = Interop.Advapi32.ControlService(serviceHandle, Interop.Advapi32.ControlOptions.CONTROL_STOP, &status);
if (!result)
{
- Exception inner = new Win32Exception(Marshal.GetLastWin32Error());
+ Exception inner = new Win32Exception();
throw new InvalidOperationException(SR.Format(SR.StopService, ServiceName, _machineName), inner);
}
}
diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceType.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceType.cs
index 64bc83b2ba93d9..cbf1a2ac583a57 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceType.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceType.cs
@@ -6,12 +6,13 @@ namespace System.ServiceProcess
[Flags]
public enum ServiceType
{
- Adapter = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_ADAPTER,
- FileSystemDriver = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_FILE_SYSTEM_DRIVER,
- InteractiveProcess = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_INTERACTIVE_PROCESS,
- KernelDriver = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_KERNEL_DRIVER,
- RecognizerDriver = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_RECOGNIZER_DRIVER,
- Win32OwnProcess = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32_OWN_PROCESS,
- Win32ShareProcess = Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32_SHARE_PROCESS
+ // Does not currently represent all of the Win32 values; see Interop.Advapi32.ServiceTypeOptions
+ Adapter = Interop.Advapi32.ServiceTypeOptions.SERVICE_ADAPTER,
+ FileSystemDriver = Interop.Advapi32.ServiceTypeOptions.SERVICE_FILE_SYSTEM_DRIVER,
+ InteractiveProcess = Interop.Advapi32.ServiceTypeOptions.SERVICE_INTERACTIVE_PROCESS,
+ KernelDriver = Interop.Advapi32.ServiceTypeOptions.SERVICE_KERNEL_DRIVER,
+ RecognizerDriver = Interop.Advapi32.ServiceTypeOptions.SERVICE_RECOGNIZER_DRIVER,
+ Win32OwnProcess = Interop.Advapi32.ServiceTypeOptions.SERVICE_WIN32_OWN_PROCESS,
+ Win32ShareProcess = Interop.Advapi32.ServiceTypeOptions.SERVICE_WIN32_SHARE_PROCESS
}
}
diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/SafeServiceControllerTests.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/SafeServiceControllerTests.cs
index 2fc6a6a8345ea2..8fe4407e2fd650 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/tests/SafeServiceControllerTests.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/tests/SafeServiceControllerTests.cs
@@ -81,12 +81,12 @@ public static void GetDevices()
ServiceController[] devices = ServiceController.GetDevices();
Assert.True(devices.Length != 0);
- const ServiceType SERVICE_TYPE_DRIVER =
+ const ServiceType SERVICE_DRIVER =
ServiceType.FileSystemDriver |
ServiceType.KernelDriver |
ServiceType.RecognizerDriver;
- Assert.All(devices, device => Assert.NotEqual(0, (int)(device.ServiceType & SERVICE_TYPE_DRIVER)));
+ Assert.All(devices, device => Assert.NotEqual(0, (int)(device.ServiceType & SERVICE_DRIVER)));
}
[Fact]
diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
index 67954fda143349..6b6aff2cc70ec7 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
@@ -223,6 +223,21 @@ public void PropagateExceptionFromOnStart()
testService.DeleteTestServices();
}
+ [ConditionalFact(nameof(IsElevatedAndSupportsEventLogs))]
+ public void NoServiceNameOnServiceBase()
+ {
+ // When installing a service, you must supply a non empty name.
+ // When a service starts itself (using StartServiceCtrlDispatcher) it's legal to pass an empty string for the name.
+ string serviceName = "NoServiceNameOnServiceBase";
+ var testService = new TestServiceProvider(serviceName);
+
+ // Ensure it has successfully written to the event log,
+ // indicating it figured out its own name.
+ Assert.True(EventLog.SourceExists(serviceName));
+
+ testService.DeleteTestServices();
+ }
+
private ServiceController ConnectToServer()
{
TestServiceProvider.DebugTrace("ServiceBaseTests.ConnectToServer: connecting");
diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs
index abff7d1c7c7425..f2e50cb593e168 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs
@@ -65,7 +65,7 @@ static int Main(string[] args)
}
else
{
- Console.WriteLine("EROOR: Invalid Service verb. Only suppot create or delete.");
+ Console.WriteLine("EROOR: Invalid Service verb. Only support create or delete.");
return 2;
}
}
diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs
index 05a7176c360317..3de8aa6edccf0d 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs
@@ -22,7 +22,11 @@ public class TestService : ServiceBase
public TestService(string serviceName, Exception throwException = null)
{
DebugTrace("TestService " + ServiceName + ": Ctor");
- this.ServiceName = serviceName;
+
+ if (serviceName != "NoServiceNameOnServiceBase")
+ {
+ this.ServiceName = serviceName;
+ }
// Enable all the events
this.CanPauseAndContinue = true;
@@ -101,7 +105,15 @@ protected override void OnStop()
base.OnStop();
// We may be stopping because the test has completed and we're cleaning up the test service so there's no client at all, so don't waitForConnect.
// Tests that verify "Stop" itself should ensure the client connection has completed before calling stop, by waiting on some other message from the pipe first.
- WriteStreamAsync(PipeMessageByteCode.Stop, waitForConnect:false).Wait();
+ try
+ {
+ WriteStreamAsync(PipeMessageByteCode.Stop, waitForConnect:false).Wait();
+ }
+ catch (AggregateException ae) when (ae.InnerException.GetType() == typeof(InvalidOperationException))
+ {
+ // Some tests don't bother to connect to the pipe, and just stop the service to clean up.
+ // Don't log this exception into the event log.
+ }
}
public async Task WriteStreamAsync(PipeMessageByteCode code, int command = 0, bool waitForConnect = true)
diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs
index 5ae0d0692e5c4e..3b9b1d0c705508 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs
@@ -77,16 +77,20 @@ public unsafe void Install()
if (serviceManagerHandle.IsInvalid)
throw new InvalidOperationException("Cannot open Service Control Manager");
- TestService.DebugTrace($"TestServiceInstaller: creating service {ServiceName} with prerequisite services {servicesDependedOn}");
+ TestService.DebugTrace($"TestServiceInstaller: creating service '{ServiceName}' with prerequisite services {servicesDependedOn}");
// Install the service
using (var serviceHandle = new SafeServiceHandle(Interop.Advapi32.CreateService(serviceManagerHandle, ServiceName,
- DisplayName, Interop.Advapi32.ServiceAccessOptions.ACCESS_TYPE_ALL, Interop.Advapi32.ServiceTypeOptions.SERVICE_TYPE_WIN32_OWN_PROCESS,
+ DisplayName, Interop.Advapi32.ServiceAccessOptions.ACCESS_TYPE_ALL, Interop.Advapi32.ServiceTypeOptions.SERVICE_WIN32_OWN_PROCESS,
(int)StartType, Interop.Advapi32.ServiceStartErrorModes.ERROR_CONTROL_NORMAL,
ServiceCommandLine, null, IntPtr.Zero, servicesDependedOn, username, password)))
{
if (serviceHandle.IsInvalid)
- throw new Win32Exception("Cannot create service");
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ string errorMessage = new Win32Exception(errorCode).Message;
+ throw new Win32Exception(errorCode, $"Cannot create service '{ServiceName}' with display name '{DisplayName}'. {errorMessage}");
+ }
// A local variable in an unsafe method is already fixed -- so we don't need a "fixed { }" blocks to protect
// across the p/invoke calls below.
@@ -98,7 +102,11 @@ public unsafe void Install()
bool success = Interop.Advapi32.ChangeServiceConfig2(serviceHandle, Interop.Advapi32.ServiceConfigOptions.SERVICE_CONFIG_DESCRIPTION, ref serviceDesc);
Marshal.FreeHGlobal(serviceDesc.description);
if (!success)
- throw new Win32Exception("Cannot set description");
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ string errorMessage = new Win32Exception(errorCode).Message;
+ throw new Win32Exception(errorCode, $"Cannot set description on '{ServiceName}' with display name '{DisplayName}'. {errorMessage}");
+ }
}
// Start the service after creating it
@@ -106,14 +114,14 @@ public unsafe void Install()
{
if (svc.Status != ServiceControllerStatus.Running)
{
- TestService.DebugTrace($"TestServiceInstaller: instructing ServiceController to start service {ServiceName}");
+ TestService.DebugTrace($"TestServiceInstaller: instructing ServiceController to start service '{ServiceName}'");
svc.Start();
if (!ServiceName.StartsWith("PropagateExceptionFromOnStart"))
- svc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(120));
+ svc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(240));
}
else
{
- TestService.DebugTrace("TestServiceInstaller: service {ServiceName} already running");
+ TestService.DebugTrace($"TestServiceInstaller: service '{ServiceName}' already running");
}
}
}
@@ -159,7 +167,7 @@ private void StopService()
}
// var sw = Stopwatch.StartNew();
- svc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(120));
+ svc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(240));
// sw.Stop();
// if (sw.Elapsed > TimeSpan.FromSeconds(30))
// {
@@ -174,17 +182,27 @@ private void DeleteService()
using (var serviceManagerHandle = new SafeServiceHandle(Interop.Advapi32.OpenSCManager(null, null, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_ALL)))
{
if (serviceManagerHandle.IsInvalid)
- throw new Win32Exception("Could not open SCM");
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ string errorMessage = new Win32Exception(errorCode).Message;
+ throw new Win32Exception(errorCode, $"Could not open SCM. {errorMessage}");
+ }
using (var serviceHandle = new SafeServiceHandle(Interop.Advapi32.OpenService(serviceManagerHandle, ServiceName, Interop.Advapi32.ServiceOptions.STANDARD_RIGHTS_DELETE)))
{
if (serviceHandle.IsInvalid)
- throw new Win32Exception($"Could not find service '{ServiceName}'");
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ string errorMessage = new Win32Exception(errorCode).Message;
+ throw new Win32Exception(errorCode, $"Could not find service '{ServiceName}'. {errorMessage}");
+ }
TestService.DebugTrace("TestServiceInstaller: instructing ServiceController to Delete service " + ServiceName);
if (!Interop.Advapi32.DeleteService(serviceHandle))
{
- throw new Win32Exception($"Could not delete service '{ServiceName}'");
+ int errorCode = Marshal.GetLastWin32Error();
+ string errorMessage = new Win32Exception(errorCode).Message;
+ throw new Win32Exception(errorCode, $"Could not delete service '{ServiceName}'. {errorMessage}");
}
}
}