工作缘故,需要为主程序写一个守护程序,经过查阅资料,实现了mfc框架下的简单守护程序。
该守护程序的原理:给系统内的所有进程拍一个快照,间隔一段时间遍历所有进程快照,如果发现主进程没有在快照内,自动启动主进程。
SetLastError(0);
HANDLE g_hMutex = ::CreateMutex(NULL, FALSE, _T("Daemon"));
if (GetLastError() == ERROR_ALREADY_EXISTS){
AfxMessageBox(_T("守护程序正在运行!"), 0, MB_OK);
EndDialog(IDCANCEL);
return FALSE;
}
SetTimer(1, 1000, NULL);
2、定义一个函数用于守护进程的启动:
void CDaemonDlg::DaemonStart(UINT_PTR nIDEvent){
if(nIDEvent == 1){
//需要守护的进程路径
TCHAR FileName[MAX_PATH];
GetModuleFileName(NULL, FileName, MAX_PATH);//取得当前守护进程的路径
CString AppName = FileName;
int npos = AppName.ReverseFind('\\');
if(npos <= 0)
return ;
AppName = AppName.Left(npos);
CString strName = _T("VideoCap.exe");//需要守护的进程名
AppName = AppName + '\\' + strName;//需要守护进程的路径
//需要守护的进程路径为空
if(AppName.IsEmpty()){
g_ProLogger.TraceError("守护进程路径为空");
return;
}
//定义ProcessEntry32结构
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
// 给系统内的所有进程拍一个快照
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hProcessSnap == INVALID_HANDLE_VALUE)
return ;
//需要启动进程的标志位,当进程关闭时,该标志位为TRUE
BOOL bNeedStart = TRUE;
//遍历进程快照,轮流显示每个进程的信息
BOOL bMore = ::Process32First(hProcessSnap, &pe32);
while(bMore){
//如果该进程名在快照中存在
if(_tccmp(pe32.szExeFile, strName) == 0){
//启动标志位置FALSE
bNeedStart = FALSE;
}
bMore = ::Process32Next(hProcessSnap, &pe32);
}
::CloseHandle(hProcessSnap);
if(bNeedStart){
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = TRUE;
//启动该进程
BOOL bRet = ::CreateProcess(NULL, AppName.GetBuffer(AppName.GetLength()), NULL,NULL
,FALSE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi);
if(bRet){
::CloseHandle (pi.hThread);
::CloseHandle (pi.hProcess);
} else{
g_ProLogger.TraceError("创建进程失败");
}
}
}
}
3、在OnTimer(UINT_PTR nIDEvent)函数中添加如下代码:
DaemonStart(nIDEvent);
该守护程序会一直监控主程序的状态,如要在退出主程序时关闭守护程序,请在OnDestroy()函数中关闭守护进程。具体操作如下所示。
1、创建一个GetProcessIdByName(LPSTR szProcessname, LPDWORD lpPID)函数。
BOOL CGlobal::GetProcessIdByName(LPSTR szProcessname, LPDWORD lpPID)
{
PROCESSENTRY32 ps;
HANDLE hSnapshot;
ZeroMemory(&ps, sizeof(PROCESSENTRY32));
ps.dwSize = sizeof(PROCESSENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if (!Process32First(hSnapshot, &ps))
{
return FALSE;
}
do
{
if (lstrcmpi(ps.szExeFile, szProcessname) == 0)
{
*lpPID = ps.th32ProcessID;
CloseHandle(hSnapshot);
return TRUE;
}
} while (Process32Next(hSnapshot, &ps));
CloseHandle(hSnapshot);
return FALSE;
}
2、在OnDestroy()函数中添加如下代码:
//关闭守护程序
DWORD pid;
g_Global.GetProcessIdByName("Daemon.exe", &pid);
HANDLE hp = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE,FALSE,pid);
if(hp != NULL)
{
TerminateProcess(hp, 0);
}
这样,一个简单的守护程序就完成了。