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