in minifi_main/MiNiFiWindowsService.cpp [258:374]
bool CreateServiceTerminationThread(std::shared_ptr<minifi::core::logging::Logger> logger, HANDLE terminationEventHandle) {
// Get hService and monitor it - if service is terminated, then terminate current exe, otherwise the exe becomes unmanageable when service is restarted.
auto hService = [&logger]() -> HANDLE {
auto hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapShot) {
logger->log_error("!CreateToolhelp32Snapshot lastError {:#x}", GetLastError());
return 0;
}
auto getProcessInfo = [&logger, &hSnapShot](DWORD processId, DWORD& parentProcessId, std::string& parentProcessName) {
parentProcessId = 0;
parentProcessName.clear();
PROCESSENTRY32 procentry{};
procentry.dwSize = sizeof(procentry);
if (!Process32First(hSnapShot, &procentry)) {
logger->log_error("!Process32First lastError {:#x}", GetLastError());
return;
}
do {
if (processId == procentry.th32ProcessID) {
parentProcessId = procentry.th32ParentProcessID;
parentProcessName = procentry.szExeFile;
return;
}
} while (Process32Next(hSnapShot, &procentry));
};
// Find current process info, which contains parentProcessId.
DWORD parentProcessId{};
std::string parentProcessName;
getProcessInfo(GetCurrentProcessId(), parentProcessId, parentProcessName);
// Find parent process info (the service which started current process), which contains service name.
DWORD parentParentProcessId{};
getProcessInfo(parentProcessId, parentParentProcessId, parentProcessName);
CloseHandle(hSnapShot);
// Just in case check that service name == current process name.
char filePath[MAX_PATH];
if (!GetModuleFileName(0, filePath, _countof(filePath))) {
logger->log_error("!GetModuleFileName lastError {:#x}", GetLastError());
return 0;
}
const auto pSlash = strrchr(filePath, '\\');
if (!pSlash) {
logger->log_error("Invalid filePath {}", filePath);
return 0;
}
const std::string fileName = pSlash + 1;
if (_stricmp(fileName.c_str(), parentProcessName.c_str())) {
logger->log_error("Parent process {} != current process {}", parentProcessName.c_str(), fileName.c_str());
return 0;
}
const auto hParentProcess = OpenProcess(SYNCHRONIZE, FALSE, parentProcessId);
if (!hParentProcess) {
logger->log_error("!OpenProcess lastError {:#x}", GetLastError());
return 0;
}
return hParentProcess;
}();
if (!hService)
return false;
using ThreadInfo = std::tuple<std::shared_ptr<minifi::core::logging::Logger>, HANDLE, HANDLE>;
auto pThreadInfo = new ThreadInfo(logger, terminationEventHandle, hService);
HANDLE hThread = (HANDLE)_beginthreadex(
0, 0,
[](void* pPar) {
const auto pThreadInfo = static_cast<ThreadInfo*>(pPar);
const auto logger = std::get<0>(*pThreadInfo);
const auto terminationEventHandle = std::get<1>(*pThreadInfo);
const auto hService = std::get<2>(*pThreadInfo);
delete pThreadInfo;
HANDLE arHandle[] = { terminationEventHandle, hService };
switch (auto res = WaitForMultipleObjects(_countof(arHandle), arHandle, FALSE, INFINITE)) {
case WAIT_FAILED:
logger->log_error("!WaitForSingleObject lastError {:#x}", GetLastError());
break;
case WAIT_OBJECT_0:
logger->log_info("Service event received");
break;
case WAIT_OBJECT_0 + 1:
logger->log_info("Service is terminated");
break;
default:
logger->log_info("WaitForMultipleObjects return {}", res);
}
SignalExitProcess();
return 0U;
},
pThreadInfo,
0, 0);
if (!hThread) {
logger->log_error("!_beginthreadex lastError {:#x}", GetLastError());
delete pThreadInfo;
return false;
}
return true;
}