在 C++/Win32 中检测进程崩溃
Detecting a process crash in C++/Win32
我正在开发一个包含 2 个程序的软件:Qt 主 exe + OpenGL 游戏 exe
我们一开始总是使用Qt Main exe。当我们点击按钮 "start game" 时,我们执行 OpenGL 游戏 exe。没问题。
问题是有时我们在 OpenGL 游戏 exe 中发生崩溃,我们想将包含日志的崩溃报告发送到我们公司的崩溃报告邮件中。
我在 Win32 中发现了一个函数 (registerwaitforsingleobject) API 但我不知道该进程是否已崩溃:
https://docs.microsoft.com/en-gb/windows/desktop/api/winbase/nf-winbase-registerwaitforsingleobject
我只想使用 win32 api(WinXP-WinVist 到 Win10)
提前致谢
使用现成的解决方案,例如 CrashRpt http://crashrpt.sourceforge.net/。它将安装一个适当的处理程序和 report/submit 抛出异常时您需要的东西。
您可以使用 Interprocess Communications with a pipe.
定时发送消息(例如,1 秒)。如果没有响应,您几乎可以确定其他程序已崩溃。
另一种不太优雅的方法是测试日志文件,每 x 秒修改一次,其值表示 "I'm still alive, not crashed"。
假设您关心的程序有一个正常的 Windows 事件循环,检查它是否以合理及时的方式处理消息的或多或少的标准方法是使用 SendMessageTimeout
to send it a WM_NULL
消息。
程序不会对 WM_NULL
做任何响应,但是如果消息在其消息队列中停留的时间过长(您选择 "too long" 表示您何时拨打电话)。所以你发了,然后看看有没有超时。
但请注意:这仅适用于处理 Windows 消息的程序。如果它没有消息循环,它总是会超时。哦,一个程序是多线程的,一个线程可以 "crash" (例如,进入无限循环),而其他线程继续正常运行,所以定义 "crashed" 的含义并不总是那么容易。
我找到了问题的解决方案:我使用了 Win32 中的 GetExitCodeProcess 函数 API (https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess)。
这是示例代码:
int main(int argc, char** arv)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
const char * prgm = "CrashedProcess.exe";
LPSTR prgmLpstr = const_cast<LPSTR>(prgm);
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
prgmLpstr, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return -1;
}
// Wait until child process exits.
auto ret = WaitForSingleObject(pi.hProcess, INFINITE);
printf("WaitForSingleObject ret = %x\n", ret);
if (ret == WAIT_OBJECT_0)
{
printf("WaitForSingleObject ret ret == WAIT_OBJECT_0\n");
}
BOOL b = FALSE;
DWORD n = 0;
b = GetExitCodeProcess(pi.hProcess, &n);
if (n == 0xC0000005)
{
printf("Process Crashed !!!\n");
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
printf("WaitForSingleObject end\n");
return 0;
}
CrashedProcess.exe源代码:
int main()
{
int * ptr = nullptr;
*ptr = 123;
return 0;
}
我正在开发一个包含 2 个程序的软件:Qt 主 exe + OpenGL 游戏 exe
我们一开始总是使用Qt Main exe。当我们点击按钮 "start game" 时,我们执行 OpenGL 游戏 exe。没问题。
问题是有时我们在 OpenGL 游戏 exe 中发生崩溃,我们想将包含日志的崩溃报告发送到我们公司的崩溃报告邮件中。
我在 Win32 中发现了一个函数 (registerwaitforsingleobject) API 但我不知道该进程是否已崩溃: https://docs.microsoft.com/en-gb/windows/desktop/api/winbase/nf-winbase-registerwaitforsingleobject
我只想使用 win32 api(WinXP-WinVist 到 Win10)
提前致谢
使用现成的解决方案,例如 CrashRpt http://crashrpt.sourceforge.net/。它将安装一个适当的处理程序和 report/submit 抛出异常时您需要的东西。
您可以使用 Interprocess Communications with a pipe.
定时发送消息(例如,1 秒)。如果没有响应,您几乎可以确定其他程序已崩溃。
另一种不太优雅的方法是测试日志文件,每 x 秒修改一次,其值表示 "I'm still alive, not crashed"。
假设您关心的程序有一个正常的 Windows 事件循环,检查它是否以合理及时的方式处理消息的或多或少的标准方法是使用 SendMessageTimeout
to send it a WM_NULL
消息。
程序不会对 WM_NULL
做任何响应,但是如果消息在其消息队列中停留的时间过长(您选择 "too long" 表示您何时拨打电话)。所以你发了,然后看看有没有超时。
但请注意:这仅适用于处理 Windows 消息的程序。如果它没有消息循环,它总是会超时。哦,一个程序是多线程的,一个线程可以 "crash" (例如,进入无限循环),而其他线程继续正常运行,所以定义 "crashed" 的含义并不总是那么容易。
我找到了问题的解决方案:我使用了 Win32 中的 GetExitCodeProcess 函数 API (https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess)。
这是示例代码:
int main(int argc, char** arv)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
const char * prgm = "CrashedProcess.exe";
LPSTR prgmLpstr = const_cast<LPSTR>(prgm);
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
prgmLpstr, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return -1;
}
// Wait until child process exits.
auto ret = WaitForSingleObject(pi.hProcess, INFINITE);
printf("WaitForSingleObject ret = %x\n", ret);
if (ret == WAIT_OBJECT_0)
{
printf("WaitForSingleObject ret ret == WAIT_OBJECT_0\n");
}
BOOL b = FALSE;
DWORD n = 0;
b = GetExitCodeProcess(pi.hProcess, &n);
if (n == 0xC0000005)
{
printf("Process Crashed !!!\n");
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
printf("WaitForSingleObject end\n");
return 0;
}
CrashedProcess.exe源代码:
int main()
{
int * ptr = nullptr;
*ptr = 123;
return 0;
}