windows下的守护进程C++

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>

//参考网站
//https://blog.csdn.net/jelly_chen_zo/article/details/21546245?utm_medium=distribute.pc_relevant.none-task-blog-title-2&spm=1001.2101.3001.4242
//https://blog.csdn.net/u013408061/article/details/53314327

//使用这个 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跳过,它已经存在了。

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Windows服务进程是一种在Windows操作系统下运行的后台程序,通常以服务的形式运行。而守护线程是服务进程中负责监控和处理特定任务的线程。 守护线程可以理解为服务进程中的"看门狗",它负责监视服务进程的运行状态并及时进行处理。它可以周期性地检查服务进程的状态,比如进程是否假死、内存是否泄露等。一旦发现异常情况,守护线程会及时采取相应措施来修复或重启服务进程,以确保服务的正常运行。 守护线程具有以下特点: 1. 自动修复:当服务进程出现异常时,守护线程可以根据预定的修复策略自动采取措施来修复问题。比如重新启动服务进程、释放内存或重置资源等。 2. 监控功能:守护线程通过检查服务进程的运行状态,包括内存使用情况、请求响应时间和CPU使用率等,来监控服务进程的健康状况。一旦发现异常情况,守护线程会及时发出警报并采取相应的处理措施。 3. 异常处理:守护线程可以捕获服务进程抛出的异常,并根据配置的策略进行处理。比如记录日志、发送通知或执行特定的修复任务。 4. 高可靠性:通过使用守护线程,可以提升服务进程的可靠性和稳定性。一旦服务进程出现异常或崩溃,守护线程能够迅速检测并采取措施,避免长时间的服务中断。 总的来说,守护线程在Windows服务进程中扮演着非常重要的角色,它能够确保服务的稳定运行,并及时监控和处理异常情况,提升了服务的可靠性和可用性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐维康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值