views:

306

answers:

2

I'm trying to write a program in C, that can detect when some Windows services (aka. NT services) are started or stopped.

There seems to be a function NotifyServiceStatusChange, but that's only available on Vista and Windows 7. I'm trying to do this on Win XP, so what's the best way? Is there any other than continuous polling?

edit:

Is anybody able to give answer in C? I'm also ok with C++, but I'd like to stay away from scripting.

+1  A: 

Looks like the closest you can get in XP is QueryServiceStatusEx (single service) or EnumServicesStatusEx (multiple services).

To avoid repeatedly calling either of these, some recommend a WMI setup, querying Win32_Service's state property. See the bottom of this thread for more details.

The following is a (basic) WMI script to monitor the alerter service's status:

strComputer = "."
Set objSWbemServices = GetObject("winmgmts:" &_
    "{impersonationLevel=impersonate}!" &_
    "\\" & strComputer & "\root\cimv2")

Set objEventSource = objSWbemServices.ExecNotificationQuery( _
    "SELECT * FROM __InstanceModificationEvent " &_
    "WITHIN 10 " &_
    "WHERE TargetInstance " &_
    "ISA 'Win32_Service' " &_
    "AND TargetInstance.Name = 'alerter'")

Set objEventObject = objEventSource.NextEvent()
Wscript.Echo "The status of the alerter service just changed."

The above, and additional examples, may be found on this TechNet page.

pianoman
A: 

You will need to do it by polling. Place the code in a separate thread and send it to sleep for as long as reasonable. Say every second, perhaps even 5 seconds to minimize system performance.

As a 'c' example for a single service:

// various handles and strings plus... SERVICE_STATUS ssStatus; ...

    schSCManager = OpenSCManager( ServiceComputerNameStr,
                                  NULL,
                                  SC_MANAGER_ALL_ACCESS );
    if ( schSCManager == NULL )
        {
//        ...  error stuff  
        goto cleanup;
        }

    scphService = OpenService( schSCManager,
                               ServiceNameStr,
//                               SERVICE_QUERY_STATUS );
                               SERVICE_ALL_ACCESS );
    if ( scphService == NULL )
        {
//        ... error stuff  
        goto cleanup;
        }

    if ( !QueryServiceStatus(scphService, ssStatus) )
        {
//        ... error stuff  
        goto cleanup;
        }

The result you want will be in the ssStatus.dwCurrentState.

David L Morris