您的位置:首页 > 其它

Win32使用Psapi库枚举系统进程信息

2014-06-08 18:03 330 查看


原文地址:http://my.oschina.net/u/111188/blog/178643


一、枚举当前的所有进程(64位的程序暂时不会处理)

通过EnumProcesses得到当前所有的进程的进程ID,然后调用OpenProcess通过进程ID得到进程句柄,再调用EnumProcessModules来得到该进程的模块句柄,GetModuleBaseName通过进程模块句柄得到进程的名字,GetModuleFileNameEx通过进程模块句柄得到进程的可执行文件名。上面所有函数的参数信息,自行F1到MSDN查询。

DWORD aProcesses[1024], cbNeeded, cProcesses;
if( !::EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
{
return;
}

cProcesses = cbNeeded / sizeof(DWORD); //计算得到的进程个数
for (unsigned int i = 0; i< cProcesses; ++i)
{
ProcessInfo oneProcess;
const DWORD& processID=  aProcesses[i]; //进程ID

//通过进程ID获得进程句柄
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE, processID);
if (nullptr != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;

//目前该函数只能对32位进程进行处理
if(::EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
{
//获得进程名
TCHAR processName[MAX_PATH];
::GetModuleBaseName(hProcess, hMod, oneProcess.processName, sizeof(processName)/sizeof(TCHAR) );

//获得进程执行文件名
TCHAR moduleName[MAX_PATH];
::GetModuleFileNameEx(hProcess, hMod, oneProcess.moduleName, sizeof(moduleName)/sizeof(TCHAR));
}
CloseHandle(hProcess);
}
}



二、获取进程的内存使用信息

通过线程ID,调用OpenProcess来获得进程句柄,获得进程句柄之后调用GetProcessMemoryInfo,来取得该进程的内存使用信息
//取得进程的内存使用信息
PROCESS_MEMORY_COUNTERS processMemCounters ;
if( ::GetProcessMemoryInfo (porcessHandle, &processMemCounters, sizeof(processMemCounters) ) )
{
processMemCounters.WorkingSetSize; //当前进程的内存使用量单位是byte,该结构体的其他成员的作用请参考MSDN
}



三、获取进程的当前的线程数

通过CreateToolhelp32Snapshot来获取系统中的所有线程快照,第二个参数指定需要包含在内的进程ID,然后通过Thread32First和Thread32Next来遍历该进程快照,通过比对进程ID来确定线程归属于哪个进程。
//得到当前系统中所有线程的快照
HANDLE hSnapThread = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, processID);
if (INVALID_HANDLE_VALUE == hSnapThread)
{
return false;
}

THREADENTRY32 te32 = {sizeof(te32)};
DWORD nCount = 0;
if (Thread32First(hSnapThread, &te32))
{
//遍历当前的所有线程
do
{
//该线程所属的进程ID
if( te32.th32OwnerProcessID == processID)
{
//如果进程ID符合,线程计数加1
++nCount;
}
} while (Thread32Next(hSnapThread, &te32));
}
CloseHandle(hSnapThread);

if(nCount)
{
//nCount就是该进程的线程数
}
else
{
//如果线程数为0说明该进程已经退出
}



四、获取进程的当前CPU使用率

通过通过进程ID,调用OpenProcess来获得进程句柄,通过进程句柄,调用GetProcessTimes来得到该进程从开始到现在所使用
FILETIME createTime;
FILETIME exitTime;
FILETIME kernelTime;
FILETIME userTime;
//获取该进程从开始到现在使用的CPU时间
BOOL bRetCode = ::GetProcessTimes(porcessHandle, &createTime, &exitTime, &kernelTime, &userTime);

if (!bRetCode)
{
return false;
}
LARGE_INTEGER lgKernelTime;
lgKernelTime.HighPart = kernelTime.dwHighDateTime;
lgKernelTime.LowPart = kernelTime.dwLowDateTime;

LARGE_INTEGER lgUserTime;
lgUserTime.HighPart = userTime.dwHighDateTime;
lgUserTime.LowPart = userTime.dwLowDateTime;

//从进程启动到现在已经使用的CPU时间, 然后在一段时间后再取一次该值, 用差值除以经过的时间差,就是使用率
LARGE_INTEGER nowCPUTime;
nowCPUTime.QuadPart = (lgKernelTime.QuadPart + lgUserTime.QuadPart)/m_processStatus.numberOfProcessors;



五、自己封装的一个类

接口GetAllProcess来获取当前系统中所有的进程的信息,

OpenMonitorProcess来打开需要开始进行监控的进程,参数是需要进程ID

如果进程打开成功,则调用GetProcessStatus获取当前进程的状态信息,如果返回空则说明进程有可能已经退出。两次调用之间相隔最好大于1秒,这样才会使CPU使用率更好计算。

CloseMonitorProcess用来关闭监控进程,并清理相关资源
//ProcessMonitor.h
#pragma once
#include <windows.h>
#include <vector>

//目前只支持32位的程序 64位的程序会失败EnumProcessModules不支持64
class CProcessMonitor
{
public:
struct ProcessStatus
{
ProcessStatus()
{
memset(this, 0,sizeof(ProcessStatus));
}

DWORD processID;
HANDLE porcessHandle;

TCHAR processName[MAX_PATH];
TCHAR moduleName[MAX_PATH];
SYSTEMTIME processCreateTime;

SIZE_T nowUseMem;
SIZE_T maxUseMem;
SYSTEMTIME maxUseMemTime;

DWORD nowThreadCount;
DWORD maxThreadCount;
SYSTEMTIME maxThreadCountTime;

DWORD numberOfProcessors;
LARGE_INTEGER lastCheckCPUTime;
LARGE_INTEGER lastCPUTime;
DWORD nowCPUUse;
DWORD maxCPUUse;
SYSTEMTIME maxCPUUseTime;
};

struct ProcessInfo
{
ProcessInfo()
:processID(-1)//PID=0 是windows系统的一个固定进程
{
lstrcpyn(processName, TEXT("Unknown"), _countof(processName));
lstrcpyn(moduleName, TEXT("Unknown"), _countof(processName));
}
DWORD processID;
TCHAR processName[MAX_PATH];
TCHAR moduleName[MAX_PATH];
};
public:
CProcessMonitor(void);
~CProcessMonitor(void);

static std::vector<ProcessInfo> GetAllProcess();

bool OpenMonitorProcess(DWORD processID);
void CloseMonitorProcess();

const ProcessStatus* GetProcessStatus();

private:
bool GetMemUse();
bool GetThreadCount();
bool GetCPUUse();

private:
ProcessStatus m_processStatus;
};


//ProcessMonitro.cpp
#include "stdafx.h"
#include "ProcessMonitor.h"

#include <Psapi.h>
#pragma comment(lib,"psapi.lib")
#include <TlHelp32.h>

CProcessMonitor::CProcessMonitor(void)
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
m_processStatus.numberOfProcessors= sysInfo.dwNumberOfProcessors;
m_processStatus.numberOfProcessors= 1; //与任务管理器对比 好像是两倍  所以暂时不使用这个

//进程提权  不明觉厉 好像没效果
HANDLE hToken;
if ( OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken) )
{
TOKEN_PRIVILEGES tkp;
LookupPrivilegeValue( nullptr,SE_DEBUG_NAME,&tkp.Privileges[0].Luid );//修改进程权限
tkp.PrivilegeCount=1;
tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges( hToken,FALSE,&tkp,sizeof tkp,nullptr,nullptr );//通知系统修改进程权限
}
}

CProcessMonitor::~CProcessMonitor(void)
{
CloseMonitorProcess();
}

std::vector<CProcessMonitor::ProcessInfo> CProcessMonitor::GetAllProcess()
{

std::vector<ProcessInfo> processList;
// Get the list of process identifiers.
DWORD aProcesses[1024], cbNeeded, cProcesses;
if( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
{
return processList;
}

cProcesses = cbNeeded / sizeof(DWORD); //计算进程个数
for (unsigned int i = 0; i< cProcesses; ++i)
{
ProcessInfo oneProcess;
oneProcess.processID= aProcesses[i];

HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE, oneProcess.processID);

if (nullptr != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;
if( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
{
//取得进程名
::GetModuleBaseName(hProcess, hMod, oneProcess.processName, sizeof(oneProcess.processName)/sizeof(TCHAR) );

//取得全文件名
::GetModuleFileNameEx(hProcess, hMod, oneProcess.moduleName, sizeof(oneProcess.moduleName)/sizeof(TCHAR));

processList.push_back(oneProcess);
}
CloseHandle( hProcess );
}
}

return processList;
}

bool CProcessMonitor::OpenMonitorProcess(DWORD processID)
{
if(m_processStatus.porcessHandle)
{
return false;
}

m_processStatus.processID= processID;
m_processStatus.porcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE, processID); //获得进程句柄

if (m_processStatus.porcessHandle)
{
HMODULE hMod;
DWORD cbNeeded;
if(EnumProcessModules(m_processStatus.porcessHandle, &hMod, sizeof(hMod), &cbNeeded) ) //枚举进程模块信息
{
//取得进程名
::GetModuleBaseName(m_processStatus.porcessHandle, hMod, m_processStatus.processName, sizeof(m_processStatus.processName)/sizeof(TCHAR) );

//取得全文件名
TCHAR szModuleName[MAX_PATH] = TEXT("<unknown>");
::GetModuleFileNameEx(m_processStatus.porcessHandle, hMod, m_processStatus.moduleName, sizeof(m_processStatus.moduleName)/sizeof(TCHAR) ) ;

//获取进程创建时间  //记录当前进程的CPU使用量
FILETIME createTime;
FILETIME exitTime;
FILETIME kernelTime;
FILETIME userTime;
auto bRetCode = GetProcessTimes(m_processStatus.porcessHandle, &createTime, &exitTime, &kernelTime, &userTime);
if (bRetCode)
{
FILETIME localFileTime;
FileTimeToLocalFileTime(&createTime, &localFileTime);
FileTimeToSystemTime(&localFileTime, &m_processStatus.processCreateTime);

LARGE_INTEGER lgKernelTime;
lgKernelTime.HighPart = kernelTime.dwHighDateTime;
lgKernelTime.LowPart = kernelTime.dwLowDateTime;

LARGE_INTEGER lgUserTime;
lgUserTime.HighPart = userTime.dwHighDateTime;
lgUserTime.LowPart = userTime.dwLowDateTime;

LARGE_INTEGER nowCPUTime;
nowCPUTime.QuadPart = (lgKernelTime.QuadPart + lgUserTime.QuadPart)/m_processStatus.numberOfProcessors;

//当前的时间
LARGE_INTEGER nowCheckCPUTime;
FILETIME now;
GetSystemTimeAsFileTime(&now);
nowCheckCPUTime.HighPart= now.dwHighDateTime;
nowCheckCPUTime.LowPart= now.dwLowDateTime;

m_processStatus.lastCheckCPUTime = nowCheckCPUTime;
m_processStatus.lastCPUTime = nowCPUTime;

m_processStatus.maxCPUUseTime= m_processStatus.processCreateTime;

Sleep(1000);//GerProcess在短时间内被调用会造成错误
return true;
}
}
}

CloseMonitorProcess();
return false;
}

void CProcessMonitor::CloseMonitorProcess()
{
if(m_processStatus.porcessHandle)
{
CloseHandle(m_processStatus.porcessHandle);
m_processStatus.porcessHandle= nullptr;
}
}

bool CProcessMonitor::GetMemUse()
{
if(!m_processStatus.porcessHandle)
{
return false;
}

//取得进程的内存使用信息
PROCESS_MEMORY_COUNTERS processMemCounters ;
if( !::GetProcessMemoryInfo (m_processStatus.porcessHandle, &processMemCounters, sizeof(processMemCounters) ) )
{
return false;
}

m_processStatus.nowUseMem= processMemCounters.WorkingSetSize/1024;   //现在的内存使用量 单位是K
if(m_processStatus.nowUseMem > m_processStatus.maxUseMem)
{
m_processStatus.maxUseMem= m_processStatus.nowUseMem;
GetLocalTime(&m_processStatus.maxUseMemTime);
}
processMemCounters.PeakWorkingSetSize;  //内存使用高峰
return true;
}

bool CProcessMonitor::GetThreadCount()
{
if (!(m_processStatus.porcessHandle && m_processStatus.processID))
{
return false;
}

HANDLE hSnapThread = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, m_processStatus.processID);
if (INVALID_HANDLE_VALUE == hSnapThread)
{
return false;
}

THREADENTRY32 te32 = {sizeof(te32)};
DWORD nCount = 0;
if (Thread32First(hSnapThread, &te32))
{
do
{
if( te32.th32OwnerProcessID == m_processStatus.processID)
{
++nCount;
}
} while (Thread32Next(hSnapThread, &te32));
}
CloseHandle(hSnapThread);

if(!nCount)
{
return false;
}

m_processStatus.nowThreadCount = nCount;
if(m_processStatus.nowThreadCount > m_processStatus.maxThreadCount)
{
m_processStatus.maxThreadCount= m_processStatus.nowThreadCount;
GetLocalTime(&m_processStatus.maxThreadCountTime);
}
return true;
}

bool CProcessMonitor::GetCPUUse()
{
if(!(m_processStatus.porcessHandle && m_processStatus.numberOfProcessors))
{
return false;
}
FILETIME createTime;
FILETIME exitTime;
FILETIME kernelTime;
FILETIME userTime;
auto bRetCode = GetProcessTimes(m_processStatus.porcessHandle, &createTime, &exitTime, &kernelTime, &userTime);

if (!bRetCode)
{
return false;
}
LARGE_INTEGER lgKernelTime;
lgKernelTime.HighPart = kernelTime.dwHighDateTime;
lgKernelTime.LowPart = kernelTime.dwLowDateTime;

LARGE_INTEGER lgUserTime;
lgUserTime.HighPart = userTime.dwHighDateTime;
lgUserTime.LowPart = userTime.dwLowDateTime;

//从进程启动到现在已经使用的CPU时间, 然后在一段时间后再取一次该值, 用差值除以经过的时间差,就是使用率
LARGE_INTEGER nowCPUTime;
nowCPUTime.QuadPart = (lgKernelTime.QuadPart + lgUserTime.QuadPart)/m_processStatus.numberOfProcessors;

//当前的时间
LARGE_INTEGER nowCheckCPUTime;
FILETIME now;
GetSystemTimeAsFileTime(&now);
nowCheckCPUTime.HighPart= now.dwHighDateTime;
nowCheckCPUTime.LowPart= now.dwLowDateTime;

m_processStatus.nowCPUUse= 100*(nowCPUTime.QuadPart - m_processStatus.lastCPUTime.QuadPart)/(nowCheckCPUTime.QuadPart - m_processStatus.lastCheckCPUTime.QuadPart);

m_processStatus.lastCheckCPUTime = nowCheckCPUTime;
m_processStatus.lastCPUTime = nowCPUTime;
if(m_processStatus.nowCPUUse > m_processStatus.maxCPUUse)
{
m_processStatus.maxCPUUse= m_processStatus.nowCPUUse;
GetLocalTime(&m_processStatus.maxCPUUseTime);
}

}

const CProcessMonitor::ProcessStatus* CProcessMonitor::GetProcessStatus()
{
if( GetMemUse()
&& GetCPUUse()
&& GetThreadCount()
)
{
return &m_processStatus;
}
else
{
return nullptr;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: