工作缘故,需要为主程序写一个守护程序,经过查阅资料,实现了mfc框架下的简单守护程序。
一、守护程序的定义
守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程常常在系统引导装入时启动,在系统关闭时终止。Linux系统有很多守护进程,大多数服务都是通过守护进程实现的,同时,守护进程还能完成许多系统任务,例如,作业规划进程 crond、打印进程lqd等(这里的结尾字母d就是Daemon的意思)。
由于在Linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。但是守护进程却能够突破这种限制,它从被执行开始运转,直到整个系统关闭时才退出。如果想让某个进程不因为用户或终端或其他地变化而受到影响,那么就必须把这个进程变成一个守护进程。更多介绍请看(http://baike.baidu.com/link?url=85YNYYRG6cdI1TdcQd6NZghNSiKZ-A_Rh7yrDFnNq-ysF6h8w0uuQCR0XqshzmcADfDv25IxYtZ6bx5DX23QTq)。
三、实现代码
1、在OnInitDialog()函数中添加如下代码:
二、实现原理
该守护程序的原理:给系统内的所有进程拍一个快照,间隔一段时间遍历所有进程快照,如果发现主进程没有在快照内,自动启动主进程。
三、实现代码
SetLastError(0);
HANDLE g_hMutex = ::CreateMutex(NULL, FALSE, _T("Daemon"));
if (GetLastError() == ERROR_ALREADY_EXISTS){
AfxMessageBox(_T("守护程序正在运行!"), 0, MB_OK);
EndDialog(IDCANCEL);
return FALSE;
}
<span style="font-size:14px;">SetTimer(1, 1000, NULL);</span>
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)函数中添加如下代码:
<span style="font-family:Microsoft YaHei;font-size:14px;">DaemonStart(nIDEvent);</span>
四、总结
该守护程序会一直监控主程序的状态,如要在退出主程序时关闭守护程序,请在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);
}
这样,一个简单的守护程序就完成了。