一.性能计数器简介:
系统性能计数器?也许好多朋友没有用过吧!(献丑了)此物可谓功能强大,顾名思义就是可以统计 Windows 系统各项性能指标的东西。在 Windows 2000 及以上系统中,如果是默认安装就会自带性能计数器程序,大家可以在 “控制面板 -〉管理 -〉性能”中看到该程序。
Windows 系统性能计数器可以实时跟踪上百项系统性能指标,在该系统程序的绘图界面上鼠标右击,选择“添加计数器”就有可能看到所有可统计的项目。常常在论坛里看到 一些新朋友问如何自己实现 任务管理器 ,及如何实时获得每个进程的CPU使用率,内存使用...等等,那么我想使用系统性能计数器应该是最佳选择。言归正传,实现方法,请看下文。
二.具体实现:
相关API简介及事例代码:
1.PdhOpenQuery:打开计数器
PDH_STATUS pdhStatus;
HQUERY phQuery = NULL;
HCOUNTER pCounterHandle = NULL;
pdhStatus = PdhOpenQuery(0, 0, &phQuery);
if (pdhStatus != ERROR_SUCCESS) return false;
// 分配计数器句柄空间
pCounterHandle = (HCOUNTER *)GlobalAlloc(GPTR, sizeof(HCOUNTER));
if (pCounterHandle == NULL) return false;
2.PdhCloseQuery:关闭计数器
pdhStatus = PdhCloseQuery(phQuery);
if (pdhStatus != ERROR_SUCCESS) return false;
3.PdhEnumObjects:枚举计数项目,该函数有6个参数(详细请看MSDN)
原型:
PDH_STATUS PdhEnumObjects(
LPCTSTR szDataSource, // 必须为 NULL
LPCTSTR szMachineName, // 机器名,如果为本机可以为NULL
LPTSTR mszObjectList, // 接收全部可用计数项目的缓冲区
LPDWORD pcchBufferLength, // 缓冲去大小(如果为 0,则该值返回所需大小)
DWORD dwDetailLevel, // 获取信息的级别
BOOL bRefresh // 一般设置为 TRUE
);
举例:
LPTSTR lpsObjectListBuffer = NULL;
LPTSTR lpsthisObject = NULL;
DWORD dwObjectListSize = 0;
// 第一步先把缓冲去大小置为0,这样可获得所需缓冲区大小
pdhStatus = PdhEnumObjects (
NULL,
lpcsMachineName,
lpsObjectListBuffer,
&dwObjectListSize,
PERF_DETAIL_WIZARD,
TRUE);
if (pdhStatus != ERROR_SUCCESS || pdhStatus != PDH_MORE_DATA) return false;
// 得到缓冲区大小后,分配缓存区内存
lpsObjectListBuffer = (LPTSTR)malloc(dwObjectListSize + 1);
if (lpsObjectListBuffer == NULL) return false;
// 第二步在此调用枚举函数真正开始枚举计数项目
pdhStatus = PdhEnumObjects (
NULL,
lpcsMachineName,
lpsObjectListBuffer,
&dwObjectListSize,
PERF_DETAIL_WIZARD,
TRUE);
if (pdhStatus != ERROR_SUCCESS) return false;
// 保存缓冲区地址
lpsthisObject = lpsObjectListBuffer;
// 打印所有可用计数项目
for ( ; *lpsthisObject != 0 ; lpsthisObject += (lstrlen(lpsthisObject) + 1))
{
printf(lpsthisObject);
}
if (lpsObjectListBuffer)
{
free (lpsObjectListBuffer);
lpsObjectListBuffer = NULL ;
dwObjectListSize = 0;
}
4.PdhEnumObjectItems:枚举计数器及实例
原型:
PDH_STATUS PdhEnumObjectItems(
LPCTSTR szDataSource, // 必须为NULL
LPCTSTR szMachineName, // 机器名,如果为本机可以为NULL
LPCTSTR szObjectName, // 计数项目(通过PdhEnumObjects函数可获得所有可用项目)
LPTSTR mszCounterList, // 计数器缓冲区
LPDWORD pcchCounterListLength, // 计数器缓冲区大小
LPTSTR mszInstanceList, // 计数实例缓冲区
LPDWORD pcchInstanceListLength, // 计数实例缓冲区大小
DWORD dwDetailLevel, // 获取信息的级别
DWORD dwFlags // 一般设置为 TRUE
);
举例:该函数的方法同上一函数(PdhEnumObjects),具体请看MSDN或本文附带的测试工程代码
5.PdhAddCounter:添加计数器
统计感兴趣的系统信息时,必须先将对应的计数器添加进来
原型:
PDH_STATUS PdhAddCounter(
PDH_HQUERY hQuery, // 为PdhOpenQuery打开的句柄
LPCTSTR szFullCounterPath, // 计数器路径(最大长度为 PDH_MAX_COUNTER_PATH)
DWORD_PTR dwUserData, // 置为 0
PDH_HCOUNTER* phCounter // 计数器句柄空间(本文中在PdhOpenQuery函数后已分配)
);
举例:
// 已获取winlogon.exe进程的CPU使用率为例
// 通过枚举并查看计数项目说明可以知道 process 项目是和进程有关的项目
// 再通过枚举计数器和事例并查看说明可以知道 process 项目下的% Processor Time计数器是关于进程CPU使率的
// 最后在计数器事例中看到winlogon进程(表明该进程正在运行)
pdhStatus = PdhAddCounter (phQuery, "//process(winlogon)//% Processor Time", 0, pCounterHandle);
if (pdhStatus != ERROR_SUCCESS) return false;
提示:有些计数器没有实例,比如:要得到系统自启动到现在所运行的秒数,那么该计数项目为System,计数器为System Up Time,计数器实例为NULL,这时的计数器路径为"/System/System Up Time"
6.PdhCollectQueryData: 准备获取当前数据
举例:
pdhStatus = PdhCollectQueryData(phQuery);
if (pdhStatus != ERROR_SUCCESS)return false;
7.PdhGetFormattedCounterValue:得到数据
举例:
pdhStatus = PdhGetFormattedCounterValue (pCounterHandle, PDH_FMT_DOUBLE,
&dwctrType, &fmtValue);
if (pdhStatus != ERROR_SUCCESS) return false;
// PDH_FMT_DOUBLE表示返回double型数据,当然还可以返回int等类型数据,请查MSDN
// 获取下一时刻数据
pdhStatus = PdhCollectQueryData(phQuery);
if (pdhStatus != ERROR_SUCCESS)return false;
提示:pCounterHandle为PdhAddCounter得到的句柄,可以不同的pCounterHandle获得不同计数值
8.PdhRemoveCounter:移出计数器
不想获取某项计数值时,应该移出该计数器,已节省资源
举例:
if (PdhRemoveCounter(pdhCouner) != ERROR_SUCCESS) return false;
该函数参数为计数器句柄
至此,如果使用计数器实时跟踪系统信息已经讲解完毕。如还有不明白的朋友请详细察看MSDN或与
三.最后实例献上
void Main::main()
{
// http://www7a.biglobe.ne.jp/~lshen/EternalWindows/WinDevelop/PDH/PDH05.html
// http://nienie.com/~masapico/api_PdhGetCounterInfo.html
// http://nienie.com/~masapico/api_PdhExpandCounterPath.html
//建立远程IPC链接(你要对方的administrator权献的用户)
NETRESOURCE nr;
nr.dwType = RESOURCETYPE_ANY;
nr.lpLocalName = NULL;
nr.lpRemoteName = "PC211";
nr.lpProvider = NULL;
nr.dwDisplayType = RESOURCEDISPLAYTYPE_DOMAIN; //RESOURCEDISPLAYTYPE_GENERIC;//
nr.dwScope = RESOURCE_CONNECTED;
nr.lpComment = NULL;
DWORD dwRet = WNetAddConnection2(&nr,"pc211","pc211",0);
if(ERROR_SUCCESS != dwRet){
printf("WNetAddConnection2 failure : %d /n",dwRet);
return;
}
HQUERY hQuery;
HCOUNTER hCounter[10];
PDH_FMT_COUNTERVALUE FmtValue;
PdhOpenQuery(NULL, 0, &hQuery);
PdhAddCounter(hQuery, "PC211//Processor(_Total)//% Processor Time", 0, &hCounter[0]);
PdhAddCounter(hQuery, "//Memory//Available Bytes", 0, &hCounter[1]);
PdhCollectQueryData(hQuery);
for(int i=0; i<10; i++) {
Sleep(1000);
PdhCollectQueryData(hQuery);
PdhGetFormattedCounterValue(hCounter[0], PDH_FMT_DOUBLE, NULL, &FmtValue);
printf("CPU使用率: %f%%/t", FmtValue.doubleValue);
PdhGetFormattedCounterValue(hCounter[1], PDH_FMT_LONG|PDH_FMT_NOSCALE, NULL, &FmtValue);
printf("MEM使用率: %d/n", FmtValue.longValue);
}
PdhCloseQuery(hQuery);
}
全部介绍完毕,希望本文能对大家有所帮助,祝大家愉快。
不明请来电询问.QQ:9309696 Email:guofengxiang-9@163.com