一,背景
一台windows电脑,只允许一个我方开发的软件,并且设置了自定义桌面的方式,也就是说没有桌面,软件一旦崩溃或者无响应,那么用户只能是重启电脑,体验很差,所以单独写一个守护进程,当主进程出现崩溃或者无响应的时候,重新启动主进程。
二,思路
1,利用进程间通信的方式,主进程和守护进程发送请求并回应请求,比如主进程向守护进程发送心跳包,守护进程收到后回应,如果守护进程约定时间内收不到,则重新启动主进程,实现方式:
(1),udp通信
(2),QtRO Qt 最新的进程间通信方式,类似linux下的dbus。
2,守护进程 定时扫码主进程是否存在,不存在则重启。
三,实现
开始利用了udp的方式进行实现,但是在运行一个第三方sdk的时候,udp会阻塞,导致守护进程以为主进程挂掉,实际主进程没有挂掉,只是慢了一些,并且不同机器,慢的时候还不一样,所以最终选择了 第二种方式,实现起来也特别简单,后期有通信需求,可以利用QtRO的方式,并且大部分函数都是依赖系统原生。
1,定时器,每隔两秒进行检查,如果进程不存在后者进程存在但是未响应,则重启启动程序。
void MainController::sl_triggered()
{
HWND hd = GetWndHwnd(const_cast<char*>("hidteacher.exe"));
bool restart = false;
if(hd==NULL){ //进程不存在或者进程未响应
restart=true;
}else{
if(IsHungAppWindow(hd)){
restart=true;
}
}
if(restart){
startApp();
}
}
#include <WinUser.h>
#include <Windows.h>
#include<iostream>
using namespace std;
typedef struct tagWNDINFO
{
DWORD dwProcessId;
HWND hWnd;
}WNDINFO, *LPWNDINFO;
BOOL MyEnumProc(HWND hWnd, LPARAM lParam)
{
DWORD dwProcId;
GetWindowThreadProcessId(hWnd, &dwProcId);
LPWNDINFO pInfo = (LPWNDINFO)lParam;
//cout << "dwProcId:" << dwProcId << " pInfo->dwProcessId:" << pInfo->dwProcessId << endl;
if (dwProcId == pInfo->dwProcessId)
{
HWND p = GetParent(hWnd);
HWND ph = GetParent(p);
if (ph != 0) {
pInfo->hWnd = ph;
return FALSE;
}
}
return TRUE;
}
HWND MainController::GetWndHwnd(char *strExeName)
{
PROCESSENTRY32 pe32;
//在使用这个结构前,先设置它的大小
pe32.dwSize = sizeof(pe32);
//给系统内所有的进程拍个快照
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return NULL;
}
//遍历进程快照,轮流显示每个进程的信息
BOOL bMore = ::Process32First(hProcessSnap, &pe32);
while (bMore)
{
char* str = QString::fromStdWString(pe32.szExeFile).toLocal8Bit().data();
if (strcmp(str, strExeName) == 0)
{
HWND game_window_hwnd = GetProcessMainWnd(pe32.th32ProcessID);
if (NULL != game_window_hwnd)
{
::CloseHandle(hProcessSnap);
return game_window_hwnd;
}
}
bMore = ::Process32Next(hProcessSnap, &pe32);
}
//不要忘记清除掉snapshot对象
::CloseHandle(hProcessSnap);
return NULL;
}
HWND MainController::GetProcessMainWnd(DWORD dwProcessId)
{
WNDINFO wi;
wi.dwProcessId = dwProcessId;
wi.hWnd = NULL;
EnumWindows(MyEnumProc, (LPARAM)&wi);
return wi.hWnd;
}
pro 文件 -》LIBS +=User32.LIB
扫码有惊喜: