After reading this post at StackOverflow, I realized that I was probably wrong to think it was OK to directly access the registry keys that Windows uses to keep track of installed services. Though the names and locations of the keys probably won’t change any time soon, it’s always better to use a higher level of abstraction when dealing with Windows internals. In this case, WMI fits the bill very nicely.
I had not written any WMI-related code up til now, simply because I’ve always been able to find other methods to get the information I need. But after reading that post and knowing of a particular program of mine that does access the registry directly to determine the start mode for a service, I decided to re-write that code to use WMI via the System.Management namespace in the .NET framework.
I came across a couple of different C# samples on the web and was able to modify them to fit my needs. Below is a new class I created for service management that will hopefully grow over time.
Imports System.Management ''' ''' Used to manage Windows services. ''' Public Class ServiceManagement 'Enumeration of service startup modes Public Enum ServiceStartMode Boot = 0 System = 1 Automatic = 2 Manual = 3 Disabled = 4 End Enum 'Return values for service-related WMI routines Public Enum ReturnValue Success = 0 NotSupported = 1 AccessDenied = 2 DependentServicesRunning = 3 InvalidServiceControl = 4 ServiceCannotAcceptControl = 5 ServiceNotActive = 6 ServiceRequestTimeout = 7 UnknownFailure = 8 PathNotFound = 9 ServiceAlreadyRunning = 10 ServiceDatabaseLocked = 11 ServiceDependencyDeleted = 12 ServiceDependencyFailure = 13 ServiceDisabled = 14 ServiceLogonFailure = 15 ServiceMarkedForDeletion = 16 ServiceNoThread = 17 StatusCircularDependency = 18 StatusDuplicateName = 19 StatusInvalidName = 20 StatusInvalidParameter = 21 StatusInvalidServiceAccount = 22 StatusServiceExists = 23 ServiceAlreadyPaused = 24 ServiceNotFound = 25 End Enum ''' ''' Gets the current start mode for the given service. ''' '''Name of an installed service. ''' Numerical code indicating the service's start mode. Public Shared Function GetStartMode(ByVal serviceName As String) As ServiceStartMode Dim service As ManagementObject = Nothing Dim servicePath As String Dim startMode As String GetStartMode = ServiceStartMode.Disabled Try servicePath = String.Format("Win32_Service.Name=""{0}""", serviceName) service = New ManagementObject(servicePath) startMode = service.GetPropertyValue("StartMode").ToString 'We can't return the exact property value because StartMode will 'show as 'Auto' rather than 'Automatic'. Since the ChangeStartMode 'WMI method will need to have 'Automatic' passed when setting the 'service to auto-start, our ServiceStartMode enum uses 'Automatic' Select Case startMode Case "Boot" Return ServiceStartMode.Boot Case "System" Return ServiceStartMode.System Case "Auto" Return ServiceStartMode.Automatic Case "Manual" Return ServiceStartMode.Manual Case "Disabled" Return ServiceStartMode.Disabled End Select Catch Throw Finally If service IsNot Nothing Then service.Dispose() End If End Try End Function ''' ''' Sets the start mode for the given service. ''' '''Name of an installed service. '''Numerical code representing the new start mode. ''' Error code indicating the result of the change operation. Public Shared Function SetStartMode(ByVal serviceName As String, ByVal startMode As ServiceStartMode) As ReturnValue Dim service As ManagementObject = Nothing Dim inParams As ManagementBaseObject = Nothing Dim outParams As ManagementBaseObject = Nothing Dim servicePath As String SetStartMode = ReturnValue.UnknownFailure Try servicePath = String.Format("Win32_Service.Name=""{0}""", serviceName) service = New ManagementObject(servicePath) inParams = service.GetMethodParameters("ChangeStartMode") inParams("StartMode") = startMode.ToString() outParams = service.InvokeMethod("ChangeStartMode", inParams, Nothing) Return DirectCast([Enum].Parse(GetType(ReturnValue), outParams("ReturnValue").ToString()), ReturnValue) Catch Throw Finally If inParams IsNot Nothing Then inParams.Dispose() End If If outParams IsNot Nothing Then outParams.Dispose() End If If service IsNot Nothing Then service.Dispose() End If End Try End Function End Class