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

原文地址: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;
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值