KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q189633: HOWTO: Query a Service for Status and Configuration

Article: Q189633
Product(s): Microsoft Visual Basic for Windows
Version(s): WINDOWS:5.0,6.0
Operating System(s): 
Keyword(s): kbOSWinNT kbOSWin2000 kbRegistry kbVBp kbVBp500 kbVBp600 kbGrpDSVB kbDSupport
Last Modified: 11-JAN-2001

-------------------------------------------------------------------------------
The information in this article applies to:

- Microsoft Visual Basic Control Creation Edition for Windows, versions 5.0, 6.0 
- Microsoft Visual Basic Professional Edition for Windows, versions 5.0, 6.0 
- Microsoft Visual Basic Enterprise Edition for Windows, versions 5.0, 6.0 
-------------------------------------------------------------------------------

SUMMARY
=======

This article provides sample code that demonstrates how to query a Windows 2000
or Windows NT Service's Status and Configuration from Visual Basic.

MORE INFORMATION
================

Step-by-Step Example
--------------------

1. Start a New Standard EXE Project in Visual Basic. Form1 is created by
  default.

2. Add a Text Box, Command Button, and a List Box to Form1.

3. Remove "Text1" from the Text property of Text1.

4. Paste the following code into the declarations section of Form1:

     Option Explicit

     Private Declare Function CloseServiceHandle Lib "advapi32.dll" _
        (ByVal hSCObject As Long) As Long

     Private Declare Function QueryServiceStatus Lib "advapi32.dll" _
        (ByVal hService As Long, _
        lpServiceStatus As SERVICE_STATUS) As Long

     Private Declare Function OpenService Lib "advapi32.dll" _
        Alias "OpenServiceA" _
        (ByVal hSCManager As Long, _
        ByVal lpServiceName As String, _
        ByVal dwDesiredAccess As Long) As Long

     Private Declare Function OpenSCManager Lib "advapi32.dll" _
        Alias "OpenSCManagerA" _
        (ByVal lpMachineName As String, _
        ByVal lpDatabaseName As String, _
        ByVal dwDesiredAccess As Long) As Long

     Private Declare Function QueryServiceConfig Lib "advapi32.dll" _
        Alias "QueryServiceConfigA" _
        (ByVal hService As Long, _
        lpServiceConfig As Byte, _
        ByVal cbBufSize As Long, _
        pcbBytesNeeded As Long) As Long

     Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" _
        (hpvDest As Any, _
        hpvSource As Any, _
        ByVal cbCopy As Long)

     Private Declare Function lstrcpy Lib "KERNEL32" Alias "lstrcpyA" _
        (ByVal lpString1 As String, _
        ByVal lpString2 As Long) As Long

     Private Type SERVICE_STATUS
        dwServiceType As Long
        dwCurrentState As Long
        dwControlsAccepted As Long
        dwWin32ExitCode As Long
        dwServiceSpecificExitCode As Long
        dwCheckPoint As Long
        dwWaitHint As Long
     End Type

     Private Type QUERY_SERVICE_CONFIG
        dwServiceType As Long
        dwStartType As Long
        dwErrorControl As Long
        lpBinaryPathName As Long 'String
        lpLoadOrderGroup As Long ' String
        dwTagId As Long
        lpDependencies As Long 'String
        lpServiceStartName As Long 'String
        lpDisplayName As Long  'String
     End Type

     Private Const SERVICE_STOPPED = &H1
     Private Const SERVICE_START_PENDING = &H2
     Private Const SERVICE_STOP_PENDING = &H3
     Private Const SERVICE_RUNNING = &H4
     Private Const SERVICE_CONTINUE_PENDING = &H5
     Private Const SERVICE_PAUSE_PENDING = &H6
     Private Const SERVICE_PAUSED = &H7
     Private Const SERVICE_ACCEPT_STOP = &H1
     Private Const SERVICE_ACCEPT_PAUSE_CONTINUE = &H2
     Private Const SERVICE_ACCEPT_SHUTDOWN = &H4
     Private Const SC_MANAGER_CONNECT = &H1
     Private Const SERVICE_INTERROGATE = &H80
     Private Const GENERIC_READ = &H80000000
     Private Const ERROR_INSUFFICIENT_BUFFER = 122

     Private Sub Command1_Click()
        Dim hSCM  As Long
        Dim hSVC As Long
        Dim pSTATUS As SERVICE_STATUS
        Dim udtConfig As QUERY_SERVICE_CONFIG
        Dim lRet As Long
        Dim lBytesNeeded As Long
        Dim sTemp As String
        Dim pFileName As Long

     List1.Clear

        ' Open The Service Control Manager
        '
        hSCM = OpenSCManager(vbNullString, vbNullString, SC_MANAGER_CONNECT)
        If hSCM = 0 Then
           MsgBox "Error - " & Err.LastDllError
        End If

        ' Open the specific Service to obtain a handle
        '
        hSVC = OpenService(hSCM, Trim(Text1.Text), GENERIC_READ)
           If hSVC = 0 Then
              MsgBox "Error - " & Err.LastDllError
              GoTo CloseHandles
           End If

        ' Fill the Service Status Structure
        '
        lRet = QueryServiceStatus(hSVC, pSTATUS)
        If lRet = 0 Then
           MsgBox "Error - " & Err.LastDllError
           GoTo CloseHandles
        End If

        ' Report the Current State
        '
        Select Case pSTATUS.dwCurrentState
        Case SERVICE_STOPPED
           sTemp = "The Service is Stopped"
        Case SERVICE_START_PENDING
           sTemp = "The Service Being Started"
        Case SERVICE_STOP_PENDING
           sTemp = "The Service is in the process of being stopped"
        Case SERVICE_RUNNING
           sTemp = "The Service is Running"
        Case SERVICE_CONTINUE_PENDING
           sTemp = "The Service is in the process of being Continued"
        Case SERVICE_PAUSE_PENDING
           sTemp = "The Service is in the process of being Paused"
        Case SERVICE_PAUSED
           sTemp = "The Service is Paused"
        Case SERVICE_ACCEPT_STOP
           sTemp = "The Service is Stopped"
        Case SERVICE_ACCEPT_PAUSE_CONTINUE
           sTemp = "The Service is "
        Case SERVICE_ACCEPT_SHUTDOWN
           sTemp = "The Service is being Shutdown"
        End Select

        List1.AddItem "Service Status : " & sTemp

        ' Call QueryServiceConfig with 1 byte buffer to generate an error
        ' that returns the size of a buffer we need.
        '
        ReDim abConfig(0) As Byte
        lRet = QueryServiceConfig(hSVC, abConfig(0), 0&, lBytesNeeded)
        If lRet = 0 And Err.LastDllError <> ERROR_INSUFFICIENT_BUFFER Then
           MsgBox "Error - " & Err.LastDllError
        End If

        ' Redim our byte array to the size necessary and call
        ' QueryServiceConfig again
        '
        ReDim abConfig(lBytesNeeded) As Byte
        lRet = QueryServiceConfig(hSVC, abConfig(0), lBytesNeeded, _
           lBytesNeeded)
        If lRet = 0 Then
           MsgBox "Error - " & Err.LastDllError
           GoTo CloseHandles
        End If

        ' Fill our Service Config User Defined Type.
        '
        CopyMemory udtConfig, abConfig(0), Len(udtConfig)

        List1.AddItem "Service Type: " & udtConfig.dwServiceType
        List1.AddItem "Service Start Type: " & udtConfig.dwStartType
        List1.AddItem "Service Error Control: " & udtConfig.dwErrorControl

        sTemp = Space(255)

        ' Now use the pointer obtained to copy the path into the temporary
        ' String Variable
        '
        lRet = lstrcpy(sTemp, udtConfig.lpBinaryPathName)
        List1.AddItem "Service Binary Path: " & sTemp

        lRet = lstrcpy(sTemp, udtConfig.lpDependencies)
        List1.AddItem "Service Dependencies: " & sTemp

        lRet = lstrcpy(sTemp, udtConfig.lpDisplayName)
        List1.AddItem "Service DisplayName: " & sTemp

        lRet = lstrcpy(sTemp, udtConfig.lpLoadOrderGroup)
        List1.AddItem "Service LoadOrderGroup: " & sTemp

        lRet = lstrcpy(sTemp, udtConfig.lpServiceStartName)
        List1.AddItem "Service Start Name: " & sTemp

     CloseHandles:
     ' Close the Handle to the Service
     '
        CloseServiceHandle (hSVC)

     ' Close the Handle to the Service Control Manager
     '
        CloseServiceHandle (hSCM)

     End Sub

5. Run the sample and type the Service Name in the Text box. For this example
  type in "Eventlog" without the quotes.

  NOTE: This is not necessarily the same as the "Display Name" that shows in the
  Services applet of the Control Panel. The Service names registered on the
  system can be located under the following registry key:

  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

6. Click the CommandButton.

  The results displayed in the list box should be similar to the following:

     Service Status : The Service is Running
     Service Type: 32
     Service Start Type: 2
     Service Error Control: 1
     Service Binary Path: C:\WINNT\system32\services.exe
     Service Dependencies:

     Service DisplayName: EventLog
     Service LoadOrderGroup: Event log
     Service Start Name: LocalSystem

Additional query words:

======================================================================
Keywords          : kbOSWinNT kbOSWin2000 kbRegistry kbVBp kbVBp500 kbVBp600 kbGrpDSVB kbDSupport 
Technology        : kbVBSearch kbAudDeveloper kbZNotKeyword6 kbZNotKeyword2 kbVB500Search kbVB600Search kbVBA500Search kbVBA500 kbVBA600 kbVB500 kbVB600 kbZNotKeyword3
Version           : WINDOWS:5.0,6.0
Issue type        : kbhowto

=============================================================================

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.