1 守护进程
1.1 需求分析
我有三个程序需要不断运行,有可能出现某些未知的原因而宕掉,需要本守护程序来进行守护,发现它运行不管,死掉就重启它,并且服务器开机就启动。
1.2 使用方法
将该程序与需要守护的程序放在同一目录。修改以下几处
- 守护的程序的绝对路径 twkWindowName_DownloadWget
- 定义守护进程名称 PROCCESS_NAME_DOWMLOADWGET
- 需要守护的程序所在的路径 PROGRAMEPATH
开发环境:
- Windows10专业版
- Visual Studio 2017 Enterprise
1.3 实现代码
/*****************************************************************************
Author: 唐维康
Date: 2020年10月05日
Code: UNICODE
description: 守护进程:查看下载+转换+维护三个程序是否因为某种原因死掉,如果死掉就重启它
开发环境: Visual Studio 2017 Enterprise 和 Windows10专业版
使用说明: PROCCESS_NAME_DOWMLOADWGET守护进程名称根据需要守护的进程修改;
twkWindowName_DownloadWget 是需要守护的程序的绝对路径
PROCCESS_NAME_MAINTENANCEPROCEDURES是需要守护的程序所在的路径 一般情况和本程序在同一目录
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <io.h>
#include <iostream>
#include <tchar.h>
//参考网站
//
//
//使用这个 TEXT 宏就可以使得程序都可以正常使用
//TEXT使路径成为Unicode字符串 必须为LPCTSTR格式,强制类型转换不行
//下面三个定义为是需要守护的程序的绝对路径
LPCTSTR twkWindowName_DownloadWget = TEXT("D:\\Desktop\\Monitor_TangWeiKang\\UpgradedMonitoringMachine_TangWeiKang\\RecordingSeparation\\code\\MP3Conversion\\Daemon\\Test01.exe");
LPCTSTR twkWindowName_MP3Conversion = TEXT("D:\\Desktop\\Monitor_TangWeiKang\\UpgradedMonitoringMachine_TangWeiKang\\RecordingSeparation\\code\\MP3Conversion\\Daemon\\Test02.exe");
LPCTSTR twkWindowName_MaintenanceProcedures = TEXT("D:\\Desktop\\Monitor_TangWeiKang\\UpgradedMonitoringMachine_TangWeiKang\\RecordingSeparation\\code\\MP3Conversion\\Daemon\\Test03.exe");
//LPCTSTR szAppWindowName = L"D:\\Desktop\\Monitor_TangWeiKang\\UpgradedMonitoringMachine_TangWeiKang\\RecordingSeparation\\code\\MP3Conversion\\Daemon\\Test01.exe";
using namespace std;
//隐藏DOS黑窗口
//#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
//定义路径最大程度
#define MAX_PATH_NUM 4096
//定义守护进程名称
#define PROCCESS_NAME_DOWMLOADWGET "Test01.exe"
#define PROCCESS_NAME_MP3CONVERSION "Test02.exe"
#define PROCCESS_NAME_MAINTENANCEPROCEDURES "Test03.exe"
//PROGRAMEPATH 是需要守护的程序所在的路径 一般情况和本程序在同一目录
#define PROGRAMEPATH "D:\\Desktop\\Monitor_TangWeiKang\\UpgradedMonitoringMachine_TangWeiKang\\RecordingSeparation\\code\\MP3Conversion\\Daemon"
//定义写入的注册表路径
#define SELFSTART_REGEDIT_PATH "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\"
BOOL SetSelfStart();
int main()
{
Notepad
获得守护的进程的句柄
HWND handle = FindWindow(NULL, szAppWindowName);
HWND handle = FindWindow(NULL, (LPCTSTR)"Notepad");
//HWND handle = FindWindow(NULL, szAppWindowName);
//if (handle != NULL)
//{
// /*MessageBox(NULL, TEXT("Application is already running"), szAppClassName, MB_ICONERROR);
// ExitProcess(1);*/
// cout << "该程序已经在运行了!" << endl;
// continue;
//}
//else
//{
// cout << "没有存在" << endl;
//}
//获取程序完整名称
char pName[MAX_PATH_NUM] = { 0 };
GetModuleFileNameA(NULL, pName, MAX_PATH_NUM);
//twk测试
/*cout << "***************" << endl;
cout << pName << endl;
cout << "***************" << endl;*/
//设置程序开机自启动
if (!SetSelfStart())
{
cout << "守护进程开机自启动失败" << endl;
return -1;
}
else
{
cout << "守护进程开机自启动成功" << endl;
}
STARTUPINFOA si;// 该结构用于指定新进程的主窗口特性
//进程对象
PROCESS_INFORMATION pi[3];
//初始化
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));//进程相关信息(句柄,标识)
//获取当前程序的路径 不用GetCurrentDirectoryA函数获取是因为开机读取了其它路径
//开机读取的路径是 pPath=C:\Windows\system32\test02.exe
char pPath_DownloadWget[MAX_PATH_NUM] = { 0 };
//GetCurrentDirectoryA(MAX_PATH_NUM, pPath_DownloadWget);
strcat(pPath_DownloadWget, PROGRAMEPATH);
char pPath_MP3Conversion[MAX_PATH_NUM] = { 0 };
//GetCurrentDirectoryA(MAX_PATH_NUM, pPath_MP3Conversion);
strcat(pPath_MP3Conversion, PROGRAMEPATH);
char pPath_MaintenanceProcedures[MAX_PATH_NUM] = { 0 };
//GetCurrentDirectoryA(MAX_PATH_NUM, pPath_MaintenanceProcedures);
strcat(pPath_MaintenanceProcedures, PROGRAMEPATH);
//拼接需要守护的程序
strcat(pPath_DownloadWget, "\\");
strcat(pPath_DownloadWget, PROCCESS_NAME_DOWMLOADWGET);
strcat(pPath_MP3Conversion, "\\");
strcat(pPath_MP3Conversion, PROCCESS_NAME_MP3CONVERSION);
strcat(pPath_MaintenanceProcedures, "\\");
strcat(pPath_MaintenanceProcedures, PROCCESS_NAME_MAINTENANCEPROCEDURES);
//cout << " pPath_MaintenanceProcedures="<<pPath_MaintenanceProcedures << endl;
//构造cmd执行守护进程的字符串
char pCmd_DownloadWget[MAX_PATH_NUM] = { 0 };
strcat(pCmd_DownloadWget,"cmd /c ");
strcat(pCmd_DownloadWget, pPath_DownloadWget);
char pCmd_MP3Conversion[MAX_PATH_NUM] = { 0 };
strcat(pCmd_MP3Conversion, "cmd /c ");
strcat(pCmd_MP3Conversion, pPath_MP3Conversion);
char pCmd_MaintenanceProcedures[MAX_PATH_NUM] = { 0 };
strcat(pCmd_MaintenanceProcedures, "cmd /c ");
strcat(pCmd_MaintenanceProcedures, pPath_MaintenanceProcedures);
//twk测试
//cout << "pPath_DownloadWget=" << pPath_DownloadWget << endl;
//char twkWindowName[MAX_PATH_NUM] = { 0 };
//strcat(twkWindowName, pPath_DownloadWget);
//LPCTSTR *twkWindowName = (LPCTSTR *)malloc(4096 * sizeof(LPCTSTR));
//sprintf(twkWindowName,"%s", (LPCTSTR)pPath_DownloadWget);
//cout << "twkWindowName=" << twkWindowName.c_str() << endl;
//cout << "szAppWindowName"<<szAppWindowName << endl;
//无限循环,监视守护进程
do {
//检查守护程序是否存在
if ((_access(pPath_DownloadWget, 0) != -1)|| (_access(pPath_MP3Conversion, 0) != -1)|| (_access(pPath_MaintenanceProcedures, 0) != -1))
{
//获得守护的进程的句柄
//HWND handle = FindWindow(NULL, szAppWindowName);
//HWND handle = FindWindow(NULL, (LPCTSTR)"Notepad");
HWND handle_DownloadWget = FindWindow(NULL, twkWindowName_DownloadWget);
//HWND handle = FindWindow(NULL, (LPCWSTR)pPath_DownloadWget);
if (handle_DownloadWget != NULL)
{
/*MessageBox(NULL, TEXT("Application is already running"), szAppClassName, MB_ICONERROR);
ExitProcess(1);*/
cout << "守护的程序DownloadWget正在运行!" << endl;
}
else
{
if (!CreateProcessA(NULL, pCmd_DownloadWget, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi[0]))
{
cout << "守护进程DownloadWget启动失败,程序即将退出" << endl;
return -1;
}
}
HWND handle_MP3Conversion = FindWindow(NULL, twkWindowName_MP3Conversion);
//HWND handle = FindWindow(NULL, (LPCWSTR)pPath_DownloadWget);
if (handle_MP3Conversion != NULL)
{
/*MessageBox(NULL, TEXT("Application is already running"), szAppClassName, MB_ICONERROR);
ExitProcess(1);*/
cout << "守护的程序MP3Conversion正在运行!" << endl;
}
else
{
if (!CreateProcessA(NULL, pCmd_MP3Conversion, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi[0]))
{
cout << "守护进程MP3Conversion启动失败,程序即将退出" << endl;
return -1;
}
}
HWND handle_MaintenanceProcedures = FindWindow(NULL, twkWindowName_MaintenanceProcedures);
//HWND handle = FindWindow(NULL, (LPCWSTR)pPath_DownloadWget);
if (handle_MaintenanceProcedures != NULL)
{
/*MessageBox(NULL, TEXT("Application is already running"), szAppClassName, MB_ICONERROR);
ExitProcess(1);*/
cout << "守护的程序MaintenanceProcedures正在运行!" << endl;
}
else
{
if (!CreateProcessA(NULL, pCmd_MaintenanceProcedures, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi[0]))
{
cout << "守护进程MaintenanceProcedures启动失败,程序即将退出" << endl;
//continue;
return -1;
}
}
for (int i = 0; i < 3; i++)
{
//启动成功,获取进程的ID
cout << "守护进程成功,ID:" << pi[i].dwProcessId << endl;
//无限等待子进程退出
WaitForSingleObject(pi[i].hProcess, INFINITE);
cout << "守护进程退出了。。。" << endl;
//关闭进程和句柄
CloseHandle(pi[i].hProcess);
CloseHandle(pi[i].hThread);
}
}
else
{
cout << "守护程序不存在" << endl;
}
//睡一下,重启
Sleep(2000);
//int a;
//a = CreateProcessA(NULL, (LPSTR)"Test01.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi[0]);
//a = CreateProcessA(NULL, (LPSTR)"Test02.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi[1]);
//a = CreateProcessA(NULL, (LPSTR)"Test03.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi[2]);
// //终止线程
for (int i = 0; i < 3; i++)
{
OpenProcess(NULL, true, pi[i].dwProcessId);
DWORD fuExitCode; // 进程的退出码
GetExitCodeProcess(pi[i].hProcess, &fuExitCode); // 获得进程的退出码
TerminateProcess(pi[i].hProcess, fuExitCode); // 终止进程
CloseHandle(pi[i].hThread);
CloseHandle(pi[i].hProcess);
}
} while (true);
return 0;
}
//设置本身开机自启动
BOOL SetSelfStart()
{
//获取程序完整名称
char pName[MAX_PATH_NUM] = { 0 };
GetModuleFileNameA(NULL, pName, MAX_PATH_NUM);
//在注册表中写入启动信息
HKEY hKey = NULL;
LONG lRet = 0;
lRet = RegOpenKeyExA(HKEY_CURRENT_USER, SELFSTART_REGEDIT_PATH, 0, KEY_ALL_ACCESS, &hKey);
//判断是否成功
if (lRet != ERROR_SUCCESS)
{
return FALSE;
}
lRet = RegSetValueExA(hKey, "Daemon", 0, REG_SZ, (const unsigned char*)pName, strlen(pName) + sizeof(char));
//判断是否成功
if (lRet != ERROR_SUCCESS)
{
return FALSE;
}
//关闭注册表
RegCloseKey(hKey);
return TRUE;
}
// 取消开机自动启动
void cancelAutoStart()
{
HKEY hKey;
string strRegPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
//1、找到系统的启动项
if (RegOpenKeyEx(HKEY_CURRENT_USER, (LPCTSTR)strRegPath.c_str(), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
{
//2、删除值
RegDeleteValue(hKey, (LPCTSTR)"GISRestart");
//3、关闭注册表
RegCloseKey(hKey);
}
}
1.4 结果显示
我用了三个程序来测试,Test01.exe Test02.exe Test03.exe 都是循环打印该进程PID,并且与守护程序放在了同一目录。
开机启动测试
界面显示系统开机程序也跟随开机。
重启程序测试
当守护程序宕掉,2秒后重启。
存在检查
如果有一个守护的程序已经运行了,就不需要管。
我们手动运行Test01.exe。界面显示Test01.exe跳过,它已经存在了。