获取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就取不到。

posted @   yangly  阅读(888)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示