Enumerate NT Services
Class declaration:
class TTrixServiceInfo {
public:
CString ServiceName;
CString DisplayName;
CString BinaryPath;
DWORD ServiceType;
DWORD StartType;
DWORD ErrorControl;
DWORD CurrentState;
public:
TTrixServiceInfo();
TTrixServiceInfo& operator=(const TTrixServiceInfo& source);
CString GetServiceType(void);
CString GetStartType(void);
CString GetErrorControl(void);
CString GetCurrentState(void);
static TTrixServiceInfo *EnumServices(DWORD serviceType,
DWORD serviceState,DWORD *count);
};
Description:
Each object of this class contains information for one service. To build a list of services, execute the static function EnumServices(). There are several possibilities:
ServiceType is a bit OR combination of SERVICE_WIN32 and
SERVICE_DRIVER.
ServiceState is a bit OR combination of SERVICE_ACTIVE and SERVICE_INACTIVE.
The static function EnumServices() returns a pointer to a list of TTrixServiceInfo objects (or NULL in case of any error). The number of objects in a list is returned via a count argument. Be sure to deallocate the memory when you no longer need the list. Following is the example:
TTrixServiceInfo *lpservice = NULL;
DWORD count;
lpservice = TTrixServiceInfo::EnumServices(SERVICE_WIN32,SERVICE_ACTIVE|SERVICE_INACTIVE,&count);
if (lpservice) {
for (DWORD index = 0; index < count; index ++) {
printf("%d. %s, %s\n", index, lpservice[index].DisplayName,
lpservice[index].GetCurrentState());
}
delete [] lpservice;
}
Other member functions return a user friendly name for various status information. Notice the operator= member function. It is a good practise to implement this operator in any similar class since it makes it very easy to copy the contents of the object (in this case returned in a list) to some other application specific data structure which contains the object of the same class. For example, if your application needs also the version information about the binary file etc., you probably declare your class in the following way:
class CServiceInfo {
public:
CVersionInformation VerInfo;
TTrixServiceInfo SrvcInfo;
...
};
Now, it is easy to populate the object of this class (pseudo code with no error checking):
TTrixServiceInfo *lpservice = TTrixServiceInfo::EnumServices(....,&count); int index = findService(name,lpservice,count); myobj.SrvcInfo = lpservice[index];
Source code:
TTrixServiceInfo::TTrixServiceInfo()
{
ServiceName.Empty();
DisplayName.Empty();
BinaryPath.Empty();
ServiceType = 0;
StartType = 0;
ErrorControl = 0;
CurrentState = 0;
}
TTrixServiceInfo& TTrixServiceInfo::operator=(const TTrixServiceInfo& source)
{
ServiceName = source.ServiceName;
DisplayName = source.DisplayName;
BinaryPath = source.BinaryPath;
ServiceType = source.ServiceType;
StartType = source.StartType;
ErrorControl = source.ErrorControl;
CurrentState = source.CurrentState;
return *this;
}
CString TTrixServiceInfo::GetServiceType(void)
{
// Winnt.h
CString str = "UNKNOWN";
if (ServiceType & SERVICE_WIN32) {
if (ServiceType &
SERVICE_WIN32_OWN_PROCESS)
str = "WIN32_OWN_PROCESS";
else if (ServiceType &
SERVICE_WIN32_SHARE_PROCESS)
str = "WIN32_SHARE_PROCESS";
if (ServiceType &
SERVICE_INTERACTIVE_PROCESS)
str += "(INTERACTIVE_PROCESS)";
}
switch (ServiceType) {
case SERVICE_KERNEL_DRIVER:
str = "KERNEL_DRIVER"; break;
case SERVICE_FILE_SYSTEM_DRIVER:
str = "FILE_SYSTEM_DRIVER";
break;
};
return str;
}
CString TTrixServiceInfo::GetStartType(void)
{
// Winnt.h
TCHAR *types[] = {
"BOOT_START", // 0
"SYSTEM_START", // 1
"AUTO_START", // 2
"DEMAND_START", // 3
"DISABLED" // 4
};
return CString(types[StartType]);
}
CString TTrixServiceInfo::GetErrorControl(void)
{
// Winnt.h
TCHAR *types[] = {
"ERROR_IGNORE", // 0
"ERROR_NORMAL", // 1
"ERROR_SEVERE", // 2
"ERROR_CRITICAL" // 3
};
return CString(types[ErrorControl]);
}
CString TTrixServiceInfo::GetCurrentState(void)
{
// Winsvc.h
TCHAR *types[] = {
"UNKNOWN",
"STOPPED", // 1
"START_PENDING", // 2
"STOP_PENDING", // 3
"RUNNING", // 4
"CONTINUE_PENDING", // 5
"PAUSE_PENDING", // 6
"PAUSED" // 7
};
return CString(types[CurrentState]);
}
// ServiceType = bit OR of SERVICE_WIN32, SERVICE_DRIVER
// ServiceState = bit OR of SERVICE_ACTIVE, SERVICE_INACTIVE
TTrixServiceInfo *TTrixServiceInfo::EnumServices(DWORD serviceType,DWORD
serviceState,DWORD *count)
{
// Maybe check if serviceType and serviceState have at least one constant specified
*count = 0;
TTrixServiceInfo *info = NULL;
SC_HANDLE scman = ::OpenSCManager(NULL,NULL,SC_MANAGER_ENUMERATE_SERVICE);
if (scman) {
ENUM_SERVICE_STATUS service, *lpservice;
BOOL rc;
DWORD bytesNeeded,servicesReturned,resumeHandle = 0;
rc = ::EnumServicesStatus(scman,serviceType,serviceState,&service,sizeof(service),
&bytesNeeded,&servicesReturned,&resumeHandle);
if ((rc == FALSE) && (::GetLastError() == ERROR_MORE_DATA)) {
DWORD bytes = bytesNeeded + sizeof(ENUM_SERVICE_STATUS);
lpservice = new ENUM_SERVICE_STATUS [bytes];
::EnumServicesStatus(scman,serviceType,serviceState,lpservice,bytes,
&bytesNeeded,&servicesReturned,&resumeHandle);
*count = servicesReturned; // Not a chance that 0 services is returned
info = new TTrixServiceInfo [servicesReturned];
TCHAR Buffer[1024];
// Should be enough for service info
QUERY_SERVICE_CONFIG *lpqch = (QUERY_SERVICE_CONFIG*)Buffer;
for (DWORD ndx = 0; ndx < servicesReturned; ndx++) {
info[ndx].ServiceName = lpservice[ndx].lpServiceName;
info[ndx].DisplayName = lpservice[ndx].lpDisplayName;
info[ndx].ServiceType = lpservice[ndx].ServiceStatus.dwServiceType;
info[ndx].CurrentState = lpservice[ndx].ServiceStatus.dwCurrentState;
SC_HANDLE sh = ::OpenService(scman,lpservice[ndx].lpServiceName,SERVICE_QUERY_CONFIG);
if (::QueryServiceConfig(sh,lpqch,sizeof(Buffer),&bytesNeeded)) {
info[ndx].BinaryPath = lpqch->lpBinaryPathName;
info[ndx].StartType = lpqch->dwStartType;
info[ndx].ErrorControl = lpqch->dwErrorControl;
}
::CloseServiceHandle(sh);
}
delete [] lpservice;
}
::CloseServiceHandle(scman);
}
return info;
}
Last updated: 20 September 1998.

Comments
Support for Advaced server and 2003
Posted by Legacy on 01/29/2004 12:00amOriginally posted by: kiran napit
Does this class or API's of Service manager for enumerating support for Advanced win 2000 server and 2003
Replykiran
Integrating the source code into your project
Posted by Legacy on 11/12/1998 12:00amOriginally posted by: Thomas Blenkers
Greetings,
at first thank you to Zoran for this nice piece of work.
When it came to me to integrate the source code, I first could not compile the TTrixServiceInfo class and ran into several dozens error messages.
Yes, your (and mine) guess is right: you need some declarations. And you have to link with the import library for the "Advanced Windows 32 Base API" (advapi32.dll).
For the API calls used, you have to
#include <winsvc.h>
in the approtiate source file (e.g. TTrixServiceInfo.h).
Next go to the project settings, make sure to enable "all configurations", go to the "Linker" tab, and specify the "Object/Library-module"
advapi32.lib
After these changes, my program compiled (and ran!) flawlessly.
Thanks again to Zoran.
Thomas Blenkers
Reply