| 1 | /*############################################################################# |
|---|
| 2 | # ENUMNTSRV.CPP |
|---|
| 3 | # |
|---|
| 4 | # SCA Software International S.A. |
|---|
| 5 | # http://www.scasoftware.com |
|---|
| 6 | # scaadmin@scasoftware.com |
|---|
| 7 | # |
|---|
| 8 | # Copyright (c) 1999 SCA Software International S.A. |
|---|
| 9 | # |
|---|
| 10 | # Date: 05.12.1999. |
|---|
| 11 | # Author: Zoran M.Todorovic |
|---|
| 12 | # |
|---|
| 13 | # This software is provided "AS IS", without a warranty of any kind. |
|---|
| 14 | # You are free to use/modify this code but leave this header intact. |
|---|
| 15 | # |
|---|
| 16 | #############################################################################*/ |
|---|
| 17 | |
|---|
| 18 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers |
|---|
| 19 | #include <windows.h> |
|---|
| 20 | #include <WinSvc.h> |
|---|
| 21 | #include "EnumNtSrv.h" |
|---|
| 22 | |
|---|
| 23 | #ifdef _DEBUG |
|---|
| 24 | //#define new DEBUG_NEW |
|---|
| 25 | #undef THIS_FILE |
|---|
| 26 | static char THIS_FILE[] = __FILE__; |
|---|
| 27 | #endif |
|---|
| 28 | |
|---|
| 29 | #define ASSERT(x) |
|---|
| 30 | |
|---|
| 31 | //============================================================================= |
|---|
| 32 | // class TNtServiceInfo |
|---|
| 33 | // |
|---|
| 34 | //============================================================================= |
|---|
| 35 | |
|---|
| 36 | TNtServiceInfo::TNtServiceInfo() |
|---|
| 37 | { |
|---|
| 38 | m_strServiceName.clear(); |
|---|
| 39 | m_strDisplayName.clear(); |
|---|
| 40 | m_strBinaryPath.clear(); |
|---|
| 41 | m_dwServiceType = 0; |
|---|
| 42 | m_dwStartType = 0; |
|---|
| 43 | m_dwErrorControl = 0; |
|---|
| 44 | m_dwCurrentState = 0; |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | TNtServiceInfo::TNtServiceInfo(const TNtServiceInfo& source) |
|---|
| 48 | { |
|---|
| 49 | *this = source; |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | TNtServiceInfo::~TNtServiceInfo() |
|---|
| 53 | { |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | TNtServiceInfo& TNtServiceInfo::operator=(const TNtServiceInfo& source) |
|---|
| 57 | { |
|---|
| 58 | m_strServiceName = source.m_strServiceName; |
|---|
| 59 | m_strDisplayName = source.m_strDisplayName; |
|---|
| 60 | m_strBinaryPath = source.m_strBinaryPath; |
|---|
| 61 | m_dwServiceType = source.m_dwServiceType; |
|---|
| 62 | m_dwStartType = source.m_dwStartType; |
|---|
| 63 | m_dwErrorControl = source.m_dwErrorControl; |
|---|
| 64 | m_dwCurrentState = source.m_dwCurrentState; |
|---|
| 65 | return *this; |
|---|
| 66 | } |
|---|
| 67 | |
|---|
| 68 | // Return a service type as a string |
|---|
| 69 | std::wstring TNtServiceInfo::GetServiceType(void) |
|---|
| 70 | { |
|---|
| 71 | std::wstring str = _T("UNKNOWN"); |
|---|
| 72 | if (m_dwServiceType & SERVICE_WIN32) { |
|---|
| 73 | if (m_dwServiceType & SERVICE_WIN32_OWN_PROCESS) |
|---|
| 74 | str = _T("WIN32_OWN_PROCESS"); |
|---|
| 75 | else if (m_dwServiceType & SERVICE_WIN32_SHARE_PROCESS) |
|---|
| 76 | str = _T("WIN32_SHARE_PROCESS"); |
|---|
| 77 | if (m_dwServiceType & SERVICE_INTERACTIVE_PROCESS) |
|---|
| 78 | str += _T(" (INTERACTIVE_PROCESS)"); |
|---|
| 79 | } |
|---|
| 80 | switch (m_dwServiceType) { |
|---|
| 81 | case SERVICE_KERNEL_DRIVER: |
|---|
| 82 | str = _T("KERNEL_DRIVER"); |
|---|
| 83 | break; |
|---|
| 84 | case SERVICE_FILE_SYSTEM_DRIVER: |
|---|
| 85 | str = _T("FILE_SYSTEM_DRIVER"); |
|---|
| 86 | break; |
|---|
| 87 | }; |
|---|
| 88 | return str; |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | // Return a service start type as a string |
|---|
| 92 | std::wstring TNtServiceInfo::GetStartType(void) |
|---|
| 93 | { |
|---|
| 94 | TCHAR *types[] = { |
|---|
| 95 | _T("BOOT_START"), // 0 |
|---|
| 96 | _T("SYSTEM_START"), // 1 |
|---|
| 97 | _T("AUTO_START"), // 2 |
|---|
| 98 | _T("DEMAND_START"), // 3 |
|---|
| 99 | _T("DISABLED") // 4 |
|---|
| 100 | }; |
|---|
| 101 | return std::wstring(types[m_dwStartType]); |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | // Return this service error control as a string |
|---|
| 105 | std::wstring TNtServiceInfo::GetErrorControl(void) |
|---|
| 106 | { |
|---|
| 107 | ASSERT(m_dwErrorControl < 4); |
|---|
| 108 | TCHAR *types[] = { |
|---|
| 109 | _T("ERROR_IGNORE"), // 0 |
|---|
| 110 | _T("ERROR_NORMAL"), // 1 |
|---|
| 111 | _T("ERROR_SEVERE"), // 2 |
|---|
| 112 | _T("ERROR_CRITICAL")// 3 |
|---|
| 113 | }; |
|---|
| 114 | return std::wstring(types[m_dwErrorControl]); |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | // Return this service current state as a string |
|---|
| 118 | std::wstring TNtServiceInfo::GetCurrentState(void) |
|---|
| 119 | { |
|---|
| 120 | ASSERT(m_dwCurrentState < 8); |
|---|
| 121 | TCHAR *types[] = { |
|---|
| 122 | _T("UNKNOWN"), |
|---|
| 123 | _T("STOPPED"), // 1 |
|---|
| 124 | _T("START_PENDING"), // 2 |
|---|
| 125 | _T("STOP_PENDING"), // 3 |
|---|
| 126 | _T("RUNNING"), // 4 |
|---|
| 127 | _T("CONTINUE_PENDING"), // 5 |
|---|
| 128 | _T("PAUSE_PENDING"), // 6 |
|---|
| 129 | _T("PAUSED") // 7 |
|---|
| 130 | }; |
|---|
| 131 | return std::wstring(types[m_dwCurrentState]); |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | // Enumerate services on this machine and return a pointer to an array of objects. |
|---|
| 135 | // Caller is responsible to delete this pointer using delete [] ... |
|---|
| 136 | // dwType = bit OR of SERVICE_WIN32, SERVICE_DRIVER |
|---|
| 137 | // dwState = bit OR of SERVICE_ACTIVE, SERVICE_INACTIVE |
|---|
| 138 | TNtServiceInfo *TNtServiceInfo::EnumServices(DWORD dwType, DWORD dwState, DWORD *pdwCount) |
|---|
| 139 | { |
|---|
| 140 | ASSERT(pdwCount != NULL); |
|---|
| 141 | // Maybe check if dwType and dwState have at least one constant specified |
|---|
| 142 | *pdwCount = 0; |
|---|
| 143 | TNtServiceInfo *info = NULL; |
|---|
| 144 | SC_HANDLE scman = ::OpenSCManager(NULL,NULL,SC_MANAGER_ENUMERATE_SERVICE); |
|---|
| 145 | if (scman) { |
|---|
| 146 | ENUM_SERVICE_STATUS service, *lpservice; |
|---|
| 147 | BOOL rc; |
|---|
| 148 | DWORD bytesNeeded,servicesReturned,resumeHandle = 0; |
|---|
| 149 | rc = ::EnumServicesStatus(scman,dwType,dwState,&service,sizeof(service), |
|---|
| 150 | &bytesNeeded,&servicesReturned,&resumeHandle); |
|---|
| 151 | if ((rc == FALSE) && (::GetLastError() == ERROR_MORE_DATA)) { |
|---|
| 152 | DWORD bytes = bytesNeeded + sizeof(ENUM_SERVICE_STATUS); |
|---|
| 153 | lpservice = new ENUM_SERVICE_STATUS [bytes]; |
|---|
| 154 | ::EnumServicesStatus(scman,dwType,dwState,lpservice,bytes, |
|---|
| 155 | &bytesNeeded,&servicesReturned,&resumeHandle); |
|---|
| 156 | *pdwCount = servicesReturned; // Not a chance that 0 services is returned |
|---|
| 157 | info = new TNtServiceInfo [servicesReturned]; |
|---|
| 158 | TCHAR Buffer[1024]; // Should be enough for service info |
|---|
| 159 | QUERY_SERVICE_CONFIG *lpqch = (QUERY_SERVICE_CONFIG*)Buffer; |
|---|
| 160 | for (DWORD ndx = 0; ndx < servicesReturned; ndx++) { |
|---|
| 161 | info[ndx].m_strServiceName = lpservice[ndx].lpServiceName; |
|---|
| 162 | info[ndx].m_strDisplayName = lpservice[ndx].lpDisplayName; |
|---|
| 163 | info[ndx].m_dwServiceType = lpservice[ndx].ServiceStatus.dwServiceType; |
|---|
| 164 | info[ndx].m_dwCurrentState = lpservice[ndx].ServiceStatus.dwCurrentState; |
|---|
| 165 | SC_HANDLE sh = ::OpenService(scman,lpservice[ndx].lpServiceName,SERVICE_QUERY_CONFIG); |
|---|
| 166 | if (::QueryServiceConfig(sh,lpqch,sizeof(Buffer),&bytesNeeded)) { |
|---|
| 167 | info[ndx].m_strBinaryPath = lpqch->lpBinaryPathName; |
|---|
| 168 | info[ndx].m_dwStartType = lpqch->dwStartType; |
|---|
| 169 | info[ndx].m_dwErrorControl = lpqch->dwErrorControl; |
|---|
| 170 | } |
|---|
| 171 | ::CloseServiceHandle(sh); |
|---|
| 172 | } |
|---|
| 173 | delete [] lpservice; |
|---|
| 174 | } |
|---|
| 175 | ::CloseServiceHandle(scman); |
|---|
| 176 | } |
|---|
| 177 | return info; |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | #define SC_BUF_LEN 4096 |
|---|
| 181 | TNtServiceInfo TNtServiceInfo::GetService(std::wstring name) |
|---|
| 182 | { |
|---|
| 183 | TNtServiceInfo info; |
|---|
| 184 | info.m_strServiceName = name; |
|---|
| 185 | SC_HANDLE scman = ::OpenSCManager(NULL,NULL,SC_MANAGER_ENUMERATE_SERVICE); |
|---|
| 186 | if (!scman) { |
|---|
| 187 | throw NTServiceException(name, _T("Could not open ServiceControl manager"), GetLastError()); |
|---|
| 188 | } |
|---|
| 189 | SC_HANDLE sh = ::OpenService(scman,name.c_str(),SERVICE_QUERY_STATUS); |
|---|
| 190 | if (!sh) { |
|---|
| 191 | DWORD bufLen = SC_BUF_LEN; |
|---|
| 192 | TCHAR *buf = new TCHAR[bufLen+1]; |
|---|
| 193 | if (GetServiceKeyName(scman, name.c_str(), buf, &bufLen) == 0) { |
|---|
| 194 | ::CloseServiceHandle(scman); |
|---|
| 195 | throw NTServiceException(name, _T("GetServiceKeyName: Could not translate service name"), GetLastError()); |
|---|
| 196 | } |
|---|
| 197 | /* |
|---|
| 198 | Why does this not work? (a bug in the API? says it should return the correct size?) |
|---|
| 199 | if (bufLen >= SC_BUF_LEN) { |
|---|
| 200 | ::CloseServiceHandle(scman); |
|---|
| 201 | throw NTServiceException(name, "Service name to long to handle", GetLastError()); |
|---|
| 202 | } |
|---|
| 203 | buf[bufLen] = 0; |
|---|
| 204 | */ |
|---|
| 205 | sh = ::OpenService(scman,buf,SERVICE_QUERY_STATUS); |
|---|
| 206 | if (sh == NULL) { |
|---|
| 207 | ::CloseServiceHandle(scman); |
|---|
| 208 | throw NTServiceException(name, _T("OpenService: Could not open Service"), GetLastError()); |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | SERVICE_STATUS state; |
|---|
| 212 | if (::QueryServiceStatus(sh, &state)) { |
|---|
| 213 | info.m_dwCurrentState = state.dwCurrentState; |
|---|
| 214 | info.m_dwServiceType = state.dwServiceType; |
|---|
| 215 | } else { |
|---|
| 216 | ::CloseServiceHandle(sh); |
|---|
| 217 | ::CloseServiceHandle(scman); |
|---|
| 218 | throw NTServiceException(name, _T("QueryServiceStatus: Could not query service status"), GetLastError()); |
|---|
| 219 | } |
|---|
| 220 | // TODO: Get more info here |
|---|
| 221 | ::CloseServiceHandle(sh); |
|---|
| 222 | ::CloseServiceHandle(scman); |
|---|
| 223 | return info; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | |
|---|
| 227 | // Enumerate services on this machine and return an STL list of service objects |
|---|
| 228 | // dwType = bit OR of SERVICE_WIN32, SERVICE_DRIVER |
|---|
| 229 | // dwState = bit OR of SERVICE_ACTIVE, SERVICE_INACTIVE |
|---|
| 230 | void TNtServiceInfo::EnumServices(DWORD dwType, DWORD dwState, TNtServiceInfoList *pList) |
|---|
| 231 | { |
|---|
| 232 | ASSERT(pList != NULL); |
|---|
| 233 | TNtServiceInfo *pSrvList = NULL; |
|---|
| 234 | DWORD dwCount = 0; |
|---|
| 235 | pSrvList = TNtServiceInfo::EnumServices(dwType, dwState, &dwCount); |
|---|
| 236 | for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex ++) { |
|---|
| 237 | pList->insert(pList->end(), pSrvList[dwIndex]); |
|---|
| 238 | } |
|---|
| 239 | delete [] pSrvList; |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | /*############################################################################# |
|---|
| 243 | # End of file ENUMNTSRV.CPP |
|---|
| 244 | #############################################################################*/ |
|---|