ServiceState class
A read-only snapshot of an installed service’s current state as reported by the SCM. Typically obtained via Services.QueryStateOfService; can also be constructed directly with New ServiceState(ServiceName).
Dim state As ServiceState
Set state = Services.QueryStateOfService("MyService")
Debug.Print state.CurrentStateText, "PID " & state.ProcessId
The snapshot is taken once at construction time and never refreshed. To monitor a service over time, call Services.QueryStateOfService again at each sampling interval — typically from a low-frequency Timer.
Methods
New
Initializes a ServiceState instance by querying the SCM for the named service’s current status.
Syntax: New ServiceState(ServiceName)
- ServiceName
- required A String naming the service as registered in the SCM database (the same value passed to Services.QueryStateOfService or stored in ServiceManager.Name).
Opens the SCM with SC_MANAGER_CONNECT, opens the named service with SERVICE_QUERY_STATUS, and calls QueryServiceStatusEx(SC_STATUS_PROCESS_INFO, ...) to populate the internal SERVICE_STATUS_PROCESS buffer. All service and SCM handles are closed before the constructor returns.
Three failure modes raise run-time error 5 with a descriptive message:
"Unable to open the Service manager (OpenSCManagerW failed). Check permissions."— the calling process lacks sufficient rights to open the SCM."Service '<name>' is not installed on this system"— no service with the given name exists in the SCM database."Unable to query the service state"—QueryServiceStatusExfailed after the service handle was opened.
Wrap the constructor in On Error Resume Next when the caller needs to distinguish “service is running” from “service is not installed”:
Private Function GetStateText(ByVal serviceName As String) As String
On Error Resume Next
Dim state As ServiceState
Set state = New ServiceState(serviceName)
If Err.Number = 0 Then
GetStateText = state.CurrentStateText
Else
GetStateText = "not installed"
End If
End Function
Properties
CheckPoint
The SCM-reported dwCheckPoint value. Long.
Services in a Pending state (StartPending, StopPending, PausePending, ContinuePending) report a periodically-incrementing CheckPoint so the SCM can tell a slow-but-progressing transition from a hung service. The package’s ServiceManager.ReportStatus auto-increments the field while the service is in a pending state and resets it to 0 on Running or Stopped.
ControlsAccepted
A bitmask of SERVICE_ACCEPT_* flags indicating which control codes the service has told the SCM it accepts. Long.
Note
Although the underlying SCM field is a flag bitmask, the property is typed plain Long in this release rather than as a typed enum. The bit values follow the Win32 documented constants — SERVICE_ACCEPT_STOP (1), SERVICE_ACCEPT_PAUSE_CONTINUE (2), SERVICE_ACCEPT_SHUTDOWN (4), SERVICE_ACCEPT_PARAMCHANGE (8), SERVICE_ACCEPT_NETBINDCHANGE (16), SERVICE_ACCEPT_HARDWAREPROFILECHANGE (32), SERVICE_ACCEPT_POWEREVENT (64), SERVICE_ACCEPT_SESSIONCHANGE (128), SERVICE_ACCEPT_PRESHUTDOWN (256), and so on.
CurrentState
The SCM-reported dwCurrentState value. Long.
Note
The property is typed plain Long in this release rather than as ServiceStatusConstants. The numeric values do match the enum (e.g. 4 is vbServiceStatusRunning), so a cast such as CType(state.CurrentState, ServiceStatusConstants) recovers typed access if needed. For display purposes CurrentStateText is usually more convenient.
CurrentStateText
A human-readable rendering of CurrentState. String.
The mapping:
| State value | Text |
|---|---|
| vbServiceStatusContinuePending | CONTINUING |
| vbServiceStatusPausePending | PAUSING |
| vbServiceStatusPaused | PAUSED |
| vbServiceStatusRunning | RUNNING |
| vbServiceStatusStartPending | STARTING |
| vbServiceStatusStopPending | STOPPING |
| vbServiceStatusStopped | STOPPED |
Any unrecognised state value is rendered as UNKNOWN STATE (<n>).
ExitCode
The Win32 exit code the service reported when it last stopped. Long. Read-only.
Syntax: state.ExitCode
- state
- required An object expression that evaluates to a ServiceState instance, obtained from Services.QueryStateOfService.
Returns the dwWin32ExitCode field from the SERVICE_STATUS_PROCESS structure the SCM fills in. For a service that stopped normally this is 0 (NO_ERROR). For a service that stopped due to an error, this is either a standard Win32 error code or the sentinel value ERROR_SERVICE_SPECIFIC_ERROR (1066) — in which case the real vendor-defined code is in ServiceSpecificExitCode.
While the service is in any state other than Stopped the SCM keeps this field at 0. The value becomes meaningful only after the service thread exits and the SCM records the terminal status.
Flags
The SCM-reported dwServiceFlags value. Long.
Only one bit is currently documented — SERVICE_RUNS_IN_SYSTEM_PROCESS (1), set when the service is hosted inside the system process (services.exe).
ProcessId
The OS process ID hosting the service, or 0 if the service is not running. Long.
Syntax: object.ProcessId
- object
- required An object expression that evaluates to a ServiceState instance, obtained from Services.QueryStateOfService.
The value is the Win32 process identifier (dwProcessId) as reported by QueryServiceStatusEx. When the service is in the Stopped state the SCM reports 0, as there is no live process. For a service in Running state the value matches the PID shown in Task Manager or returned by tasklist /svc.
Use ProcessId as a quick “is the service alive?” check in preference to string-comparing CurrentStateText:
Dim state As ServiceState
Set state = Services.QueryStateOfService("MyService")
If state.ProcessId <> 0 Then
Debug.Print "Service is alive; PID " & state.ProcessId
Else
Debug.Print "Service is not running"
End If
ServiceSpecificExitCode
The SCM-reported dwServiceSpecificExitCode value. Long.
Meaningful only when ExitCode equals ERROR_SERVICE_SPECIFIC_ERROR (1066); otherwise the field is 0 and should be ignored. Services that report custom error codes through ServiceManager.ReportStatus populate this field through the package’s machinery.
Type
The SCM-reported service type. ServiceTypeConstants. Read-only.
Syntax: state.Type
- state
- required An object expression that evaluates to a ServiceState instance, obtained from Services.QueryStateOfService.
Returns the ServiceTypeConstants value the SCM has on file for the service. For twinBASIC services this is typically one of:
- tbServiceTypeOwnProcess – the service runs in its own dedicated process.
- tbServiceTypeShareProcess – the service shares its host process with one or more other services from the same EXE.
The value is read directly from the dwServiceType field of the SERVICE_STATUS_PROCESS structure returned by QueryServiceStatusEx. It reflects whatever was registered in the SCM at install time via ServiceManager.Type.
WaitHint
The estimated upper bound, in milliseconds, of the time the current pending state transition will take. Long. Read-only.
Syntax: object.WaitHint
- object
- required An object expression that evaluates to a ServiceState instance, obtained from Services.QueryStateOfService.
Returns the dwWaitHint field from the SERVICE_STATUS_PROCESS structure the SCM fills in. The value is the estimate the service last reported through SetServiceStatus when it entered the current pending state. It is only meaningful while the service is in a Pending state (StartPending, StopPending, PausePending, ContinuePending). For services in Running or Stopped states the field is 0 or the last value set before the transition completed and should not be interpreted.
The SCM uses CheckPoint and WaitHint together to decide whether a pending service is making progress. If the CheckPoint value has not increased within the WaitHint interval, the SCM considers the service hung and may report an error. A service that expects a long pending phase should either set WaitHint large enough to cover the whole transition, or increment CheckPoint at regular sub-intervals to signal continued progress.
Example
This example reads the wait hint and check point for a service currently in a pending state and prints a progress summary.
Dim state As ServiceState
Set state = Services.QueryStateOfService("MyService")
If state.CurrentStateText = "STARTING" Or state.CurrentStateText = "STOPPING" Then
Debug.Print "Pending -- checkpoint: " & state.CheckPoint & _
", max wait: " & state.WaitHint & " ms"
End If
See Also
- WinServicesLib package – overview, lifecycle
- Services.QueryStateOfService method – constructs a ServiceState from the predeclared coordinator
- CheckPoint property – the progress counter the SCM reads alongside WaitHint
- ServiceStatusConstants enum – the values CurrentState can take
- ServiceTypeConstants enum – the values Type can take