Visual Basic Network Services
EnumServicesStatus: Enumerate Local or Remote Machine Services and Status
Posted:   Tuesday May 22, 2001
Updated:   Monday December 26, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows 2000
OS restrictions:   Windows NT3.1, Windows NT4, Windows 2000, Windows XP
Author:   VBnet - Randy Birch


EnumServicesStatus: Enumerate Local Machine Services
EnumServicesStatus: Enumerate Local Machine Services and Status

EnumServicesStatus: Enumerate Local or Remote Machine Services and Status
One of the operating systems listed under OS Restrictions above.

This demo marries the advanced EnumServicesStatus demo and the NetServerEnum demo, providing a list of machines from the local domain in the combo from which the services information is retrieved when selected. Note that this code will not retrieve service info from Win9x machines, so specifying the correct flags to limit machines returned, or interrogating the version member of the NetServerEnum sv100_platform_id would be prudent.

Also note that NetServerEnum lists machines registered on the specified domain (here, local) as they appear on the local machine's network neighbourhood. But because windows list of networked machines is not truly real-time data, machines that are no longer connected, or whose machine names have been changed, may still be listed (until the controller refreshes the machine list). Should one of these machines be selected, the call to OpenSCManager will return error 1722 - "the RPC server is unavailable".

 BAS Module Code

Option Explicit
 Form Code
To a form add three command buttons in a control array (Command1(0), Command1(1) and Command1(2)), a list box (List1), a combo (Combo1) and a label (Label1). Add the following code to the form:

Option Explicit
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
Private lastIndex As Long
'our own constant
Private Const SIZEOF_SERVICE_STATUS As Long = 36

'windows constants
Private Const LB_SETTABSTOPS As Long = &H192
Private Const ERROR_MORE_DATA = 234

'Service State for Enum Requests (Bit Mask)
Private Const SERVICE_ACTIVE = &H1
Private Const SERVICE_INACTIVE = &H2
'Service Types (Bit Mask)
'corresponds to SERVICE_STATUS.dwServiceType
Private Const SERVICE_KERNEL_DRIVER As Long = &H1
Private Const SERVICE_ADAPTER As Long = &H4
Private Const SERVICE_WIN32_OWN_PROCESS As Long = &H10
Private Const SERVICE_WIN32_SHARE_PROCESS As Long = &H20
                                      SERVICE_FILE_SYSTEM_DRIVER Or _
Private Const SERVICE_TYPE_ALL As Long = SERVICE_WIN32 Or _
                                        SERVICE_ADAPTER Or _
                                        SERVICE_DRIVER Or _
'Service State
'corresponds to SERVICE_STATUS.dwCurrentState
Private Const SERVICE_STOPPED As Long = &H1
Private Const SERVICE_START_PENDING As Long = &H2
Private Const SERVICE_STOP_PENDING As Long = &H3
Private Const SERVICE_RUNNING As Long = &H4
Private Const SERVICE_PAUSE_PENDING As Long = &H6
Private Const SERVICE_PAUSED As Long = &H7

'Controls Accepted  (Bit Mask)
'corresponds to SERVICE_STATUS.dwControlsAccepted
Private Const SERVICE_ACCEPT_STOP As Long = &H1
Private Const SERVICE_ACCEPT_SHUTDOWN   As Long = &H4

'Windows type used to call the Net API
Private Const MAX_PREFERRED_LENGTH As Long = -1
Private Const NERR_SUCCESS As Long = 0&

Private Const SV_TYPE_WORKSTATION         As Long = &H1
Private Const SV_TYPE_SERVER              As Long = &H2
Private Const SV_TYPE_SQLSERVER           As Long = &H4
Private Const SV_TYPE_DOMAIN_CTRL         As Long = &H8
Private Const SV_TYPE_DOMAIN_BAKCTRL      As Long = &H10
Private Const SV_TYPE_TIME_SOURCE         As Long = &H20
Private Const SV_TYPE_AFP                 As Long = &H40
Private Const SV_TYPE_NOVELL              As Long = &H80
Private Const SV_TYPE_DOMAIN_MEMBER       As Long = &H100
Private Const SV_TYPE_PRINTQ_SERVER       As Long = &H200
Private Const SV_TYPE_DIALIN_SERVER       As Long = &H400
Private Const SV_TYPE_XENIX_SERVER        As Long = &H800
Private Const SV_TYPE_NT                  As Long = &H1000
Private Const SV_TYPE_WFW                 As Long = &H2000
Private Const SV_TYPE_SERVER_MFPN         As Long = &H4000
Private Const SV_TYPE_SERVER_NT           As Long = &H8000
Private Const SV_TYPE_POTENTIAL_BROWSER   As Long = &H10000
Private Const SV_TYPE_BACKUP_BROWSER      As Long = &H20000
Private Const SV_TYPE_MASTER_BROWSER      As Long = &H40000
Private Const SV_TYPE_DOMAIN_MASTER       As Long = &H80000
Private Const SV_TYPE_SERVER_OSF          As Long = &H100000
Private Const SV_TYPE_SERVER_VMS          As Long = &H200000
Private Const SV_TYPE_WINDOWS             As Long = &H400000  'Win95 and above
Private Const SV_TYPE_DFS                 As Long = &H800000  'Root of DFS tree
Private Const SV_TYPE_CLUSTER_NT          As Long = &H1000000 'NT Cluster
Private Const SV_TYPE_TERMINALSERVER      As Long = &H2000000 'Terminal Server
Private Const SV_TYPE_DCE                 As Long = &H10000000'IBM DSS
Private Const SV_TYPE_ALTERNATE_XPORT     As Long = &H20000000'rtn alternate transport
Private Const SV_TYPE_LOCAL_LIST_ONLY     As Long = &H40000000'rtn local only
Private Const SV_TYPE_DOMAIN_ENUM         As Long = &H80000000
Private Const SV_TYPE_ALL                 As Long = &HFFFFFFFF

Private Const SV_PLATFORM_ID_OS2       As Long = 400
Private Const SV_PLATFORM_ID_NT        As Long = 500

'Mask applied to svX_version_major in
'order to obtain the major version number.
Private Const MAJOR_VERSION_MASK        As Long = &HF

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

   lpServiceName As Long
   lpDisplayName As Long
   ServiceStatus As SERVICE_STATUS
End Type

Private Type SERVER_INFO_100
  sv100_platform_id As Long
  sv100_name As Long
End Type

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

Private Declare Function EnumServicesStatus Lib "advapi32" _
   Alias "EnumServicesStatusA" _
  (ByVal hSCManager As Long, _
   ByVal dwServiceType As Long, _
   ByVal dwServiceState As Long, _
   lpServices As Any, _
   ByVal cbBufSize As Long, _
   pcbBytesNeeded As Long, _
   lpServicesReturned As Long, _
   lpResumeHandle As Long) As Long
Private Declare Function CloseServiceHandle Lib "advapi32" _
   (ByVal hSCObject As Long) As Long

Private Declare Function NetServerEnum Lib "netapi32" _
  (ByVal servername As Long, _
   ByVal level As Long, _
   buf As Any, _
   ByVal prefmaxlen As Long, _
   entriesread As Long, _
   totalentries As Long, _
   ByVal servertype As Long, _
   ByVal domain As Long, _
   resume_handle As Long) As Long

Private Declare Function NetApiBufferFree Lib "netapi32" _
   (ByVal Buffer As Long) As Long

Private Declare Sub CopyMemory Lib "kernel32" _
   Alias "RtlMoveMemory" _
  (pTo As Any, uFrom As Any, _
   ByVal lSize As Long)
Private Declare Function lstrlenW Lib "kernel32" _
  (ByVal lpString As Long) As Long

Private Declare Function lstrcpyA Lib "kernel32" _
  (ByVal RetVal As String, ByVal Ptr As Long) As Long
Private Declare Function lstrlenA Lib "kernel32" _
  (ByVal Ptr As Any) As Long

Private Declare Function SendMessage Lib "user32" _
   Alias "SendMessageA" _
  (ByVal hwnd As Long, _
   ByVal wMsg As Long, _
   ByVal wParam As Long, _
   lParam As Any) As Long

Private Sub Form_Load()
   ReDim TabArray(0 To 4) As Long
   TabArray(0) = 150
   TabArray(1) = 220
   TabArray(2) = 270
   TabArray(3) = 342
   TabArray(4) = 390

   Call SendMessage(List1.hwnd, LB_SETTABSTOPS, 0&, ByVal 0&)
   Call SendMessage(List1.hwnd, LB_SETTABSTOPS, 5&, TabArray(0))
   Command1(0).Caption = "Active Services"
   Command1(1).Caption = "Inactive Services"
   Command1(2).Caption = "All Services"
  'if you have a large list of machines, you may 
  'want to move this call to a command button to 
  'speed loading. 
   Call GetServers(vbNullString)
End Sub

Private Sub Combo1_Click()

   If Combo1.ListIndex > -1 Then
      Command1(lastIndex).Value = True
   End If
End Sub

Private Sub Command1_Click(Index As Integer)

   Dim sMachine As String

   If Combo1.ListIndex > -1 Then

      sMachine = Combo1.List(Combo1.ListIndex)

      Select Case Index
         Case 0:
           'active services
            EnumSystemServices SERVICE_ACTIVE, sMachine, List1

         Case 1:
           'inactive services
            EnumSystemServices SERVICE_INACTIVE, sMachine, List1

         Case 2:
           'all services
            EnumSystemServices SERVICE_STATE_ALL, sMachine, List1

      End Select

     'save the current option to allow the list
     'to refresh with the same type of data as
     'different machines are selected.
      lastIndex = Index

   End If

End Sub

Private Function GetPointerToByteStringW(ByVal dwData As Long) As String
   Dim tmp() As Byte
   Dim tmplen As Long
   If dwData <> 0 Then
      tmplen = lstrlenW(dwData) * 2
      If tmplen <> 0 Then
         ReDim tmp(0 To (tmplen - 1)) As Byte
         CopyMemory tmp(0), ByVal dwData, tmplen
         GetPointerToByteStringW = tmp
     End If
   End If
End Function

Private Function GetStrFromPtrA(ByVal lpszA As Long) As String

   GetStrFromPtrA = String$(lstrlenA(ByVal lpszA), 0)
   Call lstrcpyA(ByVal GetStrFromPtrA, ByVal lpszA)
End Function

Private Function EnumSystemServices(SERVICE_TYPE As Long, _
                                   sMachine As String, _
                                   ctl As Control) As Long

   Dim hSCManager As Long
   Dim cbBuffSize As Long
   Dim cbRequired As Long
   Dim dwReturned As Long
   Dim hEnumResume As Long
   Dim cbBuffer As Long
   Dim success As Long
   Dim i As Long
  'these five just help keep the
  'code lines from becoming too long
  'for html display
   Dim sSvcName As String
   Dim sDispName As String
   Dim dwState As Long
   Dim dwType As Long
   Dim dwCtrls As Long
  'update label to show what we're trying to view
   Label1.Caption = "Viewing " & Command1(SERVICE_TYPE - 1).Caption & " on " & sMachine
  'establish a connection to the service control
  'manager on the local computer and open
  'the local service control manager database.
   hSCManager = OpenSCManager("\\" & sMachine, _
                              vbNullString, _

   If hSCManager <> 0 Then

     'Get buffer size by calling EnumServicesStatus.
     'To determine the required buffer size, call EnumServicesStatus
     'with cbBuffer and hEnumResume set to zero. EnumServicesStatus
     'fails (returns 0), and Err.LastDLLError returns ERROR_MORE_DATA,
     'filling cbRequired with the size, in bytes, of the buffer
     'required to hold the array of structures and their data.
      success = EnumServicesStatus(hSCManager, _
                                   SERVICE_WIN32, _
                                   SERVICE_TYPE, _
                                   ByVal &H0, _
                                   &H0, _
                                   cbRequired, _
                                   dwReturned, _

     'If success is 0 and the LastDllError is
     'ERROR_MORE_DATA, use returned info to create
     'the required data buffer
      If success = 0 And Err.LastDllError = ERROR_MORE_DATA Then

        'Calculate number of structures needed
        'and redimension the array
         cbBuffer = (cbRequired \ SIZEOF_SERVICE_STATUS) + 1
         ReDim pntr(0 To cbBuffer)
        'Set cbBuffSize equal to the size of the buffer
         cbBuffSize = cbBuffer * SIZEOF_SERVICE_STATUS

        'Enumerate the services. If the function succeeds,
        'the return value is nonzero. If the function fails,
        'the return value is zero. In addition, hEnumResume
        'must be set to 0.
         hEnumResume = 0
         If EnumServicesStatus(hSCManager, _
                               SERVICE_WIN32, _
                               SERVICE_TYPE, _
                               pntr(0), _
                               cbBuffSize, _
                               cbRequired, _
                               dwReturned, _
                               hEnumResume) Then

           'pntr() array is now filled with service data,
           'so it is a simple matter of extracting the
           'required information.
            With ctl
               For i = 0 To dwReturned - 1
                  sDispName = GetStrFromPtrA(ByVal pntr(i).lpDisplayName)
                  sSvcName = GetStrFromPtrA(ByVal pntr(i).lpServiceName)
                  dwState = pntr(i).ServiceStatus.dwCurrentState
                  dwType = pntr(i).ServiceStatus.dwServiceType
                  dwCtrls = pntr(i).ServiceStatus.dwControlsAccepted
                  .AddItem sDispName & vbTab & _
                           sSvcName & vbTab & _
                           GetServiceState(dwState) & vbTab & _
                           GetServiceType(dwType) & vbTab & _
            End With
            MsgBox "EnumServicesStatus; error " & CStr(Err.LastDllError)
         End If  'If EnumServicesStatus

         MsgBox "ERROR_MORE_DATA not returned; error " & CStr(Err.LastDllError)
      End If  'If success = 0 And Err.LastDllError
      MsgBox "OpenSCManager failed; error = " & CStr(Err.LastDllError)
   End If  'If hSCManager <> 0
  'Clean up
   Call CloseServiceHandle(hSCManager)
  'return the number of services
  'returned as a sign of success
   EnumSystemServices = dwReturned

End Function

Private Function GetServers(sDomain As String) As Long

  'lists all servers of the specified type
  'that are visible in a domain.
   Dim bufptr          As Long
   Dim dwEntriesread   As Long
   Dim dwTotalentries  As Long
   Dim dwResumehandle  As Long
   Dim se100           As SERVER_INFO_100
   Dim success         As Long
   Dim nStructSize     As Long
   Dim cnt             As Long

   nStructSize = LenB(se100)
  'Call passing MAX_PREFERRED_LENGTH to have the
  'API allocate required memory for the return values.
  'The call is enumerating all machines on the
  'network (SV_TYPE_ALL); however, by Or'ing
  'specific bit masks for defined types you can
  'customize the returned data. For example, a
  'value of 0x00000003 combines the bit masks for
  'SV_TYPE_WORKSTATION (0x00000001) and
  'SV_TYPE_SERVER (0x00000002).
  'dwServerName must be Null. The level parameter
  '(100 here) specifies the data structure being
  'used (in this case a SERVER_INFO_100 structure).
  'The domain member is passed as Null, indicating
  'machines on the primary domain are to be retrieved.
  'If you decide to use this member, assign the variable
  'passed to this function (sDomain) as
  'StrPtr(sDomain), not the string itself..
   success = NetServerEnum(0&, _
                           100, _
                           bufptr, _
                           MAX_PREFERRED_LENGTH, _
                           dwEntriesread, _
                           dwTotalentries, _
                           SV_TYPE_WORKSTATION Or SV_TYPE_SERVER, _
                           0&, _

  'if all goes well
   If success = NERR_SUCCESS And _
      success <> ERROR_MORE_DATA Then
    'loop through the returned data, adding each
    'machine to the list
      For cnt = 0 To dwEntriesread - 1
        'get one chunk of data and cast
        'into an LOCALGROUP_INFO_1 type
        'in order to add the name to a list
         CopyMemory se100, ByVal bufptr + (nStructSize * cnt), nStructSize
         Combo1.AddItem GetPointerToByteStringW(se100.sv100_name)
   End If
  'clean up, regardless of success
   Call NetApiBufferFree(bufptr)

End Function

Private Function GetServiceControl(dwControl As Long) As String

   Dim tmp As String

   If dwControl Then
      If (dwControl And SERVICE_ACCEPT_STOP) Then tmp = tmp & "stop, "
      If (dwControl And SERVICE_ACCEPT_PAUSE_CONTINUE) Then tmp = tmp & "pause, "
      If (dwControl And SERVICE_ACCEPT_SHUTDOWN) Then tmp = tmp & "shutdown"
   '  tmp = vbTab
   End If

   GetServiceControl = tmp

End Function

Private Function GetServiceType(dwType As Long) As String

   Dim sType As String
   If (dwType And SERVICE_WIN32_OWN_PROCESS) Then sType = sType & "own proc, "
   If (dwType And SERVICE_WIN32_SHARE_PROCESS) Then sType = sType & "share, "
   If (dwType And SERVICE_KERNEL_DRIVER) Then sType = sType & "kernel, "
   If (dwType And SERVICE_FILE_SYSTEM_DRIVER) Then sType = sType & "filesys, "
   If (dwType And SERVICE_INTERACTIVE_PROCESS) Then sType = sType & "interactive"
   GetServiceType = sType

End Function

Private Function GetServiceState(dwState As Long) As String
   Select Case dwState
      Case SERVICE_STOPPED: GetServiceState = "stopped"
      Case SERVICE_START_PENDING: GetServiceState = "startpend"
      Case SERVICE_STOP_PENDING: GetServiceState = "stoppend"
      Case SERVICE_RUNNING: GetServiceState = "running"
      Case SERVICE_CONTINUE_PENDING: GetServiceState = "contpend"
      Case SERVICE_PAUSE_PENDING: GetServiceState = "pausepend"
      Case SERVICE_PAUSED: GetServiceState = "paused"
   End Select

End Function


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy


Hit Counter