/******************************************************* Copyright (c) 2004 by Michel van Kerkhof, ( michel000@planet.nl http://home.wxs.nl/~wijk0550/ ) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ******************************************************* This source shows you how to use EnumServicesStatusEx *******************************************************/ #include <windows.h> #include <stdio.h> typedef enum _SC_ENUM_TYPE { SC_ENUM_PROCESS_INFO=0 } SC_ENUM_TYPE; typedef BOOL (WINAPI *pEnumServicesStatusExA)( SC_HANDLE, SC_ENUM_TYPE, DWORD, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD, LPDWORD, LPCSTR ); typedef struct _SERVICE_STATUS_PROCESS { DWORD dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint; DWORD dwProcessId; DWORD dwServiceFlags; } SERVICE_STATUS_PROCESS,*LPSERVICE_STATUS_PROCESS; typedef struct _ENUM_SERVICE_STATUS_PROCESSA { LPSTR lpServiceName; LPSTR lpDisplayName; SERVICE_STATUS_PROCESS ServiceStatusProcess; } ENUM_SERVICE_STATUS_PROCESSA,*LPENUM_SERVICE_STATUS_PROCESSA; /* Function shows all running services including process id and description lpMachineName = Name of the computer to enum the services for or NULL for the local computer */ int EnumServices(LPCTSTR lpMachineName) { pEnumServicesStatusExA fnEnumServicesStatusExA; HMODULE hAdvapi32; ENUM_SERVICE_STATUS_PROCESSA *lpServiceStatus; DWORD dwSize=0, dwNumServices=0, dwResumeHandle=0; SC_HANDLE scHandle=NULL; int iRet; void *lpBuffer=NULL; char szBuffer[1024]; try { //load advapi32.dll hAdvapi32=LoadLibrary("advapi32.dll"); if (hAdvapi32 == NULL) { throw("Could not load advapi32.dll"); } //load EnumServicesStatusExA from advapi32.dll fnEnumServicesStatusExA=(pEnumServicesStatusExA)GetProcAddress(hAdvapi32,"EnumServicesStatusExA"); if (fnEnumServicesStatusExA == NULL) { throw("Could not load EnumServicesStatusExA\n"); } /* establishes a connection to the service control manager on the specified computer if lpMachineName == NULL its the local computer */ scHandle=OpenSCManager(lpMachineName,NULL,SC_MANAGER_ALL_ACCESS); if (scHandle == NULL) { throw("Could not connect to the service control manager\n"); } do { /* First time dwResumeHandle needs to be 0 and dwSize = 0 after return it is set to the size needed normaly it will only loop 2 times first time to get size of the buffer second time to fill the allocated buffer */ iRet=fnEnumServicesStatusExA( scHandle, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_ACTIVE, (LPBYTE)lpBuffer, dwSize, &dwSize, &dwNumServices, &dwResumeHandle, 0 ); /* iRet is always 0 the first time because dwSize was 0 */ if (iRet == 0 && GetLastError() != ERROR_MORE_DATA) { throw("Error getting list with services\n"); } lpServiceStatus=(ENUM_SERVICE_STATUS_PROCESSA *)lpBuffer; //first time dwNumServices == 0 so we dont loop the first time if (dwNumServices > 0) { HKEY hKey,hSubKey; /* Connect to registry to get service description this is not needed if lpMachineName is the local computer or NULL */ if (RegConnectRegistry(lpMachineName,HKEY_LOCAL_MACHINE,&hKey) != ERROR_SUCCESS) { hKey=NULL; } for (DWORD dwCount=0;dwCount<dwNumServices;dwCount++) { printf("Pid:%i %s: %s\n", lpServiceStatus[dwCount].ServiceStatusProcess.dwProcessId, lpServiceStatus[dwCount].lpServiceName, lpServiceStatus[dwCount].lpDisplayName ); if (hKey) { //create registry string sprintf(szBuffer,"SYSTEM\\CurrentControlSet\\Services\\%s",lpServiceStatus[dwCount].lpServiceName); if (RegOpenKeyEx(hKey,szBuffer,0,KEY_QUERY_VALUE,&hSubKey) == ERROR_SUCCESS) { DWORD dwType,dwSize=sizeof(szBuffer); if (RegQueryValueEx(hSubKey,"Description",NULL,&dwType,(unsigned char *)szBuffer,&dwSize) == ERROR_SUCCESS && dwType == REG_SZ) { printf("Service description:%s\n",szBuffer); } RegCloseKey(hSubKey); } } printf("\n"); } //close the key opened by RegConnectRegistry if (hKey) RegCloseKey(hKey); } if (lpBuffer) { free(lpBuffer); lpBuffer=NULL; } if (iRet == 0) { //not all entry's returned normaly this only happens the first time we loop //allocate memory lpBuffer=malloc(dwSize); if (lpBuffer == NULL) throw("Error allocating memory for buffer"); } } while (iRet == 0); throw("End EnumServices"); } catch(char * szError) { if (scHandle) CloseServiceHandle(scHandle); if (lpBuffer) free(lpBuffer); printf("%s\n",szError); } return 0; } int main() { printf("\nEnumServicesStatusEx example\n"); printf("Refer any questions to michel000@planet.nl\n\n"); EnumServices(NULL); //enum services for the local computer return 0; }