Miscellaneous Service Control Program Functions

[Previous] [Next]

Windows offers just a few more service control functions. I'd like to mention them briefly to complete our discussion.

One function looks up a service's display name from its internal name:

 BOOL GetServiceDisplayName(    SC_HANDLE hSCManager,     PCTSTR    pszServiceName,    PTSTR     pszDisplayName,    PDWORD    pdwChars); 

And another function does the reverse:

 BOOL GetServiceKeyName(    SC_HANDLE hSCManager,     PCTSTR    pszDisplayName,    PTSTR     pszServiceName,    PDWORD    pdwChars); 

The parameters passed to these functions should be self-explanatory, so I won't go into them here. See the Platform SDK documentation for more information.

The EnumServicesStatusEx function asks the SCM to enumerate all the services (and their states) contained in the database:

 BOOL EnumServicesStatusEx(    SC_HANDLE    hSCManager,    SC_ENUM_TYPE InfoLevel,    DWORD        dwServiceType,    DWORD        dwServiceState,    PBYTE        pbServices,    DWORD        dwBufSize,    PDWORD       pdwBytesNeeded,    PDWORD       pdwServicesReturned,    PDWORD       pdwResumeHandle,    PCTSTR       pszGroupName);  

The Services snap-in calls this function to populate its list of installed services. The first parameter, hSCManager, identifies the SCM whose services you wish to enumerate. The second parameter, InfoLevel, must be SC_ENUM_PROCESS_INFO, which tells the function that you wish to retrieve the name and service status for each service. Currently no other valid values exist for the InfoLevel parameter.

The third parameter, dwServiceType, tells the function to enumerate services or device drivers. For services, pass SERVICE_WIN32. The fourth parameter, dwServiceState, allows you to fine-tune your request. You can pass SERVICE_ACTIVE, SERVICE_INACTIVE, or SERVICE_STATE_ALL to enumerate running services, stopped services, or both. The last parameter, pszGroupName, allows you to fine-tune the set of returned services or device drivers even more. If pszGroupName identifies a group, only services that are part of the specified group are enumerated. If pszGroupName identifies an empty string (""), services that are not part of any group are enumerated. Finally, if pszGroupName is NULL, all services are enumerated.

All the remaining parameters are concerned with the buffer that gets the returned data. When you call EnumServicesStatusEx, you pass it a buffer that will be filled with an array of ENUM_SERVICE_STATUS_PROCESS structures that look like this:

 typedef struct _ENUM_SERVICE_STATUS_PROCESS {    LPTSTR                 lpServiceName;    LPTSTR                 lpDisplayName;    SERVICE_STATUS_PROCESS ServiceStatusProcess; } ENUM_SERVICE_STATUS_PROCESS, *LPENUM_SERVICE_STATUS_PROCESS;  

Because each service has string data associated with it, the string data is copied to the end of the buffer. The fixed-size ENUM_SERVICE_ STATUS_PROCESS structures are contiguous at the beginning of the buffer, so you can easily iterate through the returned data structures. When the function returns, the DWORD pointed to by pdwServicesReturned contains the number of ENUM_SERVICE_STATUS_PROCESS structures that fit into the buffer.

The first time you call EnumServicesStatusEx, make sure that the DWORD pointed to by pdwResumeHandle is initialized to 0. This pdwResumeHandle is used in cases in which there is more data than your buffer can hold. If the buffer is too small, EnumServicesStatusEx fills this DWORD with a special value that it uses the next time you call EnumServicesStatusEx so that it knows where to continue the enumeration. The following code shows how to allocate a buffer that is large enough to hold all the service data so that multiple calls to EnumServicesStatusEx are not necessary:

DWORD dwBytesNeeded, dwServicesReturned, dwResumeHandle = 0; EnumServicesStatusEx(hSCManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,    SERVICE_STATE_ALL, NULL, 0, &dwBytesNeeded,     &dwServicesReturned, &dwResumeHandle, NULL); ENUM_SERVICE_STATUS_PROCESS* pessp =    (ENUM_SERVICE_STATUS_PROCESS*) _alloca(dwBytesNeeded); EnumServicesStatusEx(hSCManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,    SERVICE_STATE_ALL, (PBYTE) pessp, dwBytesNeeded, &dwBytesNeeded,    &dwServicesReturned, &dwResumeHandle, NULL); for (DWORD dw = 0; dw < dwServicesReturned; dw++) {    // Refer to the members inside pessp, for example    _tprintf(TEXT("%s\n"), pessp[dw].lpDisplayName); } 

NOTE
For the sake of clarity, the preceding code does not have any error checking. In particular, the call to _alloca could raise a stack overflow exception. Structured exception handling (SEH) is required to recover from this exception gracefully and without the service terminating. Using SEH in this code is particularly important because some machines running Windows 2000 Advanced Server and Windows 2000 Data Center might have well over 200 services installed on them.

The next function that I'll discuss allows you to determine which services depend on another service:

 BOOL EnumDependentServices(    SC_HANDLE            hService,     DWORD                dwServiceState,    ENUM_SERVICE_STATUS* pess,    DWORD                dwBufSize,    PDWORD               pdwBytesNeeded,     PDWORD               pdwServicesReturned); 

This function is similar to EnumServicesStatusEx, so all of its parameters should be self-explanatory. The Services snap-in calls this function if you try to stop a service on which other services depend. For example, if I try to stop the Workstation service, I get the dialog box shown in Figure 4-1—EnumDependentServices was used to fill in the list of dependent services.

Many developers call EnumDependentServices recursively to get each service's dependent services. Doing so is not necessary because the SCM performs the recursion for you while processing the EnumDependentServices function. The set of services returned by this function is the complete set; your SCP application should simply iterate through the set to stop each of the services if desired.

Figure 4-1. The dialog box displayed when an attempt is made to stop a service that has running dependent services

Finally we come to the last two service control functions, QueryServiceObjectSecurity and SetServiceObjectSecurity:

 BOOL QueryServiceObjectSecurity(    SC_HANDLE            hService,    SECURITY_INFORMATION dwSecurityInformation,    PSECURITY_DESCRIPTOR psd,    DWORD                dwBufSize,    PDWORD               pdwBytesNeeded); BOOL SetServiceObjectSecurity(    SC_HANDLE            hService,    SECURITY_INFORMATION dwSecurityInformation,    PSECURITY_DESCRIPTOR psd); 

These two functions allow you to query and change a security descriptor associated with a service. These functions are rarely called because the default security placed on the service when CreateService is called is sufficient for most needs. See Chapter 10 for more discussion of security descriptors and related topics.



Programming Server-Side Applications for Microsoft Windows 2000
Programming Server-Side Applications for Microsoft Windows 2000 (Microsoft Programming)
ISBN: 0735607532
EAN: 2147483647
Year: 2000
Pages: 126

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net