获取windows内存、cpu及进程的信息
如题,想获取进程信息用于资源显示,在这个过程中遇到很多问题,看来需要了解下windows里面的东西才行。记录目前遇到的问题,不断更新直到解决。
当前机器操作系统win10,编译器2010。
头文件需要
#include<windows.h>
#include <time.h>
#include <TlHelp32.h>
#include <Psapi.h>
#include <Pdh.h>
#pragma comment(lib,"pdh.lib")
#pragma comment(lib, "Psapi.lib")
定义一些全局变量
typedef unsigned long long TimeT;
unsigned long m_nInterval;
void* m_hQuery;
void* m_hcCpuTime;
void* m_hcMemTime;
double m_dbTotalMem;
void* m_hSnapshot;
std::vector<std::string> m_vecPaths;
bool InitPDH() { PDH_STATUS status = PdhOpenQueryA(NULL, NULL, &m_hQuery); // 创建用于管理性能数据收集的新查询 if (status != ERROR_SUCCESS) { printf("PdhOpenQuery failed with status 0x%x.\n", status); return false; } // PdhAddCounterA 将指定的计数器添加到查询 status = PdhAddCounterA(m_hQuery, "\\Processor(_Total)\\% Processor Time", NULL, &m_hcCpuTime); // cpu使用率命令,所有CPU占用率,这个值在多核系统中会超过100%。包含空闲线程的CPU占用率 if (status != ERROR_SUCCESS) { printf("PdhAddCounter Processor Time failed with status 0x%x.\n", status); return false; } status = PdhAddCounterA(m_hQuery, "\\Memory\\Available MBytes", NULL, &m_hcMemTime);// 剩余的可用物理内存,单位兆字节,MB, if (status != ERROR_SUCCESS) { printf("PdhAddCounter Disk Time failed with status 0x%x.\n", status); return false; } MEMORYSTATUSEX st = { 0 }; st.dwLength = sizeof(MEMORYSTATUSEX); GlobalMemoryStatusEx(&st); m_dbTotalMem = st.ullTotalPhys / (1024.0*1024.0); // 物理内存 MB // CreateToolhelp32Snapshot // 可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。 // 用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS(在快照中包含系统中所有的进程)等 // 一个进程ID号,用来指定要获取哪一个进程的快照,当获取系统进程列表或获取当前进程快照时可以设为0 m_hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == m_hSnapshot) { printf("CreateToolhelp32Snapshot failed with status 0x%x.\n", GetLastError()); return false; } return CollectData(); }
获取cpu、内存查询
TimeT getCurrentTime() { time_t now_time = time(NULL); tm* t_tm = localtime(&now_time); printf("local time is : %s\n", asctime(t_tm)); return now_time; } float getMemTime() { PDH_FMT_COUNTERVALUE counterVal; PDH_STATUS status = PdhGetFormattedCounterValue(m_hcMemTime, PDH_FMT_DOUBLE, NULL, &counterVal); if (status == ERROR_SUCCESS) { printf("memory time is: %f\n",100.0 * (m_dbTotalMem - counterVal.doubleValue) / m_dbTotalMem); return 100.0 * (m_dbTotalMem - counterVal.doubleValue) / m_dbTotalMem; } return 0; } float getCpuTime() { PDH_FMT_COUNTERVALUE counterVal; PDH_STATUS status = PdhGetFormattedCounterValue(m_hcCpuTime, PDH_FMT_DOUBLE, NULL, &counterVal); if (status == ERROR_SUCCESS) { printf("cpu time is: %f\n",counterVal.doubleValue); return counterVal.doubleValue; } return 0; }
查当前系统内的进程,这里遇到了问题
OpenProcess 无法通过
bool CollectData() { PDH_STATUS status = PdhCollectQueryData(m_hQuery);// 收集指定查詢中所有計數器的目前原始資料值,並更新每個計數器的狀態碼。 if (status != ERROR_SUCCESS) { printf("PdhCollectQueryData failed with status 0x%x.\n", status); return false; } char path[MAX_PATH]; PROCESSENTRY32 pi = { 0 }; // 描述擷取快照集時,位於系統位址空間中的進程清單中的專案。用来存放快照进程信息的一个结构体。 pi.dwSize = sizeof(PROCESSENTRY32); // The size of the structure, in bytes. BOOL bRet = Process32First(m_hSnapshot, &pi);// Captures information about the first process encountered in the system snapshot set.指向第一个进程信息 while (bRet) { // OpenProcess来获得进程的句柄 // PROCESS_ALL_ACCESS 所有能获得的权限 ,表示所得到的进程句柄是否可以被继承, 被打开进程的PID // HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.th32ProcessID);//GetLastError 87 参数错误 // 不成功可能是没有权限SeDebugPrivilege HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 5476); // GetLastError 5 拒绝访问 int err = GetLastError(); if (hProcess) { GetModuleFileNameEx(hProcess, NULL, path, MAX_PATH); // ...... CloseHandle(hProcess); } bRet = Process32Next(m_hSnapshot, &pi); } return true; }
这里有个类型转换问题,char* 、 wchar_t* 和 string 转
把属性页里字符集原来的使用Unicode字符集去掉或换成其他的(比如使用多字节字符集,没试过)就可以如上不转类型了。
看网上应该要提升进程权限,添加如下代码
int AddPrivilege(const char *Name) { HANDLE hPro = GetCurrentProcess(); int d = GetLastError(); /* 要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过OpenProcessToken得到 BOOL OpenProcessToken( HANDLE ProcessHandle, //要修改访问权限的进程句柄; DWORD DesiredAccess, //指定你所需要的操作类型; PHANDLE TokenHandle //返回的访问令牌指针 ); 如要修改令牌我们要指定第二个参数为TOKEN_ADJUST_PRIVILEGES(其它一些参数可参考Platform SDK)。 通过这个函数我们就可以得到当前进程的访问令牌的句柄(指定函数的第一个参数为GetCurrentProcess()就可以了) */ HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken)) { #ifdef _DEBUG printf( "OpenProcessToken error.\n "); #endif return 1; } int b = GetLastError(); /* 我们要怎么样才能知道一个权限对应的LUID值是多少呢?这就要用到另外一个API函数LookupPrivilegevalue,其原形如下: BOOL LookupPrivilegevalue( LPCTSTR lpSystemName, // system name,第一个参数是系统的名称,如果是本地系统只要指明为NULL就可以了 LPCTSTR lpName, // privilege name,第二个参数就是指明了权限的名称,如“SeDebugPrivilege” PLUID lpLuid // locally unique identifier,第三个参数就是返回LUID的指针 ); */ LUID Luid; if (!LookupPrivilegeValue(NULL,Name,&Luid)) { #ifdef _DEBUG printf( "LookupPrivilegeValue error.\n "); #endif return 1; } int c = GetLastError(); TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; tp.Privileges[0].Luid = Luid; /* 可以调用AdjustTokenPrivileges对这个访问令牌进行修改。 BOOL AdjustTokenPrivileges( HANDLE TokenHandle, // handle to token ,第一个参数是访问令牌的句柄; BOOL DisableAllPrivileges, // disabling option,第二个参数决定是进行权限修改还是除能(Disable)所有权限; // 第三个参数指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,数据组的每个项指明了权限的类型和要进行的操作; PTOKEN_PRIVILEGES NewState, // privilege information // 第四个参数是结构PreviousState的长度,如果PreviousState为空,该参数应为NULL; DWORD BufferLength, // size of buffer // 第五个参数也是一个指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息,可空; PTOKEN_PRIVILEGES PreviousState, // original state buffer PDWORD ReturnLength // required buffer size,最后一个参数为实际PreviousState结构返回的大小。 ); typedef struct _TOKEN_PRIVILEGES { DWORD PrivilegeCount; // 数组原素的个数 LUID_AND_ATTRIBUTES Privileges[]; } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES; typedef struct _LUID_AND_ATTRIBUTES { // 第一个参数就是指权限的类型,是一个LUID的值,LUID就是指locally unique identifier,LUID是一个64位的值 LUID Luid; // 第二个参数就指明了我们要进行的操作类型,有三个可选项:SE_PRIVILEGE_ENABLED、SE_PRIVILEGE_ENABLED_BY_DEFAULT、SE_PRIVILEGE_USED_FOR_ACCESS。 DWORD Attributes; } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES */ DWORD dw=0; //if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) if (!AdjustTokenPrivileges(hToken, FALSE, &tp,0, (PTOKEN_PRIVILEGES)NULL, &dw)) { #ifdef _DEBUG printf( "AdjustTokenPrivileges error.\n "); #endif return 1; } //ERROR_NOT_ALL_ASSIGNED int a = GetLastError();//1300 并非所有被引用的特权都指派给呼叫方 CloseHandle(hToken); return 0; }
结果
AdjustTokenPrivileges 没有成功
根据网上内容,可能是所使用的用户不是最高权限,一番操作(如何获取win10用户最高权限-百度经验 (baidu.com))提升权限后没有变化。
读不出进程,但目前能读出cpu、内存,把上述代码移到同事的程序里,结果连cpu和内存也读不出了。。。换回原来的我自己的程序,也有问题读不出cpu了。。。
重新建了个2015编译器的新项目,把我的代码都移进去,编译看看。
int main() { InitPDH(); while (true) { Sleep(1000); CollectData(); //TimeT time = getCurrentTime(); float cpu = getCpuTime(); float memory = getMemTime(); } return 0; }
获取当前时间的函数需要再改改,主要想看看cpu和内存能不能读出来T_T
居然成功了。。。而且也没有用升权限,进程也进去了。。。
好开心,好茫然,谁能帮我解答一下为 什 么 !
另外获取时间报不安全要用_s结尾的函数,改了后仍然不好用,就不改函数了,还是原来的代码,属性里加_CRT_SECURE_NO_WARNINGS,就不报错了。
还要让服务器知道我是谁,发送本机IP,C++ 获得本机IP_51CTO博客_c++获取本机ip
头文件加
#pragma comment(lib, "ws2_32.lib")
// 获取本机IP char buf[256] = ""; struct hostent *ph = 0; WSADATA w; WSAStartup(0x0101, &w); gethostname(buf, 256); std::string hostName = buf; // 本机名称 ph = gethostbyname(buf); const char *IP = inet_ntoa(*((struct in_addr*)ph->h_addr_list[0])); // 本机IP WSACleanup();
发现如果不在取CPU前运行 CollectData() 函数,CPU就取不到。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App