Make sure your network's vital services are functioning properly

Developers build 32-bit applications for Windows NT networks on an infrastructure of NT services. Each service provides functionality at a system level or at a level that is available to other computers on the network. Examples of services that NT Server runs include the Computer Browser, Windows Internet Naming Service (WINS), remote procedure call (RPC), FTP, and SQL Server services.

Applications from Microsoft and third-party vendors rely on NT services to function properly. When an NT service stops running, its failure affects all the applications and users that depend on the service, reducing the users' capacity to work. Therefore, the sooner a developer or administrator learns about a service's failure, the better off everyone is.

You can interactively view and manage your local system's services using the Control Panel Services applet, but the applet doesn't let you view remote systems' services. Server Manager (which comes with NT Server and is available in all versions of Microsoft Windows NT Server Resource Kit) solves the remote management problem, but neither program produces warnings when a service fails.

To receive warnings when services on remote systems fail, you need the Services Monitor program that I build in this article. Services Monitor lists the domains and computers within your LAN or WAN, lets you choose services you want to monitor on any NT servers on the network, and alerts you when selected services fail.

Using Services Monitor
When you start Services Monitor, the program builds a tree-view display that contains an expandable icon for each domain and server in your network, as Screen 1, page 188, shows. If your network is large or widely distributed across a WAN, the tree-building process can take 30 minutes or more, depending on your network speed and the size of your WAN. If you expand the icon for a domain, Services Monitor builds a list of services for each server in that domain. You can alter Services Monitor to build the list of services at the same time you build the lists of domains and servers, but querying every server about its services increases your startup time considerably--an unnecessary inconvenience if you want to monitor services on only a few systems on the network.

Services Monitor uses Visual Basic's (VB's) Tree View control to list the domains, systems, and services on your network. You expand a domain icon to view the systems in the domain and expand a system icon to view the services that the system runs. Services Monitor displays a check box next to services that are running. You double-click a service's check box to instruct Services Monitor to monitor that service. NT services that aren't running are not available for monitoring. Services Monitor displays a red No Service circular icon next to each stopped service.

Services Monitor periodically polls the status of the services you select for monitoring. You use the Polling Interval text box to set the polling interval; polling intervals can range from 10 seconds to 60 seconds.

Services Monitor also lets you select the action that you want NT to perform when a monitored service stops. Services Monitor lets you set the program to produce a beep or play a .wav file on the machine where Services Monitor is running.

After you select monitoring options, click Start Polling to start Services Monitor. The program places an icon in the right corner of your taskbar and begins periodically polling services. You can right-click the Services Monitor icon to view the status of monitored services. The Show Service Statuses window, which Screen 2 shows, will appear. The window displays a stoplight icon next to each monitored service. When a service is active, its stoplight icon shows a green light; when a service stops, its stoplight icon shows a red light.

Inside Services Monitor
Services Monitor's core functionality rests on two types of Win32 APIs. The program uses the Windows Networking (WNet) APIs in mpr.dll to list the networked domains and servers. Then it uses the Windows Service Control Manager (SCM) APIs from advapi32.dll to poll the status of services running on local and remote NT systems. To make these APIs easy to reuse in other applications, I encapsulated them in VB classes. (For more information about the networking and service classes that Services Monitor uses, see the sidebar "Classes for Networking and Services.")

Retrieving Domain and Server Names
When Services Monitor starts, it uses the WNetOpenEnum API to open a network enumeration, then uses the WNetEnumResource API to traverse the enumeration. Services Monitor uses the com-bination of the WNetOpenEnum and WNetEnumResource functions to reveal a domain's hierarchy of resources.

When you start Services Monitor, the WNetOpenEnum function opens the network provider level, and the WNetEnumResource function lists the network's providers, such as Microsoft Windows Network, Novell NetWare, or Banyan Vines. At the next level, Services Monitor uses the WNetOpenEnum and WNetEnumResource functions to reveal the domains in the Microsoft Windows Network. The enumeration level beneath the domains lists each of the domains' networked computers that is running a server service and sharing resources on the network. This list of each domain's servers can include machines running NT Workstation, NT Server, Windows for Workgroups (WFW), Windows 95, and LAN Manager servers, but Services Monitor can monitor services only on the NT systems.

Listing 1, page 190, shows sample code that uses the WNetOpenEnum and WNetEnumResource functions. At callout A, Listing 1 contains the WNetOpenEnum function, which takes five parameters. The first parameter sets the scope of the enumeration. The value RESOURCE_GLOBALNET tells the WNetEnumResource function to display all the resources on the network. The second parameter specifies the type of network resources the WNetEnumResource function needs to list. The value RESOURCETYPE_ANY tells the function to include disk and printing resources. The third parameter further specifies the type of resource the WNetEnumResource function needs to return. The value 0 tells the function to return local and networked resources. The fourth parameter is the most critical. It is a structure that sets the level of the enumeration (i.e., network provider, domain, or server). The NETRESOURCE structure Services Monitor uses in parameter four is

As Long
As Long
As Long
As Long
As String
As String
As String
As String
End Type

You place the string Microsoft Windows Network in the lpProvider member of the NETRESOURCE structure to start Services Monitor's enumeration process. The WNetEnumResource function fills in the other structure values after it starts enumeration. The dwScope, dwType, and dwUsage members of the NETRESOURCE structure define the same information as the first three WNetOpenEnum parameters. The dwDisplayType member provides additional information about a resource's type; it reports whether network resources are domains, servers, or shares. The lpLocalName member contains the names of any remapped local devices. The lpRemoteName member contains the name of the network resource, and lpComment contains a description of the resource. The WNetOpenEnum function uses its fifth parameter to return an enumeration handle that the WNetEnumResource function uses in subsequent calls.

At B, Listing 1 calls the WNetEnumResource function to enumerate the network resources. The WNetEnumResource function takes four parameters. The first parameter is the handle that the WNetOpenEnum function returns. The second parameter identifies the number of entries the WNetEnumResource function needs to return per call. The third parameter is a buffer that contains the NETRESOURCE structure that the WNetEnumResource function returns. The fourth parameter specifies the size of the third parameter's buffer.

The NETRESOURCE structure that the WNetEnumResource function returns is a pointer. Listing 1's CopyMemory function copies the NETRESOURCE information from the buffer pointer into a structure so that Services Monitor can use the information in VB.

At C, Listing 1 uses the dwDisplayType member of the NETRESOURCE structure to determine whether the resource is a domain, server, or shared disk or printer. A VB Select statement then adds the structure information to the collection for that type of resource. If the NETRESOURCE structure contains domain information, the Select statement uses the structure information to create a new CDomain object, then passes the structure information as a parameter to the CDomain object's Init function. If the NETRESOURCE structure contains server information, the Select statement creates a CServer object and passes the structure information to the CServer class Init function. Services Monitor uses the CDomain and CServer objects to display resource information in the tree view. At D, Listing 1 uses the WNetCloseEnum function to close the enumeration.

The same NETRESOURCE structures that Services Monitor uses to represent domains can enumerate servers, the children of domains. After the WNetEnumResource function enumerates a resource, the third parameter in the calling list passes a pointer that identifies the NETRESOURCE structure to the WNetOpenEnum function. The pointer tells the WNetOpenEnum function to move to the next level of the hierarchy and open an enumeration for the resource's children. Services Monitor uses the same functions and structures to enumerate every level of the network resource hierarchy, so the WNetOpenEnum and WNetEnumResource routines must be common code that works for all the hierarchy's levels.

Listing Services
The NT SCM subsystem starts automatically when a system boots. The SCM reads information from a database in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services Registry key about two types of services: installed services, such as the SQL Server or Workstation services, and driver services, such as 4mmDAT and Atdisk (kernel and file system drivers). This Registry key contains information about each service's security context, where its executable is, whether it starts automatically or manually, whether its failure is critical to the system, and the names of other services it depends on. Services Monitor monitors only installed services, but you can alter the code to also monitor driver services.

When a user expands a domain, Services Monitor retrieves a list of installed services from every server in the domain. Listing 2 shows the code that obtains the list of installed services for each remote server.

At A, Listing 2 uses the OpenSCManager API call to list a machine's services. The OpenSCManager function takes three parameters. The first parameter contains the server name that the WNetEnumResource function returns in Listing 1. The second parameter is a string that identifies the services database for Services Monitor to open. The value "ServicesActive" tells the OpenSCManager function to open the database of active services. The third parameter specifies the type of permissions Services Monitor needs to access the target machine's SCM database; the value SC_MANAGER_ENUMERATE_SERVICE defines the access rights that Services Monitor needs. When the OpenSCManager function completes, it returns a handle that the EnumServicesStatus function uses to create a buffer of ENUM_SERVICE_STATUS structures.

At B, Listing 2 shows the EnumServicesStatus function, which takes eight parameters. The first parameter is the handle the OpenSCManager function returns. The second parameter is a constant that specifies the type of services the EnumServicesStatus function needs to poll. The value SERVICE_WIN32 tells the function to list installed services rather than driver services. The third parameter further specifies the type of services the function returns. The value SERVICE_STATE_ALL tells EnumServicesStatus to list both active and inactive services.

The fourth parameter is the buffer in which EnumServicesStatus places an array of the ENUM_SERVICE_STATUS structures the function returns. The ENUM_SERVICE_STATUS structure is

As Long
As Long
End Type

The ENUM_SERVICE_STATUS structure's members identify the service's name, the name Services Monitor will display for the service, and a nested structure called SERVICE_STATUS that contains information about the service's current status.

The fifth EnumServicesStatus parameter defines the size in bytes of the fourth parameter's buffer. The sixth parameter returns the number of bytes the buffer needs to hold the array of ENUM_SERVICE_STATUS structures. Services Monitor allocates a buffer size of 16KB, which is larger than necessary in most cases. The seventh parameter contains the number of services the EnumServicesStatus function returns. The eighth parameter tells Services Monitor how far down the target SCM database's list of services to start enumerating services. This value needs to be 0.

When the EnumServicesStatus function call completes, it returns a new value in the eighth parameter. If the function places a 0 in the eighth parameter, the buffer is large enough to enumerate all the target machine's services. If the function returns a non-zero value in the eighth parameter, the call failed, and you need to check the value of the VB Err object's LastDLLError property. If your computer's last DLL error is ERROR_MORE_DATA, the EnumServicesStatus buffer is too small, and the eighth parameter's value identifies the entry in the SCM database's services list where Services Monitor needs to resume enumeration when the buffer has space for the remaining data. When Services Monitor encounters the ERROR_MORE_DATA error, it increases the size of the buffer and tries the EnumServicesStatus call again. Services Monitor continues to try the EnumServicesStatus function call until the buffer is large enough and the call completes successfully or the call returns an error other than ERROR_MORE_DATA. Any other LastDLLError entry indicates that a more serious error prevents Services Monitor from enumerating services; if it encounters an error other than ERROR_MORE_DATA, Services Monitor exits.

At C, Listing 2 processes the array of ENUM_SERVICE_STATUS structures that the EnumServicesStatus function returns and creates a CService object for each service the EnumServicesStatus function adds to the colServices collection. As Services Monitor processes the arrays, it uses the Tree View control to display each server's list of services and each service's status. At D, Listing 2 uses the CloseServiceHandle function to close the handle to the SCM database.

Updating Services' Status
When the Services Monitor's polling timer expires, the application queries the status of each selected service using the QueryServiceStatus API. Listing 3, page 193, shows the code that queries services' status.

At A, Listing 3 uses the OpenSCManager function to connect to the SCM database. The value SC_MANAGER_CONNECT in OpenSCManager's third parameter tells the function to open a connection.

At B, the OpenService function uses the handle that the OpenSCManager function returns to acquire a handle to a service. The OpenService function takes three parameters. The first parameter is the handle to the SCM database that the OpenSCManager function returns. The second parameter is the service's short name. The third parameter is a constant that specifies the permission level the SCM operation needs. The value SERVICE_QUERY_STATUS gives the OpenService function permission to return the service's status.

At C, Listing 3 uses the QueryServiceStatus function to retrieve the service's current status. The QueryServiceStatus function takes two parameters. The first parameter is the service handle that the OpenService function returns, and the second parameter is a structure that contains the service's current status. At D, Listing 3 uses the CloseServiceHandle function to close the handles to the SCM database and the service.

Services Monitor's Functionality
This article uses the WNet and SCM APIs to build a Services Monitor application. You can immediately put this utility to work on your network or customize the code to fit your needs. Services Monitor provides a display and alarm when a service fails, but you can modify the code to perform other actions, such as send email or attempt to restart the failed service.

NT 5.0 will include another method for querying the status of services on networked systems: Active Directory Services. Nevertheless, Services Monitor offers service monitoring functionality, and the WNet and SCM APIs will continue to support NT users for the foreseeable future.