windows进程监控

最近开发一个进程监控的服务,由于对windows api不熟,所以折腾了小两周才完全跑通,特记录一下

1 由于需求需要根据进程名来进行监控,所以首先要根据进程名来获取进程句柄(同名进程可能有多个,比如,起了多个notepad.exe)
//通过进程名获取进程句柄集
// 返回值为 同名进程个数(不超过20个)
int getProcessHandle(LPCWSTR lpName, HANDLE pH[20])  
{
int num = 0;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  
    if (INVALID_HANDLE_VALUE == hSnapshot)
    {  
        return 0;
    }  
    PROCESSENTRY32 pe = { sizeof(pe) };
    BOOL fOk;  
    for (fOk = Process32First(hSnapshot, &pe); fOk; fOk = Process32Next(hSnapshot, &pe))  
    {

if (!_tcsicmp(pe.szExeFile, lpName))
        {
pH[num++] = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
        }
// 同名进程超过20个,返回20个
if (num > 20)
{
num = 20;
break;
}
    }
CloseHandle(hSnapshot);
    return num;  
}

   根据进程句柄来获取程序开始运行的时间(多个同名进程里最早的一个)

               earliesttime = COleDateTime::GetCurrentTime();
for (i = 0; i < number; i++)
{
GetProcessTimes(hProcess[i], &ftCreation, &ftExit, &ftKernel, &ftUser);
if ((earliesttime - (COleDateTime(ftCreation))).GetTotalSeconds() > 0){
earliesttime = ftCreation;
}

}

   创建子线程,来监听该程序名的所有进程句柄的结束事件,将结束时间写入redis

 for (int j = 0; j < number; j++){
pDataArray[ncount]->hProcess[j] = hProcess[j];
}
pDataArray[ncount]->procname = _strdup(name);
pDataArray[ncount]->num = number;

hThreadArray[ncount] = (HANDLE)_beginthreadex(NULL, 0, &MyThreadFunction, pDataArray[ncount], 0, NULL);

unsigned int _stdcall MyThreadFunction(LPVOID lpParam)
{
char endtime[BUFFERSIZE] = "";
char buffer[BUFFERSIZE] = "";
char buff[BUFFERSIZE] = "";
HANDLE hProcess[20];
int number = 0;
int flag = 1;
DWORD nret;
redisContext* c;
COleDateTime timeCreation, timeNow;

PMYDATA  pDataArray = (PMYDATA)lpParam;

// printf("thread--------------name=[%s]-----tid=[%ld]\n", pDataArray->procname, GetCurrentThreadId());

if (pDataArray->num > 1)
{
nret = WaitForMultipleObjects(pDataArray->num, pDataArray->hProcess, TRUE, TIMEOUT);
}
else if (pDataArray->num == 1)
{
nret = WaitForSingleObject(pDataArray->hProcess[0], TIMEOUT);
}

switch (nret)
{
case WAIT_OBJECT_0:
// 所有同名进程都结束,则写endtime
number = getProcessHandle(T2W((LPTSTR)CString(pDataArray->procname).GetBuffer(NULL)), hProcess);
if (!number)
{
sprintf_s(buff, BUFFERSIZE, "%s", removeSuffix(pDataArray->procname, ".exe"));
_strlwr_s(buff, BUFFERSIZE);
timeNow = COleDateTime::GetCurrentTime();
sprintf_s(endtime, "%02d:%02d:%02d", timeNow.GetHour(), timeNow.GetMinute(), timeNow.GetSecond(), BUFFERSIZE);
sprintf_s(buffer, "rpush %s|%s|%04d-%02d-%02d endtime|%s", mac, buff, timeNow.GetYear(), timeNow.GetMonth(), timeNow.GetDay(), endtime);
                        //    将进程结束时间写入 redis
c = redisConnect(redisip, redisport);
if (c->err)
{
printf("Connect to redisServer failed:%s\n", c->errstr);
redisFree(c);
return -1;
}
if (rpushString(c, buffer))
{
printf("setString error [%s]\n", buffer);
}
redisFree(c);
}
break;
case WAIT_TIMEOUT:
// 超时,退出
;;
break;
case WAIT_ABANDONED_0:
;;
break;
case WAIT_FAILED:
// 函数调用失败,比如传递了一个无效的句柄
;;
break;
}
return 0;

}

  将监控事件做成定时事件,30秒跑一次

    timer_id = timeSetEvent(TIMEOUT+1000, 1, (LPTIMECALLBACK)onTimeFunc, DWORD(1), TIME_PERIODIC);

  套上SCManager框架,将程序做成服务,把状态传入SCManager

你可能感兴趣的:(windows开发)