| 67 | } |
| 68 | |
| 69 | std::unique_ptr<ServiceConfiguration> ServiceManager::GetServiceConfiguration(const std::wstring& serviceName) { |
| 70 | auto hService(OpenServiceHandle(serviceName)); |
| 71 | if (!hService) |
| 72 | return nullptr; |
| 73 | |
| 74 | DWORD needed = 0; |
| 75 | ::QueryServiceConfig(hService.get(), nullptr, 0, &needed); |
| 76 | if (needed == 0) |
| 77 | return nullptr; |
| 78 | |
| 79 | auto buffer = std::make_unique<BYTE[]>(needed); |
| 80 | auto config = reinterpret_cast<QUERY_SERVICE_CONFIG*>(buffer.get()); |
| 81 | if (!::QueryServiceConfig(hService.get(), config, needed, &needed)) |
| 82 | return nullptr; |
| 83 | |
| 84 | auto result = std::make_unique<ServiceConfiguration>(); |
| 85 | result->AccountName = config->lpServiceStartName; |
| 86 | result->DispalyName = config->lpDisplayName; |
| 87 | DWORD len; |
| 88 | if (result->AccountName.empty() && (config->dwServiceType & SERVICE_USER_SERVICE)) { |
| 89 | // user service (Windows 10+) |
| 90 | // extract LUID |
| 91 | auto pos = result->DispalyName.rfind(L'_'); |
| 92 | if (pos != std::wstring::npos) { |
| 93 | auto logonId = wcstoll(result->DispalyName.c_str() + pos + 1, nullptr, 16); |
| 94 | SERVICE_STATUS_PROCESS status; |
| 95 | if (::QueryServiceStatusEx(hService.get(), SC_STATUS_PROCESS_INFO, |
| 96 | (BYTE*)&status, sizeof(status), &needed) && status.dwProcessId > 0) { |
| 97 | wil::unique_process_handle hProcess(::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,status.dwProcessId)); |
| 98 | Token token(hProcess.get(), TokenAccessMask::Query); |
| 99 | if (token) |
| 100 | result->AccountName = token.GetUserNameAndSid().first; |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | if (result->StartType == ServiceStartType::Auto) { |
| 106 | // check if delayed auto start |
| 107 | SERVICE_DELAYED_AUTO_START_INFO info; |
| 108 | auto ok = ::QueryServiceConfig2(hService.get(), |
| 109 | SERVICE_CONFIG_DELAYED_AUTO_START_INFO,// Delayed auto start |
| 110 | (BYTE*)&info, sizeof(info), &len); |
| 111 | if (ok) |
| 112 | result->DeleayedAutoStart = info.fDelayedAutostart ? true : false; |
| 113 | else |
| 114 | result->DeleayedAutoStart = false; |
| 115 | } |
| 116 | |
| 117 | // check if trigger start |
| 118 | { |
| 119 | BYTE buffer[1 << 10]; |
| 120 | DWORD len; |
| 121 | auto ok = ::QueryServiceConfig2(hService.get(), SERVICE_CONFIG_TRIGGER_INFO, buffer, 1024, &len); |
| 122 | if (ok) { |
| 123 | auto& info = (SERVICE_TRIGGER_INFO&)*buffer; |
| 124 | result->TriggerStart = info.cTriggers > 0; |
| 125 | } |
| 126 | } |
nothing calls this directly
no test coverage detected