系统性能计数器[Z]
FROM:http://hi.baidu.com/wlzqi/blog/item/d9782e73f4b4ba1c8701b092.html
上面的地址是专家的地址,有什么问题请那边看
一.性能计数器简介:
系统性能计数器?也许好多朋友没有用过吧!(献丑了)此物可谓功能强大,顾名思义就是可以统计 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, " 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或与
Email: 或 QQ:8573980联系。
三.最后再附带介绍一个相关API PdhGetCounterInfo,这个API与使用计数器并无关系,但是,它可以让你明白你所感兴趣的计数器的路径。既它可以得到每个计数器的项目的描述信息(可是中文的哦!)
举例:
以获取系统自启动到现在所运行的秒数为例
PDH_COUNTER_INFO pdhCounterInfo;
DWORD dwCounterBuffsize;
// 添加计数器
pdhStatus = PdhAddCounter(phQuery, " Up Time", 0, pCounterHandle);
if (pdhStatus != ERROR_SUCCESS) return false;
// 得到缓冲区大小
pdhStatus = PdhGetCounterInfo(*pCounterHandle, TRUE, &dwCounterBuffsize, NULL);
if (pdhStatus != ERROR_SUCCESS || pdhStatus != PDH_MORE_DATA) return false;
// 设置缓冲区
BYTE * byCounterBuff = (BYTE *)malloc(dwCounterBuffsize);
// 获取信息
pdhStatus = PdhGetCounterInfo (*pCounterHandle, TRUE, &dwCounterBuffsize, (PPDH_COUNTER_INFO)byCounterBuff);
if (pdhStatus != ERROR_SUCCESS) return false;
pdhCounterInfo = * (PPDH_COUNTER_INFO)byCounterBuff;
// 打印得到的信息
printf(pdhCounterInfo->szExplainText);
以上打印得信息类似:"System Up Time 指计算机自上次启动后已经运行的时间(用秒计算)。这个计数值显示启动时间和当前时间之差。"
全部介绍完毕,希望本文能对大家有所帮助,祝大家愉快。
在别处找到的一个PDH的一些关键定义
#define PDH_CSTATUS_VALID_DATA 0x0
#define PDH_CSTATUS_NEW_DATA 0x1
#define PDH_CSTATUS_NO_MACHINE 0x800007D0
#define PDH_CSTATUS_NO_INSTANCE 0x800007D1
#define PDH_MORE_DATA 0x800007D2
#define PDH_CSTATUS_ITEM_NOT_VALIDATED 0x800007D3
#define PDH_RETRY 0x800007D4
#define PDH_NO_DATA 0x800007D5
#define PDH_CALC_NEGATIVE_DENOMINATOR 0x800007D6
#define PDH_CALC_NEGATIVE_TIMEBASE 0x800007D7
#define PDH_CALC_NEGATIVE_VALUE 0x800007D8
#define PDH_DIALOG_CANCELLED 0x800007D9
#define PDH_CSTATUS_NO_OBJECT 0xC0000BB8
#define PDH_CSTATUS_NO_COUNTER 0xC0000BB9
#define PDH_CSTATUS_INVALID_DATA 0xC0000BBA
#define PDH_MEMORY_ALLOCATION_FAILURE 0xC0000BBB
#define PDH_INVALID_HANDLE 0xC0000BBC
#define PDH_INVALID_ARGUMENT 0xC0000BBD
#define PDH_FUNCTION_NOT_FOUND 0xC0000BBE
#define PDH_CSTATUS_NO_COUNTERNAME 0xC0000BBF
#define PDH_CSTATUS_BAD_COUNTERNAME 0xC0000BC0
#define PDH_INVALID_BUFFER 0xC0000BC1
#define PDH_INSUFFICIENT_BUFFER 0xC0000BC2
#define PDH_CANNOT_CONNECT_MACHINE 0xC0000BC3
#define PDH_INVALID_PATH 0xC0000BC4
#define PDH_INVALID_INSTANCE 0xC0000BC5
#define PDH_INVALID_DATA 0xC0000BC6
#define PDH_NO_DIALOG_DATA 0xC0000BC7
#define PDH_CANNOT_READ_NAME_STRINGS 0xC0000BC8