如何在Windows上用C++实现互为看门狗的进程配对,并且不使用递归?
我正在用C++(使用MSVC)开发一个Windows控制台应用程序,并且我想实现一个互相看门狗系统。
目标:我有两个进程:MainApp.exe 和 Watchdog.exe。
- 如果
MainApp被关闭或崩溃,Watchdog应该重新启动它。 - 如果
Watchdog被终止,MainApp应该重新启动它。
问题:目前我遇到了一个“进程递归”的问题。当 MainApp 启动时,它会启动 Watchdog。之后 Watchdog 会检查 MainApp,如果它不能正确识别现有的父进程,它就会启动一个新的 MainApp 实例,而这又会启动一个新的 Watchdog,如此往复,直到耗尽系统资源。
bool ProcessGuard::IsProcessAlive(DWORD pid) {
HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (!h) return false;
DWORD exitCode;
bool alive = GetExitCodeProcess(h, &exitCode) && exitCode == STILL_ACTIVE;
CloseHandle(h);
return alive;
}
我本来想这样做,但我理解到当我的MainApp启动watchdog时,watchdog不知道mainApp的进程ID。
解决方案
实现可以如下所示(代码 请参考自)
void WaitForProcess(HANDLE hProcess, BOOL bMain);
void StartProcess(BOOL bMain)
{
if (PWSTR lpApplicationName = new WCHAR[MINSHORT])
{
GetModuleFileNameW(0, lpApplicationName, MINSHORT);
if (!GetLastError())
{
HANDLE hProcess;
STARTUPINFOEXW si = { { sizeof(si) } };
SIZE_T s = 0;
ULONG dwError;
while (ERROR_INSUFFICIENT_BUFFER == (dwError = InitializeProcThreadAttributeList(
si.lpAttributeList, 1, 0, &s) ? NOERROR : GetLastError()))
{
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(s);
}
if (NOERROR == dwError && UpdateProcThreadAttribute(si.lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &hProcess, sizeof(hProcess), 0, 0) &&
DuplicateHandle(NtCurrentProcess(), NtCurrentProcess(), NtCurrentProcess(),
&hProcess, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
PWSTR lpCommandLine = 0;
int len = 0;
while (0 < (len = _snwprintf(lpCommandLine, len, L"\n%p\r*%x*", hProcess, bMain)))
{
if (lpCommandLine)
{
PROCESS_INFORMATION pi;
if (CreateProcessW(lpApplicationName, lpCommandLine, 0, 0, TRUE,
EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi))
{
NtClose(pi.hThread);
WaitForProcess(pi.hProcess, bMain);
NtClose(pi.hProcess);
}
break;
}
lpCommandLine = (PWSTR)alloca(++len * sizeof(WCHAR));
}
NtClose(hProcess);
}
}
delete [] lpApplicationName;
}
}
VOID
NTAPI
wcb (
_Inout_ PTP_CALLBACK_INSTANCE /*Instance*/,
_Inout_opt_ PVOID Context,
_Inout_ PTP_WAIT Wait,
_In_ TP_WAIT_RESULT /*WaitResult*/
)
{
TpReleaseWait(Wait);
StartProcess((BOOL)(ULONG_PTR)Context);
}
void WaitForProcess(HANDLE hProcess, BOOL bMain)
{
PTP_WAIT Wait;
if (0 <= TpAllocWait(&Wait, wcb, (PVOID)(ULONG_PTR)bMain, 0))
{
TpSetWait(Wait, hProcess, 0);
}
}
void WINAPI ep(void*)
{
BOOL bMain = TRUE;
if (PWSTR psz = wcschr(GetCommandLineW(), '*'))
{
ULONG b = wcstoul(psz + 1, &psz, 16);
if ('*' == *psz)
{
bMain = b;
}
}
if (PWSTR psz = wcschr(GetCommandLineW(), '\n'))
{
HANDLE hProcess = (HANDLE)(ULONG_PTR)_wcstoui64(psz + 1, &psz, 16);
if ('\r' == *psz)
{
WaitForProcess(hProcess, !bMain);
NtClose(hProcess);
}
}
else
{
StartProcess(!bMain);
}
MessageBoxW(0, 0, bMain ? L"MainApp" : L"Watchdog", bMain ? MB_ICONINFORMATION : MB_ICONWARNING);
ExitProcess(0);
}
这可以通过以下方式终止:
void Assign(HANDLE hJob, DWORD pid)
{
if (HANDLE hProcess = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, pid))
{
AssignProcessToJobObject(hJob, hProcess);
CloseHandle(hProcess);
}
}
void Kill2(DWORD pid1, DWORD pid2)
{
if (HANDLE hJob = CreateJobObjectW(0, 0))
{
Assign(hJob, pid1);
Assign(hJob, pid2);
TerminateJobObject(hJob, 0);
CloseHandle(hJob);
}
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。